1. Go to this page and download the library: Download wappcode/gqlpdss library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
wappcode / gqlpdss example snippets
return [
// Configuración específica del módulo
'version' => '1.0.0',
'description' => 'Módulo principal de la aplicación'
];
namespace AppModule;
use AppModule\Entities\User;
use DateTime;
use GPDCore\Contracts\AppContextInterface;
use GPDCore\Core\AbstractModule;
use GPDCore\Graphql\ResolverFactory;
use GPDCore\Graphql\ResolverPipelineFactory;
class AppModule extends AbstractModule
{
/**
* Configuración del módulo
*/
public function getConfig(): array
{
return 'factories' => [],
'aliases' => []
];
}
/**
* Tipos GraphQL personalizados
*/
public function getTypes(): array
{
return [];
}
/**
* Middlewares HTTP del módulo
*/
public function getMiddlewares(): array
{
return [];
}
/**
* Rutas REST del módulo (opcional)
*/
public function getRoutes(): array
{
return [];
}
/**
* Resolvers GraphQL del módulo
*/
public function getResolvers(): array
{
// Middleware de ejemplo
$proxyEcho1 = fn($resolver) => fn($root, $args, $context, $info) =>
'Proxy 1 ' . $resolver($root, $args, $context, $info);
$proxyEcho2 = fn($resolver) => fn($root, $args, $context, $info) =>
'Proxy 2 ' . $resolver($root, $args, $context, $info);
$echoResolve = fn($root, $args, $context, $info) => $args['msg'];
return [
// Resolver simple
'Query::showDate' => fn($root, $args, AppContextInterface $context, $info) => new DateTime(),
'Query::echo' => $echoResolve,
// Resolvers con middleware pipeline
'Query::echoProxy' => ResolverPipelineFactory::createPipeline($echoResolve, [
ResolverPipelineFactory::createWrapper($proxyEcho1),
]),
'Query::echoProxies' => ResolverPipelineFactory::createPipeline($echoResolve, [
ResolverPipelineFactory::createWrapper($proxyEcho2),
ResolverPipelineFactory::createWrapper($proxyEcho1),
]),
// Resolvers CRUD automáticos usando ResolverFactory
'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 adicionales (opcional)
*/
public function getQueryFields(): array
{
return [];
}
}
return [
// Configuración general de la aplicación
'app' => [
'name' => 'Mi API GraphQL',
'version' => '1.0.0',
'debug' => false
],
];
use AppModule\AppModule;
use GPDCore\Contracts\AppContextInterface;
use GPDCore\Core\AppConfig;
use GPDCore\Core\Application;
use GPDCore\Factory\EntityManagerFactory;
use GraphqlModule\GraphqlModule;
use Laminas\Diactoros\ServerRequestFactory;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
use Laminas\ServiceManager\ServiceManager;
$masterConfig);
// Inicializar ServiceManager
$serviceManager = new ServiceManager();
// Crear EntityManager
$entityManagerOptions = file_exists($configFile) ? ; // Módulo principal
// Ejecutar aplicación y emitir respuesta
$response = $app->run($request);
$emitter = new SapiEmitter();
$emitter->emit($response);
// Aplicación en la raíz del dominio → baseHref no es necesario
// https://midominio.com/api → ruta interna: /api
$app = new Application($config, $entityManager, $environment);
// Aplicación en una subcarpeta → baseHref es obligatorio
// https://midominio.com/mi-app/api → ruta interna: /api
$app = new Application($config, $entityManager, $environment, '/mi-app/public');
use GPDCore\Factory\EntityManagerFactory;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
neORMModule";
$entityManager = EntityManagerFactory::createInstance($options, $cacheDir, true);
return ConsoleRunner::createHelperSet($entityManager);
namespace AppModule\Entities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use PDSSUtilities\AbstractEntityModelUlid;
#[ORM\Entity()]
#[ORM\Table(name: 'users')]
class User extends AbstractEntityModelUlid
{
#[ORM\Column(type: 'string', length: 255)]
private string $name;
#[ORM\Column(type: 'string', length: 255)]
private string $email;
#[ORM\JoinTable(name: 'users_accounts')]
#[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: false)]
#[ORM\InverseJoinColumn(name: 'account_code', referencedColumnName: 'code', nullable: false)]
#[ORM\ManyToMany(targetEntity: Account::class)]
private Collection $accounts;
#[ORM\OneToMany(targetEntity: Post::class, mappedBy: 'user')]
private Collection $posts;
public function __construct()
{
parent::__construct();
$this->accounts = new ArrayCollection();
$this->posts = new ArrayCollection();
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function getAccounts(): Collection
{
return $this->accounts;
}
public function getPosts(): Collection
{
return $this->posts;
}
}
namespace AppModule;
use AppModule\Controllers\IndexController;
use GPDCore\Core\AbstractModule;
use GPDCore\Routing\RouteModel;
class AppModule extends AbstractModule
{
public function getRoutes(): array
{
return [
// Ruta simple
new RouteModel('GET', '/index/{id:.+}', IndexController::class),
// Más rutas
new RouteModel('POST', '/users', UserController::class),
new RouteModel('GET', '/users/{id:\d+}', UserDetailController::class),
new RouteModel('PUT', '/users/{id:\d+}', UserUpdateController::class),
new RouteModel('DELETE', '/users/{id:\d+}', UserDeleteController::class),
];
}
}
namespace AppModule\Controllers;
use GPDCore\Routing\AbstractAppController;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class IndexController extends AbstractAppController
{
public function dispatch(ServerRequestInterface $request): ResponseInterface
{
// Obtener parámetros de ruta
$id = $this->getRouteParam("id");
// Obtener query parameters (?key=value)
$queryParams = $request->getQueryParams();
$specificParam = $queryParams["queryParams"] ?? "";
// Obtener el body del request (POST/PUT)
$body = $request->getParsedBody();
// Obtener headers
$headers = $request->getHeaders();
$authHeader = $request->getHeaderLine('Authorization');
// Crear respuesta JSON
return $this->jsonResponse([
'success' => true,
'data' => [
'id' => $id,
'queryParams' => $specificParam,
'message' => 'Procesado correctamente'
]
], 200);
}
}
// Obtener parámetros de ruta
$this->getRouteParam("id");
$this->getRouteParam("slug");
// Crear respuesta JSON
$this->jsonResponse(['data' => $result], 200);
// Crear respuesta de error
$this->jsonResponse(['error' => 'Not found'], 404);
// Acceder al EntityManager
$entityManager = $this->getEntityManager();
// Acceder al ServiceManager
$serviceManager = $this->getServiceManager();
// Acceder al contexto de la aplicación
$context = $this->getAppContext();
public function getRoutes(): array
{
return [
new RouteModel('GET', '/api/users', UserListController::class),
new RouteModel('GET', '/api/users/{id:\d+}', UserDetailController::class),
new RouteModel('POST', '/api/users', UserCreateController::class),
new RouteModel('PUT', '/api/users/{id:\d+}', UserUpdateController::class),
new RouteModel('DELETE', '/api/users/{id:\d+}', UserDeleteController::class),
];
}
use GPDCore\DataLoaders\EntityDataLoader;
$userDataLoader = new EntityDataLoader(User::class, $entityManager);
// En el módulo
'Post::author' => ResolverFactory::forEntity($userDataLoader, 'author')
'User::posts' => ResolverFactory::forCollection(User::class, 'posts', Post::class)
'User::activePosts' => ResolverFactory::forCollection(
User::class,
'posts',
Post::class,
new class implements QueryModifierInterface {
public function modify(QueryBuilder $qb, array $args): QueryBuilder {
return $qb->andWhere('target.status = :status')
->setParameter('status', 'published');
}
}
)
// Middleware de ejemplo
$authMiddleware = fn($resolver) => fn($root, $args, $context, $info) => {
if (!$context->isAuthenticated()) {
throw new UnauthorizedException('Authentication ver($root, $args, $context, $info);
$duration = microtime(true) - $startTime;
error_log("Resolver {$info->fieldName} executed in {$duration}s");
return $result;
};
// Aplicar middlewares (se ejecutan en orden inverso)
'Query::protectedData' => ResolverPipelineFactory::createPipeline($baseResolver, [
ResolverPipelineFactory::createWrapper($loggingMiddleware),
ResolverPipelineFactory::createWrapper($authMiddleware),
])
use GPDCore\Graphql\ResolverFactory;
use GPDCore\Graphql\ResolverPipelineFactory;
use GPDCore\Graphql\ResolverTransactionMiddlewareFactory;
'Mutation::createUser' => ResolverPipelineFactory::createPipeline(
ResolverFactory::forCreate(User::class),
[
ResolverTransactionMiddlewareFactory::createMiddleware(),
]
),
'Mutation::createUser' => ResolverPipelineFactory::createPipeline(
ResolverFactory::forCreate(User::class),
[
// 3° en ejecutarse (más interno, justo antes del resolver): autorización
ResolverPipelineFactory::createWrapper($authMiddleware),
// 2° en ejecutarse: validación
ResolverPipelineFactory::createWrapper($validationMiddleware),
// 1° en ejecutarse (más externo): envuelve toda la operación dentro de la transacción
ResolverTransactionMiddlewareFactory::createMiddleware(),
]
),
public function getTypes(): array
{
return [
DateType::NAME => DateType::class,
DateTimeType::NAME => DateTimeType::class,
JSONData::NAME => JSONData::class,
// Tus tipos personalizados
'MyCustomType' => MyCustomType::class,
];
}
// Evita el problema N+1
class UserResolvers
{
private EntityDataLoader $userDataLoader;
public function __construct(EntityManager $em)
{
$this->userDataLoader = new EntityDataLoader(User::class, $em);
}
public static function getPostsAuthorResolver(): callable
{
return ResolverFactory::forEntity($this->userDataLoader, 'author');
}
}
use GPDCore\Exceptions\GQLException;
'Query::sensitiveData' => function($root, $args, AppContextInterface $context, $info) {
try {
if (!$context->getCurrentUser()) {
throw new GQLException('Not authenticated', 'UNAUTHENTICATED');
}
if (!$context->getCurrentUser()->hasRole('admin')) {
throw new GQLException('Insufficient permissions', 'FORBIDDEN');
}
return $this->getSensitiveData();
} catch (\Exception $e) {
throw new GQLException(
'Failed to fetch sensitive data: ' . $e->getMessage(),
'INTERNAL_ERROR'
);
}
}