PHPackages                             digiaonline/graphql - 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. digiaonline/graphql

AbandonedArchivedLibrary[API Development](/categories/api)

digiaonline/graphql
===================

A PHP7 implementation of the GraphQL specifications.

v1.1.0(7y ago)2159.1k↓100%101MITPHPPHP &gt;=7.1

Since Aug 19Pushed 4y ago19 watchersCompare

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

READMEChangelog (10)Dependencies (4)Versions (18)Used By (1)

GraphQL
=======

[](#graphql)

[![GitHub Actions status](https://github.com/digiaonline/graphql-php/workflows/Test/badge.svg)](https://github.com/digiaonline/graphql-php/actions)[![Coverage Status](https://camo.githubusercontent.com/93f6f87716e253ab2b9f278f410ce3f8cc5a72e1a3d76176a258727d38eb47dc/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f64696769616f6e6c696e652f6772617068716c2d7068702f62616467652e7376673f6272616e63683d6d61696e)](https://coveralls.io/github/digiaonline/graphql-php?branch=main)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/5f3cfb67f900276e30e6e018578217b4846d0c1cfac14f97ea2a3be695f7a666/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f64696769616f6e6c696e652f6772617068716c2d7068702f6261646765732f7175616c6974792d73636f72652e706e673f623d6d61696e)](https://scrutinizer-ci.com/g/digiaonline/graphql-php/?branch=main)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](https://raw.githubusercontent.com/digiaonline/graphql-php/main/LICENSE)[![Backers on Open Collective](https://camo.githubusercontent.com/b70cbb48ba8cee07855d9d05da658060881d2fcfeaa6dccb9e25c604b3ca0648/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f6261636b6572732f62616467652e737667)](#backers)[![Sponsors on Open Collective](https://camo.githubusercontent.com/7eb61cd107d9958d18a6dc44abca011d99401525c102c5b95e610cd9b06e8619/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f72732f62616467652e737667)](#sponsors)

This is a PHP implementation of the [GraphQL specification](https://facebook.github.io/graphql/) based on the JavaScript [reference implementation](https://github.com/graphql/graphql-js).

Related projects
----------------

[](#related-projects)

- [DateTime scalar](https://github.com/digiaonline/graphql-datetime-scalar-php)
- [Relay support](https://github.com/digiaonline/graphql-relay-php)

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

[](#requirements)

- PHP version &gt;= 7.1
- ext-mbstring

Table of contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Example](#example)
- [Creating a schema](#creating-a-schema)
    - [Resolver registry](#resolver-registry)
    - [Resolver middleware](#resolver-middleware)
- [Execution](#execution)
    - [Queries](#queries)
    - [Resolvers](#resolvers)
        - [The N+1 problem](#the-n1-problem)
    - [Variables](#variables)
    - [Context](#context)
- [Scalars](#scalars)
    - [Custom scalars](#custom-scalars)
- [Advanced usage](#advanced-usage)
- [Integration](#integration)
    - [Laravel](#laravel)

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

[](#installation)

Run the following command to install the package through Composer:

```
composer require digiaonline/graphql
```

Example
-------

[](#example)

Here is a simple example that demonstrates how to build an executable schema from a GraphQL schema file that contains the Schema Definition Language (SDL) for a Star Wars-themed schema (for the schema definition itself, see below). In this example we use that SDL to build an executable schema and use it to query for the name of the hero. The result of that query is an associative array with a structure that resembles the query we ran.

```
use Digia\GraphQL\Language\FileSourceBuilder;
use function Digia\GraphQL\buildSchema;
use function Digia\GraphQL\graphql;

$sourceBuilder = new FileSourceBuilder(__DIR__ . '/star-wars.graphqls');

$schema = buildSchema($sourceBuilder->build(), [
    'Query' => [
        'hero' => function ($rootValue, $arguments) {
            return getHero($arguments['episode'] ?? null);
        },
    ],
]);

$result = graphql($schema, '
query HeroNameQuery {
  hero {
    name
  }
}');

\print_r($result);
```

The script above produces the following output:

```
Array
(
    [data] => Array
    (
        [hero] => Array
        (
            [name] => "R2-D2"
        )

    )

)
```

The GraphQL schema file used in this example contains the following:

```
schema {
    query: Query
}

type Query {
    hero(episode: Episode): Character
    human(id: String!): Human
    droid(id: String!): Droid
}

interface Character {
    id: String!
    name: String
    friends: [Character]
    appearsIn: [Episode]
}

type Human implements Character {
    id: String!
    name: String
    friends: [Character]
    appearsIn: [Episode]
    homePlanet: String
}

type Droid implements Character {
    id: String!
    name: String
    friends: [Character]
    appearsIn: [Episode]
    primaryFunction: String
}

enum Episode { NEWHOPE, EMPIRE, JEDI }
```

Creating a schema
-----------------

[](#creating-a-schema)

In order to execute queries against your GraphQL API, you first need to define the structure of your API. This is done by creating a schema. There are two ways to do this, you can either do it using SDL or you can do it programmatically. However, we strongly encourage you to use SDL, because it is easier to work with. To make an executable schema from SDL you need to call the `buildSchema` function.

The `buildSchema` function takes three arguments:

- `$source` The schema definition (SDL) as a `Source` instance
- `$resolverRegistry` An associative array or a `ResolverRegistry` instance that contains all resolvers
- `$options` The options for building the schema, which also includes custom types and directives

To create the `Source` instance you can use the provided `FileSourceBuilder` or `MultiFileSourceBuilder` classes.

### Resolver registry

[](#resolver-registry)

The resolver registry is essentially a flat map with the type names as its keys and their corresponding resolver instances as its values. For smaller projects you can use an associative array and lambda functions to define your resolver registry. However, in larger projects we suggest that you implement your own resolvers instead. You can read more about resolvers under the [Resolvers](#resolvers) section.

Associative array example:

```
$schema = buildSchema($source, [
    'Query' => [
        'hero' => function ($rootValue, $arguments) {
            return getHero($arguments['episode'] ?? null);
        },
    ],
]);
```

Resolver class example:

```
$schema = buildSchema($source, [
    'Query' => [
        'hero' => new HeroResolver(),
    ],
]);
```

### Resolver middleware

[](#resolver-middleware)

If you find yourself writing the same logic in multiple resolvers you should consider using middleware. Resolver middleware allow you to efficiently manage functionality across multiple resolvers.

Before middleware example:

```
$resolverRegistry = new ResolverRegristry([
    'Query' => [
        'hero' => function ($rootValue, $arguments) {
            return getHero($arguments['episode'] ?? null);
        },
    ],
], [
    'middleware' => [new BeforeMiddleware()],
]);
$schema = buildSchema($source, $resolverRegistry);
```

```
class BeforeMiddleware implements ResolverMiddlewareInterface
{
    public function resolve(callable $resolveCallback, $rootValue, array $arguments, $context, ResolveInfo $info) {
        $newRootValue = $this->doSomethingBefore();
        return $resolveCallback($newRootValue, $arguments, $context, $info);
    }
}
```

After middleware example:

```
$resolverRegistry = new ResolverRegristry([
    'Query' => [
        'hero' => function ($rootValue, $arguments) {
            return getHero($arguments['episode'] ?? null);
        },
    ],
], [
    'middleware' => [new AfterMiddleware()],
]);
$schema = buildSchema($source, $resolverRegistry);
```

```
class AfterMiddleware implements ResolverMiddlewareInterface
{
    public function resolve(callable $resolveCallback, $rootValue, array $arguments, $context, ResolveInfo $info) {
        $result = $resolveCallback($rootValue, $arguments, $context, $info);
        $this->doSomethingAfter();
        return $result;
    }
}
```

Resolver middleware can be useful for a number of things; such as logging, input sanitization, performance measurement, authorization and caching.

If you want to learn more about schemas you can refer to the [specification](https://graphql.org/learn/schema/).

Execution
---------

[](#execution)

### Queries

[](#queries)

To execute a query against your schema you need to call the `graphql` function and pass it your schema and the query you wish to execute. You can also run *mutations* and *subscriptions* by changing your query.

```
$query = '
query HeroNameQuery {
  hero {
    name
  }
}';

$result = graphql($schema, $query);
```

If you want to learn more about queries you can refer to the [specification](https://graphql.org/learn/queries/).

### Resolvers

[](#resolvers)

Each type in a schema has a resolver associated with it that allows for resolving the actual value. However, most types do not need a custom resolver, because they can be resolved using the default resolver. Usually these resolvers are lambda functions, but you can also define your own resolvers by extending `AbstractTypeResolver` or `AbstractFieldResolver`. Alternatively you can also implement the `ResolverInterface` directly.

A resolver function receives four arguments:

- `$rootValue` The parent object, which can also be `null` in some cases
- `$arguments` The arguments provided to the field in the query
- `$context` A value that is passed to every resolver that can hold important contextual information
- `$info` A value which holds field-specific information relevant to the current query

Lambda function example:

```
function ($rootValue, array $arguments, $context, ResolveInfo $info): string {
    return [
        'type'       => 'Human',
        'id'         => '1000',
        'name'       => 'Luke Skywalker',
        'friends'    => ['1002', '1003', '2000', '2001'],
        'appearsIn'  => ['NEWHOPE', 'EMPIRE', 'JEDI'],
        'homePlanet' => 'Tatooine',
    ];
}
```

Type resolver example:

```
class HumanResolver extends AbstractTypeResolver
{
    public function resolveName($rootValue, array $arguments, $context, ResolveInfo $info): string
    {
        return $rootValue['name'];
    }
}
```

Field resolver example:

```
class NameResolver extends AbstractFieldResolver
{
    public function resolve($rootValue, array $arguments, $context, ResolveInfo $info): string
    {
       return $rootValue['name'];
    }
}
```

#### The N+1 problem

[](#the-n1-problem)

The resolver function can return a value, a [promise](https://github.com/reactphp/promise) or an array of promises. This resolver function below illustrates how to use promise to solve the N+1 problem, the full example can be found in this [test case](/tests/Functional/Execution/DeferredResolverTest.php).

```
$movieType = newObjectType([
    'fields' => [
        'title'    => ['type' => stringType()],
        'director' => [
            'type'    => $directorType,
            'resolve' => function ($movie, $args) {
                DirectorBuffer::add($movie['directorId']);

                return new Promise(function (callable $resolve, callable $reject) use ($movie) {
                    DirectorBuffer::loadBuffered();
                    $resolve(DirectorBuffer::get($movie['directorId']));
                });
            }
        ]
    ]
]);
```

### Variables

[](#variables)

You can pass in variables when executing a query by passing them to the `graphql` function.

```
$query = '
query HeroNameQuery($id: ID!) {
  hero(id: $id) {
    name
  }
}';

$variables = ['id' => '1000'];

$result = graphql($schema, $query, null, null, $variables);
```

### Context

[](#context)

In case you need to pass in some important contextual information to your queries you can use the `$contextValues`argument on `graphql` to do so. This data will be passed to all of your resolvers as the `$context` argument.

```
$contextValues = [
    'currentlyLoggedInUser' => $currentlyLoggedInUser,
];

$result = graphql($schema, $query, null, $contextValues, $variables);
```

Scalars
-------

[](#scalars)

The leaf nodes in a schema are called scalars and each scalar resolves to some concrete data. The built-in, or specified scalars in GraphQL are the following:

- Boolean
- Float
- Int
- ID
- String

### Custom scalars

[](#custom-scalars)

In addition to the specified scalars you can also define your own custom scalars and let your schema know about them by passing them to the `buildSchema` function as part of its `$options` argument.

Custom Date scalar type example:

```
$dateType = newScalarType([
    'name'         => 'Date',
    'serialize'    => function ($value) {
        if ($value instanceof DateTime) {
            return $value->format('Y-m-d');
        }
        return null;
    },
    'parseValue'   => function ($value) {
        if (\is_string($value)){
            return new DateTime($value);
        }
        return null;
    },
    'parseLiteral' => function ($node) {
        if ($node instanceof StringValueNode) {
            return new DateTime($node->getValue());
        }
        return null;
    },
]);

$schema = buildSchema($source, [
    'Query' => QueryResolver::class,
    [
        'types' => [$dateType],
    ],
]);
```

Every scalar has to be coerced, which is done by three different functions. The `serialize` function converts a PHP value into the corresponding output value. The`parseValue` function converts a variable input value into the corresponding PHP value and the `parseLiteral` function converts an AST literal into the corresponding PHP value.

Advanced usage
--------------

[](#advanced-usage)

If you are looking for something that isn't yet covered by this documentation your best bet is to take a look at the [tests](./tests) in this project. You'll be surprised how many examples you'll find there.

Integration
-----------

[](#integration)

### Laravel

[](#laravel)

Here is an example that demonstrates how you can use this library in your Laravel project. You need an application service to expose this library to your application, a service provider to register that service, a controller and a route for handling the GraphQL POST requests.

**app/GraphQL/GraphQLService.php**

```
class GraphQLService
{
    private $schema;

    public function __construct(Schema $schema)
    {
        $this->schema = $schema;
    }

    public function executeQuery(string $query, array $variables, ?string $operationName): array
    {
        return graphql($this->schema, $query, null, null, $variables, $operationName);
    }
}
```

**app/GraphQL/GraphQLServiceProvider.php**

```
class GraphQLServiceProvider
{
    public function register()
    {
        $this->app->singleton(GraphQLService::class, function () {
            $schemaDef = \file_get_contents(__DIR__ . '/schema.graphqls');

            $executableSchema = buildSchema($schemaDef, [
                'Query' => QueryResolver::class,
            ]);

            return new GraphQLService($executableSchema);
        });
    }
}
```

**app/GraphQL/GraphQLController.php**

```
class GraphQLController extends Controller
{
    private $graphqlService;

    public function __construct(GraphQLService $graphqlService)
    {
        $this->graphqlService = $graphqlService;
    }

    public function handle(Request $request): JsonResponse
    {
        $query         = $request->get('query');
        $variables     = $request->get('variables') ?? [];
        $operationName = $request->get('operationName');

        $result = $this->graphqlService->executeQuery($query, $variables, $operationName);

        return response()->json($result);
    }
}
```

**routes/api.php**

```
Route::post('/graphql', 'app\GraphQL\GraphQLController@handle');
```

Contributors
------------

[](#contributors)

This project exists thanks to all the people who contribute. [Contribute](.github/CONTRIBUTING.md).

[![](https://camo.githubusercontent.com/ee76eceaf491b6efc49540be25e3dbfc7af5f848eb28e6d5813eaf66eae28974/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f636f6e7472696275746f72732e7376673f77696474683d38393026627574746f6e3d66616c7365)](graphs/contributors)

Backers
-------

[](#backers)

Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/graphql-php#backer)

[![](https://camo.githubusercontent.com/cf477dfe84bc233979345c3e6949b9e62cccd548b65f87f6f15bece6bb59a8b3/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f6261636b6572732e7376673f77696474683d383930)](https://opencollective.com/graphql-php#backers)

Sponsors
--------

[](#sponsors)

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/graphql-php#sponsor)

[![](https://camo.githubusercontent.com/ba42813d678fb5e9386e9cbd4543cb37d83d3332b841a7407f4816f4439099cb/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f302f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/0/website)[![](https://camo.githubusercontent.com/828239adda03f1d5cfdb84ebf867e8359966fee21a5ceb061108b5a70723e8f4/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f312f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/1/website)[![](https://camo.githubusercontent.com/4d76c7fdfbe93542a1bda63a4c03e5bf35f0f5e64a2b482710c89d7042fd2d6c/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f322f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/2/website)[![](https://camo.githubusercontent.com/efbbcaa259073cbd88bf818b1c8dbfe7827781e48a3182456f941f26fa3e26d5/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f332f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/3/website)[![](https://camo.githubusercontent.com/adfba741e787be272b0c31e3a725bb599d78a0834fd8afed4bc92fa8031cc637/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f342f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/4/website)[![](https://camo.githubusercontent.com/5d49d7e5543b353580f7be04cd10baf71d65b7d0672c97acb0e27af2c2f52825/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f352f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/5/website)[![](https://camo.githubusercontent.com/78740d84e7d2b0da4d51963dd0d9f89282cb4e339137cd6d291261ff1d3dd8d7/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f362f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/6/website)[![](https://camo.githubusercontent.com/66e45da96925876adb112fdd5eaaaacaeb5ca908d4fef978380dac42e3f4303d/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f372f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/7/website)[![](https://camo.githubusercontent.com/33fc4c3bdc445fc75999b67d7cb75d8a4a7898216070ddac7629d052a4dcd7e4/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f382f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/8/website)[![](https://camo.githubusercontent.com/b621a7666d788f002f8e5177a56e99ab12a2a4b779045ba161bc5fa4f025c70b/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6772617068716c2d7068702f73706f6e736f722f392f6176617461722e737667)](https://opencollective.com/graphql-php/sponsor/9/website)

License
-------

[](#license)

See [LICENCE](LICENSE).

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity40

Moderate usage in the ecosystem

Community30

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

Top contributor holds 64.1% 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 ~14 days

Recently: every ~26 days

Total

13

Last Release

2653d ago

### Community

Maintainers

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

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

![](https://www.gravatar.com/avatar/2a7a06397f81bf8434136ee6d71e2bc8f16018f28e6f794781a4dec6ac5b5b98?d=identicon)[hungneox](/maintainers/hungneox)

---

Top Contributors

[![cniska](https://avatars.githubusercontent.com/u/1044868?v=4)](https://github.com/cniska "cniska (243 commits)")[![q-hung](https://avatars.githubusercontent.com/u/199614?v=4)](https://github.com/q-hung "q-hung (59 commits)")[![Jalle19](https://avatars.githubusercontent.com/u/1106133?v=4)](https://github.com/Jalle19 "Jalle19 (44 commits)")[![hugovk](https://avatars.githubusercontent.com/u/1324225?v=4)](https://github.com/hugovk "hugovk (24 commits)")[![fubhy](https://avatars.githubusercontent.com/u/1172528?v=4)](https://github.com/fubhy "fubhy (2 commits)")[![spawnia](https://avatars.githubusercontent.com/u/12158000?v=4)](https://github.com/spawnia "spawnia (2 commits)")[![symm](https://avatars.githubusercontent.com/u/69390?v=4)](https://github.com/symm "symm (1 commits)")[![cgrice](https://avatars.githubusercontent.com/u/17614?v=4)](https://github.com/cgrice "cgrice (1 commits)")[![monkeywithacupcake](https://avatars.githubusercontent.com/u/7316730?v=4)](https://github.com/monkeywithacupcake "monkeywithacupcake (1 commits)")[![SerafimArts](https://avatars.githubusercontent.com/u/2461257?v=4)](https://github.com/SerafimArts "SerafimArts (1 commits)")[![acelot](https://avatars.githubusercontent.com/u/1065215?v=4)](https://github.com/acelot "acelot (1 commits)")

---

Tags

apigraphqlphpphp-libraryphp7

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/digiaonline-graphql/health.svg)

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

###  Alternatives

[team-reflex/discord-php

An unofficial API to interact with the voice and text service Discord.

1.1k379.4k24](/packages/team-reflex-discord-php)[web3p/web3.php

Ethereum web3 interface.

1.3k325.5k41](/packages/web3p-web3php)[mpociot/slack-client

A better Slack client, with RTM API support

51263.6k1](/packages/mpociot-slack-client)[leinonen/php-dataloader

Port of Facebook's dataloader to PHP

1615.8k](/packages/leinonen-php-dataloader)

PHPackages © 2026

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