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

ActiveYii2-extension[API Development](/categories/api)

pomelchenko/yii2-graphql
========================

facebook graphql server side for yii2 php framework

0.16.1(5mo ago)02BSD-3-ClausePHPPHP &gt;=7.4.0CI passing

Since Nov 28Pushed 5mo agoCompare

[ Source](https://github.com/pOmelchenko/yii2-graphql)[ Packagist](https://packagist.org/packages/pomelchenko/yii2-graphql)[ RSS](/packages/pomelchenko-yii2-graphql/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (6)Dependencies (8)Versions (8)Used By (0)

yii-graphql
===========

[](#yii-graphql)

Using Facebook [GraphQL](http://facebook.github.io/graphql/) PHP server implementation. Extends [graphql-php](https://github.com/webonyx/graphql-php) to apply to YII2.

[![Latest Stable Version](https://camo.githubusercontent.com/f24c2a8d4984f79a18604a6d6b89aa1301c388c91ad69c2a164c3bcd3ac1bf90/68747470733a2f2f706f7365722e707567782e6f72672f706f6d656c6368656e6b6f2f796969322d6772617068716c2f762f737461626c652e737667)](https://packagist.org/packages/pomelchenko/yii2-graphql)[![CI](https://github.com/pOmelchenko/yii2-graphql/actions/workflows/ci.yml/badge.svg)](https://github.com/pOmelchenko/yii2-graphql/actions)[![Coverage Status](https://camo.githubusercontent.com/e7be5d3a4fa33c0e3d0ba4099ce0a5a24447971dd72bfe83e9828a422d344b21/68747470733a2f2f636f6465636f762e696f2f67682f704f6d656c6368656e6b6f2f796969322d6772617068716c2f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/pOmelchenko/yii2-graphql)[![Total Downloads](https://camo.githubusercontent.com/b49dd89841e0a1546876f1b3087e9a06e06fbe83584fcfaaab20112a6c482696/68747470733a2f2f706f7365722e707567782e6f72672f706f6d656c6368656e6b6f2f796969322d6772617068716c2f646f776e6c6f6164732e737667)](https://packagist.org/packages/pomelchenko/yii2-graphql)

Languages: [English](/README.md) | [Русский](/docs/README-ru.md) | [中文](/docs/README-zh.md)

> Originally created by [tsingsun](https://github.com/tsingsun); continued development in this fork.

---

Features

- Configuration includes simplifying the definition of standard graphql protocols.
- Based on the full name defined by the type, implementing on-demand loading and lazy loading, and no need to define all type definitions into the system at load.
- Mutation input validation support.
- Provide controller integration and authorization support.

### Install

[](#install)

Using [composer](https://getcomposer.org/)

```
composer require pomelchenko/yii2-graphql

```

Requires PHP ≥ 7.4 and is tested against [webonyx/graphql-php](https://github.com/webonyx/graphql-php) 14.x and [ecodev/graphql-upload](https://github.com/Ecodev/graphql-upload) 6.1.x.

### Development

[](#development)

Run PHP\_CodeSniffer and PHPStan locally before opening PRs:

```
composer lint

# See all warnings (line length, legacy bootstrap, etc.)
composer lint:strict

# Static analysis
composer stan

```

### Type

[](#type)

The type system is the core of GraphQL, which is embodied in `GraphQLType`. By deconstructing the GraphQL protocol and using the [graph-php](https://github.com/webonyx/graphql-php) library to achieve fine-grained control of all elements, it is convenient to extend the class according to its own needs

#### The main elements of `GraphQLType`

[](#the-main-elements-of-graphqltype)

The following elements can be declared in the `$attributes` property of the class, or as a method, unless stated otherwise. This also applies to all elements after this.

ElementTypeDescription`name`string**Required** Each type needs to be named, with unique names preferred to resolve potential conflicts. The property needs to be defined in the `$attributes` property.`description`stringA description of the type and its use. The property needs to be defined in the `$attributes` property.`fields`array**Required** The included field content is represented by the `fields()` method.`resolveField`callback`function($value, $args, $context, GraphQL\Type\Definition\ResolveInfo $info)` For the interpretation of a field. For example: the fields definition of the user property, the corresponding method is `resolveUserField()`, and `$value` is the passed type instance defined by `type`.### Query

[](#query)

`GraphQLQuery` and `GraphQLMutation` inherit `GraphQLField`. The element structure is consistent, and if you would like a reusable `Field`, you can inherit it. Each query of `Graphql` needs to correspond to a `GraphQLQuery` object

#### The main elements of `GraphQLField`

[](#the-main-elements-of-graphqlfield)

ElementTypeDescription`type`ObjectTypeFor the corresponding query type. The single type is specified by `GraphQL::type`, and a list by `Type::listOf(GraphQL::type)`.`args`arrayThe available query parameters, each of which is defined by `Field`.`resolve`callback`function($value, $args, $context, GraphQL\Type\Definition\ResolveInfo $info)` `$value` is the root data, `$args` is the query parameters, `$context` is the `yii\web\Application` object, and `$info` resolves the object for the query. The root object is handled in this method.### Mutation

[](#mutation)

Definition is similar to `GraphQLQuery`, please refer to the above.

#### Inline query definitions

[](#inline-query-definitions)

If you prefer not to create a dedicated `GraphQLQuery` class, schema entries may also be declared as plain arrays using the same structure that `webonyx/graphql-php` expects. Provide the type, args, and resolver (closure, callable array, etc.) directly in the configuration. `GraphQL::type()` can be referenced even before `Yii::$app` is instantiated, so simply pass the resulting `Type`:

```
'schema' => [
    'query' => [
        'me' => [
            'type' => GraphQL::type(UserType::class),
            'args' => [
                'id' => ['type' => Type::id()],
            ],
            'resolve' => [UserResolver::class, 'resolveMe'],
        ],
    ],
],
```

This is useful for simple fields or when you already have reusable resolver classes. For more complex logic you can still rely on dedicated `GraphQLQuery`/`GraphQLMutation` classes so that `type()`, `args()`, `resolve()` and `rules()` remain encapsulated.

### Simplified Field Definition

[](#simplified-field-definition)

Simplifies the declarations of `Field`, removing the need to defined as an array with the type key.

#### Standard Definition

[](#standard-definition)

```
//...
'id' => [
    'type' => Type::id(),
],
//...
```

#### Simplified Definition

[](#simplified-definition)

```
//...
'id' => Type::id(),
//...
```

### Yii Implementation

[](#yii-implementation)

### General configuration

[](#general-configuration)

JsonParser configuration required

```
'components' => [
    'request' => [
        'parsers' => [
            'application/json' => \yii\web\JsonParser::class,
        ],
    ],
];
```

#### Module support

[](#module-support)

Can easily be implemented by extending `yii\graphql\GraphQLModule` (or implementing `GraphQLModuleInterface` and using the trait). The trait is responsible for initialization.

```
class MyModule extends \yii\graphql\GraphQLModule
{
}
```

In your application configuration file:

```
'modules'=>[
    'moduleName ' => [
        'class' => 'path\to\module'
        //graphql config
        'schema' => [
            'query' => [
                'user' => \app\graphql\query\UsersQuery::class
            ],
            'mutation' => [
                'login'
            ],
            // you do not need to set the types if your query contains interfaces or fragments
            // the key must same as your defined class
            'types' => [
                'Story' => \yiiunit\extensions\graphql\objects\types\StoryType::class
            ],
        ],
    ],
];
```

Use the controller to receive requests by using `yii\graphql\GraphQLAction`

```
class MyController extends Controller
{
    function actions()
    {
        return [
            'index' => [
                'class' => \yii\graphql\GraphQLAction::class,
            ],
        ];
    }
}
```

#### Component Support

[](#component-support)

also you can include the trait with your own components,then initialization yourself.

```
'components' => [
    'componentsName' => [
        'class' => 'path\to\components'
        //graphql config
        'schema' => [
            'query' => [
                'user' => \app\graphql\query\UsersQuery::class
            ],
            'mutation' => [
                'login'
            ],
            // you do not need to set the types if your query contains interfaces or fragments
            // the key must same as your defined class
            'types'=>[
                'Story' => \yiiunit\extensions\graphql\objects\types\StoryType::class,
            ],
        ],
    ],
];
```

### Input validation

[](#input-validation)

Validation rules are supported. In addition to graphql based validation, you can also use Yii Model validation, which is currently used for the validation of input parameters. The rules method is added directly to the mutation definition.

```
public function rules()
{
    return [
        ['password', 'boolean'],
    ];
}
```

#### Mutation validation helper

[](#mutation-validation-helper)

`GraphQLMutation` ships with the `yii\graphql\traits\ShouldValidate` trait. Whenever your mutation defines `rules()` (same format as a regular Yii model), the trait wraps the resolver and calls `DynamicModel::validateData()` before `resolve()` executes. If validation fails, an `InvalidParamException` is thrown automatically and the resolver is not executed.

```
use yii\graphql\base\GraphQLMutation;
use GraphQL\Type\Definition\Type;

class UpdatePasswordMutation extends GraphQLMutation
{
    public function type()
    {
        return Type::boolean();
    }

    public function args()
    {
        return [
            'password' => ['type' => Type::nonNull(Type::string())],
        ];
    }

    public function rules()
    {
        return [
            ['password', 'string', 'min' => 12],
        ];
    }

    public function resolve($root, $args)
    {
        // Arguments are already validated here.
        // ...
        return true;
    }
}
```

Custom validators, inline callbacks, and any other Yii rule syntax are fully supported, so you can reuse existing validation logic without duplicating it inside resolvers.

### Authorization verification

[](#authorization-verification)

Since graphql queries can be combined, such as when a query merges two query, and the two query have different authorization constraints, custom authentication is required. I refer to this query as "graphql actions"; when all graphql actions conditions are configured, it passes the authorization check.

#### Authenticate

[](#authenticate)

In the behavior method of controller, the authorization method is set as follows

```
function behaviors()
{
    return [
        'authenticator' => [
            'class' => \yii\graphql\filter\auth\CompositeAuth::class,
            'authMethods' => [
                \yii\filters\auth\QueryParamAuth::class,
            ],
            'except' => ['hello'],
        ],
    ];
}
```

If you want to support IntrospectionQuery authorization, the corresponding graphql action is `__schema`

#### Authorization

[](#authorization)

If the user has passed authentication, you may want to check the access for the resource. You can use `GraphqlAction`'s `checkAccess` method in the controller. It will check all graphql actions.

```
class GraphqlController extends Controller
{
    public function actions()
    {
        return [
            'index' => [
                'class' => \yii\graphql\GraphQLAction::class,
                'checkAccess'=> [$this,'checkAccess'],
            ]
        ];
    }

    /**
     * authorization
     * @param $actionName
     * @throws \yii\web\ForbiddenHttpException
     */
     public function checkAccess($actionName)
     {
         $permissionName = $this->module->id . '/' . $actionName;
         $pass = Yii::$app->getAuthManager()->checkAccess(Yii::$app->user->id, $permissionName);
         if (!$pass) {
             throw new \yii\web\ForbiddenHttpException('Access Denied');
         }
    }
}
```

### Multipart upload support

[](#multipart-upload-support)

`GraphQLAction` detects [`operations`/`map`](https://github.com/jaydenseric/graphql-multipart-request-spec) payloads and delegates parsing to `ecodev/graphql-upload`. Ensure `multipart/form-data` requests include those keys so uploaded files are injected into GraphQL variables.

### Testing

[](#testing)

Run the test suite locally or via Docker:

```
docker compose up -d --build
docker compose exec app composer install
docker compose exec app composer test
docker compose exec app composer test-coverage
```

This exercises the GraphQL facade, controller action, upload middleware, and custom types to guard against regressions when dependencies are upgraded.

### GitLab release pipeline

[](#gitlab-release-pipeline)

When this repository is mirrored into GitLab (Settings → Repository → Mirroring repositories) and the **Trigger pipelines when updates are mirrored** option is enabled, the bundled `.gitlab-ci.yml` automatically runs whenever a tag arrives. The single `publish_package` job uses the GitLab Packages API plus the job token to update your private Composer registry entry based on `CI_COMMIT_TAG`.

Steps to keep releases automated:

1. Configure mirroring (or push from GitHub Actions) so GitLab sees every new tag.
2. Enable the “trigger pipelines” flag on the mirror or push directly so GitLab CI starts for mirrored updates.
3. Create/push a semantic tag like `v0.15.2`; once the mirror updates, the pipeline publishes that version to the Composer registry without extra manual jobs or variables.

### Demo

[](#demo)

#### Creating queries based on graphql protocols

[](#creating-queries-based-on-graphql-protocols)

Each query corresponds to a GraphQLQuery file.

```
class UserQuery extends GraphQLQuery
{
    public function type()
    {
        return GraphQL::type(UserType::class);
    }

    public function args()
    {
        return [
            'id'=>[
                'type' => Type::nonNull(Type::id())
            ],
        ];
    }

    public function resolve($value, $args, $context, ResolveInfo $info)
    {
        return DataSource::findUser($args['id']);
    }
}
```

Define type files based on query protocols

```
class UserType extends GraphQLType
{
    protected $attributes = [
        'name'=>'user',
        'description'=>'user is user'
    ];

    public function fields()
    {
        $result = [
            'id' => [
                'type'=>Type::id()
            ],
            'email' => Types::email(),
            'email2' => Types::email(),
            'photo' => [
                'type' => GraphQL::type(ImageType::class),
                'description' => 'User photo URL',
                'args' => [
                    'size' => Type::nonNull(GraphQL::type(ImageSizeEnumType::class)),
                ]
            ],
            'firstName' => [
                'type' => Type::string(),
            ],
            'lastName' => [
                'type' => Type::string(),
            ],
            'lastStoryPosted' => GraphQL::type(StoryType::class),
            'fieldWithError' => [
                'type' => Type::string(),
                'resolve' => function() {
                    throw new \Exception("This is error field");
                }
            ]
        ];
        return $result;
    }

    public function resolvePhotoField(User $user,$args)
    {
        return DataSource::getUserPhoto($user->id, $args['size']);
    }

    public function resolveIdField(User $user, $args)
    {
        return $user->id.'test';
    }

    public function resolveEmail2Field(User $user, $args)
    {
        return $user->email2.'test';
    }
}
```

#### Query instance

[](#query-instance)

```
'hello' => '
    query hello {
        hello
    }
',
'singleObject' => '
    query user {
        user(id:"2") {
            id
            email
            email2
            photo(size:ICON) {
                id
                url
            }
            firstName
            lastName
        }
    }
',
'multiObject' => '
    query multiObject {
        user(id: "2") {
            id
            email
            photo(size:ICON) {
                id
                url
            }
        }
        stories(after: "1") {
            id
            author{
                id
            }
            body
        }
    }
',
'updateObject' => '
    mutation updateUserPwd{
        updateUserPwd(id: "1001", password: "123456") {
            id,
            username
        }
    }
'
```

### Exception Handling

[](#exception-handling)

You can config the error formater for graph. The default handle uses `yii\graphql\ErrorFormatter`, which optimizes the processing of Model validation results.

```
'modules' => [
    'moduleName' => [
       'class' => 'path\to\module'
       'errorFormatter' => [\yii\graphql\ErrorFormatter::class, 'formatError'],
    ],
];
```

### Future

[](#future)

- `ActiveRecord` tool for generating query and mutation class.
- Some of the special syntax for graphql, such as `@Directives`, has not been tested

###  Health Score

29

—

LowBetter than 60% of packages

Maintenance72

Regular maintenance activity

Popularity2

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity30

Early-stage or recently created project

 Bus Factor1

Top contributor holds 62.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 ~1 days

Total

7

Last Release

160d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/968257772f7f85d0a2a97f8312fffd6af6f1204f19106adac9b18a62a2e2239f?d=identicon)[p.Omelchenko](/maintainers/p.Omelchenko)

---

Top Contributors

[![pOmelchenko](https://avatars.githubusercontent.com/u/3578284?v=4)](https://github.com/pOmelchenko "pOmelchenko (72 commits)")[![tsingsun](https://avatars.githubusercontent.com/u/5848549?v=4)](https://github.com/tsingsun "tsingsun (43 commits)")[![TerraSkye](https://avatars.githubusercontent.com/u/5426161?v=4)](https://github.com/TerraSkye "TerraSkye (1 commits)")

---

Tags

graphqlyii2

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[aimeos/ai-admin-graphql

Aimeos Admin GraphQL API extension

944100.0k4](/packages/aimeos-ai-admin-graphql)[oxid-esales/graphql-base

OXID eSales GraphQL base module

24101.0k10](/packages/oxid-esales-graphql-base)[rubix/server

Deploy your Rubix ML models to production with scalable stand-alone inference servers.

632.3k](/packages/rubix-server)[apexwire/yii2-restclient

Tools to use API as ActiveRecord for Yii2

143.5k](/packages/apexwire-yii2-restclient)

PHPackages © 2026

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