PHPackages                             fedorgrecha/php-graphql-projection - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. fedorgrecha/php-graphql-projection

ActiveLibrary[API Development](/categories/api)

fedorgrecha/php-graphql-projection
==================================

GraphQL projections generator for Laravel

0.1.1(7mo ago)42MITPHPPHP ^8.2

Since Oct 9Pushed 7mo ago1 watchersCompare

[ Source](https://github.com/fedorgrecha/php-graphql-projection)[ Packagist](https://packagist.org/packages/fedorgrecha/php-graphql-projection)[ RSS](/packages/fedorgrecha-php-graphql-projection/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (2)Versions (3)Used By (0)

GraphQL Projection Generator for Laravel
========================================

[](#graphql-projection-generator-for-laravel)

A PHP library for generating type-safe GraphQL queries and projections for Laravel applications. Build GraphQL requests with full IDE autocomplete, type safety, and a fluent interface.

Installation
------------

[](#installation)

Install via Composer:

```
composer require --dev fedorgrecha/php-graphql-projection
```

Publish configuration:

```
php artisan vendor:publish --tag=config-graphql-projection
```

Configuration
-------------

[](#configuration)

Configure in `config/graphql-projection.php`:

```
return [
    'build' => [
        'namespace' => env('GRAPHQL_PROJECTION_NAMESPACE', 'Build\\GraphQLProjection\\'),
        'buildDir' => env('GRAPHQL_PROJECTION_PATH', 'build/graphql-projection'),
    ],

    'endpoint' => env('GRAPHQL_PROJECTION_ENDPOINT', '/graphql'),

    'schema' => [
        'provider' => env('GRAPHQL_PROJECTION_SCHEMA_PROVIDER', 'lighthouse'),
        'providers' => [
            'lighthouse' => LighthouseSchemaProvider::class,
            'rebing' => RebingSchemaProvider::class,
        ],
    ],

    /*
     * Register custom scalar types:
     *
     * Just for represent data in PHP objects
     */
    'typeMapping' => [
        'Email' => [
            'type' => 'string',
        ],
        'Date' => [
            'type' => Carbon::class,
            'format' => 'Y-m-d',
        ],
    ],
];
```

> **Note:** Add `build/` to `.gitignore` (contains generated files).

### Configure Composer Autoload

[](#configure-composer-autoload)

Update the `autoload-dev` section in your root `composer.json` file:

```
"autoload-dev": {
    "psr-4": {
        "Build\\GraphQLProjection\\": "build/graphql-projection/",
        // other namespaces
    }
},

```

> **Note:** Use namespace and path from your configuration.

After updating `composer.json`, run:

```
composer dump-autoload
```

Quick Start
-----------

[](#quick-start)

### Generate Classes

[](#generate-classes)

Generate type-safe classes from your GraphQL schema:

```
php artisan graphql:projection
```

This creates:

- Query classes - Execute GraphQL operations
- Projection classes - Select fields to retrieve
- Input classes - Type-safe input data
- Type classes - Response data models

### Build Your First Query

[](#build-your-first-query)

```
use GraphQLProjection\Client\Serialization\GraphQLQueryRequest;
use GraphQLProjection\Client\Execution\GraphQLTestHelpers;

class ArticleTest extends TestCase
{
    use GraphQLTestHelpers;

    public function test_create_article(): void
    {
        $this->actingAs($user);

        // Build input data
        $input = ArticleInput::builder()
            ->title('My First Article')
            ->content('Article content here...')
            ->active(true)
            ->publishedAt(now())
            ->build();

        // Create query
        $query = CreateArticleGraphQLQuery::newRequest()
            ->input($input)
            ->build();

        // Define projection (select fields)
        $projection = CreateArticleProjection::new()
            ->id()
            ->title()
            ->content()
            ->active()
            ->publishedAt()
            ->author()
                ->name()
                ->email()
            ->getRoot();

        // Execute and get typed response
        $request = new GraphQLQueryRequest($query, $projection);
        $article = $this->graphql()->executeAndExtract($request);

        // Work with typed object
        $this->assertInstanceOf(Article::class, $article);
        $this->assertEquals('My First Article', $article->getTitle());
    }
}
```

Usage Examples
--------------

[](#usage-examples)

### Nested Objects and Arrays

[](#nested-objects-and-arrays)

Work with complex nested structures effortlessly:

```
$input = ArticleInput::builder()
    ->title('Multilingual Article')
    ->author(
        AuthorInput::builder()
            ->name('John Doe')
            ->email('john@example.com')
            ->build()
    )
    ->translations([
        TranslationInput::builder()
            ->language('en')
            ->title('Article in English')
            ->content('English content...')
            ->build(),
        TranslationInput::builder()
            ->language('es')
            ->title('Artículo en Español')
            ->content('Contenido en español...')
            ->build(),
    ])
    ->tags(['php', 'laravel', 'graphql'])
    ->build();

$projection = ArticleProjection::new()
    ->id()
    ->title()
    ->author()
        ->id()
        ->name()
        ->avatar()
            ->url()
            ->getParent()
        ->getRoot()
    ->translations()
        ->language()
        ->title()
        ->content()
        ->getRoot()
    ->tags()
    ->getRoot();
```

### File Uploads

[](#file-uploads)

Upload single files, multiple files, or files within nested inputs:

```
// Single file
$input = ArticleInput::builder()
    ->title('Article with Cover')
    ->coverImage(UploadedFile::fake()->image('cover.jpg'))
    ->build();

// Multiple files
$input = ArticleInput::builder()
    ->title('Photo Gallery')
    ->images([
        UploadedFile::fake()->image('photo1.jpg'),
        UploadedFile::fake()->image('photo2.jpg'),
        UploadedFile::fake()->image('photo3.jpg'),
    ])
    ->build();

// Files in nested inputs
$input = ArticleInput::builder()
    ->translations([
        TranslationInput::builder()
            ->language('en')
            ->thumbnail(UploadedFile::fake()->image('en-thumb.jpg'))
            ->build(),
        TranslationInput::builder()
            ->language('es')
            ->thumbnail(UploadedFile::fake()->image('es-thumb.jpg'))
            ->build(),
    ])
    ->build();

$query = CreateArticleGraphQLQuery::newRequest()
    ->input($input)
    ->build();

$projection = ArticleProjection::new()
    ->id()
    ->coverImage()
        ->url()
        ->size()
        ->mimeType();

$request = new GraphQLQueryRequest($query, $projection);
$article = $this->graphql()->executeAndExtract($request);
```

### Field Arguments

[](#field-arguments)

Pass arguments to specific fields:

```
$projection = UserProjection::new()
    ->id()
    ->name()
    ->posts(10, PostStatus::PUBLISHED) // Arguments: limit, status
        ->id()
        ->title()
        ->createdAt()
        ->getRoot()
    ->avatar('large') // Argument: size
        ->url()
        ->width()
        ->height()
        ->getRoot();
```

### Union Types

[](#union-types)

Handle GraphQL union and interface types:

```
$projection = SearchProjection::new()
    ->results()
        ->onArticle() // Union type: Article
            ->id()
            ->title()
            ->author()
                ->name()
                ->getParent()
            ->getParent()
        ->onUser() // Union type: User
            ->id()
            ->name()
            ->email()
            ->getParent()
        ->onComment() // Union type: Comment
            ->id()
            ->text()
            ->createdAt()
            ->getRoot();
```

### Pagination

[](#pagination)

Built-in support for paginated queries:

```
$query = ArticlesGraphQLQuery::newRequest()
    ->first(20)
    ->page(1)
    ->build();

$projection = ArticlesProjection::new()
    ->paginatorInfo()
        ->currentPage()
        ->lastPage()
        ->total()
        ->perPage()
        ->getRoot()
    ->data()
        ->id()
        ->title()
        ->description()
        ->publishedAt();

$request = new GraphQLQueryRequest($query, $projection);
$paginator = $this->graphql()->executeAndExtract($request);

// Work with paginated data
$articles = $paginator->getData(); // Article[]
$currentPage = $paginator->getPaginatorInfo()->getCurrentPage();
$total = $paginator->getPaginatorInfo()->getTotal();
```

### Error Handling

[](#error-handling)

Two approaches for handling errors:

```
// Option 1: executeAndExtract - throws exception on errors
try {
    $article = $this->graphql()->executeAndExtract($request);

    // Work with successful response
    $this->assertEquals('Expected Title', $article->getTitle());
} catch (GraphQLException $e) {
    // Handle GraphQL errors
    foreach ($e->getErrors() as $error) {
        echo $error['message'];

        // Access validation errors
        if (isset($error['extensions']['validation'])) {
            $validationErrors = $error['extensions']['validation'];
        }
    }
}

// Option 2: execute - manual error checking
$response = $this->graphql()->execute($request);

if ($response->hasErrors()) {
    // Handle errors
    $errors = $response->getErrors();
    $firstError = $response->getFirstError();
} else {
    // Get raw data or extract to typed object
    $rawData = $response->getData();
}
```

### Working with Enums

[](#working-with-enums)

Native PHP enum support:

```
enum ArticleStatus: string
{
    case DRAFT = 'DRAFT';
    case PUBLISHED = 'PUBLISHED';
    case ARCHIVED = 'ARCHIVED';
}

$input = ArticleInput::builder()
    ->title('My Article')
    ->status(ArticleStatus::PUBLISHED)
    ->build();

$query = CreateArticleGraphQLQuery::newRequest()
    ->input($input)
    ->build();
```

### Date and Time Handling

[](#date-and-time-handling)

Automatic Carbon conversion:

```
$input = ArticleInput::builder()
    ->publishedAt(now())
    ->scheduledFor(Carbon::parse('2024-12-25 10:00:00'))
    ->expiresAt(now()->addDays(30))
    ->build();

// Response automatically converts to Carbon
$article = $this->graphql()->executeAndExtract($request);
$publishedDate = $article->getPublishedAt(); // Carbon instance
```

API Reference
-------------

[](#api-reference)

### GraphQLTestHelpers (Trait)

[](#graphqltesthelpers-trait)

Use in your test classes:

```
use GraphQLProjection\Client\Execution\GraphQLTestHelpers;

class MyTest extends TestCase
{
    use GraphQLTestHelpers;

    public function test_example()
    {
        $executor = $this->graphql(); // Returns GraphQLQueryExecutor
    }
}
```

### GraphQLQueryExecutor

[](#graphqlqueryexecutor)

Execute GraphQL requests: **Methods:**

- `execute(GraphQLQueryRequest $request): GraphQLResponse` - Execute query, return raw response
- `executeAndExtract(GraphQLQueryRequest $request): mixed` - Execute query, return typed object

### GraphQLResponse

[](#graphqlresponse)

GraphQL response wrapper:

**Methods:**

- `getData(): mixed` - Get response data
- `getErrors(): array` - Get errors array
- `hasErrors(): bool` - Check if response has errors
- `getFirstError(): ?array` - Get first error
- `isSuccessful(): bool` - Check if request was successful
- `getRawResponse(): array` - Get raw response array

### GraphQLException

[](#graphqlexception)

Exception thrown on GraphQL errors:

**Methods:**

- `getErrors(): array` - Get GraphQL errors
- `getRawResponse(): array` - Get full response
- `getMessage(): string` - Get error message

### Projection Navigation

[](#projection-navigation)

Navigate through nested projections:

**Methods:**

- `getRoot()` - Return to root projection
- `getParent()` - Return to parent projection

```
$projection = RootProjection::new()
    ->field1()
    ->level1()
        ->field2()
        ->level2()
            ->field3()
            ->level3()
                ->field4()
                ->getRoot() // Back to RootProjection
    ->field5()
        ->level6()
        ->getParent() // Back to field5;
```

### Builder Pattern

[](#builder-pattern)

All Input and Type classes support builder pattern:

```
$input = ArticleInput::builder()
    ->field1($value1)
    ->field2($value2)
    ->optionalField($value3) // Optional fields
    ->build();
```

Supported GraphQL Features
--------------------------

[](#supported-graphql-features)

### Scalar Types

[](#scalar-types)

- `String`, `Int`, `Float`, `Boolean`, `ID`
- Custom scalars (with automatic conversion)

### Complex Types

[](#complex-types)

- **Objects** - Nested object types
- **Input** Objects - Input type support
- **Arrays** - Lists of any type
- **Nullable** Fields - Optional fields with null support
- **Union** Types - GraphQL unions with type discrimination
- **Interface** Types - GraphQL interfaces

### Special Features

[](#special-features)

- **File Uploads** - GraphQL Multipart Request Spec compliant
- **Pagination** - Cursor and offset-based pagination
- **Enums** - Native PHP enum support
- **Dates** - Automatic Carbon/DateTime conversion
- **Custom Scalars** - Extensible scalar handling

Generated Code Structure
------------------------

[](#generated-code-structure)

### Query Class

[](#query-class)

```
class CreateArticleGraphQLQuery extends GraphQLQuery
{
    public function getOperationName(): string
    {
        return 'createArticle';
    }

    public function getOperation(): string
    {
        return 'mutation'; // or 'query'
    }

    public function getResponseType(): string
    {
        return Article::class;
    }

    public function isList(): bool
    {
        return false;
    }
}
```

### Input Class

[](#input-class)

```
class ArticleInput extends BaseInput
{
    private string $title;
    private bool $active;
    private ?Carbon $publishedAt;

    public function getTitle(): string { return $this->title; }
    public function setTitle(string $title): void { $this->title = $title; }

    public static function builder(): ArticleInputBuilder
    {
        return new ArticleInputBuilder();
    }
}
```

### Type Class

[](#type-class)

```
class Article
{
    private int|string $id;
    private string $title;
    private Author $author;

    public function getId(): int|string { return $this->id; }
    public function getTitle(): string { return $this->title; }
    public function getAuthor(): Author { return $this->author; }

    public static function builder(): ArticleBuilder
    {
        return new ArticleBuilder();
    }
}
```

Requirements
------------

[](#requirements)

- PHP 8.2 or higher
- Laravel 10.x, 11.x, or 12.x
- Lighthouse or Rebing GraphQL Laravel package

### Compatible GraphQL Servers

[](#compatible-graphql-servers)

- Lighthouse - Laravel GraphQL server
- Rebing GraphQL Laravel - Laravel GraphQL implementation

License
-------

[](#license)

The MIT License (MIT).

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance65

Regular maintenance activity

Popularity6

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

212d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/f1f080a9f11696272793b0767b54d71811bfeb2b88093ec799efe980e36a43fc?d=identicon)[FedosDN](/maintainers/FedosDN)

---

Top Contributors

[![fedorgrecha](https://avatars.githubusercontent.com/u/25326809?v=4)](https://github.com/fedorgrecha "fedorgrecha (9 commits)")

---

Tags

laravelgraphqlcodegenprojectionlaravel-graphqllighthouserebing

### Embed Badge

![Health badge](/badges/fedorgrecha-php-graphql-projection/health.svg)

```
[![Health](https://phpackages.com/badges/fedorgrecha-php-graphql-projection/health.svg)](https://phpackages.com/packages/fedorgrecha-php-graphql-projection)
```

###  Alternatives

[nuwave/lighthouse

A framework for serving GraphQL from Laravel

3.5k10.7M92](/packages/nuwave-lighthouse)[joselfonseca/lighthouse-graphql-passport-auth

Add GraphQL types and mutations for login and recover password functionalities

234769.9k1](/packages/joselfonseca-lighthouse-graphql-passport-auth)[mll-lab/laravel-graphiql

Easily integrate GraphiQL into your Laravel project

683.2M9](/packages/mll-lab-laravel-graphiql)[yakovenko/laravel-lighthouse-graphql-multi-schema

A Laravel package that provides multi-schema support for Lighthouse GraphQL.

1562.5k](/packages/yakovenko-laravel-lighthouse-graphql-multi-schema)[scrnhq/laravel-bakery

An on-the-fly GraphQL Schema generator from Eloquent models for Laravel.

10518.2k](/packages/scrnhq-laravel-bakery)[alexaandrov/laravel-graphql-client

GraphQL client for laravel/lumen

125.6k](/packages/alexaandrov-laravel-graphql-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
