{"id":28089000,"url":"https://github.com/studio-net/laravel-graphql","last_synced_at":"2025-05-13T12:53:12.361Z","repository":{"id":57060575,"uuid":"98440527","full_name":"studio-net/laravel-graphql","owner":"studio-net","description":"GraphQL implementation with power of Laravel","archived":false,"fork":false,"pushed_at":"2019-03-14T14:39:53.000Z","size":416,"stargazers_count":56,"open_issues_count":6,"forks_count":5,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-11-25T15:59:40.495Z","etag":null,"topics":["eloquent","entity","generator","graphql","laravel","mutations","query","transformer"],"latest_commit_sha":null,"homepage":"https://github.com/studio-net/laravel-graphql/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/studio-net.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-26T15:50:38.000Z","updated_at":"2023-10-23T01:05:12.000Z","dependencies_parsed_at":"2022-08-24T07:30:47.295Z","dependency_job_id":null,"html_url":"https://github.com/studio-net/laravel-graphql","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studio-net%2Flaravel-graphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studio-net%2Flaravel-graphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studio-net%2Flaravel-graphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studio-net%2Flaravel-graphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/studio-net","download_url":"https://codeload.github.com/studio-net/laravel-graphql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253947913,"owners_count":21988947,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eloquent","entity","generator","graphql","laravel","mutations","query","transformer"],"created_at":"2025-05-13T12:53:11.617Z","updated_at":"2025-05-13T12:53:12.342Z","avatar_url":"https://github.com/studio-net.png","language":"PHP","funding_links":[],"categories":["Packages"],"sub_categories":["REST/Web Services"],"readme":"Laravel GraphQL\n===============\n\nUse Facebook GraphQL with Laravel 5.2 \u003e=. It is based on the PHP\nimplementation [here](https://github.com/webonyx/graphql-php). You can find more\ninformation about GraphQL in the [GraphQL Introduction](http://facebook.github.io/react/blog/2015/05/01/graphql-introduction.html)\non the [React](http://facebook.github.io/react) blog or you can read the\n[GraphQL specifications](https://facebook.github.io/graphql/).\n\n[![Latest Stable Version](https://poser.pugx.org/studio-net/laravel-graphql/v/stable)](https://packagist.org/packages/studio-net/laravel-graphql)\n[![Latest Unstable Version](https://poser.pugx.org/studio-net/laravel-graphql/v/unstable)](https://packagist.org/packages/studio-net/laravel-graphql)\n[![Total Downloads](https://poser.pugx.org/studio-net/laravel-graphql/downloads)](https://packagist.org/packages/studio-net/laravel-graphql)\n[![Monthly Downloads](https://poser.pugx.org/studio-net/laravel-graphql/d/monthly)](https://packagist.org/packages/studio-net/laravel-graphql)\n[![Daily Downloads](https://poser.pugx.org/studio-net/laravel-graphql/d/daily)](https://packagist.org/packages/studio-net/laravel-graphql)\n[![License](https://poser.pugx.org/studio-net/laravel-graphql/license)](https://packagist.org/packages/studio-net/laravel-graphql)\n[![Build Status](https://api.travis-ci.org/studio-net/laravel-graphql.svg?branch=master)](https://travis-ci.org/studio-net/laravel-graphql)\n\n## Installation\n\n```bash\ncomposer require studio-net/laravel-graphql @dev\n```\n\nIf you're not using Laravel 5.5\u003e=, don't forget to append facade and service\nprovider to you `config/app.php` file. Next, you have to publish vendor.\n\n```bash\nphp artisan vendor:publish --provider=\"StudioNet\\GraphQL\\ServiceProvider\"\n```\n\n## Usage\n\n- [Definition](#definition)\n- [Query](#query)\n- [Mutation](#mutation)\n- [Pipeline](#pipeline)\n- [Require authorization](#require-authorization)\n- [Self documentation](#self-documentation)\n- [Examples](#examples)\n- [N+1 Problem](#n1-problem)\n\n### Definition\n\nEach source of data must have a corresponding definition in order to retrieve\nfetchable and mutable fields.\n\n```php\n# app/GraphQL/Definition/UserDefinition.php\n\nnamespace App\\GraphQL\\Definition;\n\nuse StudioNet\\GraphQL\\Definition\\Type;\nuse StudioNet\\GraphQL\\Support\\Definition\\EloquentDefinition;\nuse StudioNet\\GraphQL\\Filter\\EqualsOrContainsFilter;\nuse App\\User;\nuse Auth;\n\n/**\n * Specify user GraphQL definition\n *\n * @see EloquentDefinition\n */\nclass UserDefinition extends EloquentDefinition {\n\t/**\n\t * Set a name to the definition. The name will be lowercase in order to\n\t * retrieve it with `\\GraphQL::type` or `\\GraphQL::listOf` methods\n\t *\n\t * @return string\n\t */\n\tpublic function getName() {\n\t\treturn 'User';\n\t}\n\n\t/**\n\t * Set a description to the definition\n\t *\n\t * @return string\n\t */\n\tpublic function getDescription() {\n\t\treturn 'Represents a User';\n\t}\n\n\t/**\n\t * Represents the source of the data. Here, Eloquent model\n\t *\n\t * @return string\n\t */\n\tpublic function getSource() {\n\t\treturn User::class;\n\t}\n\n\t/**\n\t * Which fields are queryable ?\n\t *\n\t * @return array\n\t */\n\tpublic function getFetchable() {\n\t\treturn [\n\t\t\t'id'          =\u003e Type::id(),\n\t\t\t'name'        =\u003e Type::string(),\n\t\t\t'last_login'  =\u003e Type::datetime(),\n\t\t\t'is_admin'    =\u003e Type::bool(),\n\t\t\t'permissions' =\u003e Type::json(),\n\n\t\t\t// Relationship between user and posts\n\t\t\t'posts'       =\u003e \\GraphQL::listOf('post')\n\t\t];\n\t}\n\n\t/**\n\t * Which fields are filterable ? And how ?\n\t *\n\t * @return array\n\t */\n\tpublic function getFilterable() {\n\t\treturn [\n\t\t\t'id'       =\u003e new EqualsOrContainsFilter(),\n\t\t\t\"nameLike\" =\u003e function($builder, $value) {\n\t\t\t\treturn $builder-\u003ewhereRaw('name like ?', $value),\n\t\t\t},\n\t\t];\n\t}\n\n\t/**\n\t * Resolve field `permissions`\n\t *\n\t * @param  User $user\n\t * @return array\n\t */\n\tpublic function resolvePermissionsField(User $user) {\n\t\treturn $user-\u003egetPermissions();\n\t}\n\n\t/**\n\t * Which fields are mutable ?\n\t *\n\t * @return array\n\t */\n\tpublic function getMutable() {\n\t\treturn [\n\t\t\t'id'          =\u003e Type::id(),\n\t\t\t'name'        =\u003e Type::string(),\n\t\t\t'is_admin'    =\u003e Type::bool(),\n\t\t\t'permissions' =\u003e Type::array(),\n\t\t\t'password'    =\u003e Type::string()\n\t\t];\n\t}\n}\n\n# config/graphql.php\n\nreturn [\n\t// ...\n\t'definitions' =\u003e [\n\t\t\\App\\GraphQL\\Definition\\UserDefinition::class,\n\t\t\\App\\GraphQL\\Definition\\PostDefinition::class\n\t],\n\t// ...\n]\n```\n\nThe definition is an essential part in the process. It defines queryable and\nmutable fields. Also, it allows you to apply transformers for only some data\nwith the `getTransformers` methods. There's 5 kind of transformers to apply on :\n\n* `list`  : create a query to fetch many objects (`User =\u003e users`)\n* `view`  : create a query to retrieve one object (`User =\u003e user`)\n* `drop`  : create a mutation to delete an object (`User =\u003e deleteUser`)\n* `store` : create a mutation to update an object (`User =\u003e user`)\n* `batch` : create a mutation to update many object at once (`User =\u003e users`)\n* `restore` : create a mutation to restore an object (`User =\u003e restoreUser`)\n\nBy the default, the definition abstract class handles Eloquent model\ntransformation.\n\nA definition is composed from types. Our custom class extend the default\n`GraphQL\\Type\\Definition\\Type` class in order to implement `json` and `datetime`\navailabled types.\n\n### Query\n\nIf you want create a query by hand, it's possible.\n\n```php\n# app/GraphQL/Query/Viewer.php\n\nnamespace App\\GraphQL\\Query;\n\nuse StudioNet\\GraphQL\\Support\\Definition\\Query;\nuse Illuminate\\Support\\Facades\\Auth;\nuse App\\User;\nuse Auth;\n\nclass Viewer extends Query {\n\t/**\n\t * {@inheritDoc}\n\t */\n\tprotected function authorize(array $args) {\n\t\t// check, that user is not a guest\n\t\treturn !Auth::guest();\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t */\n\tpublic function getRelatedType() {\n\t\treturn \\GraphQL::type('user');\n\t}\n\t\n\t/**\n\t * {@inheritdoc}\n\t */\n\tpublic function getSource() {\n\t\treturn User::class;\n\t}\n\n\t/**\n\t * Return logged user\n\t *\n\t * @return User|null\n\t */\n\tpublic function getResolver($opts) {\n\t\treturn Auth::user();\n\t}\n}\n\n# config/graphql.php\n\nreturn [\n\t'schema' =\u003e [\n\t\t'definitions' =\u003e [\n\t\t\t'default' =\u003e [\n\t\t\t\t'query' =\u003e [\n\t\t\t\t\t'viewer' =\u003e \\App\\GraphQL\\Query\\Viewer::class\n\t\t\t\t]\n\t\t\t]\n\t\t]\n\t],\n\n\t'definitions' =\u003e [\n\t\t\\App\\GraphQL\\Definition\\UserDefinition::class\n\t]\n];\n```\n\n`getResolver()` receives an array-argument with followed item:\n\n- `root` 1st argument given by webonyx library - `GraphQL\\Executor\\Executor::resolveOrError()`\n- `args` 2nd argument given by webonyx library\n- `context` 3rd argument given by webonyx library\n- `info` 4th argument given by webonyx library\n- `fields` array of fields, that were fetched from query. Limited by depth in `StudioNet\\GraphQL\\GraphQL::FIELD_SELECTION_DEPTH`\n- `with` array of relations, that could/should be eager loaded. **NOTICE:** Finding this relations happens ONLY, if `getSource()` is defined - this method should return a class name of a associated root-type in query. If `getSource()` is not defined, then `with` will be always empty.\n\n### Mutation\n\nMutation are used to update or create data.\n\n```php\n# app/GraphQL/Mutation/Profile.php\n\nnamespace App\\GraphQL\\Mutation;\n\nuse StudioNet\\GraphQL\\Support\\Definition\\Mutation;\nuse StudioNet\\GraphQL\\Definition\\Type;\nuse App\\User;\n\nclass Profile extends Mutation {\n\t/**\n\t * {@inheritDoc}\n\t */\n\tprotected function authorize(array $args) {\n\t\t// check, that user is not a guest\n\t\treturn !Auth::guest();\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t *\n\t * @return ObjectType\n\t */\n\tpublic function getRelatedType() {\n\t\treturn \\GraphQL::type('user');\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t */\n\tpublic function getArguments() {\n\t\treturn [\n\t\t\t'id'      =\u003e ['type' =\u003e Type::nonNull(Type::id())],\n\t\t\t'blocked' =\u003e ['type' =\u003e Type::string()]\n\t\t];\n\t};\n\n\t/**\n\t * Update user\n\t *\n\t * @param  mixed $root\n\t * @param  array $args\n\t *\n\t * @return User\n\t * @SuppressWarnings(PHPMD.UnusedFormalParameter)\n\t */\n\tpublic function getResolver($root, array $args) {\n\t\t$user = User::findOrFail($args['id']);\n\t\t$user-\u003eupdate($args);\n\n\t\treturn $user;\n\t}\n}\n\n# config/graphql.php\n\nreturn [\n\t'schema' =\u003e [\n\t\t'definitions' =\u003e [\n\t\t\t'default' =\u003e [\n\t\t\t\t'query' =\u003e [\n\t\t\t\t\t'viewer' =\u003e \\App\\GraphQL\\Query\\Viewer::class\n\t\t\t\t],\n\t\t\t\t'mutation' =\u003e [\n\t\t\t\t\t'viewer' =\u003e \\App\\GraphQL\\Mutation\\Profile::class\n\t\t\t\t]\n\t\t\t]\n\t\t]\n\t],\n\n\t'definitions' =\u003e [\n\t\t\\App\\GraphQL\\Definition\\UserDefinition::class\n\t]\n];\n```\n\n### Pipeline\n\nPipeline are used to convert a definition into queryable and mutable operations.\nBut, you can easily create your own and manage useful cases like asserting ACL\nbefore doing anything, etc.\n\nPipeline is implemented using the same [Laravel Middleware](https://laravel.com/docs/5.7/middleware) format\nbut pass as first argument the Eloquent Query Builder.\n\n## Create new pipe\n\n```php\nnamespace App/GraphQL/Pipe;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Builder;\n\nclass OnlyAuthored {\n\t/**\n\t * returns only posts that the viewer handle\n\t *\n\t * @param  Builder $builder\n\t * @param  Closure $next\n\t * @param  array $opts\n\t * @return \\Illuminate\\Database\\Eloquent\\Model\n\t */\n\tpublic function handle(Builder $builder, Closure $next, array $opts) {\n\t\t$builder-\u003ewhere('author_id', $opts['context']-\u003egetKey());\n\n\t\treturn $next($builder);\n\t}\n}\n```\n\n```php\nnamespace App\\GraphQL\\Definition;\n\nclass PostDefinition extends EloquentDefinition {\n\t// ...\n\n\t/**\n\t * {@inheritDoc}\n\t *\n\t * @return array\n\t */\n\tpublic function getPipes(): array {\n\t\treturn array_merge_recursive(parent::getPipes(), [\n\t\t\t'list' =\u003e [\\App\\GraphQL\\Pipe\\OnlyAuthored::class],\n\t\t]);\n\t}\n\t\n\t// ...\n}\n```\n\nWith this sample, when you'll query `posts` query, you'll only get viewer posts,\nnot all one. Also, you can specify arguments in the pipe, like following :\n\n```php\nnamespace App/GraphQL/Pipe;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse GraphQL\\Type\\Definition\\Type;\nuse StudioNet\\GraphQL\\Support\\Pipe\\Argumentable;\nuse StudioNet\\GraphQL\\Support\\Definition\\Definition;\n\nclass FilterableGroups implements Argumentable {\n\t/**\n\t * returns only given groups\n\t *\n\t * @param  Builder $builder\n\t * @param  Closure $next\n\t * @param  array $opts\n\t * @return \\Illuminate\\Database\\Eloquent\\Model\n\t */\n\tpublic function handle(Builder $builder, Closure $next, array $opts) {\n\t\tif (array_get($opts, ['args.group_ids', false])) {\n\t\t\t$builder-\u003ewhereIn('group_id', $opts['args']['group_ids']);\n\t\t}\n\n\t\treturn $next($builder);\n\t}\n\n\t/**\n\t * @implements\n\t *\n\t * @param  Definition $definition\n\t * @return array\n\t * @SuppressWarnings(PHPMD.UnusedFormalParameter)\n\t */\n\tpublic function getArguments(Definition $definition): array {\n\t\treturn [\n\t\t\t'groups_id' =\u003e [\n\t\t\t\t'type' =\u003e Type::json(),\n\t\t\t\t'description' =\u003e 'Filtering by group IDs'\n\t\t\t]\n\t\t];\n\t}\n}\n```\n\n### Require authorization\n\nCurrently you have a possibility to protect your own queries and mutations. You have to implement `authorize()` method in your query/mutation, that return a boolean, that indicates, if requested query/mutation has to be executed. If method return `false`, an `UNAUTHORIZED` GraphQL-Error will be thrown.\n\nUsage examples are in query and mutation above.\n\nProtection of definition transformers are currently not implemented, but may be will in the future. By now you have to define your query/mutation yourself, and protect it then with logic in `authorize()`.\n\n### Self documentation\n\nA documentation generator is implemented with the package. By default, you can access it by navigate to `/doc/graphql`. You can change this behavior within the configuration file. The built-in documentation is implemented from [this repository](https://github.com/mhallin/graphql-docs).\n\n### Examples\n\n```graphql\nquery {\n\tviewer {\n\t\tname\n\t\temail\n\n\t\tposts {\n\t\t\ttitle\n\t\t\tcontent\n\t\t}\n\t}\n}\n\n# is equivalent to (if user id exists)\n\nquery {\n\tuser (id: 1) {\n\t\tname\n\t\temail\n\n\t\tposts {\n\t\t\ttitle\n\t\t\tcontent\n\t\t}\n\t}\n}\n```\n\n#### Using filters\n\nWhen declaring the `getFilterable` array, you can define filters for fields.\n\nYou can either use a closure, an array, or give object of class implementing FilterInterface.\n\nThe closure (or the `FilterInterface::updateBuilder` method) is then called\nwith:\n\n* $builder : the current laravel query builder\n* $value : the filter value\n* $key : the filter key\n\nYou also may define graphql type for you filterable input field. By default `Type::json()` is used. There are several\noptions to define the type (all examples are listed in following code-block):\n\n- if you are using class that implements `TypedFilterInterface`, returned type from method\n`TypedFilterInterface::getType` is used;\n- if you are using closure, you have to define an array with keys `type` containing type you wish and `resolver` \ncontaining closure;\n- if you define an array, and in `resolver` is passed an object of class with implemented `TypedFilterInterface`, \nthen type of `TypedFilterInterface::getType` will overwrite the type in an array key `type`;\n- in all other situations `Type::json()` will be used as default type\n\nYou can also use the predefined `EqualsOrContainsFilter` like below.\n\n```php\n\tpublic function getFilterable() {\n\t\treturn [\n\t\t\t// Simple equality check (or \"in\" if value is an array). Type is Type::json()\n\t\t\t'id'       =\u003e new EqualsOrContainsFilter(),\n\t\t\t\n\t\t\t// Customized filter. Type is Type::json()\n\t\t\t\"nameLike\" =\u003e function($builder, $value) {\n\t\t\t\treturn $builder-\u003ewhereRaw('name like ?', $value);\n\t\t\t},\n\t\t\t\n\t\t\t// type is Type::string()\n\t\t\t\"anotherFilter\" =\u003e [\n\t\t\t\t\"type\" =\u003e Type::string(),\n\t\t\t\t\"resolver\" =\u003e function($builder, $value) {\n\t\t\t\t\treturn $builder-\u003ewhereRaw('anotherFilter like ?', $value);\t\t\t\t\n\t\t\t\t}\n\t\t\t],\n\t\t\t\n\t\t\t// type is what is returned from `ComplexFilter::getType()`.\n\t\t\t// This is the preffered way to define filters, as it keeps definitions code clean\n\t\t\t\"complexFilter\" =\u003e new ComplexFilter(),\n\t\t\t\n\t\t\t// type in array will be overriden by what is returned from `ComplexFilter::getType()`.\n\t\t\t// this kind of difinition is not clear, but is implemented for backward compatibilities. Please don't use it\n\t\t\t\"complexFilter2\" =\u003e [\n\t\t\t\t\"type\" =\u003e Type::int(),\n\t\t\t\t\"resolver\" =\u003e new ComplexFilter()\n\t\t\t],\n\t\t];\n\t}\n```\n\n\n```graphql\nquery {\n\tusers (take: 2, filter: {\"id\", \"1\"}) {\n\t\titems {\n\t\t\tid\n\t\t\tname\n\t\t}\n\t}\n}\n```\nThis will execute a query : `WHERE id = 1`\n\n```graphql\nquery {\n\tusers (take: 2, filter: {\"id\", [\"1,2\"]}) {\n\t\titems {\n\t\t\tid\n\t\t\tname\n\t\t}\n\t}\n}\n```\nThis will execute a query : `WHERE id in (1,2)`\n\n```graphql\nquery {\n\tusers (take: 2, filter: {\"nameLike\", \"%santiago%\"}) {\n\t\titems {\n\t\t\tid\n\t\t\tname\n\t\t}\n\t}\n}\n```\nThis will execute a query : `WHERE name like '%santiago%'`\n\n#### Ordering (`order_by`)\n\nYou can specify the order of the results (which calls Eloquent's `orderBy`) with\nthe `order_by` argument (which is a `String[]`).\n\n```graphql\nquery {\n\tusers (order_by: [\"name\"]) { items { id, name } }\n}\n```\n\nYou can specify a direction by appending `asc` (which is the default) or `desc`\nto the order field :\n\n```graphql\nquery {\n\tusers (order_by: [\"name_desc\"]) { items { id, name } }\n}\n```\n\nYou can specify multiple `order_by` :\n\n```graphql\nquery {\n\tusers (order_by: [\"name_asc\", \"email_desc\"]) { items { id, name } }\n}\n```\n\n#### Pagination : limit (`take`), offset (`skip`)\n\nYou can limit the number of results with `take` (`Int`) :\n\n```graphql\nquery {\n\tusers (order_by: [\"name\"], take: 5) { items { id, name } }\n}\n```\n\nYou can skip some results with `skip` (`Int`) :\n\n```graphql\nquery {\n\tusers (order_by: [\"name\"], take: 5, skip: 10) { items { id, name } }\n}\n```\n\nYou can get useful pagination information :\n\n```graphql\nquery {\n\tusers (order_by: [\"name\"], take: 5, skip: 10) {\n\t\tpagination {\n\t\t\ttotalCount\n\t\t\tpage\n\t\t\tnumPages\n\t\t\thasNextPage\n\t\t\thasPreviousPage\n\t\t}\n\t\titems {\n\t\t\tid\n\t\t\tname\n\t\t}\n\t}\n}\n```\n\nWhere :\n\n* `totalCount` is the total number of results\n* `page` is the current page (based on `take` which is used as the page size)\n* `numPages` is the total number of pages\n* `hasNextPage`, true if there is a next page\n* `hasPreviousPage`, true if there is a previous page\n\n#### Mutation\n\n```graphql\nmutation {\n\t# Delete object\n\tdelete : deleteUser(id: 5) {\n\t\tfirst_name\n\t\tlast_name\n\t},\n\n\t# Update object\n\tupdate : user(id: 5, with : { first_name : \"toto\" }) {\n\t\tid\n\t\tfirst_name\n\t\tlast_name\n\t},\n\n\t# Create object\n\tcreate : user(with : { first_name : \"toto\", last_name : \"blabla\" }) {\n\t\tid\n\t\tfirst_name\n\t\tlast_name\n\t},\n\n\t# Update or create many objects at once\n\tbatch  : users(objects: [{with: {first_name: 'studio'}}, {with: {first_name: 'net'}}]) {\n\t\tid\n\t\tfirst_name\n\t}\n}\n```\n\n#### Mutation: custom input fields\n\nYou can specify a \"mutable\" field which is not in the Eloquent Model, and define\na custom method to it.\n\nFor a field named `foo_bar`, the method has to be named `inputFooBarField`, and\nit has the Eloquent Model and the user input value as arguments.\n\nExemple (in `Definition`) :\n\n```php\n\tuse Illuminate\\Database\\Eloquent\\Model;\n\n\t/* ... */\n\n\tpublic function getMutable() {\n\t\treturn [\n\t\t\t'id' =\u003e Type::id(),\n\t\t\t'name' =\u003e Type::string(),\n\t\t\t// ...\n\t\t\t// Define a custom input field, which will uppercase the value\n\t\t\t'name_uppercase' =\u003e Type::string(),\n\t\t];\n\t}\n\n\t/* ... */\n\n\t/**\n\t * Custom input field for name_uppercase\n\t *\n\t * @param Model $model\n\t * @param string $value\n\t */\n\tpublic function inputNameUppercaseField(Model $model, $value) {\n\t\t$model-\u003ename = mb_strtoupper($value);\n\t}\n```\n\nThe input method is executed before the model is saved.\n\nYou can return an array with a \"saved\" callback, which will be executed\npost-save (which can be useful for eloquent relational models) :\n\n```php\n\t/**\n\t * Custom input field for name_uppercase\n\t *\n\t * @param Model $model\n\t * @param string $value\n\t */\n\tpublic function inputNameUppercaseField(Model $model, $value) {\n\t\t$model-\u003ename = mb_strtoupper($value);\n\n\t\treturn [\n\t\t\t'saved' =\u003e function() use ($model, $value) {\n\t\t\t\t// Executed after save\n\t\t\t}\n\t\t];\n\t}\n```\n\n### N+1 Problem\n\nThe common question is, if graphql library solves n+1 problem. This occures, when graphql resolves relation. Often entities are fetched without relations, and when graphql query needs to fetch relation, for each fetched entity relation would be fetched from SQL separately. So instead of executing 2 SQL queries, you will get N+1 queries, where N is the count of results of root entity. In that example you would query only one relation. If you query more relations, then it becomes N^2+1 problem.\n\nTo solve it, Eloquent has already options to eager load relations. Transformers in this library use eager loading, depends on what you query.\n\nCurrently this smart detection works perfect only on View and List Transformers. Other transformers will be reworked soon.\n\n## Contribution\n\nIf you want participate to the project, thank you ! In order to work properly,\nyou should install all dev dependencies and run the following commands before\npushing in order to prevent bad PR :\n\n```bash\n$\u003e ./vendor/bin/phpmd src text phpmd.xml\n$\u003e ./vendor/bin/phpmd tests text phpmd.xml\n$\u003e ./vendor/bin/phpstan analyse --autoload-file=_ide_helper.php --level 1 src\n$\u003e ./vendor/bin/php-cs-fixer fix\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstudio-net%2Flaravel-graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstudio-net%2Flaravel-graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstudio-net%2Flaravel-graphql/lists"}