wappcode / gqlpdss
Utilidades para crear una api GraphQL
Installs: 289
Dependents: 5
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/wappcode/gqlpdss
Requires
- php: >7.1
- doctrine/annotations: ^1.13
- doctrine/dbal: 3.1.4
- doctrine/orm: ^2.10.2
- ecodev/graphql-doctrine: ^7.1
- laminas/laminas-servicemanager: ^3.7
- nikic/fast-route: ^1.3
- symfony/cache: ^5.3
- symfony/yaml: 2.*
- wappcode/pdss-utilities: ^3.2
- webonyx/graphql-php: ^14.11
Requires (Dev)
- dev-master
- 4.1.1
- 4.1.0
- 4.0.2
- 3.0.2
- 3.0.0
- 2.2.0
- 2.1.4
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.28
- 2.0.27
- 2.0.26
- 2.0.25
- 2.0.24
- 2.0.23
- 2.0.22
- 2.0.21
- 2.0.20
- 2.0.19
- 2.0.18
- 2.0.17
- 2.0.16
- 2.0.15
- 2.0.14
- 2.0.12
- 2.0.11
- 2.0.10
- 2.0.8
- 2.0.7
- 2.0.6
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- dev-dev
- dev-5.0.0-SNAPSHOT
- dev-V4-SNAPSHOT
- dev-devTest
- dev-docs
This package is not auto-updated.
Last update: 2026-02-06 16:23:03 UTC
README
Ingresa al siguiente link para más información. Quick Start
Intalar
Usar Composer
Ejecutar
./composer.phar init
Agregar al archivo composer.json las referencias a la libreria
{
"name": "name/project",
"type": "project",
"require": {
"wappcode/gqlpdss": "^2.0.0"
},
}
Ejecutar
./composer.phar install
Crear estructura de directorios
config
data
modules
public
Crear módulo principal AppModule en la carpeta modules
Crear la siguiente estructura de directorios
modules
AppModule
config
module.config.php
schema.graphql (opcional)
src
AppModule.php
Entities
Graphql
Resolvers*.php (opcional, para organizar resolvers)
Services
Crear archivo modules/AppModule/config/module.config.php
<?php return [ // Configuración específica del módulo ];
Agregar el archivo modules/AppModule/src/AppModule.php
<?php namespace AppModule; use GPDCore\Core\AbstractModule; use GPDCore\Graphql\ResolverFactory; use GPDCore\Contracts\AppContextInterface; class AppModule extends AbstractModule { /** * Array con la configuración del módulo. */ public function getConfig(): array { return require __DIR__ . '/../config/module.config.php'; } /** * Schema GraphQL del módulo */ public function getSchema(): string { $schema = @file_get_contents(__DIR__ . '/../config/schema.graphql'); return $schema ?: ''; } /** * Servicios del módulo para ServiceManager. */ public function getServices(): array { return [ 'invokables' => [], 'factories' => [], 'aliases' => [] ]; } /** * Tipos GraphQL personalizados del módulo. */ public function getTypes(): array { return []; } /** * Middlewares HTTP del módulo. */ public function getMiddlewares(): array { return []; } /** * Resolvers GraphQL del módulo. * * @return array array(string $key => callable $resolver) */ public function getResolvers(): array { return [ // Ejemplo de resolver simple 'Query::echo' => fn($root, $args, AppContextInterface $context, $info) => $args['message'], // Ejemplo usando ResolverFactory para CRUD // 'Query::getUsers' => ResolverFactory::forConnection(User::class), // 'Query::getUser' => ResolverFactory::forItem(User::class), // 'Mutation::createUser' => ResolverFactory::forCreate(User::class), // 'Mutation::updateUser' => ResolverFactory::forUpdate(User::class), // 'Mutation::deleteUser' => ResolverFactory::forDelete(User::class), ]; } /** * Campos Query definidos programáticamente (opcional). * Nota: Preferible usar schema.graphql + getResolvers() */ public function getQueryFields(): array { return []; } /** * Campos Mutation definidos programáticamente (opcional). * Nota: Preferible usar schema.graphql + getResolvers() */ public function getMutationFields(): array { return []; } }
Agregar al archivo composer.json el siguiente código
"autoload": {
"psr-4": {
"AppModule\\": "modules/AppModule/src/"
}
}
Ejecutar ./composer.phar dump-autoload -o
Crear un archivo de configuración maestro
config/master.config.php
<?php return [ // Configuración general de la aplicación ];
Crear un archivo para configuración local (no versionado)
config/local.config.php (opcional)
<?php return [ // Configuración local que sobreescribe master.config.php ];
Crear un archivo public/index.php con el siguiente contenido
<?php use AppModule\AppModule; use GPDCore\Factory\EntityManagerFactory; use GPDCore\Core\AppConfig; use GPDCore\Core\Application; use GPDCore\Contracts\AppContextInterface; use Laminas\Diactoros\ServerRequestFactory; use Laminas\HttpHandlerRunner\Emitter\SapiEmitter; use Laminas\ServiceManager\ServiceManager; require_once __DIR__ . '/../vendor/autoload.php'; // Configuración $configFile = __DIR__ . '/../config/doctrine.local.php'; $cacheDir = __DIR__ . '/../data/DoctrineORMModule'; $enviroment = getenv('APP_ENV') ?: 'development'; $masterConfig = require __DIR__ . '/../config/master.config.php'; // Inicializar ServiceManager y Config $serviceManager = new ServiceManager(); $config = AppConfig::getInstance()->setMasterConfig($masterConfig); // Crear EntityManager $options = file_exists($configFile) ? require $configFile : []; $isDevMode = $enviroment !== AppContextInterface::ENV_PRODUCTION; $entityManager = EntityManagerFactory::createInstance($options, $cacheDir, $isDevMode); // Crear Request PSR-7 $request = ServerRequestFactory::fromGlobals(); // Crear y configurar Application $app = new Application($config, $entityManager, $enviroment); $app->addModule(AppModule::class); // Ejecutar aplicación y emitir respuesta $response = $app->run($request); $emitter = new SapiEmitter(); $emitter->emit($response);
Agregar archivo config/doctrine.entities.php con el siguiente contenido
<?php
return [
"AppModule\Entities" => __DIR__."/../modules/AppModule/src/Entities",
];
Agregar archivo config/doctrine.local.php con el siguiente contenido
<?php
return [
"driver"=> [
'user' => '',
'password' => '',
'dbname' => '',
'driver' => 'pdo_mysql',
'host' => '127.0.0.1',
'charset' => 'utf8mb4'
],
"entities"=> require __DIR__."/doctrine.entities.php"
];
Crear archivo cli-config.php con el siguiente código
<?php
use GPDCore\Factory\EntityManagerFactory;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
require_once __DIR__."/vendor/autoload.php";
$options = require __DIR__."/config/doctrine.local.php";
$cacheDir = __DIR__ . "/data/DoctrineORMModule";
$entityManager = EntityManagerFactory::createInstance($options, $cacheDir, true, '');
return ConsoleRunner::createHelperSet($entityManager);
Crear entities en AppModule
Crear archivo modules/AppModule/src/Entities/Post.php
<?php
declare(strict_types=1);
namespace GraphQLTests\Doctrine\Blog\Model;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
use GPDCore\Entities\AbstractEntityModel;
/**
*
* @ORM\Entity
*
*/
final class Post extends AbstractEntityModel
{
const STATUS_PRIVATE = 'private';
const STATUS_PUBLIC = 'public';
/**
* @var string
*
* @ORM\Column(type="string", length=50, options={"default" = ""})
*/
private $title = '';
/**
* @var string
*
* @ORM\Column(type="text")
*/
private $body = '';
/**
* @var DateTimeImmutable
*
* @ORM\Column(type="datetime_immutable")
*/
private $publicationDate;
/**
* @var string
*
* @ORM\Column(type="string", options={"default" = Post::STATUS_PRIVATE})
*/
private $status = self::STATUS_PRIVATE;
/**
*
* @return string
*/
public function getTitle(): string
{
return $this->title;
}
/**
*
* @param string $title
*
* @return self
*/
public function setTitle(string $title)
{
$this->title = $title;
return $this;
}
/**
*
* @return string
*/
public function getBody(): string
{
return $this->body;
}
/**
*
* @param string $body
*
* @return self
*/
public function setBody(string $body)
{
$this->body = $body;
return $this;
}
/**
*
* @return DateTimeImmutable
*/
public function getPublicationDate(): DateTimeImmutable
{
return $this->publicationDate;
}
/**
*
* @param DateTimeImmutable $publicationDate
*
* @return self
*/
public function setPublicationDate(DateTimeImmutable $publicationDate)
{
$this->publicationDate = $publicationDate;
return $this;
}
/**
*
* @return string
*/
public function getStatus()
{
return $this->status;
}
/**
*
* @param string $status
*
* @return self
*/
public function setStatus(string $status)
{
$this->status = $status;
return $this;
}
}
Actualizar archivo doctrine.entities.php con la ubicación de las entidades
return [
"AppModule\Entities" => __DIR__."/../modules/AppModule/src/Entities",
]
Ejecutar el siguiente comando para generar el código SQL para actualizar la base de datos
./vendor/bin/doctrine orm:schema-tool:update --dump-sql
O Ejecutar el siguiente comando para actualizar la base de datos
./vendor/bin/doctrine orm:schema-tool:update --force
NOTA: Estos comandos no deben ser utilizados en producción
Iniciar con el comándo
php -S localhost:8000 public/index.php
Para consultar api Graphql la ruta es http://localhost:8000/api
API
ConnectionTypeFactory
Clase que genera tipos connection para consultas de listas con paginación
Metodos
createConnectionType (\GraphQL\Type\Definition\ObjectType $type, string $name, string $description): \GraphQL\Type\Definition\ObjectType
Crea un tipo connection con los siguientes campos
{
totalCount: int!
pageInfo: PaginationInput {
hasPreviousPage: bool!
hasNextPage: bool!
startCursor: string!
endCursor: string!
},
edges: [EdgeType]! {
cursor: string!,
node: ObjectType!
}
}
createEdgeType(\GraphQL\Type\Definition\ObjectType $nodeType): \GraphQL\Type\Definition\ObjectType
Crea un tipo Edge
{
cursor: string!,
node: ObjectType!
}
ResolverFactory
Clase que facilita la creación de resolvers para operaciones CRUD comunes con Doctrine ORM.
Métodos principales
forConnection(string $entityClass, ?QueryModifierInterface $queryModifier = null): callable
Crea un resolver para consultas paginadas siguiendo el estándar Relay Connection.
'Query::getUsers' => ResolverFactory::forConnection(User::class)
forItem(string $entityClass): callable
Crea un resolver para obtener un único elemento por ID.
'Query::getUser' => ResolverFactory::forItem(User::class)
forCreate(string $entityClass): callable
Crea un resolver para operaciones de creación.
'Mutation::createUser' => ResolverFactory::forCreate(User::class)
forUpdate(string $entityClass): callable
Crea un resolver para operaciones de actualización.
'Mutation::updateUser' => ResolverFactory::forUpdate(User::class)
forDelete(string $entityClass): callable
Crea un resolver para operaciones de eliminación.
'Mutation::deleteUser' => ResolverFactory::forDelete(User::class)
forEntity(DataLoaderInterface $dataLoader, string $fieldName): callable
Crea un resolver para relaciones many-to-one usando DataLoader (prevención N+1).
$buffer = new EntityDataLoader(User::class, $entityManager); 'Post::author' => ResolverFactory::forEntity($buffer, 'author')
forCollection(string $entityClass, string $fieldName, string $targetEntity, ?QueryModifierInterface $queryModifier = null): callable
Crea un resolver para relaciones one-to-many usando DataLoader.
'User::posts' => ResolverFactory::forCollection(User::class, 'posts', Post::class)
ResolverMiddleware
Permite aplicar middleware a resolvers GraphQL para agregar lógica transversal (autenticación, logging, etc.).
Métodos
wrap(callable $resolver, ResolverPipelineHandlerInterface|callable|null $middleware): callable
Envuelve un resolver con un middleware.
$authMiddleware = fn($next) => fn($root, $args, $context, $info) => { if (!$context->isAuthenticated()) { throw new UnauthorizedException(); } return $next($root, $args, $context, $info); }; 'Query::protected' => ResolverMiddleware::wrap($resolver, $authMiddleware)
chain(callable $resolver, array $middlewares): callable
Aplica múltiples middlewares en secuencia.
'Query::echo' => ResolverMiddleware::chain($echoResolver, [ $authMiddleware, $loggingMiddleware, $cachingMiddleware ])
MiddlewareCallable
Clase para crear middlewares reutilizables que implementan ResolverPipelineHandlerInterface.
use GPDCore\Graphql\MiddlewareCallable; $authMiddleware = MiddlewareCallable::create(function(callable $next) { return function($root, $args, $context, $info) use ($next) { // Lógica antes $result = $next($root, $args, $context, $info); // Lógica después return $result; }; });