diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index eca48c266a..4de9d38037 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,7 +15,5 @@ If so, describe the necessary changes in UPGRADE.md. --> ## Changelog diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f552a5bf0..a4a7867acc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Lighthouse Contribution Guide Thank you for contributing to Lighthouse. -Here are some tips and guidelines to make this easy for you. +Here are some tips and guidelines to help you. ## Open a Pull Request @@ -26,9 +26,9 @@ Before you release a new version, make sure to familiarize yourself with: To create a new release, follow these steps: 1. Copy the `## Changelog` sections of the pull requests merged since the last release into [`CHANGELOG.md`](CHANGELOG.md), appending each pull request URL. -Add missing entries if needed. + Add missing entries if needed. 2. Based on those entries and the previous version, define the next version number. -Add it to [`CHANGELOG.md`](CHANGELOG.md). + Add it to [`CHANGELOG.md`](CHANGELOG.md). 3. [Draft a new release](https://github.com/nuwave/lighthouse/releases/new) 4. Add the version number as both tag and title 5. Add the changelog entries as the description diff --git a/UPGRADE.md b/UPGRADE.md index 931a0fdd78..253b6b2763 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -14,9 +14,9 @@ Compare your `lighthouse.php` against the latest [default configuration](src/lig Methods you need to explicitly call to set up test traits were removed in favor of automatic setup. - Remove calls to `Nuwave\Lighthouse\Testing\RefreshesSchemaCache::bootRefreshesSchemaCache()`. -This only works when your test class uses the trait `Nuwave\Lighthouse\Testing\MakesGraphQLRequests`. + This only works when your test class uses the trait `Nuwave\Lighthouse\Testing\MakesGraphQLRequests`. - Replace calls to `Nuwave\Lighthouse\Testing\MakesGraphQLRequests::setUpSubscriptionEnvironment()` with ` use Nuwave\Lighthouse\Testing\TestsSubscriptions`. -This only works when your test class extends `Illuminate\Foundation\Testing\TestCase`. + This only works when your test class extends `Illuminate\Foundation\Testing\TestCase`. ### `EnsureXHR` is enabled in the default configuration @@ -240,7 +240,7 @@ final class MyDirective extends BaseDirective implements FieldResolver ### Simplify wrapping resolvers in `FieldMiddleware` directives -Wrapping resolvers is very common in `FieldMiddleware` directives and is now simplified. +Wrapping resolvers is common in `FieldMiddleware` directives and is now simplified. ```diff use Nuwave\Lighthouse\Execution\ResolveInfo; @@ -306,7 +306,8 @@ Use `executeQueryString()` for executing a string query or `executeParsedQuery() See https://github.com/webonyx/graphql-php/blob/master/UPGRADE.md#breaking-removed-error-extension-field-category. You can [leverage `GraphQL\Error\ProvidesExtensions`](https://lighthouse-php.com/master/digging-deeper/error-handling.html#additional-error-information) to restore `category` in your custom exceptions. -Additionally, you may [implement a custom error handler](https://lighthouse-php.com/master/digging-deeper/error-handling.html#registering-error-handlers) that wraps well-known third-party exceptions with your own exception that adds an appropriate `category`. +Additionally, you may [implement a custom error handler](https://lighthouse-php.com/master/digging-deeper/error-handling.html#registering-error-handlers) that wraps well-known third-party exceptions with your own exception. +Your exception adds an appropriate `category`. ### Use native interface for errors with extensions @@ -359,7 +360,8 @@ If you had previously depended on the presence of the schema in your cache, then ### Register `ScoutServiceProvider` if you use `@search` -If you use the `@search` directive in your schema, you will now need to register the service provider `Nuwave\Lighthouse\Scout\ScoutServiceProvider`, it is no longer registered by default. +If you use the `@search` directive in your schema, register the service provider `Nuwave\Lighthouse\Scout\ScoutServiceProvider`. +It is no longer registered by default. See [registering providers in Laravel](https://laravel.com/docs/providers#registering-providers). ### Update `lighthouse.guard` configuration @@ -402,8 +404,7 @@ The recommended process for finding breaking changes is: 1. Print your schema before upgrading: `php artisan lighthouse:print-schema > old.graphql` 1. Upgrade, then re-print your schema: `php artisan lighthouse:print-schema > new.graphql` -1. Use [graphql-inspector](https://github.com/kamilkisiela/graphql-inspector) to compare your -changes: `graphql-inspector diff old.graphql new.graphql` +1. Use [graphql-inspector](https://github.com/kamilkisiela/graphql-inspector) to compare your changes: `graphql-inspector diff old.graphql new.graphql` ### Rename `resolve` to `__invoke` @@ -432,13 +433,14 @@ type Query { } ``` -Note that [@guard](docs/master/api-reference/directives.md#guard) does not log in users. -To ensure the user is logged in, add the `AttemptAuthenticate` middleware to your `lighthouse.php` middleware config, see the [default config](src/lighthouse.php) for an example. +[@guard](docs/master/api-reference/directives.md#guard) does not log in users. +To ensure the user is logged in, add the `AttemptAuthenticate` middleware to your `lighthouse.php` middleware config. +See the [default config](src/lighthouse.php) for an example. If you used `@middleware` for authorization, replace it with [@can](docs/master/api-reference/directives.md#can). Other functionality can be replaced by a custom [`FieldMiddleware`](docs/master/custom-directives/field-directives.md#fieldmiddleware) directive. -Just like Laravel Middleware, it can wrap around individual field resolvers. +Like Laravel Middleware, it can wrap around individual field resolvers. ### Directives must have an SDL definition @@ -452,7 +454,7 @@ If you previously implemented `DefinedDirective`, remove it from your directives +class TrimDirective extends BaseDirective implements ArgTransformerDirective ``` -Instead of just providing the name of the directive, all directives must now return an SDL definition that formally describes them. +Instead of only providing the name of the directive, all directives must now return an SDL definition that formally describes them. ```diff - public function name() @@ -503,7 +505,8 @@ Client queries will have to be changed like this: } ``` -If you absolutely cannot break your clients, you can re-implement `@orderBy` in your project. It is a relatively simple `ArgManipulator` directive. +If you absolutely cannot break your clients, you can re-implement `@orderBy` in your project. +It is a small `ArgManipulator` directive. ### `@modelClass` and `@model` changed @@ -545,9 +548,9 @@ type Mutation { } ``` -### `@method` passes down just ordered arguments +### `@method` passes down only ordered arguments -Instead of passing down the usual resolver arguments, the `@method` directive will now pass just the arguments given to a field. +Instead of passing down the usual resolver arguments, the `@method` directive will now pass only the arguments given to a field. This behavior could previously be enabled through the `passOrdered` option, which is now removed. ```graphql @@ -571,7 +574,8 @@ This affects custom directives that implemented one of the following interfaces: - `Nuwave\Lighthouse\Support\Contracts\ArgTransformerDirective` - `Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective` -Whereas those interfaces previously extended `Nuwave\Lighthouse\Support\Contracts\ArgDirective`, you now have to choose if you want them to apply to entire lists of arguments, elements within that list. +Those interfaces previously extended `Nuwave\Lighthouse\Support\Contracts\ArgDirective`. +Now you have to choose if you want them to apply to entire lists of arguments, or to elements within that list. Or both. Change them as follows to make them behave like in v4: @@ -589,10 +593,10 @@ use Nuwave\Lighthouse\Support\Contracts\DefinedDirective; The application of directives that implement the `ArgDirective` interface is split into three distinct phases: - Sanitize: Clean the input, e.g. trim whitespace. -Directives can hook into this phase by implementing `ArgSanitizerDirective`. + Directives can hook into this phase by implementing `ArgSanitizerDirective`. - Validate: Ensure the input conforms to the expectations, e.g. check a valid email is given - Transform: Change the input before processing it further, e.g. hashing passwords. -Directives can hook into this phase by implementing `ArgTransformerDirective` + Directives can hook into this phase by implementing `ArgTransformerDirective` ### Replace custom validation directives with validator classes @@ -642,13 +646,16 @@ type Mutation { The event is no longer fired, and the event class was removed. Lighthouse now uses a queued job instead. -If you manually fired the event, replace it by queuing a `Nuwave\Lighthouse\Subscriptions\BroadcastSubscriptionJob` or a call to `Nuwave\Lighthouse\Subscriptions\Contracts\BroadcastsSubscriptions::queueBroadcast()`. +If you manually fired the event, queue a `Nuwave\Lighthouse\Subscriptions\BroadcastSubscriptionJob` instead. +Alternatively, call `Nuwave\Lighthouse\Subscriptions\Contracts\BroadcastsSubscriptions::queueBroadcast()`. -In case you depend on an event being fired whenever a subscription is queued, you can bind your own implementation of `Nuwave\Lighthouse\Subscriptions\Contracts\BroadcastsSubscriptions`. +You may depend on an event being fired whenever a subscription is queued. +Then bind your own implementation of `Nuwave\Lighthouse\Subscriptions\Contracts\BroadcastsSubscriptions`. ### `TypeRegistry` does not register duplicates by default -Calling `register()` on the `Nuwave\Lighthouse\Schema\TypeRegistry` now throws when passing a type that was already registered, as this most likely is an error. +Calling `register()` on the `Nuwave\Lighthouse\Schema\TypeRegistry` now throws when passing a type that was already registered. +This is most likely an error. If you want to previous behavior of overwriting existing types, use `overwrite()` instead. @@ -662,7 +669,7 @@ $typeRegistry = app(\Nuwave\Lighthouse\Schema\TypeRegistry::class); Since GraphQL constrains allowed inputs by design, mass assignment protection is not needed. By default, Lighthouse will use `forceFill()` when populating a model with arguments in mutation directives. -This allows you to use mass assignment protection for other cases where it is actually useful. +This allows you to use mass assignment protection for other cases where it is useful. If you need to revert to the old behavior of using `fill()`, you can change your `lighthouse.php`: diff --git a/docs/master/api-reference/commands.md b/docs/master/api-reference/commands.md index d99ee18c88..12dde2ea61 100644 --- a/docs/master/api-reference/commands.md +++ b/docs/master/api-reference/commands.md @@ -61,7 +61,8 @@ A great way to keep up to date with your current version of Lighthouse is to add ], ``` -If the generated definitions conflict with those provided by your IDE, try `--omit-built-in` to avoid redefining built-in directives such as `@deprecated`. +If the generated definitions conflict with those of your IDE, try `--omit-built-in`. +It avoids redefining built-in directives such as `@deprecated`. ## interface @@ -89,7 +90,7 @@ Compile the GraphQL schema and print the result. php artisan lighthouse:print-schema ``` -This can be quite useful, as the root `.graphql` files do not necessarily contain the whole schema. +This is useful, as the root `.graphql` files do not necessarily contain the whole schema. Schema imports, native PHP types and schema manipulation may influence the final schema. Use the `-W` / `--write` option to output the schema to default file storage (usually `storage/app`). diff --git a/docs/master/api-reference/directives.md b/docs/master/api-reference/directives.md index 1fad092db3..b39a3e1e7a 100644 --- a/docs/master/api-reference/directives.md +++ b/docs/master/api-reference/directives.md @@ -156,11 +156,10 @@ type Query { Defer the execution of mutations to [queued jobs](https://laravel.com/docs/queues). This directive must only be used on fields of the root mutation type. -When the field is executed, a `Nuwave\Lighthouse\Async\AsyncMutation` job is dispatched -and the value `true` is returned - thus the fields return type must be `Boolean!`. +When the field is executed, a `Nuwave\Lighthouse\Async\AsyncMutation` job is dispatched and the value `true` is returned. +Thus, the field's return type must be `Boolean!`. -Once a [queue worker](https://laravel.com/docs/queues#running-the-queue-worker) picks up the job, -it will actually execute the underlying field resolver. +Once a [queue worker](https://laravel.com/docs/queues#running-the-queue-worker) picks up the job, it executes the underlying field resolver. Errors that occur during execution are reported through the Laravel exception handler. The handlers in the `config/lighthouse.php` option `error_handlers` are not called. """ @@ -221,8 +220,8 @@ Resolves a field through the Eloquent `BelongsTo` relationship. """ directive @belongsTo( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -273,8 +272,8 @@ Resolves a field through the Eloquent `BelongsToMany` relationship. """ directive @belongsToMany( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -303,8 +302,8 @@ directive @belongsToMany( maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -371,8 +370,9 @@ type User { You may want to allow accessing data that describes the relation between the models and is stored in the intermediate table. See [retrieving intermediate table columns in Laravel](https://laravel.com/docs/eloquent-relationships#retrieving-intermediate-table-columns). -Just like in Laravel, you can access the `pivot` attribute on the models (or its alias). -Even though this attribute is always present when querying the model through the relation, it may not be present when reaching the node through another path in the schema. +Like in Laravel, you can access the `pivot` attribute on the models (or its alias). +This attribute is always present when querying the model through the relation. +It may be missing when reaching the node through another path in the schema. It is recommended to define the field as nullable (no `!`). The following example assumes the intermediate table between `User` and `Role` defines a column `meta`. @@ -418,7 +418,8 @@ type RoleUserPivot { } ``` -When using the `type` argument with pagination style `CONNECTION`, you may create your own [edge type](https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types) that either contains the attributes of the intermediate table or contains a `pivot` field with the corresponding type. +When using the `type` argument with pagination style `CONNECTION`, you may create your own [edge type](https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types). +It contains either the attributes of the intermediate table or a `pivot` field with the corresponding type. The custom edge type must contain at least the following two fields: @@ -613,6 +614,8 @@ final class AddUsersToCompany ```graphql """ Broadcast the results of a mutation to subscribed clients. + +Place this after other field middleware directives that may transform the result, so it broadcasts the final value. """ directive @broadcast( """ @@ -678,8 +681,7 @@ scalar BuilderValue You must point to a `method` that receives the builder instance. That method can apply additional constraints to the query. -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). When used on an argument, the method is only called when the argument is specified (may be `null`). @@ -719,6 +721,8 @@ final class MyClass ```graphql """ Cache the result of a resolver. + +Place this after other field middleware to ensure it caches the correct transformed value. """ directive @cache( """ @@ -729,8 +733,8 @@ directive @cache( """ Limit access to cached data to the currently authenticated user. - When the field is accessible by guest users, this will not have - any effect, they will access a shared cache. + This has no effect when guest users can access the field. + Guest users access a shared cache. """ private: Boolean = false ) on FIELD_DEFINITION @@ -818,8 +822,7 @@ injectArgs: Boolean! = false """ Statically defined arguments that are passed to `Gate::check`. -You may pass arbitrary GraphQL literals, -e.g.: [1, 2, 3] or { foo: "bar" } +You may pass any GraphQL literal, e.g. `[1, 2, 3]` or `{ foo: "bar" }`. """ args: CanArgs @@ -831,18 +834,24 @@ action: CanAction! = EXCEPTION_PASS """ Value to return if the user is not authorized and `action` is `RETURN_VALUE`. """ -returnValue: CanArgs -""" +returnValue: CanReturnValue ``` Types are specified as: ```graphql """ -Any constant literal value: https://graphql.github.io/graphql-spec/draft/#sec-Input-Values +Any constant literal value. +See https://graphql.github.io/graphql-spec/draft/#sec-Input-Values. """ scalar CanArgs +""" +Any constant literal value. +See https://graphql.github.io/graphql-spec/draft/#sec-Input-Values. +""" +scalar CanReturnValue + enum CanAction { """ Pass exception to the client. @@ -855,7 +864,7 @@ enum CanAction { EXCEPTION_NOT_AUTHORIZED """ - Return the value specified in `returnValue` argument to conceal the real error. + Return the value specified in the `returnValue` directive argument to conceal the real error. """ RETURN_VALUE } @@ -869,11 +878,11 @@ You can find usage examples of these directives in [the authorization docs](../s """ Check a Laravel Policy to ensure the current user is authorized to access a field. -Query for specific model instances to check the policy against, using primary key(s) from specified argument. +Query for specific model instances to check the policy against, using the primary key(s) from the specified argument. """ directive @canFind( """ - Specify the name of the field argument that contains its primary key(s). + Specify the name of the field argument that contains the primary key(s). You may pass the string in dot notation to use nested inputs. """ @@ -919,8 +928,8 @@ directive @canModel( """ Check a Laravel Policy to ensure the current user is authorized to access a field. -Query for specific model instances to check the policy against, using arguments -with directives that add constraints to the query builder, such as `@eq`. +Query for specific model instances to check the policy against. +Use arguments with directives that add constraints to the query builder, such as `@eq`. """ directive @canQuery( """ @@ -1049,6 +1058,8 @@ Replaces incoming empty strings `""` with `null`. When used upon fields, empty strings for non-nullable inputs will pass unchanged. Only explicitly placing this on non-nullable inputs will force the conversion. + +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @convertEmptyStringsToNull on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION ``` @@ -1081,14 +1092,7 @@ type Mutation { } ``` -If you want this for all your fields, add this directive to your global field middleware in `lighthouse.php`: - -```php - 'field_middleware' => [ - \Nuwave\Lighthouse\Schema\Directives\ConvertEmptyStringsToNullDirective::class, - ... - ], -``` +The default `field_middleware` setting in `lighthouse.php` applies this directive to every field. ## @count @@ -1159,8 +1163,7 @@ directive @create( """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION @@ -1212,8 +1215,7 @@ directive @createMany( """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION @@ -1246,8 +1248,7 @@ directive @delete( """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String @@ -1296,7 +1297,8 @@ type Mutation { } ``` -If the model relates to a single other model through a `HasOne`, `MorphOne`, `BelongsTo` or `MorphTo` relationship, you can pass a Boolean instead of an ID, as there is only one possible model that can be deleted. +For a `HasOne`, `MorphOne`, `BelongsTo` or `MorphTo` relationship to a single other model, you can pass a Boolean instead of an ID. +There is only one possible model to delete. ```graphql type Mutation { @@ -1373,7 +1375,7 @@ directive @feature( Specify what the state of the feature should be for the field to be included. """ when: FeatureState! = ACTIVE -) on FIELD_DEFINITION | OBJECT +) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION | OBJECT """ Options for the `when` argument of `@feature`. @@ -1391,7 +1393,8 @@ enum FeatureState { } ``` -Requires the installation of [Laravel Pennant](https://laravel.com/docs/pennant) and manual registration of the service provider `Nuwave\Lighthouse\Pennant\PennantServiceProvider`, see [registering providers in Laravel](https://laravel.com/docs/providers#registering-providers). +Requires the installation of [Laravel Pennant](https://laravel.com/docs/pennant). +Register the service provider `Nuwave\Lighthouse\Pennant\PennantServiceProvider` manually, see [registering providers in Laravel](https://laravel.com/docs/providers#registering-providers). ## @field @@ -1421,7 +1424,8 @@ type Mutation { } ``` -You can take advantage of the default namespaces that are defined in the [configuration](../getting-started/configuration.md), The following will look for a class in `App\GraphQL\Queries` by default. +You can take advantage of the default namespaces that are defined in the [configuration](../getting-started/configuration.md). +The following will look for a class in `App\GraphQL\Queries` by default. ```graphql type Query { @@ -1541,15 +1545,14 @@ type Mutation { } ``` -Works very similar to the [@delete](#delete) directive. +Works like the [@delete](#delete) directive. ## @enum ```graphql """ Assign an internal value to an enum key. -When dealing with the Enum type in your code, -you will receive the defined value instead of the string key. +Your code receives the internal value instead of the string key. """ directive @enum( """ @@ -1668,8 +1671,8 @@ final class PlacedOrder """ Converts between IDs/types and global IDs. -When used upon a field, it encodes; -when used upon an argument, it decodes. +On a field, it encodes the value. +On an argument, it decodes the value. """ directive @globalId( """ @@ -1689,18 +1692,19 @@ enum GlobalIdDecode { ARRAY """ - Return just `$type`. + Return only `$type`. """ TYPE """ - Return just `$id`. + Return only `$id`. """ ID } ``` -Instead of the original ID, the `id` field will now return a base64-encoded String that globally identifies the User and can be used for querying the `node` endpoint. +Instead of the original ID, the `id` field now returns a base64-encoded String that globally identifies the User. +Clients can use it to query the `node` endpoint. ```graphql type User { @@ -1725,8 +1729,7 @@ You may rebind the `Nuwave\Lighthouse\Support\Contracts\GlobalId` interface to a """ Run authentication through one or more guards from `config/auth.php`. -This is run per field and may allow unauthenticated -users to still receive partial results. +This runs per field, so unauthenticated users may still receive partial results. Used upon an object, it applies to all fields within. """ @@ -1739,7 +1742,7 @@ directive @guard( ) repeatable on FIELD_DEFINITION | OBJECT ``` -Note that [@guard](#guard) does not log in users. +[@guard](#guard) does not log in users. To ensure the user is logged in, add the `AttemptAuthenticate` middleware to your `lighthouse.php` middleware config. ```php @@ -1797,8 +1800,8 @@ Corresponds to [the Eloquent relationship HasMany](https://laravel.com/docs/eloq """ directive @hasMany( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -1827,8 +1830,8 @@ directive @hasMany( maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -1888,8 +1891,8 @@ Corresponds to [the Eloquent relationship HasManyThrough](https://laravel.com/do """ directive @hasManyThrough( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -1918,8 +1921,8 @@ directive @hasManyThrough( maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -1957,8 +1960,8 @@ Corresponds to [the Eloquent relationship HasOne](https://laravel.com/docs/eloqu """ directive @hasOne( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -1991,8 +1994,8 @@ Corresponds to [the Eloquent relationship HasOneThrough](https://laravel.com/doc """ directive @hasOneThrough( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -2032,8 +2035,7 @@ directive @in( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```graphql @@ -2051,17 +2053,14 @@ Inject a value from the context object into the arguments. directive @inject( """ A path to the property of the context that will be injected. - If the value is nested within the context, you may use dot notation - to get it, e.g. "user.id". + Use dot notation to get a nested value from the context, e.g. `user.id`. """ context: String! """ The target name of the argument into which the value is injected. - You can use dot notation to set the value at arbitrary depth - within the incoming argument. - Use an asterisk `*` as a path segment to inject the value into every - element of a list found at that position. + Use dot notation to set the value at any depth within the incoming arguments. + Use an asterisk `*` as a path segment to inject the value into every element of a list found at that position. """ name: String! ) repeatable on FIELD_DEFINITION @@ -2088,8 +2087,8 @@ type Mutation { } ``` -If you need to inject a value into every element of a list, such as a nested `create` mutation -for a `HasMany` relation, use an asterisk `*` as a wildcard path segment. +To inject a value into every element of a list, use an asterisk `*` as a wildcard path segment. +An example is a nested `create` mutation for a `HasMany` relation. ```graphql type Mutation { @@ -2181,7 +2180,7 @@ directive @hide( Compared against the value returned from `app()->environment()`. """ env: [String!]! -) repeatable on FIELD_DEFINITION +) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION | OBJECT ``` See [feature toggles](../digging-deeper/feature-toggles.md). @@ -2190,8 +2189,7 @@ See [feature toggles](../digging-deeper/feature-toggles.md). ```graphql """ -Perform a [lazy eager load](https://laravel.com/docs/eloquent-relationships#lazy-eager-loading) -on the relations of a list of models. +Perform a [lazy eager load](https://laravel.com/docs/eloquent-relationships#lazy-eager-loading) on the relations of a list of models. """ directive @lazyLoad( """ @@ -2225,8 +2223,7 @@ directive @like( key: String """ - Fixate the positions of wildcards (`%`, `_`) in the LIKE comparison around the - placeholder `{}`, e.g. `%{}`, `__{}` or `%{}%`. + Fix the positions of wildcards (`%`, `_`) around the placeholder `{}` in the LIKE comparison, e.g. `%{}`, `__{}` or `%{}%`. If specified, wildcard characters in the client-given input are escaped. If not specified, the client can pass wildcards unescaped. """ @@ -2240,26 +2237,24 @@ directive @like( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ## @limit ```graphql """ -Allow clients to specify the maximum number of results to return when used on an argument, -or statically limit them when used on a field. +On an argument, allow clients to specify the maximum number of results to return. +On a field, limit the number of results statically. -By default, this directive does not influence the number of results the resolver queries internally, -but limits how much of it is returned to clients. Use the `builder` argument to change this. +By default, this directive does not change how many results the resolver queries internally. +It only limits how many of them are returned to clients. +Use the `builder` argument to change this. """ directive @limit( """ - You may set this to `true` if the field uses a query builder, - then this directive will apply a LIMIT clause to it. - Typically, this option should only be used for root fields, - as it may cause wrong results with batched relation queries. + Set this to `true` to apply a LIMIT clause to the query builder of the field. + Only use this on root fields, as it may cause wrong results with batched relation queries. """ builder: Boolean! = false ) on ARGUMENT_DEFINITION | FIELD_DEFINITION @@ -2310,8 +2305,7 @@ type Query { """ Resolve a field by calling a method on the parent object. -Use this if the data is not accessible through simple property access or if you -want to pass argument to the method. +Use this if the data is not accessible through simple property access, or to pass arguments to the method. """ directive @method( """ @@ -2393,8 +2387,8 @@ Corresponds to [Eloquent's MorphMany-Relationship](https://laravel.com/docs/eloq """ directive @morphMany( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -2423,8 +2417,8 @@ directive @morphMany( maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -2472,8 +2466,8 @@ Corresponds to [Eloquent's MorphOne-Relationship](https://laravel.com/docs/eloqu """ directive @morphOne( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -2504,8 +2498,8 @@ Corresponds to [Eloquent's MorphTo-Relationship](https://laravel.com/docs/eloque """ directive @morphTo( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -2532,8 +2526,8 @@ Corresponds to [Eloquent's ManyToMany-Polymorphic-Relationship](https://laravel. """ directive @morphToMany( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -2562,8 +2556,8 @@ directive @morphToMany( maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -2670,8 +2664,7 @@ directive @neq( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```graphql @@ -2684,8 +2677,7 @@ type User { ```graphql """ -A no-op nested arg resolver that delegates all calls -to the ArgResolver directives attached to the children. +A no-op nested arg resolver that delegates all calls to the ArgResolver directives of its children. """ directive @nest on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` @@ -2722,8 +2714,7 @@ type User { """ Register a type for Relay's global object identification. -When used without any arguments, Lighthouse will attempt -to resolve the type through a model with the same name. +Without arguments, Lighthouse tries to resolve the type through the model with the same name. """ directive @node( """ @@ -2807,8 +2798,7 @@ directive @notIn( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```graphql @@ -2899,8 +2889,7 @@ input OrderByRelation { } ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). See [ordering](../digging-deeper/ordering.md). @@ -3000,8 +2989,7 @@ type Query { } ``` -> When you want to paginate a relationship, use the to-many relationship -> directives such as [@hasMany](directives.md#hasmany) instead. +> When you want to paginate a relationship, use the to-many relationship directives such as [@hasMany](directives.md#hasmany) instead. The schema definition is automatically transformed to this: @@ -3124,8 +3112,7 @@ But means that the response does not hold information about the total number of If you wish to use the `simplePaginate` method, set the `type` to `SIMPLE`. -> Please note that the `SIMPLE` paginator does not have the attributes -> `lastPage` and `total`. +> The `SIMPLE` paginator does not have the attributes `lastPage` and `total`. > > If you need those fields, you should use the default `PAGINATOR`. @@ -3242,7 +3229,7 @@ type Query { ### Custom builder -If simply querying Eloquent does not fit your use-case, you can specify a custom `builder`. +If a plain Eloquent query does not fit your use case, you can specify a custom `builder`. ```graphql type Query { @@ -3253,8 +3240,7 @@ type Query { Your method receives the typical resolver arguments. It must return an instance of `Illuminate\Database\Query\Builder`. -> If you actually want to query a model and possibly its relations through nested fields, -> make sure to return an Eloquent builder, e.g. `Post::query()`. +> If you want to query a model and possibly its relations through nested fields, make sure to return an Eloquent builder, e.g. `Post::query()`. ```php namespace App\Models; @@ -3376,7 +3362,7 @@ type Mutation { } ``` -Works very similar to the [@delete](#delete) directive. +Works like the [@delete](#delete) directive. ## @rules @@ -3387,10 +3373,9 @@ Validate an argument using [Laravel validation](https://laravel.com/docs/validat directive @rules( """ Specify the validation rules to apply to the field. - This can either be a reference to [Laravel's built-in validation rules](https://laravel.com/docs/validation#available-validation-rules), - or the fully qualified class name of a custom validation rule. + Reference either one of [Laravel's built-in validation rules](https://laravel.com/docs/validation#available-validation-rules) or the fully qualified class name of a custom validation rule. - Validation rules that mutate the given input values are _not_ supported: + Validation rules that mutate the given input value are _not_ supported: - `exclude_if` - `exclude_unless` Use ArgTransformerDirectives or FieldMiddlewareDirectives instead. @@ -3443,8 +3428,7 @@ Run validation on an array itself, using [Laravel built-in validation](https://l directive @rulesForArray( """ Specify the validation rules to apply to the field. - This can either be a reference to any of Laravel's built-in validation rules: https://laravel.com/docs/validation#available-validation-rules, - or the fully qualified class name of a custom validation rule. + Reference either one of [Laravel's built-in validation rules](https://laravel.com/docs/validation#available-validation-rules) or the fully qualified class name of a custom validation rule. Validation rules that mutate the given input values are _not_ supported: - `exclude_if` @@ -3529,7 +3513,7 @@ scalar DateTime Adds a scope to the query builder. The scope method will receive the client-given value of the argument as the second parameter. -This also works with custom query builders, it simply calls its methods with the argument value. +This also works with custom query builders, it calls its methods with the argument value. """ directive @scope( """ @@ -3540,8 +3524,7 @@ directive @scope( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```graphql @@ -3584,7 +3567,8 @@ directive @search( ) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -Requires the installation of [Laravel Scout](https://laravel.com/docs/scout) and manual registration of the service provider `Nuwave\Lighthouse\Scout\ScoutServiceProvider`, see [registering providers in Laravel](https://laravel.com/docs/providers#registering-providers). +Requires the installation of [Laravel Scout](https://laravel.com/docs/scout). +Register the service provider `Nuwave\Lighthouse\Scout\ScoutServiceProvider` manually, see [registering providers in Laravel](https://laravel.com/docs/providers#registering-providers). The model `search()` method is called with the argument value. It uses the Scout driver you configured. @@ -3603,7 +3587,8 @@ The [@search](#search) directive only works in combination with filter directive Scout is only activated if an argument annotated with [@search](#search) is present with a string value. Passing `null` behaves the same as leaving the argument out and falls back to a database query. -When using [@convertEmptyStringsToNull](#convertemptystringstonull), nullable `String` arguments with an empty string value may be converted to `null` and therefore not activate Scout. +With [@convertEmptyStringsToNull](#convertemptystringstonull), nullable `String` arguments with an empty string value may become `null`. +Those do not activate Scout. If you need empty-string search behavior, prefer an explicit schema contract such as a dedicated search field or a non-null search argument. Normally the search will be performed using the index specified by the model's `searchableAs` method. @@ -3623,11 +3608,11 @@ Includes the annotated element from the schema conditionally. """ directive @show( """ - Specify which environments include this element, e.g. ["testing"]. + Specify which environments include this element, e.g. `["testing"]`. Compared against the value returned from `app()->environment()`. """ env: [String!]! -) repeatable on FIELD_DEFINITION +) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION | OBJECT ``` See [feature toggles](../digging-deeper/feature-toggles.md). @@ -3637,8 +3622,7 @@ See [feature toggles](../digging-deeper/feature-toggles.md). ```graphql """ Allows to filter if trashed elements should be fetched. -This manipulates the schema by adding the argument -`trashed: Trashed @trashed` to the field. +This adds the argument `trashed: Trashed @trashed` to the field. """ directive @softDeletes on FIELD_DEFINITION ``` @@ -3665,8 +3649,7 @@ Find out how the added filter works: [@trashed](#trashed) ```graphql """ -Merge the fields of a nested input object into the arguments of its parent -when processing the field arguments given by a client. +Merge the fields of a nested input object into the arguments of its parent when processing the field arguments given by a client. """ directive @spread on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` @@ -3714,7 +3697,7 @@ Internally, the arguments are transformed into a flat structure before they are ] ``` -Note that Lighthouse spreads out the arguments **after** all other [ArgDirectives](../custom-directives/field-argument-directives) have been applied, e.g. validation, transformation. +Lighthouse spreads out the arguments **after** all other [ArgDirectives](../custom-directives/field-argument-directives) have been applied, e.g. validation, transformation. ## @subscription @@ -3745,7 +3728,8 @@ type Subscription { ```graphql """ -Sets rate limit to access the field. Does the same as ThrottleRequests Laravel Middleware. +Limit the rate of access to the field. +Works like the Laravel middleware `ThrottleRequests`. """ directive @throttle( """ @@ -3786,8 +3770,7 @@ Allows to filter if trashed elements should be fetched. directive @trashed on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). The most convenient way to use this directive is through [@softDeletes](#softdeletes). @@ -3809,6 +3792,8 @@ Remove whitespace from the beginning and end of a given input. This can be used on: - a single argument or input field to sanitize that subtree - a field to trim all strings + +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @trim on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION ``` @@ -3829,14 +3814,7 @@ type Mutation { } ``` -If you want this for all your fields, add this directive to your global field middleware in `lighthouse.php`: - -```php - 'field_middleware' => [ - \Nuwave\Lighthouse\Schema\Directives\TrimDirective::class, - ... - ], -``` +The default `field_middleware` setting in `lighthouse.php` applies this directive to every field. ## @union @@ -3915,8 +3893,7 @@ directive @update( """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION @@ -3966,8 +3943,7 @@ directive @updateMany( """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION @@ -3990,8 +3966,8 @@ input UpdatePostInput { ```graphql """ -Uploads given file to storage, removes the argument and sets -the returned path to the attribute key provided. +Upload the given file to storage and remove the argument. +The returned path is set to the given attribute key. This does not change the schema from a client perspective. """ @@ -4049,14 +4025,13 @@ directive @upsert( """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -Lighthouse will try to fetch the model by its primary key, just like [@update](#update). +Lighthouse will try to fetch the model by its primary key, like [@update](#update). If the model doesn't exist, it will be newly created with a given `id`. In case no `id` is specified, an auto-generated fresh ID will be used instead. @@ -4099,8 +4074,7 @@ directive @upsertMany( """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION @@ -4133,7 +4107,8 @@ input UpsertUserInput { } ``` -For `@upsertMany`, all configured identifying columns must be present with non-null values for every input item, otherwise the upsert fails with a GraphQL error. +For `@upsertMany`, every input item must have non-null values for all configured identifying columns. +Otherwise, the upsert fails with a GraphQL error. ## @validator @@ -4145,9 +4120,8 @@ directive @validator( """ The name of the class to use. - If defined on an input, this defaults to a class called `{$inputName}Validator` in the - default validator namespace. For fields, it uses the namespace of the parent type - and the field name: `{$parent}\{$field}Validator`. + If defined on an input, this defaults to a class called `{$inputName}Validator` in the default validator namespace. + For fields, it uses the namespace of the parent type and the field name: `{$parent}\{$field}Validator`. """ class: String ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION | INPUT_OBJECT @@ -4197,8 +4171,7 @@ Any constant literal value: https://graphql.github.io/graphql-spec/draft/#sec-In scalar WhereValue ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). You can specify simple operators: @@ -4269,8 +4242,7 @@ directive @whereAuth( ) on FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). The following query returns all posts that belong to the currently authenticated user. @@ -4288,8 +4260,7 @@ type Query { """ Verify that a column's value is between two values. -The type of the input value this is defined upon should be -an `input` object with two fields. +The type of the argument or input field should be an `input` object with two fields. """ directive @whereBetween( """ @@ -4300,8 +4271,7 @@ directive @whereBetween( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). This example defines an `input` to filter that a value is between two dates. @@ -4343,8 +4313,7 @@ directive @whereJsonContains( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```graphql @@ -4400,8 +4369,7 @@ type Mutation { """ Verify that a column's value lies outside two values. -The type of the input value this is defined upon should be -an `input` object with two fields. +The type of the argument or input field should be an `input` object with two fields. """ directive @whereNotBetween( """ @@ -4412,8 +4380,7 @@ directive @whereNotBetween( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```graphql @@ -4450,8 +4417,7 @@ directive @whereNotNull( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```graphql @@ -4481,8 +4447,7 @@ directive @whereNull( ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```graphql @@ -4499,8 +4464,8 @@ Eager-load an Eloquent relation. """ directive @with( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -4520,7 +4485,7 @@ type User { } ``` -If you just want to return the relation as-is, see [handling Eloquent relationships](../eloquent/relationships.md). +To return the relation as-is, see [handling Eloquent relationships](../eloquent/relationships.md). ## @withCount @@ -4528,9 +4493,9 @@ If you just want to return the relation as-is, see [handling Eloquent relationsh """ Eager-load the count of an Eloquent relation if the field is queried. -Note that this does not return a value for the field, the count is simply -prefetched, assuming it is used to compute the field value. Use `@count` -if the field should simply return the relation count. +This does not return a value for the field. +It only prefetches the count, assuming the field value is computed from it. +Use `@count` to return the relation count as the field value. """ directive @withCount( """ @@ -4553,7 +4518,7 @@ type User { } ``` -If you just want to return the count itself as-is, use [@count](#count). +To return the count as-is, use [@count](#count). ## @withoutGlobalScopes @@ -4572,8 +4537,7 @@ directive @withoutGlobalScopes( ) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -> This directive only works when the field resolver passes its builder through -> `$resolveInfo->enhanceBuilder()`. +> This directive only works when the field resolver passes its builder through `$resolveInfo->enhanceBuilder()`. > Built-in field resolver directives that query the database do this, such as [@all](#all) or [@hasMany](#hasmany). ```php diff --git a/docs/master/api-reference/events.md b/docs/master/api-reference/events.md index 2d1871e043..1a0426abcf 100644 --- a/docs/master/api-reference/events.md +++ b/docs/master/api-reference/events.md @@ -15,23 +15,18 @@ use Illuminate\Support\Carbon; /** * Fires right after a request reaches the GraphQLController. * - * Can be used for logging or for measuring and monitoring - * the time a request takes to resolve. + * Can be used for logging or for measuring and monitoring the time a request takes to resolve. * * @see \Nuwave\Lighthouse\Http\GraphQLController */ class StartRequest { - /** - * The point in time when the request started. - */ + /** The point in time when the request started. */ public Carbon $moment; public function __construct( - /** - * The request sent from the client. - */ - public Request $request + /** The request sent from the client. */ + public Request $request, ) { $this->moment = Carbon::now(); } @@ -54,7 +49,7 @@ class StartOperationOrOperations * * @var \GraphQL\Server\OperationParams|array */ - public OperationParams|array $operationOrOperations + public OperationParams|array $operationOrOperations, ) {} } ``` @@ -72,10 +67,8 @@ class StartOperationOrOperations class BuildSchemaString { public function __construct( - /** - * The root schema that was defined by the user. - */ - public string $userSchema + /** The root schema that was defined by the user. */ + public string $userSchema, ) {} } ``` @@ -114,7 +107,7 @@ class ManipulateAST /** * The AST that can be manipulated. */ - public DocumentAST &$documentAST + public DocumentAST &$documentAST, ) {} } ``` @@ -134,37 +127,23 @@ use Nuwave\Lighthouse\Support\Contracts\GraphQLContext; */ class StartExecution { - /** - * The point in time when the query execution started. - */ + /** The point in time when the query execution started. */ public Carbon $moment; public function __construct( - /** - * The parsed schema. - */ + /** The parsed schema. */ public Schema $schema, - - /** - * The client given parsed query string. - */ + /** The client given parsed query string. */ public DocumentNode $query, - /** * The client given variables, neither validated nor transformed. * * @var array|null */ public ?array $variables, - - /** - * The client given operation name. - */ + /** The client given operation name. */ public ?string $operationName, - - /** - * The context for the operation. - */ + /** The context for the operation. */ public GraphQLContext $context, ) { $this->moment = Carbon::now(); @@ -180,8 +159,7 @@ use GraphQL\Executor\ExecutionResult; /** * Fires after a query was resolved. * - * Listeners may return a @see \Nuwave\Lighthouse\Execution\ExtensionsResponse - * to include in the response. + * Listeners may return a @see \Nuwave\Lighthouse\Execution\ExtensionsResponse to include in the response. */ class BuildExtensionsResponse { @@ -217,8 +195,7 @@ use GraphQL\Executor\ExecutionResult; /** * Fires after resolving each individual query. * - * This gives listeners an easy way to manipulate the query - * result without worrying about batched execution. + * This lets listeners manipulate the query result without worrying about batched execution. */ class ManipulateResult { @@ -226,7 +203,7 @@ class ManipulateResult /** * The result of resolving an individual query. */ - public ExecutionResult &$result + public ExecutionResult &$result, ) {} } ``` @@ -242,16 +219,12 @@ use Illuminate\Support\Carbon; */ class EndExecution { - /** - * The point in time when the result was ready. - */ + /** The point in time when the result was ready. */ public Carbon $moment; public function __construct( - /** - * The result of resolving a single operation. - */ - public ExecutionResult $result + /** The result of resolving a single operation. */ + public ExecutionResult $result, ) { $this->moment = Carbon::now(); } @@ -272,7 +245,7 @@ class EndOperationOrOperations * * @var array|array> $resultOrResults */ - public array $resultOrResults + public array $resultOrResults, ) {} } ``` @@ -286,23 +259,18 @@ use Symfony\Component\HttpFoundation\Response; /** * Fires right after building the HTTP response in the GraphQLController. * - * Can be used for logging or for measuring and monitoring - * the time a request takes to resolve. + * Can be used for logging or for measuring and monitoring the time a request takes to resolve. * * @see \Nuwave\Lighthouse\Http\GraphQLController */ class EndRequest { - /** - * The point in time when the response was ready. - */ + /** The point in time when the response was ready. */ public Carbon $moment; public function __construct( - /** - * The response that is about to be sent to the client. - */ - public Response $response + /** The response that is about to be sent to the client. */ + public Response $response, ) { $this->moment = Carbon::now(); } @@ -326,9 +294,7 @@ use GraphQL\Type\Schema; class ValidateSchema { public function __construct( - /** - * The final schema to validate. - */ + /** The final schema to validate. */ public Schema $schema, ) {} } diff --git a/docs/master/api-reference/resolvers.md b/docs/master/api-reference/resolvers.md index 66bc3862bb..92ba2ba5da 100644 --- a/docs/master/api-reference/resolvers.md +++ b/docs/master/api-reference/resolvers.md @@ -17,15 +17,15 @@ function (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolv For example, for a field call like `user(name: "Bob")` it would be `['name' => 'Bob']` 3. `GraphQLContext $context`: Arbitrary data that is shared between all fields of a single query. Lighthouse passes in an instance of `Nuwave\Lighthouse\Schema\Context` by default. -4. `ResolveInfo $resolveInfo`: Information about the query itself, - such as the execution state, the field name, path to the field from the root, and more. +4. `ResolveInfo $resolveInfo`: Information about the query itself. + Includes execution state, field name, path to the field from the root, and more. The return value of this must fit the return type defined for the corresponding field from the schema. ## Root resolvers -Root resolvers are classes with an `__invoke` method that sit directly in the configured -`lighthouse.namespaces.queries` or `lighthouse.namespaces.mutations` namespaces. +Root resolvers are classes with an `__invoke` method. +They sit directly in the configured `lighthouse.namespaces.queries` or `lighthouse.namespaces.mutations` namespaces. Lighthouse calls them with positional arguments `($root, $args, $context, $resolveInfo)` where `$root` is always `null` for root types. Omitting `$root` causes Lighthouse's positional `null` to bind to `$args`, producing TypeErrors at runtime. @@ -61,8 +61,8 @@ You can define your own complexity function with the [@complexity](../api-refere function (int $childrenComplexity, array $args): int ``` -1. `$childrenComplexity`: The complexity of the children of the field. In case you expect to return - multiple children, it can be useful to do some maths on this. +1. `$childrenComplexity`: The complexity of the children of the field. + In case you expect to return multiple children, it can be useful to do some maths on this. 2. `array $args`: The arguments that were passed into the field. For example, for a field call like `user(name: "Bob")` it would be `['name' => 'Bob']` diff --git a/docs/master/api-reference/scalars.md b/docs/master/api-reference/scalars.md index a06ffb6273..afdbcadf38 100644 --- a/docs/master/api-reference/scalars.md +++ b/docs/master/api-reference/scalars.md @@ -63,6 +63,7 @@ scalar Upload ``` This Scalar can only be used as an argument, not as a return type. -For more information, please refer to the [file uploads guide](../digging-deeper/file-uploads.md). +For more information, see the [file uploads guide](../digging-deeper/file-uploads.md). -The multipart form request is handled by Lighthouse, the resolver gets passed an instance of [`Illuminate\Http\UploadedFile`](https://laravel.com/api/9.x/Illuminate/Http/UploadedFile.html) in the argument `array $variables`. +Lighthouse handles the multipart form request. +The resolver receives an instance of [`Illuminate\Http\UploadedFile`](https://laravel.com/api/9.x/Illuminate/Http/UploadedFile.html) in the argument `array $variables`. diff --git a/docs/master/concepts/arg-resolvers.md b/docs/master/concepts/arg-resolvers.md index 55c88bb130..aed36063d9 100644 --- a/docs/master/concepts/arg-resolvers.md +++ b/docs/master/concepts/arg-resolvers.md @@ -5,16 +5,18 @@ To understand the concept behind arg resolvers, you should familiarize yourself ## Motivation Arg resolvers are an extension of the ideas behind GraphQL field execution, applied to input arguments. -Since GraphQL queries can be used to fetch complex and deeply nested data from the client, it is natural to assume that such complex data can also be passed as the input arguments to a query. +Clients can use GraphQL queries to fetch complex and deeply nested data. +So it is natural to assume that clients can also pass such complex data as input arguments to a query. -GraphQL's execution engine allows you to write small and focused field resolver functions that only care about returning the data that it is immediately responsible for. +GraphQL's execution engine lets you write small and focused field resolver functions. +Each one only returns the data it is immediately responsible for. That makes the code much simpler and avoids duplication. However, a single field resolver still has to take care of all the input arguments that are passed to it. Handling complex input data in a single function is hard because of their dynamic nature. The input given by a client might be nested arbitrarily deep and come in many different variations. -The following example shows an example mutation that is actually composed out of multiple distinct operations. +The following example shows an example mutation that is composed out of multiple distinct operations. ```graphql type Mutation { @@ -59,7 +61,7 @@ function createTaskWithNotes(mixed $root, array $args): \App\Models\Task { // Create the new task with the remaining args $task = \App\Models\Task::create($args); - // If the client actually passed notes, create and attach them + // If the client passed notes, create and attach them if ($notes) { foreach($notes as $note) { $task->notes()->create($note); @@ -70,15 +72,16 @@ function createTaskWithNotes(mixed $root, array $args): \App\Models\Task { } ``` -In this contrived example, the function is still quite small. +In this contrived example, the function is still small. However, separation of concerns is already violated: A single function is responsible for creating both tasks and notes. -We might want to extend our schema to support more operations in the future, such as updating a task and creating, updating or deleting notes or other, more deeply nested relations. +We might want to extend our schema to support more operations in the future. +For example, updating a task and creating, updating or deleting notes or other, more deeply nested relations. Such changes would force us to duplicate code and increase the complexity of our single function. ## Solution -Ideally, we would want to write small and focused functions that deal with just a part of the given input arguments. +Ideally, we would want to write small and focused functions that deal with only a part of the given input arguments. The execution engine should traverse the given input and take care of calling the appropriate functions with their respective arguments. ```php diff --git a/docs/master/concepts/request-lifecycle.md b/docs/master/concepts/request-lifecycle.md index e4f9716ea5..a45c91fb37 100644 --- a/docs/master/concepts/request-lifecycle.md +++ b/docs/master/concepts/request-lifecycle.md @@ -36,7 +36,8 @@ Starting from the root level, the fields within the query are executed. Each field may be wrapped with field middleware, which can add authentication, authorization, fine-grained validation, and more. Finally, the field resolver is called to produce a value for the field. -If the field contains a subselection, the same process happens for the nested fields, until we either abort with an error or traversed the entire query tree. +If the field contains a subselection, the same process happens for the nested fields. +This continues until we either abort with an error or traverse the entire query tree. [Learn more about GraphQL execution](https://graphql.org/learn/execution). diff --git a/docs/master/custom-directives/field-directives.md b/docs/master/custom-directives/field-directives.md index fefe8bf3d4..550ec39eb8 100644 --- a/docs/master/custom-directives/field-directives.md +++ b/docs/master/custom-directives/field-directives.md @@ -4,13 +4,14 @@ Field directives can be applied to any [FieldDefinition](https://graphql.github. ## FieldResolver -Perhaps the most important directive interface, a [`Nuwave\Lighthouse\Support\Contracts\FieldResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/FieldResolver.php) lets you add a resolver for a field through a directive. +A [`Nuwave\Lighthouse\Support\Contracts\FieldResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/FieldResolver.php) lets you add a resolver for a field through a directive. +It is perhaps the most important directive interface. It can be a great way to reuse resolver logic within a schema. ## FieldMiddleware -A [`Nuwave\Lighthouse\Support\Contracts\FieldMiddleware`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/FieldMiddleware.php) directive allows you to wrap around the field resolver, just like [Laravel Middleware](https://laravel.com/docs/middleware). +A [`Nuwave\Lighthouse\Support\Contracts\FieldMiddleware`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/FieldMiddleware.php) directive allows you to wrap around the field resolver, like [Laravel Middleware](https://laravel.com/docs/middleware). You may use it to handle incoming values before reaching the final resolver as well as the outgoing result of resolving the field. @@ -76,7 +77,8 @@ A [`Nuwave\Lighthouse\Support\Contracts\FieldManipulator`](https://github.com/nu ## ValidationDirective -This directive type is implemented as an abstract class rather than a pure interface and allows you to define complex validation rules for a field with ease. +This directive type is an abstract class rather than a pure interface. +It lets you define complex validation rules for a field. [Read more about it in the Validation section](../security/validation.md#validator-for-fields). diff --git a/docs/master/custom-directives/getting-started.md b/docs/master/custom-directives/getting-started.md index 42959b95c0..d1210996df 100644 --- a/docs/master/custom-directives/getting-started.md +++ b/docs/master/custom-directives/getting-started.md @@ -13,7 +13,7 @@ The class name of a directive must follow the following pattern: Directive -Let's implement a simple `@upperCase` directive as a part of this introduction. +Let's implement an `@upperCase` directive as a part of this introduction. Use the artisan generator command to create it: ```shell @@ -56,7 +56,7 @@ Depending on what your directive should do, you can pick one or more of the prov They serve as the point of contact to Lighthouse. In this case, our directive needs to run after the actual resolver. -Just like [Laravel Middleware](https://laravel.com/docs/middleware), we can wrap around it by using the `FieldMiddleware` directive. +Like [Laravel Middleware](https://laravel.com/docs/middleware), we can wrap around it by using the `FieldMiddleware` directive. ```php namespace App\GraphQL\Directives; @@ -97,9 +97,8 @@ Now that we defined and implemented the directive, how can Lighthouse find it? When Lighthouse encounters a directive within the schema, it starts looking for a matching class in the following order: 1. User-defined namespaces as configured in `config/lighthouse.php`, defaults to `App\GraphQL\Directives` -1. The [RegisterDirectiveNamespaces](../api-reference/events.md#registerdirectivenamespaces) event is dispatched - to gather namespaces defined by plugins, extensions or other listeners +1. The [RegisterDirectiveNamespaces](../api-reference/events.md#registerdirectivenamespaces) event is dispatched to gather namespaces defined by plugins, extensions or other listeners 1. Lighthouse's built-in directive namespace -This means that our directive is already registered, just by matter of defining it in the default namespace. +This means that our directive is already registered, because it is defined in the default namespace. Will take precedence over potential other directives with the same name. diff --git a/docs/master/custom-directives/input-value-directives.md b/docs/master/custom-directives/input-value-directives.md index 3426bc20fe..054de6b286 100644 --- a/docs/master/custom-directives/input-value-directives.md +++ b/docs/master/custom-directives/input-value-directives.md @@ -2,12 +2,11 @@ Some directives can be applied to field arguments or input fields (any [InputValueDefinition](https://graphql.github.io/graphql-spec/June2018/#InputValueDefinition)). -As arguments may be contained within a list in the schema definition, you must specify what your directive should apply to in addition to its function. +Arguments may be contained within a list in the schema definition. +Thus, in addition to its function, you must specify what your directive applies to. -- If it applies to the individual items within the list, - implement the [`Nuwave\Lighthouse\Support\Contracts\ArgDirective`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ArgDirective.php) interface. -- Else, if it should apply to the whole list, - implement the [`Nuwave\Lighthouse\Support\Contracts\ArgDirectiveForArray`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ArgDirectiveForArray.php) interface. +- If it applies to the individual items within the list, implement the [`Nuwave\Lighthouse\Support\Contracts\ArgDirective`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ArgDirective.php) interface. +- Else, if it should apply to the whole list, implement the [`Nuwave\Lighthouse\Support\Contracts\ArgDirectiveForArray`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ArgDirectiveForArray.php) interface. You must implement exactly one of those two interfaces in order for an argument directive to work. @@ -71,7 +70,8 @@ final class TrimDirective extends BaseDirective implements ArgSanitizerDirective } ``` -The `sanitize` method takes an argument which represents the actual incoming value that is given to an argument in a query and is expected to modify the value, if needed. +The `sanitize` method takes the incoming value that is given to an argument in a query. +It is expected to modify the value, if needed. Return it. For example, if we have the following schema. @@ -111,7 +111,8 @@ Notable differences are: ## ArgBuilderDirective -An [`Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective`](https://github.com/nuwave/lighthouse/blob/master/src/Support/Contracts/ArgBuilderDirective.php) directive allows using arguments passed by the client to dynamically modify the database query that Lighthouse creates for a field. +An [`Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective`](https://github.com/nuwave/lighthouse/blob/master/src/Support/Contracts/ArgBuilderDirective.php) directive modifies the database query that Lighthouse creates for a field. +It uses the arguments passed by the client. Currently, the following directives use arguments to modify the query: @@ -198,16 +199,19 @@ input DateRange { ## ArgResolver -An [`Nuwave\Lighthouse\Support\Contracts\ArgResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ArgResolver.php) directive allows you to compose resolvers for complex nested inputs, similar to the way that field resolvers are composed together. +An [`Nuwave\Lighthouse\Support\Contracts\ArgResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ArgResolver.php) directive lets you compose resolvers for complex nested inputs. +This is similar to the way that field resolvers are composed. For an in-depth explanation of the concept of composing arg resolvers, read the [explanation of arg resolvers](../concepts/arg-resolvers.md). ## SaveAwareArgResolver -A [`Nuwave\Lighthouse\Support\Contracts\SaveAwareArgResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/SaveAwareArgResolver.php) extends `ArgResolver` and allows control over whether the resolver runs before or after the parent model is saved. +A [`Nuwave\Lighthouse\Support\Contracts\SaveAwareArgResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/SaveAwareArgResolver.php) extends `ArgResolver`. +It controls whether the resolver runs before or after the parent model is saved. This is useful when your directive needs to set attributes or foreign keys on the model before it is persisted. -For example, a directive that resolves a BelongsTo relationship must associate the related model before the parent is saved, since the foreign key column may have a NOT NULL constraint. +For example, a directive that resolves a BelongsTo relationship must associate the related model before the parent is saved. +The foreign key column may have a NOT NULL constraint. ```php use Illuminate\Database\Eloquent\Model; @@ -246,5 +250,5 @@ final class GeocodeDirective extends BaseDirective implements SaveAwareArgResolv When `runBeforeSave()` returns `true`, the resolver is invoked before `$model->save()`, allowing it to set attributes on the model. When it returns `false`, the resolver runs after the model is saved — the same timing as any `ArgResolver` that does not implement this interface. -Note that `__invoke()` receives `null` as `$args` if the client sends `null` for a nullable input field. +`__invoke()` receives `null` as `$args` if the client sends `null` for a nullable input field. Guard accordingly. diff --git a/docs/master/digging-deeper/adding-types-programmatically.md b/docs/master/digging-deeper/adding-types-programmatically.md index 80d2a55a61..32af35e41f 100644 --- a/docs/master/digging-deeper/adding-types-programmatically.md +++ b/docs/master/digging-deeper/adding-types-programmatically.md @@ -4,7 +4,8 @@ You might want to add additional types to the schema programmatically. ## Additional Schema Definitions -If you want to use the SDL to define additional types dynamically, you can listen for the [`BuildSchemaString`](../api-reference/events.md#buildschemastring) event and return additional schema definitions as a string: +To define additional types dynamically with SDL, listen for the [`BuildSchemaString`](../api-reference/events.md#buildschemastring) event. +Return additional schema definitions as a string: ```php $dispatcher = app(\Illuminate\Contracts\Events\Dispatcher::class); @@ -16,7 +17,7 @@ $dispatcher->listen( ); ``` -When your schema is defined within files and you want to use `#import` to combine them, you can use the `Nuwave\Lighthouse\Schema\Source\SchemaStitcher` to load your file: +When your schema is split into files that you combine with `#import`, load them with `Nuwave\Lighthouse\Schema\Source\SchemaStitcher`: ```php $stitcher = new \Nuwave\Lighthouse\Schema\Source\SchemaStitcher(__DIR__ . '/path/to/schema.graphql'); @@ -29,7 +30,8 @@ While Lighthouse is an SDL-first GraphQL server, you can also use native PHP typ Check out the [webonyx/graphql-php documentation](https://webonyx.github.io/graphql-php/type-definitions) on how to define types. -Note that you will not have access to a large portion of Lighthouse functionality that is provided through server-side directives and the definition is much more verbose. +You will not have access to a large portion of Lighthouse functionality that is provided through server-side directives. +The definition is also much more verbose. Because of this, we do not recommend you use native PHP types for complex object types. diff --git a/docs/master/digging-deeper/client-directives.md b/docs/master/digging-deeper/client-directives.md index 3bf598a75f..2344331180 100644 --- a/docs/master/digging-deeper/client-directives.md +++ b/docs/master/digging-deeper/client-directives.md @@ -18,8 +18,7 @@ Allows for conditional exclusion during execution as described by the `if` argum ```graphql directive @skip( """ - If the value passed into the if field is true the field this - is decorating will not be included in the query response. + If the value passed into the if field is true the field this is decorating will not be included in the query response. """ if: Boolean! ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT @@ -94,7 +93,8 @@ The following example illustrates how a field `foo` can be referenced three time } ``` -You can get all arguments for every node that is referencing the field you are currently resolving, passing the fourth [resolver argument `ResolveInfo $resolveInfo`](../api-reference/resolvers.md#resolver-function-signature): +You can get all arguments for every node that references the field you are resolving. +Pass the fourth [resolver argument `ResolveInfo $resolveInfo`](../api-reference/resolvers.md#resolver-function-signature): ```php $arguments = $clientDirective->forField($resolveInfo); diff --git a/docs/master/digging-deeper/error-handling.md b/docs/master/digging-deeper/error-handling.md index 9e8a663c0a..1bcd9c4a25 100644 --- a/docs/master/digging-deeper/error-handling.md +++ b/docs/master/digging-deeper/error-handling.md @@ -17,7 +17,8 @@ Head over their [Error Handling docs](https://webonyx.github.io/graphql-php/erro Lighthouse will catch exceptions thrown during the execution of a query and return them as part of the response. -The error handler `Nuwave\Lighthouse\Execution\ReportingErrorHandler` is included in the default configuration and reports non-client-safe errors through the default Laravel exception handler. +The default configuration includes the error handler `Nuwave\Lighthouse\Execution\ReportingErrorHandler`. +It reports non-client-safe errors through the default Laravel exception handler. Client-safe errors are assumed to be something that: @@ -26,7 +27,7 @@ Client-safe errors are assumed to be something that: Thus, they are typically not actionable for server developers. -However, you can choose to report client-safe errors by replacing `Nuwave\Lighthouse\Execution\ReportingErrorHandler` with `Nuwave\Lighthouse\Execution\AlwaysReportingErrorHandler` in the `lighthouse.php` config: +To also report client-safe errors, replace `Nuwave\Lighthouse\Execution\ReportingErrorHandler` with `Nuwave\Lighthouse\Execution\AlwaysReportingErrorHandler` in the `lighthouse.php` config: ```diff 'error_handlers' => [ @@ -39,7 +40,7 @@ However, you can choose to report client-safe errors by replacing `Nuwave\Lighth ## Additional Error Information -The interface [`GraphQL\Error\ProvidesExtensions`](https://github.com/webonyx/graphql-php/blob/master/src/Error/ProvidesExtensions.php) may be implemented to add more information than just an error message to the rendered error output. +The interface [`GraphQL\Error\ProvidesExtensions`](https://github.com/webonyx/graphql-php/blob/master/src/Error/ProvidesExtensions.php) may be implemented to add more information than an error message to the rendered error output. This custom exception contains information about the reason the exception was thrown: diff --git a/docs/master/digging-deeper/extending-lighthouse.md b/docs/master/digging-deeper/extending-lighthouse.md index 0b4aa5e4e8..b30a4f1045 100644 --- a/docs/master/digging-deeper/extending-lighthouse.md +++ b/docs/master/digging-deeper/extending-lighthouse.md @@ -42,8 +42,8 @@ You may override this by calling `GraphQL\Executor\Executor::setDefaultFieldReso The context is the third argument of any resolver function. -You may replace the default `Nuwave\Lighthouse\Schema\Context` with your own implementation of the interface `Nuwave\Lighthouse\Support\Contracts\GraphQLContext`. -The following example is just a starting point of what you can do: +You may replace the default `Nuwave\Lighthouse\Schema\Context` with your own implementation of `Nuwave\Lighthouse\Support\Contracts\GraphQLContext`. +The following example is only a starting point of what you can do: ```php namespace Nuwave\Lighthouse\Schema; diff --git a/docs/master/digging-deeper/feature-toggles.md b/docs/master/digging-deeper/feature-toggles.md index 578ea8bdbe..50b570ed64 100644 --- a/docs/master/digging-deeper/feature-toggles.md +++ b/docs/master/digging-deeper/feature-toggles.md @@ -7,7 +7,8 @@ Lighthouse allows you to conditionally show or hide elements (fields, types, arg The directives [@show](../api-reference/directives.md#show) and [@hide](../api-reference/directives.md#hide) work in a similar way. Are logical opposites of each other. -For example, you might want to limit an experimental new field to test environments. [@show](../api-reference/directives.md#show) is most suitable for this: +For example, you might want to limit an experimental new field to test environments. +[@show](../api-reference/directives.md#show) is most suitable for this: ```graphql type Query { @@ -26,7 +27,7 @@ type Query { ## @feature -The [@feature](../api-reference/directives.md#feature) directive allows to include fields, types, arguments, or input fields in the schema depending on whether a [Laravel Pennant](https://laravel.com/docs/pennant) feature is active. +The [@feature](../api-reference/directives.md#feature) directive allows to include fields, types, arguments, or input fields in the schema if a [Laravel Pennant](https://laravel.com/docs/pennant) feature is active. For example, you might want a new experimental field only to be available when the according feature is active: @@ -72,9 +73,11 @@ type Query { ## Interaction With Schema Cache [@show](../api-reference/directives.md#show) and [@hide](../api-reference/directives.md#hide) work by manipulating the schema. -This means that when using their `env` option, the inclusion or exclusion of elements depends on the value of `app()->environment()` at the time the schema is built and not update on later environment changes. +With their `env` option, the inclusion or exclusion of elements depends on the value of `app()->environment()` at the time the schema is built. +It does not update on later environment changes. If you are pre-generating your schema cache, make sure to match the environment to your deployment target. The same goes for [@feature](../api-reference/directives.md#feature). Whether a field is included in the schema will be based on the state of a feature at the time the schema is built. -In addition, if you are pre-generating your schema cache, you will only be able to use features that support [nullable scopes](https://laravel.com/docs/pennant#nullable-scope), as there won't be an authenticated user to check the feature against. +In addition, if you pre-generate your schema cache, you can only use features that support [nullable scopes](https://laravel.com/docs/pennant#nullable-scope). +There is no authenticated user to check the feature against. diff --git a/docs/master/digging-deeper/file-uploads.md b/docs/master/digging-deeper/file-uploads.md index b881ca9d81..c941f325d9 100644 --- a/docs/master/digging-deeper/file-uploads.md +++ b/docs/master/digging-deeper/file-uploads.md @@ -55,8 +55,7 @@ final class Upload In order to upload a file, you must send a `multipart/form-data` request. Use any of the [available client implementations](https://github.com/jaydenseric/graphql-multipart-request-spec#client) or look at the [specification examples](https://github.com/jaydenseric/graphql-multipart-request-spec#multipart-form-field-structure) to roll your own. -> If you are using [the EnsureXHR middleware to protect against CSRF](../security/csrf.md), -> add the header `X-Requested-With: XMLHttpRequest` to your request. +> If you are using [the EnsureXHR middleware to protect against CSRF](../security/csrf.md), add the header `X-Requested-With: XMLHttpRequest` to your request. To test the example above, prepare a file you can upload. diff --git a/docs/master/digging-deeper/ordering.md b/docs/master/digging-deeper/ordering.md index 5c9819882b..a730fbced9 100644 --- a/docs/master/digging-deeper/ordering.md +++ b/docs/master/digging-deeper/ordering.md @@ -10,7 +10,8 @@ type Query { } ``` -The type of the argument can be left blank as `_` , as Lighthouse will automatically generate an input that takes enumerated column names, together with the `SortOrder` enum. +You can leave the type of the argument blank as `_`. +Lighthouse then generates an input that takes enumerated column names, together with the `SortOrder` enum. Add that to your schema: ```graphql @@ -84,7 +85,7 @@ enum PostColumn { ``` Lighthouse will still automatically generate the necessary input types and the `SortOrder` enum. -Instead of generating enums for the allowed columns, it will simply use the existing `PostColumn` enum. +Instead of generating enums for the allowed columns, it uses the existing `PostColumn` enum. ### Ordering By Relations diff --git a/docs/master/eloquent/complex-where-conditions.md b/docs/master/eloquent/complex-where-conditions.md index 29856b5851..16fe31291d 100644 --- a/docs/master/eloquent/complex-where-conditions.md +++ b/docs/master/eloquent/complex-where-conditions.md @@ -3,7 +3,8 @@ **Experimental: not enabled by default, not guaranteed to be stable.** Adding query conditions ad-hoc can be cumbersome and limiting when you require manifold ways to filter query results. -Lighthouse's `WhereConditions` extension can give advanced query capabilities to clients and allow them to apply complex, dynamic WHERE conditions to queries. +Lighthouse's `WhereConditions` extension gives clients advanced query capabilities. +They can apply complex, dynamic WHERE conditions to queries. ## Setup @@ -16,7 +17,8 @@ return [ ] ``` -For other versions, register the service provider `Nuwave\Lighthouse\WhereConditions\WhereConditionsServiceProvider`, see [registering providers in Laravel](https://laravel.com/docs/providers#registering-providers). +For other versions, register the service provider `Nuwave\Lighthouse\WhereConditions\WhereConditionsServiceProvider`. +See [registering providers in Laravel](https://laravel.com/docs/providers#registering-providers). Install the dependency [mll-lab/graphql-php-scalars](https://github.com/mll-lab/graphql-php-scalars): @@ -159,13 +161,13 @@ enum PersonColumn { ``` Lighthouse will still automatically generate the necessary input types. -Instead of creating enums for the allowed columns, it will simply use the existing `PersonColumn` enum. +Instead of creating enums for the allowed columns, it uses the existing `PersonColumn` enum. It is recommended to either use the `columns` or the `columnsEnum` argument. When you don't define any allowed columns, clients can specify arbitrary column names as a `String`. This approach should by taken with care, as it carries potential performance and security risks and offers little type safety. -A simple query for a person who is exactly 42 years old would look like this: +A query for a person who is exactly 42 years old would look like this: ```graphql { @@ -175,7 +177,7 @@ A simple query for a person who is exactly 42 years old would look like this: } ``` -Note that the operator defaults to `EQ` (`=`) if not given, so you could also omit it from the previous example and get the same result. +The operator defaults to `EQ` (`=`) if not given, so you could also omit it from the previous example and get the same result. The following query gets actors over age 37 who either have red hair or are at least 150cm: @@ -237,16 +239,15 @@ Qualify such columns with the table name, e.g. `@whereConditions(columns: ["role ```graphql """ -Allows clients to filter a query based on the existence of a related model, using -a dynamically controlled `WHERE` condition that applies to the relationship. +Allow clients to filter a query by the existence of a related model. +A dynamically controlled `WHERE` condition applies to the relationship. """ directive @whereHasConditions( """ The Eloquent relationship that the conditions will be applied to. - This argument can be omitted if the argument name follows the naming - convention `has{$RELATION}`. For example, if the Eloquent relationship - is named `posts`, the argument name must be `hasPosts`. + This argument can be omitted if the argument name follows the naming convention `has{$RELATION}`. + For example, if the Eloquent relationship is named `posts`, the argument name must be `hasPosts`. """ relation: String @@ -279,7 +280,7 @@ directive @whereHasConditions( ) on ARGUMENT_DEFINITION ``` -This directive works very similar to [@whereConditions](#whereconditions), except that the conditions are applied to a relation sub query: +This directive works like [@whereConditions](#whereconditions), except that the conditions are applied to a relation sub query: ```graphql type Query { @@ -322,7 +323,7 @@ enum QueryPeopleHasRoleColumn { } ``` -A simple query for a person who has an access level of at least 5, through one of their roles, looks like this: +A query for a person who has an access level of at least 5, through one of their roles, looks like this: ```graphql { @@ -332,7 +333,8 @@ A simple query for a person who has an access level of at least 5, through one o } ``` -You can also query for relationship existence without any condition; simply use an empty object as argument value. +You can also query for relationship existence without any condition. +Use an empty object as argument value. This query would retrieve all persons that have a role: ```graphql @@ -343,7 +345,7 @@ This query would retrieve all persons that have a role: } ``` -Just like with the [@whereCondition](../api-reference/directives.md#whereconditions) directive, using `null` as argument value does not have any effect on the query. +Like with the [@whereCondition](../api-reference/directives.md#whereconditions) directive, using `null` as argument value does not have any effect on the query. This query would retrieve all persons, no matter if they have a role or not: ```graphql diff --git a/docs/master/eloquent/getting-started.md b/docs/master/eloquent/getting-started.md index 74d40974b8..3a59986b45 100644 --- a/docs/master/eloquent/getting-started.md +++ b/docs/master/eloquent/getting-started.md @@ -1,6 +1,6 @@ # Eloquent: Getting Started -Lighthouse makes it easy for you to perform queries and mutations on your Eloquent models. +Lighthouse lets you perform queries and mutations on your Eloquent models. ## Defining Models @@ -26,7 +26,8 @@ type Query { } ``` -The [@all](../api-reference/directives.md#all) directive will assume the name of your model to be the same as the return type of the Field you are trying to resolve and automatically uses Eloquent to resolve the field. +The [@all](../api-reference/directives.md#all) directive assumes that your model has the same name as the return type of the field. +It uses Eloquent to resolve the field. The following query: @@ -165,7 +166,7 @@ SELECT * FROM `users` WHERE `email_verified_at` IS NOT NULL ## Create -The easiest way to create data on your server is to use the [@create](../api-reference/directives.md#create) directive. +Create data on your server with the [@create](../api-reference/directives.md#create) directive. ```graphql type Mutation { @@ -262,7 +263,8 @@ type Mutation { } ``` -When using `identifyingColumns`, all configured identifying columns must be provided with non-null values, otherwise the upsert fails with a GraphQL error. +When using `identifyingColumns`, all configured identifying columns must have non-null values. +Otherwise, the upsert fails with a GraphQL error. Since upsert can create or update your data, your input should mark the minimum required fields as non-nullable. @@ -292,8 +294,7 @@ To upsert multiple models at once, use the [@upsertMany](../api-reference/direct ## Delete -Deleting models is a breeze using the [@delete](../api-reference/directives.md#delete) directive. -Dangerously easy. +Delete models with the [@delete](../api-reference/directives.md#delete) directive. ```graphql type Mutation { @@ -301,7 +302,7 @@ type Mutation { } ``` -Simply call it with the ID of the user you want to delete. +Call it with the ID of the user you want to delete. ```graphql mutation { diff --git a/docs/master/eloquent/nested-mutations.md b/docs/master/eloquent/nested-mutations.md index c3beaa8455..212f5df27a 100644 --- a/docs/master/eloquent/nested-mutations.md +++ b/docs/master/eloquent/nested-mutations.md @@ -37,7 +37,8 @@ Because the GraphQL Specification does not support polymorphic Input types (yet) It is not possible to have an argument that can contain different types. Would be necessary to pass the attributes the different related models might have. -For now, we can only support cases where the input type does not change across related models, e.g. connecting through an ID, disconnecting or deleting the relation. +For now, we only support cases where the input type does not change across related models. +Examples are connecting through an ID, disconnecting or deleting the relation. See [this issue](https://github.com/nuwave/lighthouse/issues/900) for further discussion. @@ -69,7 +70,7 @@ input CreatePostInput { The first argument `title` is a value of the `Post` itself and corresponds to a column in the database. -The second argument `author` is named just like the relationship method that is defined on the `Post` model. +The second argument `author` is named like the relationship method that is defined on the `Post` model. A nested `BelongsTo` relationship exposes the following operations: - `connect` it to an existing model @@ -80,7 +81,7 @@ A nested `BelongsTo` relationship exposes the following operations: - `delete` the related model and the association to it Both `disconnect` and `delete` don't make much sense when creating a new model. -You can control what operations are possible by defining just what you need in the `input`. +You can control what operations are possible by defining only what you need in the `input`. We choose to expose the following operations on the related `User` model: ```graphql @@ -181,8 +182,9 @@ input UpdateUserBelongsTo { } ``` -You must pass a truthy value to `disconnect` and `delete` for them to actually run. -This structure was chosen as it is consistent with updating `BelongsToMany` relationships and allows the query string to be mostly static, taking a variable value to control its behavior. +You must pass a truthy value to `disconnect` and `delete` for them to run. +This structure is consistent with updating `BelongsToMany` relationships. +It allows the query string to be mostly static, with a variable value to control its behavior. ```graphql mutation UpdatePost($disconnectAuthor: Boolean) { @@ -217,7 +219,7 @@ If `false` or `null` is passed, it will not change. ``` When issuing an `upsert`, you may expose the same nested operations as an `update`. -In case a new model is created, they will simply be ignored. +In case a new model is created, they are ignored. ```graphql mutation UpdatePost($disconnectAuthor: Boolean) { @@ -251,7 +253,8 @@ mutation UpdatePost($disconnectAuthor: Boolean) { ## MorphTo -The basic structure of this nested mutation type is similar to [BelongsTo](#belongsto), the main difference being that the `connect` operation requires an input type with both the `id` and `type` of the related model. +The basic structure of this nested mutation type is similar to [BelongsTo](#belongsto). +The main difference is that the `connect` operation requires an input type with both the `id` and `type` of the related model. ```graphql type Task { @@ -685,10 +688,10 @@ type UserMoviePivot { } ``` -Laravel's `sync()`, `syncWithoutDetach()` or `connect()` methods allow you to pass an array where the keys are IDs of related models and the values are pivot data. +Laravel's `sync()`, `syncWithoutDetach()` or `connect()` methods accept an array with IDs of related models as keys and pivot data as values. Lighthouse exposes this capability through the nested operations on many-to-many relations. -Instead of passing just a list of IDs, you can define an `input` type that also contains pivot data. +Instead of passing only a list of IDs, you can define an `input` type that also contains pivot data. It must contain a field called `id` to contain the ID of the related model, all other fields will be inserted into the pivot table. ```graphql diff --git a/docs/master/eloquent/polymorphic-relationships.md b/docs/master/eloquent/polymorphic-relationships.md index ef5de1f768..704278bab9 100644 --- a/docs/master/eloquent/polymorphic-relationships.md +++ b/docs/master/eloquent/polymorphic-relationships.md @@ -1,10 +1,10 @@ # Polymorphic Relationships -Just like in Laravel, you can define [Polymorphic Relationships](https://laravel.com/docs/eloquent-relationships#polymorphic-relationships) in your schema. +Like in Laravel, you can define [Polymorphic Relationships](https://laravel.com/docs/eloquent-relationships#polymorphic-relationships) in your schema. ## One to One -Suppose you have defined a model structure just like the Laravel example docs. +Suppose you have defined a model structure like the Laravel example docs. You have two models, `Post` and `User` which may both have an `Image` assigned. Let's start off with the plain type definitions, without any relations. @@ -26,7 +26,7 @@ type Image { } ``` -First, let's go ahead and add the relations to `Image` since they are straightforward. +First, add the relations to `Image`. The field name should match your relationship method name and be annotated with the [@morphOne](../api-reference/directives.md#morphone) directive. ```graphql @@ -64,7 +64,7 @@ type Image { ``` The default type resolver will be able to determine which concrete object type is returned when dealing with Eloquent models. -Your definition should just work. +Your definition works without further changes. Given you have a field `images` that returns a list of `[Image!]!`, you could query it like this: diff --git a/docs/master/eloquent/relationships.md b/docs/master/eloquent/relationships.md index 5081351649..2053cefdd9 100644 --- a/docs/master/eloquent/relationships.md +++ b/docs/master/eloquent/relationships.md @@ -1,6 +1,6 @@ # Eloquent Relationships -Just like in Laravel, you can define [Eloquent Relationships](https://laravel.com/docs/eloquent-relationships) in your schema. +Like in Laravel, you can define [Eloquent Relationships](https://laravel.com/docs/eloquent-relationships) in your schema. Suppose you have defined the following model: @@ -25,7 +25,7 @@ final class Post extends Model } ``` -Add fields to your type that are named just like the relationships: +Add fields to your type that are named like the relationships: ```graphql type Post { @@ -34,21 +34,22 @@ type Post { } ``` -Because Laravel relationships can be accessed just like regular properties on your model, the default field resolver will work just fine. +Because Laravel relationships can be accessed like regular properties on your model, the default field resolver works for them. ## Avoiding the N+1 performance problem When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". -This means the relationship data is not actually loaded until you first access the property. +This means the relationship data is not loaded until you first access the property. This leads to a common performance pitfall that comes with the nested nature of GraphQL queries: the so-called N+1 query problem. [Learn more](../performance/n-plus-one.md). -When you decorate your relationship fields with Lighthouse's built-in relationship directives, queries are automatically combined through a technique called _batch loading_. +When you decorate your relationship fields with Lighthouse's built-in relationship directives, Lighthouse combines their queries. +This technique is called _batch loading_. That means you get fewer database requests and better performance without doing much work. -> Batch loading might not provide ideal performance for all use cases. You can turn -> it off by setting the config option `batchload_relations` to `false`. +> Batch loading might not provide ideal performance for all use cases. +> You can turn it off by setting the config option `batchload_relations` to `false`. ## One To One diff --git a/docs/master/eloquent/soft-deleting.md b/docs/master/eloquent/soft-deleting.md index 3aa201488a..411b8d1c71 100644 --- a/docs/master/eloquent/soft-deleting.md +++ b/docs/master/eloquent/soft-deleting.md @@ -4,7 +4,8 @@ Lighthouse offers convenient helpers to work with models that use [soft deletes] ## Filter Soft Deleted Models -If your model uses the `Illuminate\Database\Eloquent\SoftDeletes` trait, you can add the [@softDeletes](../api-reference/directives.md#softdeletes) directive to a field to be able to query `onlyTrashed`, `withTrashed` or `withoutTrashed` elements. +If your model uses the `Illuminate\Database\Eloquent\SoftDeletes` trait, add the [@softDeletes](../api-reference/directives.md#softdeletes) directive to a field. +Then you can query `onlyTrashed`, `withTrashed` or `withoutTrashed` elements. ```graphql type Query { @@ -49,7 +50,7 @@ type Mutation { } ``` -Simply call the field with the ID of the flight you want to restore. +Call the field with the ID of the flight you want to restore. ```graphql mutation { @@ -72,7 +73,7 @@ type Mutation { } ``` -Simply call it with the ID of the `Flight` you want to permanently remove. +Call it with the ID of the `Flight` you want to permanently remove. ```graphql mutation { diff --git a/docs/master/federation/entities.md b/docs/master/federation/entities.md index dd0da3499c..4006f5b6ec 100644 --- a/docs/master/federation/entities.md +++ b/docs/master/federation/entities.md @@ -6,4 +6,5 @@ For a given `__typename` in the given `$representations`, Lighthouse will look f ## Extends You have to use `@extends` in place of `extend type` to annotate type references. -This is because Lighthouse merges type extensions before the final schema is produced, thus they would not be preserved to appear in the federation schema SDL. +This is because Lighthouse merges type extensions before it produces the final schema. +Thus, they would not appear in the federation schema SDL. diff --git a/docs/master/federation/entity-representations.md b/docs/master/federation/entity-representations.md index a600a5817d..cd9b8f18e5 100644 --- a/docs/master/federation/entity-representations.md +++ b/docs/master/federation/entity-representations.md @@ -28,7 +28,7 @@ type Comment @extends @key(fields: "id") { ## Non-Eloquent representation -If entities don't have an Eloquent relationship within the subgraph, it's necessary to specify a separate resolver that will return the required information. +If entities don't have an Eloquent relationship within the subgraph, specify a separate resolver that returns the required information. The resolver should return data containing information about the `__typename` field. This corresponds to the entity's name and the primary key that can identify the entity. The `__typename` can either be provided as an explicit field or implicitly by returning an object with a matching class name. diff --git a/docs/master/federation/getting-started.md b/docs/master/federation/getting-started.md index 81df858246..8a35b0ce77 100644 --- a/docs/master/federation/getting-started.md +++ b/docs/master/federation/getting-started.md @@ -47,7 +47,8 @@ extend schema ## Federated tracing -In order to use federated tracing, you need to enable [tracing](../performance/tracing.md) and set the driver to `Nuwave\Lighthouse\Tracing\FederatedTracing\FederatedTracing::class` in your `config/lighthouse.php`: +To use federated tracing, enable [tracing](../performance/tracing.md). +Then set the driver to `Nuwave\Lighthouse\Tracing\FederatedTracing\FederatedTracing::class` in your `config/lighthouse.php`: ```php 'tracing' => [ @@ -55,7 +56,7 @@ In order to use federated tracing, you need to enable [tracing](../performance/t ], ``` -Note that federated tracing requires `google/protobuf` to be installed (for better performance you can also install the `protobuf` php extension). +Federated tracing requires `google/protobuf` to be installed (for better performance you can also install the `protobuf` php extension). ### Unsupported features diff --git a/docs/master/federation/reference-resolvers.md b/docs/master/federation/reference-resolvers.md index c2703f0806..217f23a682 100644 --- a/docs/master/federation/reference-resolvers.md +++ b/docs/master/federation/reference-resolvers.md @@ -4,7 +4,7 @@ To enable the current subgraph to provide entities for other subgraphs, you need These reference resolvers act as helpers to enable cross-subgraph communication and provide data from one subgraph to another when needed. Read more about reference resolvers in the [Apollo Federation docs](https://www.apollographql.com/docs/federation/v1/entities#reference-resolvers). -Lighthouse will look for a class which name is equivalent to `__typename` in the namespace configured in `lighthouse.federation.entities_resolver_namespace`. +Lighthouse looks for a class named like `__typename` in the namespace configured in `lighthouse.federation.entities_resolver_namespace`. When you need to retrieve information from subgraphs, the gateway automatically generates a request to the corresponding endpoint of the subgraph. More details about this can be found in section [Query.\_entities of the Apollo Federation docs](https://www.apollographql.com/docs/federation/building-supergraphs/subgraphs-overview#query_entities). @@ -23,7 +23,8 @@ An example of such a request is shown below: ## Single Entity Resolvers -After validating that type `Foo` exists, Lighthouse will look for a resolver class in the namespace configured in `lighthouse.federation.entities_resolver_namespace`. +After validating that type `Foo` exists, Lighthouse looks for a resolver class. +It searches the namespace configured in `lighthouse.federation.entities_resolver_namespace`. The resolver class is expected to contain a method `__invoke()` which takes a single argument: the array form of the representation. ```php @@ -62,7 +63,8 @@ final class Foo ## Batched Entity Resolvers When the client requests a large number of entities with the same type, it can be more efficient to resolve them all at once. -When your entity resolver class implements `Nuwave\Lighthouse\Federation\BatchedEntityResolver`, Lighthouse will call it a single time with an array of all representations of its type. +When your entity resolver class implements `Nuwave\Lighthouse\Federation\BatchedEntityResolver`, Lighthouse calls it once. +It passes an array of all representations of its type. The resolver can then do some kind of batch query to resolve them and return them all at once. ```php @@ -112,7 +114,8 @@ final class Product implements BatchedEntityResolver ## Eloquent Model Resolvers -When no resolver class can be found, Lighthouse will attempt to find the model that matches the type `__typename`, using the namespaces configured in `lighthouse.namespaces.models`. +When no resolver class can be found, Lighthouse tries to find the model that matches the type `__typename`. +It uses the namespaces configured in `lighthouse.namespaces.models`. ```graphql { diff --git a/docs/master/getting-started/migrating-to-lighthouse.md b/docs/master/getting-started/migrating-to-lighthouse.md index 531660db6a..38e0000f23 100644 --- a/docs/master/getting-started/migrating-to-lighthouse.md +++ b/docs/master/getting-started/migrating-to-lighthouse.md @@ -8,7 +8,7 @@ The most important thing to get you started using Lighthouse will be a schema th If you already have a server with another library up and running, you can use introspection to retrieve this schema and save it to a file. -A simple tool that is also generally useful is [graphql-cli](https://github.com/graphql-cli/graphql-cli). +A generally useful tool is [graphql-cli](https://github.com/graphql-cli/graphql-cli). npm install -g graphql-cli graphql init @@ -20,7 +20,8 @@ Sometimes, additional annotations or a PHP implementation is required. ## Resolver logic -If you are coming from libraries such as [Folkloreatelier/laravel-graphql](https://github.com/Folkloreatelier/laravel-graphql), [rebing/laravel-graphql](https://github.com/rebing/graphql-laravel) or any other library that is originally based upon [webonyx/graphql-php](https://github.com/webonyx/graphql-php), you should be able to reuse much of your existing code. +Many libraries are based upon [webonyx/graphql-php](https://github.com/webonyx/graphql-php), such as [Folkloreatelier/laravel-graphql](https://github.com/Folkloreatelier/laravel-graphql) and [rebing/laravel-graphql](https://github.com/rebing/graphql-laravel). +If you are coming from one of them, you should be able to reuse much of your existing code. You can also register your existing types within Lighthouse's type registry, so you won't have to rewrite them in SDL. [Use native PHP types](../digging-deeper/adding-types-programmatically.md#native-php-types). diff --git a/docs/master/performance/caching.md b/docs/master/performance/caching.md index d0e4cda179..831afe6f58 100644 --- a/docs/master/performance/caching.md +++ b/docs/master/performance/caching.md @@ -120,11 +120,12 @@ Register the service provider `Nuwave\Lighthouse\CacheControl\CacheControlServic You can change the [`Cache-Control` header](https://developer.mozilla.org/de/docs/Web/HTTP/Headers/Cache-Control) of your response regardless of [@cache](../api-reference/directives.md#cache) by adding the [@cacheControl](../api-reference/directives.md#cachecontrol) directive to a field. The directive can be defined on the field-level or type-level. -Note that field-level settings override type-level settings. +Field-level settings override type-level settings. The final header settings are calculated based on these rules: -- `max-age` equals the lowest `maxAge` among all fields. If that value is 0, `no-cache` is used instead +- `max-age` equals the lowest `maxAge` among all fields. + If that value is 0, `no-cache` is used instead - visibility is `public` unless the scope of a queried field is `PRIVATE` The following defaults apply: diff --git a/docs/master/performance/n-plus-one.md b/docs/master/performance/n-plus-one.md index b84307fa7e..b40aaccda9 100644 --- a/docs/master/performance/n-plus-one.md +++ b/docs/master/performance/n-plus-one.md @@ -22,7 +22,8 @@ The associated author for each post would be lazily loaded, querying the databas When dealing with Laravel relationships, [eager loading](https://laravel.com/docs/eloquent-relationships#eager-loading) is commonly used to alleviate the N+1 query problem. -You can leverage eager loading by informing Lighthouse of the relationships between your models, using directives such as [@belongsTo](../api-reference/directives.md#belongsto), [@hasMany](../api-reference/directives.md#hasmany) and [@with](../api-reference/directives.md#with). +Lighthouse can use eager loading when you tell it about the relationships between your models. +Use directives such as [@belongsTo](../api-reference/directives.md#belongsto), [@hasMany](../api-reference/directives.md#hasmany) and [@with](../api-reference/directives.md#with). ```graphql type Post { @@ -71,7 +72,7 @@ Since we have multiple users, `User.posts` would be resolved multiple times in t We want to have a batch loader for `User.posts`, since it loads posts from a third party and the call to fetch them is slow when run sequentially. This is assuming the posts service offers a method to query posts for multiple users in one call. -In order for Lighthouse to perform batch loading, it needs to group fields that are on the same level in the query tree, but nested under different indices. +To perform batch loading, Lighthouse groups fields that are on the same level in the query tree, but nested under different indices. When looking at the query path from `posts`, they may look like: - `users.0.posts` @@ -80,7 +81,7 @@ When looking at the query path from `posts`, they may look like: In order to combine them, you need to have a single stateful batch loader instance for `users.posts`. Use `Nuwave\Lighthouse\Execution\BatchLoader\BatchLoaderRegistry` to resolve such instances. The following code is the resolver for `User.posts`. -See [resolver precedence](../the-basics/fields.md#resolver-precedence) on how it could actually be assigned to a field. +See [resolver precedence](../the-basics/fields.md#resolver-precedence) on how it could be assigned to a field. ```php use GraphQL\Deferred; @@ -98,7 +99,8 @@ function (User $user, array $args, GraphQLContext $context, ResolveInfo $resolve } ``` -The implementation of `UserPostsBatchLoader` is up to you, the only important thing is that the resolver returns an instance of `GraphQL\Deferred`, see [webonyx/graphql-php docs](https://webonyx.github.io/graphql-php/data-fetching/#solving-n1-problem). +The implementation of `UserPostsBatchLoader` is up to you. +The resolver must return an instance of `GraphQL\Deferred`, see [webonyx/graphql-php docs](https://webonyx.github.io/graphql-php/data-fetching/#solving-n1-problem). The following example illustrates some common patterns that may be found in a batch loader implementation: ```php @@ -132,8 +134,7 @@ final class UserPostsBatchLoader { $this->users[$user->id] = $user; - // The wrapped callable will run after load() has been called - // with all users in the current query. + // The wrapped callable will run after load() has been called with all users in the current query. return new Deferred(function () use ($user): array { // Ensure we only perform the actual loading exactly once. if (! $this->hasResolved) { @@ -145,7 +146,7 @@ final class UserPostsBatchLoader } /** - * Actually call out to the posts service and resolve them all at once. + * Call out to the posts service and resolve them all at once. */ protected function resolve(): void { diff --git a/docs/master/performance/query-caching.md b/docs/master/performance/query-caching.md index d79910cafb..1ccdc6bf0e 100644 --- a/docs/master/performance/query-caching.md +++ b/docs/master/performance/query-caching.md @@ -42,7 +42,8 @@ In some scenarios, you may need to clear the query cache completely. The Artisan command works based on your current configuration for `query_cache` in `config/lighthouse.php`. -- When using the modes [`store`](#mode-store) or [`hybrid`](#mode-hybrid), all entries in the configured cache store will be removed regardless of their age or whether they even belong to Lighthouse. +- When using the modes [`store`](#mode-store) or [`hybrid`](#mode-hybrid), the command removes all entries in the configured cache store. + That includes entries of any age and entries that do not belong to Lighthouse. - When using the modes [`opcache`](#mode-opcache) or [`hybrid`](#mode-hybrid), all cached query files will be removed. When you plan to change `query_cache.mode`, clear your cache while your current configuration is still in place. @@ -74,7 +75,8 @@ You can enable it by setting `validation_cache.enable` to `true` in `config/ligh ## Testing caveats -If you are mocking Laravel cache classes like `Illuminate\Support\Facades\Cache` or `Illuminate\Cache\Repository` and asserting expectations in your unit tests, it might be best to disable the query cache in your `phpunit.xml`: +Your unit tests might mock Laravel cache classes like `Illuminate\Support\Facades\Cache` or `Illuminate\Cache\Repository` and assert expectations. +In that case, it might be best to disable the query cache in your `phpunit.xml`: ```diff diff --git a/docs/master/performance/server-configuration.md b/docs/master/performance/server-configuration.md index 561c14b335..04b7997948 100644 --- a/docs/master/performance/server-configuration.md +++ b/docs/master/performance/server-configuration.md @@ -5,7 +5,7 @@ You can tune the configuration of your PHP server for Lighthouse. ## OPcache The nature of the schema operations in Lighthouse plays nicely with [PHP's OPcache](https://php.net/manual/en/book.opcache.php). -If you have the freedom to install it on your server, it's an easy way to get a nice performance boost. +If you can install it on your server, it improves performance. ## Xdebug diff --git a/docs/master/security/authentication.md b/docs/master/security/authentication.md index db9b35d1d4..ae0e9edd0e 100644 --- a/docs/master/security/authentication.md +++ b/docs/master/security/authentication.md @@ -4,7 +4,8 @@ You can use [standard Laravel mechanisms](https://laravel.com/docs/authenticatio ## AttemptAuthentication middleware -As all GraphQL requests are served at a single HTTP endpoint, middleware added through the `lighthouse.php` config will run for all queries against your server. +All GraphQL requests are served at a single HTTP endpoint. +Thus, middleware added through the `lighthouse.php` config runs for all queries against your server. In most cases, your schema will have some publicly accessible fields and others that require authentication. As multiple checks for authentication or permissions may be required in a single request, it is convenient to attempt authentication once per request. @@ -17,9 +18,9 @@ As multiple checks for authentication or permissions may be required in a single ], ``` -Note that the `AttemptAuthentication` middleware does _not_ protect your fields from unauthenticated access, decorate them with [@guard](../api-reference/directives.md#guard) as needed. +The `AttemptAuthentication` middleware does _not_ protect your fields from unauthenticated access, decorate them with [@guard](../api-reference/directives.md#guard) as needed. -If you want to guard all your fields against unauthenticated access, you can simply add Laravel's built-in auth middleware. +If you want to guard all your fields against unauthenticated access, add Laravel's built-in auth middleware. Beware that this approach does not allow any GraphQL operations for guest users. So you will have to handle login outside GraphQL. @@ -45,7 +46,8 @@ Stateless guards are recommended for most use cases, such as the default `api` g ### Laravel Sanctum -If you are using [Laravel Sanctum](https://laravel.com/docs/sanctum) for your API, set the guard to `sanctum` and register Sanctum's `EnsureFrontendRequestsAreStateful` as the first middleware for Lighthouse's route. +If you are using [Laravel Sanctum](https://laravel.com/docs/sanctum) for your API, set the guard to `sanctum`. +Then register Sanctum's `EnsureFrontendRequestsAreStateful` as the first middleware for Lighthouse's route. ```php 'route' => [ @@ -59,7 +61,7 @@ If you are using [Laravel Sanctum](https://laravel.com/docs/sanctum) for your AP 'guards' => ['sanctum'], ``` -Note that Sanctum requires you to send an CSRF token as [header](https://laravel.com/docs/csrf#csrf-x-csrf-token) with all GraphQL requests, regardless of whether the user is authenticated or not. +Sanctum requires you to send an CSRF token as [header](https://laravel.com/docs/csrf#csrf-x-csrf-token) with all GraphQL requests, regardless of whether the user is authenticated or not. When using [mll-lab/laravel-graphiql](https://github.com/mll-lab/laravel-graphiql), follow the [instructions to add a CSRF token](https://github.com/mll-lab/laravel-graphiql#configure-session-authentication). @@ -98,7 +100,7 @@ extend type Query { ## Get the current user -Lighthouse provides a really simple way to fetch the information of the currently authenticated user. +Lighthouse can fetch the information of the currently authenticated user. Add a field that returns your `User` type and decorate it with the [@auth](../api-reference/directives.md#auth) directive. ```graphql @@ -121,7 +123,9 @@ It returns `null` if the request is not authenticated. ## Stateful Authentication Example -You can create or destroy a session with mutations instead of separate API endpoints (`/login`, `/logout`). **This only works when Lighthouse's guard uses a session driver.** Laravel's token based authentication does not allow logging in or out on the server side. +You can create or destroy a session with mutations instead of separate API endpoints (`/login`, `/logout`). +**This only works when Lighthouse's guard uses a session driver.** +Laravel's token based authentication does not allow logging in or out on the server side. The implementation in the docs is only an example and may have to be adapted to your specific use case. diff --git a/docs/master/security/authorization.md b/docs/master/security/authorization.md index de84df9814..0108e04270 100644 --- a/docs/master/security/authorization.md +++ b/docs/master/security/authorization.md @@ -3,7 +3,8 @@ Not every user in your application may be allowed to see all data or do any action. You can control what they can do by enforcing authorization rules. -Before you can apply authorization, make sure you cover [authentication](authentication.md) first - it's a prerequisite to have your users logged in before checking what they can do. +Before you apply authorization, cover [authentication](authentication.md) first. +Your users must be logged in before you check what they can do. ## Use the Viewer pattern @@ -12,7 +13,7 @@ For example, a user may only be able to see notes they created. You can use the nested nature of GraphQL queries to naturally limit access to such fields. Begin with a field that represents the currently authenticated user, commonly called `me` or `viewer`. -You can resolve that field quite easily by using the [@auth](../api-reference/directives.md#auth) directive. +Resolve that field with the [@auth](../api-reference/directives.md#auth) directive. ```graphql type Query { @@ -38,7 +39,7 @@ type Note { } ``` -Now, authenticated users can query for items that belong to them and are naturally limited to seeing just those. +Now, authenticated users can query for items that belong to them and are naturally limited to seeing only those. ```graphql { @@ -116,7 +117,7 @@ final class PostPolicy For some models, you may want to restrict access for already resolved instance of a model. Use the [@canResolved](../api-reference/directives.md#canresolved) directive to do so. -> This will actually run the field before checking permissions, do not use in mutations. +> This runs the field before checking permissions, do not use in mutations. ```graphql type Query { @@ -203,7 +204,7 @@ final class PostPolicy } ``` -When you combine both ways of passing arguments, the policy will be passed the `injectArgs` as the second parameter and the static `args` as the third parameter: +When you combine both ways, the policy receives `injectArgs` as the second parameter and the static `args` as the third: ```php final class PostPolicy diff --git a/docs/master/security/resource-exhaustion.md b/docs/master/security/resource-exhaustion.md index d7147bac99..833b458ccb 100644 --- a/docs/master/security/resource-exhaustion.md +++ b/docs/master/security/resource-exhaustion.md @@ -3,8 +3,8 @@ GraphQL gives enormous power to clients. With great power, there must also come great responsibility 🕷. -Since clients have the possibility to craft very complex queries, we must be ready to handle them properly. -These queries may be abusive queries from evil clients, or may simply be huge queries used by legitimate clients. +Since clients have the possibility to craft complex queries, we must be ready to handle them properly. +These queries may be abusive queries from evil clients, or huge queries used by legitimate clients. In both of these cases, the client can potentially take your GraphQL server down. _This intro was taken from HowToGraphQL, we recommend reading their full chapter on security https://www.howtographql.com/advanced/4-security/_ diff --git a/docs/master/security/sanitization.md b/docs/master/security/sanitization.md index 5c20de2141..6768dc72ad 100644 --- a/docs/master/security/sanitization.md +++ b/docs/master/security/sanitization.md @@ -1,12 +1,13 @@ # Sanitization When dealing with user input, you need to make sure the given data is valid. -While [validation](validation) is a great first line of defense, there are cases where it is most practical to modify the given input to ensure it is valid or safe to use. +[Validation](validation) is a great first line of defense. +In some cases, it is most practical to modify the given input to ensure it is valid or safe to use. ## Single arguments A great way to deal with single values is to use an [`ArgTransformerDirective`](../custom-directives/field-argument-directives#argtransformerdirective). -Lighthouse offers a few built-in options, but it is also really easy to build your own. +Lighthouse offers a few built-in options, and you can build your own. Here is how you can remove whitespace of a given input string by using the built-in [@trim](../api-reference/directives.md#trim) directive: @@ -18,4 +19,5 @@ type Mutation { ## Complex arguments -When you need to look at multiple input fields in order to run sanitization, you can use a [`FieldMiddlewareDirective`](../custom-directives/field-directives.md#fieldmiddleware) to transform the given inputs before passing them along to the final resolver. +When sanitization needs to look at multiple input fields, use a [`FieldMiddlewareDirective`](../custom-directives/field-directives.md#fieldmiddleware). +It can transform the given inputs before passing them along to the final resolver. diff --git a/docs/master/security/validation.md b/docs/master/security/validation.md index 742d839f64..f51971f6b1 100644 --- a/docs/master/security/validation.md +++ b/docs/master/security/validation.md @@ -4,7 +4,7 @@ Lighthouse allows you to use [Laravel's validation](https://laravel.com/docs/val ## Single Arguments -The simplest way to leverage the built-in validation rules is to use the [@rules](../api-reference/directives.md#rules) directive. +Apply the built-in validation rules with the [@rules](../api-reference/directives.md#rules) directive. ```graphql type Mutation { @@ -149,7 +149,8 @@ input UpdateUserInput @validator { ``` We need to back that with a validator class. -Lighthouse uses a simple naming convention for validator classes, use the name of the input type and append `Validator`: +Lighthouse uses a naming convention for validator classes. +Use the name of the input type and append `Validator`: ```shell php artisan lighthouse:validator UpdateUserInputValidator @@ -181,7 +182,7 @@ final class UpdateUserInputValidator extends Validator } ``` -Note that this gives you access to all kinds of programmatic validation rules that Laravel provides. +This gives you access to all kinds of programmatic validation rules that Laravel provides. This can give you additional flexibility when you need it. ### Custom Validator Messages @@ -310,7 +311,8 @@ type Mutation { By default, Lighthouse enables all default query validation rules from `webonyx/graphql-php`. This covers fundamental checks, e.g. queried fields match the schema, variables have values of the correct type. -If you want to add custom rules or change which ones are used, you can bind a custom implementation of the interface `Nuwave\Lighthouse\Support\Contracts\ProvidesCacheableValidationRules` through a service provider. +To add custom rules or change which ones are used, implement the interface `Nuwave\Lighthouse\Support\Contracts\ProvidesCacheableValidationRules`. +Bind your implementation through a service provider. ```php use Nuwave\Lighthouse\Support\Contracts\ProvidesValidationRules; diff --git a/docs/master/subscriptions/defining-fields.md b/docs/master/subscriptions/defining-fields.md index ff15fe6ae8..7c81c894ac 100644 --- a/docs/master/subscriptions/defining-fields.md +++ b/docs/master/subscriptions/defining-fields.md @@ -17,7 +17,8 @@ php artisan lighthouse:subscription PostUpdated Lighthouse will look for a class matching the capitalized name of the field within the default subscription namespace. For example, the field `postUpdated` should have a corresponding class at `App\GraphQL\Subscriptions\PostUpdated`. -All subscription field classes **must** implement the abstract class `Nuwave\Lighthouse\Schema\Types\GraphQLSubscription` and implement the two methods `authorize` and `filter`. +All subscription field classes **must** extend the abstract class `Nuwave\Lighthouse\Schema\Types\GraphQLSubscription`. +They implement the two methods `authorize` and `filter`. ```php namespace App\GraphQL\Subscriptions; @@ -48,8 +49,7 @@ final class PostUpdated extends GraphQLSubscription { $user = $subscriber->context->user; - // Don't broadcast the subscription to the same - // person who updated the post. + // Don't broadcast the subscription to the same person who updated the post. return $root->updated_by !== $user->id; } @@ -75,8 +75,7 @@ final class PostUpdated extends GraphQLSubscription */ public function resolve(mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Post { - // Optionally manipulate the `$root` item before it gets broadcasted to - // subscribed client(s). + // Optionally manipulate the `$root` item before it gets broadcasted to subscribed client(s). $root->load(['author', 'author.achievements']); return $root; @@ -84,4 +83,5 @@ final class PostUpdated extends GraphQLSubscription } ``` -If the default namespaces are not working with your application structure or you want to be more explicit, you can use the [@subscription](../api-reference/directives.md#subscription) directive to point to a different class. +If the default namespaces do not fit your application structure, or you want to be more explicit, use the [@subscription](../api-reference/directives.md#subscription) directive. +It points to a different class. diff --git a/docs/master/subscriptions/filtering-subscriptions.md b/docs/master/subscriptions/filtering-subscriptions.md index 3c6d132093..8e980fe50f 100644 --- a/docs/master/subscriptions/filtering-subscriptions.md +++ b/docs/master/subscriptions/filtering-subscriptions.md @@ -29,8 +29,7 @@ final class PostUpdatedSubscription extends GraphQLSubscription // Clients arguments when subscribing $args = $subscriber->args; - // Ensure that the Post ($root) id matches - // the requested `post_id` + // Ensure that the Post ($root) id matches the requested `post_id` return $root->id == $args['post_id']; } } @@ -38,7 +37,7 @@ final class PostUpdatedSubscription extends GraphQLSubscription ## Only To Others -When building an application that uses event broadcasting, you may occasionally need to broadcast an event to all subscribers of a channel except for the current user. +An application that uses event broadcasting may need to broadcast an event to all subscribers of a channel except the current user. You may accomplish this using the filter function, this following snippet is equivalent to [the `toOthers()` method from Laravel's broadcast helper](https://laravel.com/docs/9.x/broadcasting#only-to-others). ```php @@ -61,10 +60,11 @@ final class PostUpdatedSubscription extends GraphQLSubscription ``` When you initialize a Laravel Echo instance, a socket ID is assigned to the connection. -If you are using a global [Axios](https://github.com/mzabriskie/axios) instance to make HTTP requests from your JavaScript application, the socket ID will automatically be attached to every outgoing request in the `X-Socket-ID` header. +If your JavaScript application uses a global [Axios](https://github.com/mzabriskie/axios) instance for HTTP requests, the socket ID is attached to every outgoing request. +It is sent in the `X-Socket-ID` header. Then, you can access that in your filter function. -If you are not using a global Axios instance, you will need to manually configure your JavaScript application to send the `X-Socket-ID` header with all outgoing requests. +Without a global Axios instance, configure your JavaScript application to send the `X-Socket-ID` header with all outgoing requests. You may retrieve the socket ID using the `Echo.socketId()` method: ```js diff --git a/docs/master/subscriptions/getting-started.md b/docs/master/subscriptions/getting-started.md index 4e26b0f3d3..f1cd9dc850 100644 --- a/docs/master/subscriptions/getting-started.md +++ b/docs/master/subscriptions/getting-started.md @@ -26,17 +26,17 @@ When using subscriptions with [Laravel Octane](https://laravel.com/docs/octane), ### Empty Response Optimization Lighthouse returns the subscription channel as part of the response under `extensions`. -If `subscriptions.exclude_empty` in `lighthouse.php` is set to `true`, API responses without a subscription channel will not contain `lighthouse_subscriptions` in `extensions`. -This optimizes performance by sending less data, -but clients must anticipate this appropriately. +Set `subscriptions.exclude_empty` in `lighthouse.php` to `true` to change this. +Then responses without a subscription channel omit `lighthouse_subscriptions` from `extensions`. +This optimizes performance by sending less data, but clients must anticipate this appropriately. ## Expiring Subscriptions Subscriptions do not expire by themselves. Unless you delete a subscription, it will continue to broadcast events after the client has disconnected. -The easiest way to expire subscriptions automatically is to use the env `LIGHTHOUSE_SUBSCRIPTION_STORAGE_TTL` to set an expiration time in seconds (e.g. -`LIGHTHOUSE_SUBSCRIPTION_STORAGE_TTL=3600` to expire in one hour). +Automate expiry by setting `LIGHTHOUSE_SUBSCRIPTION_STORAGE_TTL` to an expiration time in seconds. +For example, `LIGHTHOUSE_SUBSCRIPTION_STORAGE_TTL=3600` expires subscriptions after one hour. ## Encrypted Subscriptions @@ -60,8 +60,8 @@ More details on how to enable encryption are defined in the [Pusher documentatio ### Pusher Expiration Webhook If you are using the Pusher driver, you can use a [`channel existence`](https://pusher.com/docs/channels/server_api/webhooks/#channel-existence-events) webhook to mitigate this problem. -When a Pusher channel is vacated (i.e. there are no subscribers), it will trigger the webhook, -which will instruct Lighthouse to delete the subscription. +When a Pusher channel is vacated (i.e. there are no subscribers), it triggers the webhook. +The webhook instructs Lighthouse to delete the subscription. The webhook URL will typically be: diff --git a/docs/master/testing/extensions.md b/docs/master/testing/extensions.md index 326d257487..405842c9a8 100644 --- a/docs/master/testing/extensions.md +++ b/docs/master/testing/extensions.md @@ -39,9 +39,22 @@ final class MyCustomDirectiveTest extends TestCase ## Mock resolvers When testing custom functionality through a dummy schema, you still need to have a way to resolve fields. -Lighthouse provides a simple way to mock resolvers in a dummy schema. +Lighthouse can mock resolvers in a dummy schema. +Mark the fields to mock with the `@mock` directive: -Add the `MocksResolvers` trait to your test class: +```graphql +""" +Resolve the field with a mock resolver registered in the test, see `MocksResolvers`. +""" +directive @mock( + """ + Specify a unique key for the mock resolver. + """ + key: String = "default" +) on FIELD_DEFINITION +``` + +Then add the `MocksResolvers` trait to your test class: ```php namespace Tests; @@ -63,7 +76,7 @@ Reverses a string, e.g. 'foo' => 'oof'. directive @reverse on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION ``` -The simplest way to mock a resolver is to have it return static data: +A mock resolver can return static data: ```php public function testReverseField(): void @@ -89,8 +102,8 @@ public function testReverseField(): void ``` Since we get back an instance of PHPUnit's `InvocationMocker`, we can also assert that our resolver is called with certain values. -Note that we are not passing an explicit resolver function here. -The default resolver will simply return `null`. +We are not passing an explicit resolver function here. +The default resolver returns `null`. ```php public function testReverseInput(): void diff --git a/docs/master/testing/phpunit.md b/docs/master/testing/phpunit.md index f000307606..3a0a825a05 100644 --- a/docs/master/testing/phpunit.md +++ b/docs/master/testing/phpunit.md @@ -1,13 +1,13 @@ # Testing with PHPUnit -Lighthouse makes it easy to add automated tests through [PHPUnit](https://phpunit.de). +Lighthouse supports automated tests through [PHPUnit](https://phpunit.de). ## Setup Lighthouse offers some useful test helpers. Keep in mind they only work when your test class extends `Illuminate\Foundation\Testing\TestCase`. -The `MakesGraphQLRequests` trait make it easy to call your API: +The `MakesGraphQLRequests` trait lets you call your API: ```diff +use Nuwave\Lighthouse\Testing\MakesGraphQLRequests; @@ -106,7 +106,7 @@ public function testPostsSubscription(): void Now that we know how to query our server in tests, we need to make sure the returned results match our expectations. -The returned `TestResponse` conveniently offers assertions that work quite well with the JSON data returned by GraphQL. +The returned `TestResponse` offers assertions that work well with the JSON data returned by GraphQL. The `assertJson` method asserts that the response is a superset of the given JSON. @@ -192,7 +192,7 @@ $response->assertGraphQLSubscriptionNotAuthorized($this); Once you do your subscription query and get a `TestResponse $response`, you can run the following assertions on it. -To assert the subscription actually received some broadcasts: +To assert the subscription received some broadcasts: ``` // any other way to broadcast would also work @@ -228,14 +228,14 @@ $spy->shouldNotHaveReceived('broadcast', function (Subscriber $subscriber, $broa ### TestResponse Assertion Mixins -Lighthouse conveniently provides additional assertions as mixins to the `TestResponse` class. +Lighthouse provides additional assertions as mixins to the `TestResponse` class. Make sure to [generate the latest IDE-helper file](../api-reference/commands.md#ide-helper) to get proper autocompletion: ```shell php artisan lighthouse:ide-helper ``` -The provided assertions are prefixed with `assertGraphQL` for easy discovery. +The provided assertions are prefixed with `assertGraphQL`, so you can find them through autocompletion. They offer useful shortcuts to common testing tasks. For example, you might want to ensure that validation works properly: @@ -251,9 +251,11 @@ $this ## Testing Errors -Depending on your debug and error handling configuration, Lighthouse catches most if not all errors produced within queries and includes them within the result. +Depending on your debug and error handling configuration, Lighthouse catches most if not all errors produced within queries. +It includes them in the result. -One way to test for errors is to examine the `TestResponse`, either by looking at the JSON response manually or by using the provided [assertion mixins](#testresponse-assertion-mixins) such as `assertGraphQLErrorMessage()`: +One way to test for errors is to examine the `TestResponse`. +Look at the JSON response manually or use the provided [assertion mixins](#testresponse-assertion-mixins) such as `assertGraphQLErrorMessage()`: ```php $this diff --git a/docs/master/testing/rector.md b/docs/master/testing/rector.md index fc2b3d1728..bcff2461a5 100644 --- a/docs/master/testing/rector.md +++ b/docs/master/testing/rector.md @@ -84,9 +84,11 @@ $rectorConfig->ruleWithConfiguration(RootResolverSignatureRector::class, [ ### Known Limitation -The rule assumes every class with an `__invoke` method found under the resolver directories (e.g. `App\GraphQL\Queries`, `App\GraphQL\Mutations`) is a root resolver. +The rule assumes that every class with an `__invoke` method in the resolver directories is a root resolver. +Examples of those directories are `App\GraphQL\Queries` and `App\GraphQL\Mutations`. -Classes that are **not** root resolvers — such as nested field resolvers that receive a parent model as their first argument — will be incorrectly rewritten. +The rule incorrectly rewrites classes that are **not** root resolvers. +Examples are nested field resolvers that receive a parent model as their first argument. **Mitigations:** diff --git a/docs/master/the-basics/best-practices.md b/docs/master/the-basics/best-practices.md index 4d8d0d9d73..d8a6f41b37 100644 --- a/docs/master/the-basics/best-practices.md +++ b/docs/master/the-basics/best-practices.md @@ -5,7 +5,7 @@ We recommend you use [GraphQL Rules](https://github.com/graphql-rules/graphql-ru ## In the mutation response, return a field of type Query -If you decide to [return the `Query` object in every mutation payload](https://github.com/graphql-rules/graphql-rules/blob/master/docs/rules/06-mutations/mutation-payload-query.md), Lighthouse makes it very easy. +If you decide to [return the `Query` object in every mutation payload](https://github.com/graphql-rules/graphql-rules/blob/master/docs/rules/06-mutations/mutation-payload-query.md), Lighthouse supports it. ```graphql type Mutation { diff --git a/docs/master/the-basics/directives.md b/docs/master/the-basics/directives.md index 482bcf5f59..edbf187395 100644 --- a/docs/master/the-basics/directives.md +++ b/docs/master/the-basics/directives.md @@ -34,9 +34,9 @@ type Query { ## Usage -Lighthouse provides a plethora of built-in schema directives that are ready to be consumed and can simply be used from within the schema. +Lighthouse provides a plethora of built-in schema directives that you can use in your schema. -The following example is quite dense, but it should give you an idea of what directives are capable of. +The following example is dense, but it should give you an idea of what directives are capable of. ```graphql type Query { diff --git a/docs/master/the-basics/fields.md b/docs/master/the-basics/fields.md index 375b7d26fe..11512278a2 100644 --- a/docs/master/the-basics/fields.md +++ b/docs/master/the-basics/fields.md @@ -20,7 +20,8 @@ type Query { This defines the shape of our data and informs the client what they can expect. You need to implement the actual resolver next. -By default, Lighthouse looks for a class with the capitalized name of the field in `App\GraphQL\Queries` or `App\GraphQL\Mutations` and calls its `__invoke` function with [the usual resolver arguments](../api-reference/resolvers.md#resolver-function-signature). +By default, Lighthouse looks for a class with the capitalized name of the field in `App\GraphQL\Queries` or `App\GraphQL\Mutations`. +It calls its `__invoke` function with [the usual resolver arguments](../api-reference/resolvers.md#resolver-function-signature). In this case, our field is a query and is called `hello`, so we need to define our class as follows: @@ -36,7 +37,7 @@ final class Hello } ``` -The easiest way to create such a class is to use the built-in `artisan` commands `lighthouse:query` and `lighthouse:mutation`. +Create such a class with the built-in `artisan` commands `lighthouse:query` and `lighthouse:mutation`. They both take a single argument: the name of the field you want to generate. For example, this is how you generate a class for the field `hello`: @@ -66,7 +67,7 @@ This query will return the following response: ## Fields with arguments As we learned, _every_ field has a resolver function associated with it. -Just like functions, fields can take arguments to control their behavior. +Like functions, fields can take arguments to control their behavior. Let's construct a query that greets the user. We add a required argument `name` that is used to construct the greeting. @@ -169,7 +170,7 @@ Let's suppose it returns an instance of `App\Model\User`. Next, the field sub-selection will be resolved - the two requested fields are `id` and `name`. Since we already resolved the User in the parent field, we do not want to fetch it again to get its attributes. -Conveniently, the first argument of each resolver is the return value of the parent field, in this case a User model. +The first argument of each resolver is the return value of the parent field, in this case a User model. A naive implementation of a resolver for `id` might look like this: @@ -198,12 +199,12 @@ function resolveUserAttribute(User $user, array $args, GraphQLContext $context, ``` Fortunately, the underlying GraphQL implementation already provides [a sensible default resolver](https://webonyx.github.io/graphql-php/data-fetching/#default-field-resolver). -Plays quite nicely with the data you would typically return from a root resolver, e.g. -`Eloquent` models or associative arrays. +It works well with the data you would typically return from a root resolver, e.g. `Eloquent` models or associative arrays. This means that in most cases, you will only have to provide resolvers for the root fields and make sure they return data in the proper shape. -If you need to implement custom resolvers for fields that are not on one of the root types `Query` or `Mutation`, you can create a resolver class using the built-in `artisan` command `lighthouse:field`. +Fields that are not on the root types `Query` or `Mutation` may need custom resolvers. +Create a resolver class for them with the `artisan` command `lighthouse:field`. For example, this is how you generate a class for the field `name` on type `User`: ```shell @@ -217,8 +218,8 @@ Lighthouse uses the following logic to locate field resolvers. First, it checks if the field definition in the schema is annotated with a [FieldResolver](../custom-directives/field-directives.md#fieldresolver) directive. If so, it uses the resolver provided by the directive. -The interface [`Nuwave\Lighthouse\Support\Contracts\ProvidesResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ProvidesResolver.php) is expected to provide a resolver in case no resolver directive is defined for a field. -When the field is defined on the root `Subscription` type, the [`Nuwave\Lighthouse\Support\Contracts\ProvidesSubscriptionResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ProvidesSubscriptionResolver.php) interface is used instead. +The interface [`Nuwave\Lighthouse\Support\Contracts\ProvidesResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ProvidesResolver.php) provides a resolver when a field has no resolver directive. +On the root `Subscription` type, the [`Nuwave\Lighthouse\Support\Contracts\ProvidesSubscriptionResolver`](https://github.com/nuwave/lighthouse/tree/master/src/Support/Contracts/ProvidesSubscriptionResolver.php) interface is used instead. The default implementation of those interfaces check if there is a class that matches the capitalized name of the field. Defines a method `__invoke`, in one of the configured default namespaces, depending on the parent type the field is a part of. @@ -230,11 +231,13 @@ Defines a method `__invoke`, in one of the configured default namespaces, depend | `Subscription` | `lighthouse.namespaces.subscriptions` | | Any other type | `lighthouse.namespaces.types` | -For example, given `lighthouse.namespaces.queries` is defined as `'App\GraphQL\Queries'` and the field `Query.users`, Lighthouse would expect a resolver class `App\GraphQL\Queries\User`. +For example, take `lighthouse.namespaces.queries` defined as `'App\GraphQL\Queries'` and the field `Query.users`. +Lighthouse expects a resolver class `App\GraphQL\Queries\Users`. If there are multiple namespaces, they are checked in order and the first found class is used. Non-root types are combined with the configured namespaces. -For example, given `lighthouse.namespaces.types` is defined as `['App\GraphQL\Types', 'MyModule\GraphQL\Types']` and the field `User.name`, Lighthouse would look for the resolver class `App\GraphQL\Types\User\Name`, then `MyModule\GraphQL\Types\User\Name`. +For example, take `lighthouse.namespaces.types` defined as `['App\GraphQL\Types', 'MyModule\GraphQL\Types']` and the field `User.name`. +Lighthouse looks for the resolver class `App\GraphQL\Types\User\Name`, then `MyModule\GraphQL\Types\User\Name`. Resolvers for root fields are mandatory, Lighthouse will throw during schema validation if a root field has no resolver. Non-root fields fall back to [webonyx's default resolver](https://webonyx.github.io/graphql-php/data-fetching/#default-field-resolver). diff --git a/docs/master/the-basics/types.md b/docs/master/the-basics/types.md index 7be6281fba..4c138f2d4e 100644 --- a/docs/master/the-basics/types.md +++ b/docs/master/the-basics/types.md @@ -84,7 +84,7 @@ type Query { } ``` -In this example, the underlying values are actually integers. +In this example, the underlying values are integers. When the models are retrieved from the database, the mapping is applied and the integers are converted to the defined string keys. ```php @@ -311,7 +311,7 @@ Read more about them in the [GraphQL Reference](https://graphql.org/learn/schema ## Union -A Union is an abstract type that simply enumerates other Object Types. +A Union is an abstract type that enumerates other Object Types. They are similar to interfaces in that they can return different types. But do not prescribe any common fields. @@ -329,7 +329,7 @@ type Employee { } ``` -Just like Interfaces, you need a way to determine the concrete Object Type for a Union, based on the resolved value. +Like Interfaces, you need a way to determine the concrete Object Type for a Union, based on the resolved value. If the default type resolver does not work for you, define your own with `php artisan lighthouse:union `. It is automatically put in the default namespace where Lighthouse can discover it by itself. diff --git a/src/Async/AsyncDirective.php b/src/Async/AsyncDirective.php index 0be52a0dfb..837fb8f6ab 100644 --- a/src/Async/AsyncDirective.php +++ b/src/Async/AsyncDirective.php @@ -26,11 +26,10 @@ public static function definition(): string Defer the execution of mutations to [queued jobs](https://laravel.com/docs/queues). This directive must only be used on fields of the root mutation type. -When the field is executed, a `Nuwave\Lighthouse\Async\AsyncMutation` job is dispatched -and the value `true` is returned - thus the fields return type must be `Boolean!`. +When the field is executed, a `Nuwave\Lighthouse\Async\AsyncMutation` job is dispatched and the value `true` is returned. +Thus, the field's return type must be `Boolean!`. -Once a [queue worker](https://laravel.com/docs/queues#running-the-queue-worker) picks up the job, -it will actually execute the underlying field resolver. +Once a [queue worker](https://laravel.com/docs/queues#running-the-queue-worker) picks up the job, it executes the underlying field resolver. Errors that occur during execution are reported through the Laravel exception handler. The handlers in the `config/lighthouse.php` option `error_handlers` are not called. """ diff --git a/src/Auth/BaseCanDirective.php b/src/Auth/BaseCanDirective.php index 3401ec37c6..d709773a63 100644 --- a/src/Auth/BaseCanDirective.php +++ b/src/Auth/BaseCanDirective.php @@ -34,8 +34,7 @@ protected static function commonArguments(): string """ Statically defined arguments that are passed to `Gate::check`. - You may pass arbitrary GraphQL literals, - e.g.: [1, 2, 3] or { foo: "bar" } + You may pass any GraphQL literal, e.g. `[1, 2, 3]` or `{ foo: "bar" }`. """ args: CanArgs @@ -104,8 +103,7 @@ public function handleField(FieldValue $fieldValue): void try { $resolved = $this->authorizeRequest($root, $args, $context, $resolveInfo, $trackedResolver, $authorizeModel); if ($hasResolved) { - // A batch loaded relation resolves to a promise, so authorization runs when - // that promise is fulfilled, which is after this try-catch has been left. + // A batch loaded relation resolves to a promise, so authorization runs when that promise is fulfilled, which is after this try-catch has been left. // Handle its failure the same way to keep `action` meaningful either way. return $resolved instanceof SyncPromise ? $resolved->then(null, fn (\Throwable $throwable): mixed => $this->handleAuthorizationFailure($throwable)) @@ -159,8 +157,7 @@ abstract protected function authorizeRequest(mixed $root, array $args, GraphQLCo */ protected function authorizeModel(Gate $gate, string|array $ability, mixed $model, array $arguments): void { - // The signature of the second argument `$arguments` of `Gate::check` - // should be [modelClassName, additionalArg, additionalArg...] + // The signature of the second argument `$arguments` of `Gate::check` should be [modelClassName, additionalArg, additionalArg...] array_unshift($arguments, $model); Utils::applyEach( diff --git a/src/Auth/CanDirective.php b/src/Auth/CanDirective.php index 21eb99249d..b698ec86e8 100644 --- a/src/Auth/CanDirective.php +++ b/src/Auth/CanDirective.php @@ -44,8 +44,7 @@ public static function definition(): string """ Check a Laravel Policy to ensure the current user is authorized to access a field. -When `injectArgs` and `args` are used together, the client given -arguments will be passed before the static args. +When `injectArgs` and `args` are used together, the client-given arguments are passed before the static args. """ directive @can( """ @@ -75,16 +74,15 @@ public static function definition(): string """ Statically defined arguments that are passed to `Gate::check`. - You may pass arbitrary GraphQL literals, - e.g.: [1, 2, 3] or { foo: "bar" } + You may pass any GraphQL literal, e.g. `[1, 2, 3]` or `{ foo: "bar" }`. CanArgs pseudo-scalar is defined in BaseCanDirective. """ args: CanArgs """ - Query for specific model instances to check the policy against, using arguments - with directives that add constraints to the query builder, such as `@eq`. + Query for specific model instances to check the policy against. + Use arguments with directives that add constraints to the query builder, such as `@eq`. Mutually exclusive with `resolved`, `find`, and `root`. """ @@ -96,8 +94,7 @@ public static function definition(): string scopes: [String!] """ - If your policy checks against specific model instances, specify - the name of the field argument that contains its primary key(s). + If your policy checks against specific model instances, specify the name of the field argument that contains their primary key(s). You may pass the string in dot notation to use nested inputs. @@ -248,8 +245,7 @@ public static function missingKeyToFindModel(string $find): Error */ protected function authorize(Gate $gate, string|array $ability, string|Model|null $model, array $arguments): void { - // The signature of the second argument `$arguments` of `Gate::check` - // should be [modelClassName, additionalArg, additionalArg...] + // The signature of the second argument `$arguments` of `Gate::check` should be [modelClassName, additionalArg, additionalArg...] array_unshift($arguments, $model); Utils::applyEach( diff --git a/src/Auth/CanFindDirective.php b/src/Auth/CanFindDirective.php index 3f8cc8682a..3213390488 100644 --- a/src/Auth/CanFindDirective.php +++ b/src/Auth/CanFindDirective.php @@ -28,13 +28,13 @@ public static function definition(): string """ Check a Laravel Policy to ensure the current user is authorized to access a field. -Query for specific model instances to check the policy against, using primary key(s) from specified argument. +Query for specific model instances to check the policy against, using the primary key(s) from the specified argument. """ directive @canFind( {$commonArguments} """ - Specify the name of the field argument that contains its primary key(s). + Specify the name of the field argument that contains the primary key(s). You may pass the string in dot notation to use nested inputs. """ diff --git a/src/Auth/CanQueryDirective.php b/src/Auth/CanQueryDirective.php index 8b7c417a73..4edee6ac4f 100644 --- a/src/Auth/CanQueryDirective.php +++ b/src/Auth/CanQueryDirective.php @@ -15,8 +15,8 @@ public static function definition(): string """ Check a Laravel Policy to ensure the current user is authorized to access a field. -Query for specific model instances to check the policy against, using arguments -with directives that add constraints to the query builder, such as `@eq`. +Query for specific model instances to check the policy against. +Use arguments with directives that add constraints to the query builder, such as `@eq`. """ directive @canQuery( {$commonArguments} diff --git a/src/Auth/GuardDirective.php b/src/Auth/GuardDirective.php index e2b1a1ed10..a9e608a613 100644 --- a/src/Auth/GuardDirective.php +++ b/src/Auth/GuardDirective.php @@ -32,8 +32,7 @@ public static function definition(): string """ Run authentication through one or more guards from `config/auth.php`. -This is run per field and may allow unauthenticated -users to still receive partial results. +This runs per field, so unauthenticated users may still receive partial results. Used upon an object, it applies to all fields within. """ diff --git a/src/Bind/BindDirective.php b/src/Bind/BindDirective.php index 3e25f62cd2..2a2fbb9f2c 100644 --- a/src/Bind/BindDirective.php +++ b/src/Bind/BindDirective.php @@ -117,9 +117,8 @@ public function attribute(): ?string public function transform(mixed $argumentValue): mixed { - // When validating required bindings, the \Nuwave\Lighthouse\Bind\Validation\BindingExists validation rule - // should call transform() before it is called by the directive resolver. To avoid resolving the bindings - // multiple times, we should remember the resolved binding and reuse it every time transform() is called. + // When validating required bindings, the \Nuwave\Lighthouse\Bind\Validation\BindingExists rule calls transform() before the directive resolver does. + // To avoid resolving the bindings multiple times, we should remember the resolved binding and reuse it every time transform() is called. if (! $this->binding instanceof PendingBinding) { return $this->binding; } diff --git a/src/Bind/ModelBinding.php b/src/Bind/ModelBinding.php index af6adfb58f..e611abe1ec 100644 --- a/src/Bind/ModelBinding.php +++ b/src/Bind/ModelBinding.php @@ -33,10 +33,8 @@ public function __invoke(int|string|array $value, BindDefinition $definition): M /** @param \Illuminate\Database\Eloquent\Collection $results */ protected function modelInstance(EloquentCollection $results): ?Model { - // While "too few records" errors are handled as (client-safe) validation errors by applying - // the `BindingExists` rule on the BindDirective depending on whether the binding is required, - // "too many records" should be considered as (non-client-safe) configuration errors as it - // means the binding was not resolved using a unique identifier. + // Too few records are client-safe validation errors, see the `BindingExists` rule in BindDirective. + // Too many records mean the binding does not use a unique identifier, which is a configuration error. if ($results->count() > 1) { throw new MultipleRecordsFoundException($results->count()); } diff --git a/src/Cache/CacheDirective.php b/src/Cache/CacheDirective.php index ff43a1c812..923d7e82ac 100644 --- a/src/Cache/CacheDirective.php +++ b/src/Cache/CacheDirective.php @@ -36,8 +36,8 @@ public static function definition(): string """ Limit access to cached data to the currently authenticated user. - When the field is accessible by guest users, this will not have - any effect, they will access a shared cache. + This has no effect when guest users can access the field. + Guest users access a shared cache. """ private: Boolean = false ) on FIELD_DEFINITION @@ -76,7 +76,7 @@ public function handleField(FieldValue $fieldValue): void path: $path, ); - // We found a matching value in the cache, so we can return early without actually running the query. + // We found a matching value in the cache, so we can return early without running the query. $value = $cache->get($cacheKey); if ($value !== null) { // Deferring the result will allow nested deferred resolves to be bundled together, see https://github.com/nuwave/lighthouse/pull/2270#discussion_r1072414584. @@ -86,8 +86,7 @@ public function handleField(FieldValue $fieldValue): void // In Laravel cache, null is considered a non-existent value, see https://laravel.com/docs/9.x/cache#checking-for-item-existence: // > The `has` method [...] will also return false if the item exists but its value is null. // - // If caching `null` value becomes something worthwhile, one possible way to achieve it is to - // encapsulate the `$result` at writing time : + // If caching `null` value becomes something worthwhile, one possible way to achieve it is to encapsulate the `$result` at writing time : // // $storeInCache = static function ($result) use ($cacheKey, $maxAge, $cache): void { // $value = ['rawValue' => $result]; @@ -102,9 +101,9 @@ public function handleField(FieldValue $fieldValue): void // return $value['rawValue']; // } // - // Such a change would introduce some potential BC, if for instance cached value was already containing - // an object with a `rawValue` key prior the implementation change. A possible workaround is to choose a - // less collision-probable key instead of `rawValue` (e.g. "lighthouse:rawValue"). + // Such a change could break backwards compatibility. + // For instance, a value cached before the change might already contain an object with a `rawValue` key. + // A possible workaround is to choose a less collision-probable key instead of `rawValue` (e.g. "lighthouse:rawValue"). $resolved = $resolver($root, $args, $context, $resolveInfo); diff --git a/src/Console/LighthouseGeneratorCommand.php b/src/Console/LighthouseGeneratorCommand.php index b4b077fa00..f4d16a2f79 100644 --- a/src/Console/LighthouseGeneratorCommand.php +++ b/src/Console/LighthouseGeneratorCommand.php @@ -55,8 +55,7 @@ public static function commonNamespace(array $namespaces): string // Save the first namespace $preferredNamespaceFallback = reset($namespaces); - // If the strings are sorted, any prefix common to all strings - // will be common to the sorted first and last strings. + // If the strings are sorted, any prefix common to all strings will be common to the sorted first and last strings. // All the strings in the middle can be ignored. sort($namespaces); @@ -78,8 +77,7 @@ public static function commonNamespace(array $namespaces): string $matching[] = $part; } - // We could not determine a common part of the configured namespaces, - // so we assume the user will prefer the first one in the list. + // We could not determine a common part of the configured namespaces, so we assume the user will prefer the first one in the list. if ($matching === []) { return $preferredNamespaceFallback; } diff --git a/src/Defer/Defer.php b/src/Defer/Defer.php index 5055fff566..0a8864d313 100644 --- a/src/Defer/Defer.php +++ b/src/Defer/Defer.php @@ -154,8 +154,7 @@ function (): void { // We've hit the max execution time or max nested levels of deferred fields. $this->shouldDeferFurther = false; - // We process remaining deferred fields, but are no longer allowing additional - // fields to be deferred. + // We process remaining deferred fields, but are no longer allowing additional fields to be deferred. if ($this->hasRemainingDeferred()) { $this->executeDeferred(); } diff --git a/src/Defer/DeferrableDirective.php b/src/Defer/DeferrableDirective.php index ff420fde2a..50e48026a4 100644 --- a/src/Defer/DeferrableDirective.php +++ b/src/Defer/DeferrableDirective.php @@ -26,8 +26,8 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -Do not use this directive directly, it is automatically added to the schema -when using the defer extension. +Do not use this directive directly. +Lighthouse adds it to the schema when you use the defer extension. """ directive @deferrable on FIELD_DEFINITION GRAPHQL; diff --git a/src/Events/BuildExtensionsResponse.php b/src/Events/BuildExtensionsResponse.php index 2c1a9216f8..d59d1b6c66 100644 --- a/src/Events/BuildExtensionsResponse.php +++ b/src/Events/BuildExtensionsResponse.php @@ -7,8 +7,7 @@ /** * Fires after a query was resolved. * - * Listeners may return a @see \Nuwave\Lighthouse\Execution\ExtensionsResponse - * to include in the response. + * Listeners may return a @see \Nuwave\Lighthouse\Execution\ExtensionsResponse to include in the response. */ class BuildExtensionsResponse { diff --git a/src/Events/ManipulateResult.php b/src/Events/ManipulateResult.php index 068c4d412f..c5fa0a8984 100644 --- a/src/Events/ManipulateResult.php +++ b/src/Events/ManipulateResult.php @@ -7,8 +7,7 @@ /** * Fires after resolving each individual query. * - * This gives listeners an easy way to manipulate the query result. - * It avoids worrying about batched execution. + * This lets listeners manipulate the query result without worrying about batched execution. */ class ManipulateResult { diff --git a/src/Execution/Arguments/ArgPartitioner.php b/src/Execution/Arguments/ArgPartitioner.php index 498d85c50d..5874d10de2 100644 --- a/src/Execution/Arguments/ArgPartitioner.php +++ b/src/Execution/Arguments/ArgPartitioner.php @@ -20,8 +20,7 @@ class ArgPartitioner /** * Partition the arguments into nested and regular. * - * SaveAwareArgResolvers where runBeforeSave() returns true stay in the regular set - * so they reach SaveModel for execution before $model->save(). + * SaveAwareArgResolvers where runBeforeSave() returns true stay in the regular set so they reach SaveModel for execution before $model->save(). * * @return array{ * 0: \Nuwave\Lighthouse\Execution\Arguments\ArgumentSet, @@ -184,14 +183,12 @@ public static function methodReturnsRelation( } /** - * Recursively collect the pre-save resolvers within @nest arguments, - * so they can run before $root->save() instead of after it. + * Recursively collect the pre-save resolvers within @nest arguments, so they can run before $root->save() instead of after it. * * The result is an ordered list rather than a name-keyed set: * field names are unique per input type, not across a whole input tree. * - * Leaves the given arguments untouched, as they may be shared with cached - * or spread ArgumentSets that the caller still owns. + * Leaves the given arguments untouched, as they may be shared with cached or spread ArgumentSets that the caller still owns. * * @return list<\Nuwave\Lighthouse\Execution\Arguments\Argument> */ diff --git a/src/Execution/Arguments/ArgumentSet.php b/src/Execution/Arguments/ArgumentSet.php index 8fecdb1206..03cb7e89f9 100644 --- a/src/Execution/Arguments/ArgumentSet.php +++ b/src/Execution/Arguments/ArgumentSet.php @@ -69,9 +69,8 @@ public function exists(string $key): bool /** * Add a value at the dot-separated path. * - * Works just like @see \Illuminate\Support\Arr::add(), but a path segment - * of `*` injects the value into every element of the list found at that - * position instead of a single key. + * Works like @see \Illuminate\Support\Arr::add(). + * A path segment of `*` injects the value into every element of the list at that position, instead of a single key. */ public function addValue(string $path, mixed $value): self { @@ -102,16 +101,15 @@ private function addValueAtKeys(array $keys, mixed $value): void $throughWildcard = $keys[0] === '*'; - // The branch leading up to a `*` might not have been given by the client - // at all, e.g. an optional nested input that was omitted. In that case, - // there is nothing to inject into, so we just do nothing. + // The branch leading up to a `*` might not have been given by the client at all, e.g. an optional nested input that was omitted. + // In that case, there is nothing to inject into, so we do nothing. if ($throughWildcard && ! isset($this->arguments[$key])) { return; } - // If the key doesn't exist at this depth, we will create an empty ArgumentSet - // to hold the next value, allowing us to create the ArgumentSet to hold a final - // value at the correct depth. Then we'll keep digging into the ArgumentSet. + // If the key doesn't exist at this depth, we create an empty ArgumentSet to hold the next value. + // This lets us create the ArgumentSet for the final value at the correct depth. + // Then we'll keep digging into the ArgumentSet. if (! isset($this->arguments[$key])) { $argument = new Argument(); $argument->value = new self(); diff --git a/src/Execution/Arguments/ArgumentSetFactory.php b/src/Execution/Arguments/ArgumentSetFactory.php index 695b5f17cf..a7a17f2243 100644 --- a/src/Execution/Arguments/ArgumentSetFactory.php +++ b/src/Execution/Arguments/ArgumentSetFactory.php @@ -107,8 +107,7 @@ protected function wrapWithType(mixed $valueOrValues, ListType|NamedType $type) return null; } - // We have to do this conversion as we are resolving a client query - // because the incoming arguments put a bound on recursion depth + // We have to do this conversion as we are resolving a client query because the incoming arguments put a bound on recursion depth if ($type instanceof ListType) { $typeInList = $type->type; diff --git a/src/Execution/Arguments/NestedBelongsTo.php b/src/Execution/Arguments/NestedBelongsTo.php index 7a446f0840..71e17402fb 100644 --- a/src/Execution/Arguments/NestedBelongsTo.php +++ b/src/Execution/Arguments/NestedBelongsTo.php @@ -56,9 +56,8 @@ public function __invoke($model, $args): void public static function disconnectOrDelete(BelongsTo $relation, ArgumentSet $args): void { // We proceed with disconnecting/deleting only if the given $values is truthy. - // There is no other information to be passed when issuing those operations, - // but GraphQL forces us to pass some value. It would be unintuitive for - // the end user if the given value had no effect on the execution. + // There is no other information to be passed when issuing those operations, but GraphQL forces us to pass some value. + // It would be unintuitive for the end user if the given value had no effect on the execution. if ( $args->has('disconnect') && $args->arguments['disconnect']->value diff --git a/src/Execution/Arguments/NestedManyToMany.php b/src/Execution/Arguments/NestedManyToMany.php index 8978997ac8..dbaa6cb169 100644 --- a/src/Execution/Arguments/NestedManyToMany.php +++ b/src/Execution/Arguments/NestedManyToMany.php @@ -93,8 +93,7 @@ protected function generateRelationArray(Argument $args): array return []; } - // Since GraphQL inputs are monomorphic, we can look at the first - // given value for an argument and deduce the type of all values. + // Since GraphQL inputs are monomorphic, we can look at the first given value for an argument and deduce the type of all values. $exemplaryValue = $values[0]; // We assume that the values contain pivot information @@ -108,7 +107,7 @@ protected function generateRelationArray(Argument $args): array return $relationArray; } - // The default case is simply a flat array of IDs which we don't have to transform + // The default case is a flat array of IDs which we don't have to transform return $values; } } diff --git a/src/Execution/Arguments/ResolveNested.php b/src/Execution/Arguments/ResolveNested.php index fbcf86abfb..83c675bf52 100644 --- a/src/Execution/Arguments/ResolveNested.php +++ b/src/Execution/Arguments/ResolveNested.php @@ -77,8 +77,7 @@ protected function resolveNestedArguments(mixed $root, ArgumentSet $nestedArgs, assert($value instanceof ArgumentSet, 'NestDirective validates that @nest is used on non-list input object types.'); // Partitioning attaches the resolvers of the children, including implicitly detected relations. - // Its classification is irrelevant here: there is no saver to hand regular arguments to, - // and children the saver did not run must still resolve. + // Its classification is irrelevant here: there is no saver to hand regular arguments to, and children the saver did not run must still resolve. ($this->argPartitioner)($value, $root); $this->resolveNestedArguments($root, $value, $alreadyRun); continue; diff --git a/src/Execution/Arguments/SaveModel.php b/src/Execution/Arguments/SaveModel.php index 59328bb7de..41827b2cc9 100644 --- a/src/Execution/Arguments/SaveModel.php +++ b/src/Execution/Arguments/SaveModel.php @@ -84,8 +84,7 @@ public function __invoke($model, $args): Model } if ($this->parentRelation instanceof HasOneOrMany) { - // If we are already resolving a nested create, we might - // already have an instance of the parent relation available. + // If we are already resolving a nested create, we might already have an instance of the parent relation available. // In that case, use it to set the current model as a child. $this->parentRelation->save($model); @@ -97,9 +96,8 @@ public function __invoke($model, $args): Model if ($this->parentRelation instanceof BelongsTo) { $childModel = $this->parentRelation->associate($model); - // If the child Model does not exist (still to be saved), - // a save could break any pending belongsTo relations that still - // need to be created and associated with it. + // If the child Model does not exist yet, saving it could break pending belongsTo relations. + // Those still need to be created and associated with it. if ($childModel->exists) { $childModel->save(); } diff --git a/src/Execution/ModelsLoader/PaginatedModelsLoader.php b/src/Execution/ModelsLoader/PaginatedModelsLoader.php index 46b04c44b1..dd1def6f8c 100644 --- a/src/Execution/ModelsLoader/PaginatedModelsLoader.php +++ b/src/Execution/ModelsLoader/PaginatedModelsLoader.php @@ -80,8 +80,7 @@ protected function loadRelatedModels(EloquentCollection $parents): EloquentColle $relatedModels = $mergedRelationQuery->get(); return $relatedModels->unique( - // Compare all attributes because there might not be a unique primary key - // or there could be differing pivot attributes. + // Compare all attributes because there might not be a unique primary key or there could be differing pivot attributes. static fn (Model $relatedModel): string => serialize($relatedModel->getRawOriginal()), ); } diff --git a/src/Execution/ModelsLoader/SimpleModelsLoader.php b/src/Execution/ModelsLoader/SimpleModelsLoader.php index 1420babc6d..2b3c345959 100644 --- a/src/Execution/ModelsLoader/SimpleModelsLoader.php +++ b/src/Execution/ModelsLoader/SimpleModelsLoader.php @@ -22,7 +22,7 @@ public function extract(Model $model): mixed // Dot notation may be used to eager load nested relations $parts = explode('.', $this->relation); - // We just return the first level of relations for now. + // We only return the first level of relations for now. // They hold the nested relations in case they are needed. $firstRelation = $parts[0]; diff --git a/src/Execution/Utils/FieldPath.php b/src/Execution/Utils/FieldPath.php index 8493aa0b8f..d88566bf8a 100644 --- a/src/Execution/Utils/FieldPath.php +++ b/src/Execution/Utils/FieldPath.php @@ -14,15 +14,12 @@ public static function withoutLists(array $path): string $significantPathSegments = array_filter( $path, // Ignore numeric path entries, as those signify a list of fields. - // Combining the queries for lists is the very purpose of the - // batch loader, so they must not be included. + // Combining the queries for lists is the purpose of the batch loader, so they must not be included. static fn (int|string $segment): bool => ! is_numeric($segment), ); - // Using . as the separator would combine relations in nested fields with - // higher up relations using dot notation, matching the field path. - // We might optimize this in the future to enable batching them anyway, - // but employ this solution for now, as it preserves correctness. + // Using . as the separator would combine relations in nested fields with higher up relations using dot notation, matching the field path. + // We might optimize this in the future to enable batching them anyway, but employ this solution for now, as it preserves correctness. return implode('|', $significantPathSegments); } } diff --git a/src/Execution/Utils/Subscription.php b/src/Execution/Utils/Subscription.php index 2830ee927a..cc981bb59b 100644 --- a/src/Execution/Utils/Subscription.php +++ b/src/Execution/Utils/Subscription.php @@ -13,8 +13,7 @@ class Subscription /** Broadcast subscription to client(s). */ public static function broadcast(string $subscriptionField, mixed $root, ?bool $shouldQueue = null): void { - // Ensure we have a schema and registered subscription fields - // in the event we are calling this method in code. + // Ensure we have a schema and registered subscription fields in the event we are calling this method in code. $schemaBuilder = Container::getInstance()->make(SchemaBuilder::class); $schemaBuilder->schema(); diff --git a/src/Federation/ASTManipulator.php b/src/Federation/ASTManipulator.php index 240e494c44..0c16c025a6 100644 --- a/src/Federation/ASTManipulator.php +++ b/src/Federation/ASTManipulator.php @@ -70,8 +70,7 @@ protected function addEntityUnion(DocumentAST &$documentAST): void protected function addRootFields(DocumentAST &$documentAST): void { - // In federation, it is fine for a schema to not have a user-defined root query type, - // since we add two federation related fields to it here. + // In federation, it is fine for a schema to not have a user-defined root query type, since we add two federation related fields to it here. $documentAST->types[RootType::QUERY] ??= Parser::objectTypeDefinition(/** @lang GraphQL */ 'type Query'); $queryType = $documentAST->types[RootType::QUERY]; diff --git a/src/Federation/Directives/ComposeDirectiveDirective.php b/src/Federation/Directives/ComposeDirectiveDirective.php index 6ad144fec0..4142609abd 100644 --- a/src/Federation/Directives/ComposeDirectiveDirective.php +++ b/src/Federation/Directives/ComposeDirectiveDirective.php @@ -12,9 +12,7 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -Indicates to composition that all uses of a particular custom type system directive -in the subgraph schema should be preserved in the supergraph schema -(by default, composition omits most directives from the supergraph schema). +Indicates to composition that all uses of a particular custom type system directive in the subgraph schema should be preserved in the supergraph schema (by default, composition omits most directives from the supergraph schema). ```graphql extend schema diff --git a/src/Federation/Directives/ExtendsDirective.php b/src/Federation/Directives/ExtendsDirective.php index 11fada6851..2a874d0550 100644 --- a/src/Federation/Directives/ExtendsDirective.php +++ b/src/Federation/Directives/ExtendsDirective.php @@ -13,8 +13,8 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -Some libraries such as graphql-java don't have native support for type extensions in their printer. Apollo Federation -supports using an @extends directive in place of extend type to annotate type references: +Some libraries such as graphql-java don't have native support for type extensions in their printer. +Apollo Federation supports using an @extends directive in place of extend type to annotate type references: type User @key(fields: "id") @extends { diff --git a/src/Federation/Directives/ExternalDirective.php b/src/Federation/Directives/ExternalDirective.php index cb272ade40..fb5f79af16 100644 --- a/src/Federation/Directives/ExternalDirective.php +++ b/src/Federation/Directives/ExternalDirective.php @@ -17,9 +17,9 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -Individual federated services should be runnable without having the entire graph present. Fields marked with @external -are declarations of fields that are defined in another service. All fields referred to in @key, @requires, and @provides -directives need to have corresponding @external fields in the same service. +Individual federated services should be runnable without having the entire graph present. +Fields marked with @external are declarations of fields that are defined in another service. +All fields referred to in @key, @requires, and @provides directives need to have corresponding @external fields in the same service. https://www.apollographql.com/docs/apollo-server/federation/federation-spec/#schema-modifications-glossary """ @@ -31,7 +31,7 @@ public function resolveField(FieldValue $fieldValue): callable { $defaultFieldResolver = Executor::getDefaultFieldResolver(); - // The parent might just hold a foreign key to the external object, in which case we just return that. + // The parent might only hold a foreign key to the external object, in which case we return that. return static fn (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): mixed => is_scalar($root) ? $root : $defaultFieldResolver($root, $args, $context, $resolveInfo); diff --git a/src/Federation/Directives/InaccessibleDirective.php b/src/Federation/Directives/InaccessibleDirective.php index 500226d4ef..dd3dda0c25 100644 --- a/src/Federation/Directives/InaccessibleDirective.php +++ b/src/Federation/Directives/InaccessibleDirective.php @@ -12,8 +12,7 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -Indicates that a definition in the subgraph schema should be omitted from the router's API schema, -even if that definition is also present in other subgraphs. +Indicates that a definition in the subgraph schema should be omitted from the router's API schema, even if that definition is also present in other subgraphs. This means that the field is not exposed to clients at all. ```graphql @@ -24,10 +23,8 @@ public static function definition(): string } ``` -An @inaccessible field or type is not omitted from the supergraph schema, so the router -still knows it exists (but clients can't include it in operations). -This is what enables the router to use an @inaccessible field as part of an entity's @key -when combining entity fields from multiple subgraphs. +An @inaccessible field or type is not omitted from the supergraph schema, so the router still knows it exists (but clients can't include it in operations). +This is what enables the router to use an @inaccessible field as part of an entity's @key when combining entity fields from multiple subgraphs. If a type is marked @inaccessible, all fields that return that type must also be marked @inaccessible. Otherwise, a composition error occurs. diff --git a/src/Federation/Directives/InterfaceObjectDirective.php b/src/Federation/Directives/InterfaceObjectDirective.php index 20646200a3..d82cc1a508 100644 --- a/src/Federation/Directives/InterfaceObjectDirective.php +++ b/src/Federation/Directives/InterfaceObjectDirective.php @@ -15,8 +15,7 @@ public static function definition(): string Indicates that an object definition serves as an abstraction of another subgraph's entity interface. This abstraction enables a subgraph to automatically contribute fields to all entities that implement a particular entity interface. -During composition, the fields of every @interfaceObject are added both to their corresponding interface definition -and to all entity types that implement that interface. +During composition, the fields of every @interfaceObject are added both to their corresponding interface definition and to all entity types that implement that interface. https://www.apollographql.com/docs/federation/federated-types/federated-directives#interfaceobject """ diff --git a/src/Federation/Directives/KeyDirective.php b/src/Federation/Directives/KeyDirective.php index 9d92c24336..ef5148b3cc 100644 --- a/src/Federation/Directives/KeyDirective.php +++ b/src/Federation/Directives/KeyDirective.php @@ -16,8 +16,7 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -The @key directive is used to indicate a combination of fields that -can be used to uniquely identify and fetch an object or interface. +The @key directive is used to indicate a combination of fields that can be used to uniquely identify and fetch an object or interface. """ directive @key( """ diff --git a/src/Federation/Directives/OverrideDirective.php b/src/Federation/Directives/OverrideDirective.php index a29cda79b9..de45e2e578 100644 --- a/src/Federation/Directives/OverrideDirective.php +++ b/src/Federation/Directives/OverrideDirective.php @@ -12,8 +12,8 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -Indicates that an object field is now resolved by this subgraph instead of another subgraph -where it's also defined. This enables you to migrate a field from one subgraph to another. +Indicates that an object field is now resolved by this subgraph instead of another subgraph where it's also defined. +This enables you to migrate a field from one subgraph to another. You can apply @override to entity fields and fields of the root operation types (such as Query and Mutation). @@ -24,8 +24,9 @@ public static function definition(): string } ``` -You can apply @override to a @shareable field. If you do, only the subgraph you provide -in the from argument no longer resolves that field. Other subgraphs can still resolve the field. +You can apply @override to a @shareable field. +If you do, only the subgraph you provide in the from argument no longer resolves that field. +Other subgraphs can still resolve the field. Only one subgraph can @override any given field. If multiple subgraphs attempt to @override the same field, a composition error occurs. diff --git a/src/Federation/Directives/ProvidesDirective.php b/src/Federation/Directives/ProvidesDirective.php index edc6151bb9..0177570e10 100644 --- a/src/Federation/Directives/ProvidesDirective.php +++ b/src/Federation/Directives/ProvidesDirective.php @@ -12,8 +12,8 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -The `@provides` directive is used to annotate the expected returned fieldset from a field -on a base type that is guaranteed to be selectable by the gateway. Given the following example: +The `@provides` directive is used to annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. +Given the following example: ```graphql type Review @key(fields: "id") { @@ -26,10 +26,8 @@ public static function definition(): string } ``` -When fetching `Review.product` from the Reviews service, it is possible to request the `name` -with the expectation that the Reviews service can provide it when going from review to product. -`Product.name` is an external field on an external type which is why the local type extension -of `Product` and annotation of `name` is required. +When fetching `Review.product` from the Reviews service, it is possible to request the `name` with the expectation that the Reviews service can provide it when going from review to product. +`Product.name` is an external field on an external type which is why the local type extension of `Product` and annotation of `name` is required. https://www.apollographql.com/docs/federation/federation-spec/#provides """ diff --git a/src/Federation/Directives/RequiresDirective.php b/src/Federation/Directives/RequiresDirective.php index 140272ba48..fe478ac107 100644 --- a/src/Federation/Directives/RequiresDirective.php +++ b/src/Federation/Directives/RequiresDirective.php @@ -13,9 +13,9 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -The @requires directive is used to annotate the required input fieldset from a base type for a resolver. It is used to -develop a query plan where the required fields may not be needed by the client, but the service may need additional -information from other services. For example: +The @requires directive is used to annotate the required input fieldset from a base type for a resolver. +It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. +For example: extend type User @key(fields: "id") { id: ID! @external @@ -25,8 +25,7 @@ public static function definition(): string """ directive @requires( """ - It is used to develop a query plan where the required fields may not be needed by the client, but the service may - need additional information from other services. + It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. """ fields: _FieldSet! ) on FIELD_DEFINITION diff --git a/src/Federation/Directives/ShareableDirective.php b/src/Federation/Directives/ShareableDirective.php index 718ba1d8f7..bced58bb45 100644 --- a/src/Federation/Directives/ShareableDirective.php +++ b/src/Federation/Directives/ShareableDirective.php @@ -12,8 +12,7 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -Indicates that an object type's field is allowed to be resolved by multiple subgraphs -(by default in Federation 2, object fields can be resolved by only one subgraph). +Indicates that an object type's field is allowed to be resolved by multiple subgraphs (by default in Federation 2, object fields can be resolved by only one subgraph). If applied to an object type definition, all of that type's fields are considered @shareable. ```graphql @@ -28,11 +27,9 @@ public static function definition(): string } ``` -If a field is marked @shareable in any subgraph, it must be marked as either -@shareable or @external in every Federation 2 subgraph that defines it. +If a field is marked @shareable in any subgraph, it must be marked as either @shareable or @external in every Federation 2 subgraph that defines it. -If a field is included in an entity's @key directive, that field is automatically -considered @shareable and the directive is not required in the corresponding subgraph(s). +If a field is included in an entity's @key directive, that field is automatically considered @shareable and the directive is not required in the corresponding subgraph(s). https://www.apollographql.com/docs/federation/federated-types/federated-directives#shareable """ diff --git a/src/Federation/Directives/TagDirective.php b/src/Federation/Directives/TagDirective.php index c3ba87fe8a..e29d8b1a0e 100644 --- a/src/Federation/Directives/TagDirective.php +++ b/src/Federation/Directives/TagDirective.php @@ -12,8 +12,8 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -Applies arbitrary string metadata to a schema location. Custom tooling can use this metadata -during any step of the schema delivery flow, including composition, static analysis, and documentation. +Applies arbitrary string metadata to a schema location. +Custom tooling can use this metadata during any step of the schema delivery flow, including composition, static analysis, and documentation. ```graphql extend schema diff --git a/src/Federation/Types/Any.php b/src/Federation/Types/Any.php index 4305a385e2..f332e8f781 100644 --- a/src/Federation/Types/Any.php +++ b/src/Federation/Types/Any.php @@ -66,7 +66,7 @@ public function parseValue($value): array $keyFieldsSelections = $entityResolverProvider->keyFieldsSelections($definition); $entityResolverProvider->firstSatisfiedKeyFields($keyFieldsSelections, $value); - // Ensure we actually have a resolver for the type available + // Ensure we have a resolver for the type available $entityResolverProvider->resolver($typename); // @phpstan-ignore-next-line type inference is too weak diff --git a/src/GlobalId/Base64GlobalId.php b/src/GlobalId/Base64GlobalId.php index cb2fcaa31a..e40d9658f2 100644 --- a/src/GlobalId/Base64GlobalId.php +++ b/src/GlobalId/Base64GlobalId.php @@ -5,7 +5,7 @@ /** * The default encoding of global IDs in Lighthouse. * - * The way that IDs are generated basically works like this: + * The way that IDs are generated works like this: * * 1. Take the name of a type, e.g. "User" and an ID, e.g. 123 * 2. Glue them together, separated by a colon, e.g. "User:123" diff --git a/src/GlobalId/GlobalId.php b/src/GlobalId/GlobalId.php index 5debb2c238..cd8ebe8015 100644 --- a/src/GlobalId/GlobalId.php +++ b/src/GlobalId/GlobalId.php @@ -20,9 +20,9 @@ public function encode(string $type, int|string $id): string; */ public function decode(string $globalID): array; - /** Decode the Global ID and get just the ID. */ + /** Decode the Global ID and get only the ID. */ public function decodeID(string $globalID): string; - /** Decode the Global ID and get just the type. */ + /** Decode the Global ID and get only the type. */ public function decodeType(string $globalID): string; } diff --git a/src/GlobalId/GlobalIdDirective.php b/src/GlobalId/GlobalIdDirective.php index 7037ca5362..2b6b00f39c 100644 --- a/src/GlobalId/GlobalIdDirective.php +++ b/src/GlobalId/GlobalIdDirective.php @@ -23,8 +23,8 @@ public static function definition(): string """ Converts between IDs/types and global IDs. -When used upon a field, it encodes; -when used upon an argument, it decodes. +On a field, it encodes the value. +On an argument, it decodes the value. """ directive @globalId( """ @@ -44,12 +44,12 @@ enum GlobalIdDecode { ARRAY """ - Return just `$type`. + Return only `$type`. """ TYPE """ - Return just `$id`. + Return only `$id`. """ ID } diff --git a/src/GlobalId/NodeDirective.php b/src/GlobalId/NodeDirective.php index c0c7fba5e9..1546a72f15 100644 --- a/src/GlobalId/NodeDirective.php +++ b/src/GlobalId/NodeDirective.php @@ -32,8 +32,7 @@ public static function definition(): string """ Register a type for Relay's global object identification. -When used without any arguments, Lighthouse will attempt -to resolve the type through a model with the same name. +Without arguments, Lighthouse tries to resolve the type through the model with the same name. """ directive @node( """ diff --git a/src/GlobalId/NodeRegistry.php b/src/GlobalId/NodeRegistry.php index d986f785d0..89b5540a34 100644 --- a/src/GlobalId/NodeRegistry.php +++ b/src/GlobalId/NodeRegistry.php @@ -24,7 +24,7 @@ class NodeRegistry * The stashed current type. * * PHP resolves fields synchronously and one after another. - * So we can safely stash just this one value. + * So we can safely stash only this one value. * Should the need arise, this can probably be a map from the unique field path to the type. */ protected string $currentType; @@ -56,8 +56,7 @@ public function resolve(mixed $root, array $args, GraphQLContext $context, Resol { [$decodedType, $decodedId] = $args['id']; - // This check forces Lighthouse to eagerly load the type, which might not have - // happened if the client only references it indirectly through an interface. + // This check forces Lighthouse to eagerly load the type, which might not have happened if the client only references it indirectly through an interface. // Loading the type in turn causes the TypeMiddleware to run and thus register the type in the NodeRegistry. $this->typeRegistry->has($decodedType) ?: throw new Error("[{$decodedType}] is not a type and cannot be resolved."); diff --git a/src/GraphQL.php b/src/GraphQL.php index 6c5e7918af..0bad1a5abf 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -129,8 +129,7 @@ public function executeParsedQueryRaw( ?string $operationName = null, ?string $queryHash = null, ): ExecutionResult { - // Building the executable schema might take a while to do, - // so we do it before we fire the StartExecution event. + // Building the executable schema might take a while to do, so we do it before we fire the StartExecution event. // This allows tracking the time for batched queries independently. $schema = $this->schemaBuilder->schema(); diff --git a/src/Http/Middleware/AcceptJson.php b/src/Http/Middleware/AcceptJson.php index c7c58db8da..7da6f615df 100644 --- a/src/Http/Middleware/AcceptJson.php +++ b/src/Http/Middleware/AcceptJson.php @@ -7,7 +7,7 @@ /** * Always set the `Accept: application/json` header. * - * This makes it easier to do simple GET requests from clients with limited HTTP configuration options. + * This makes it easier to do GET requests from clients with limited HTTP configuration options. * It also ensures clients receive a proper result, even in case of unforeseen errors. */ class AcceptJson diff --git a/src/Http/routes.php b/src/Http/routes.php index 408babde77..6df44b0ee5 100644 --- a/src/Http/routes.php +++ b/src/Http/routes.php @@ -9,7 +9,7 @@ $config = $container->make(ConfigRepository::class); if ($routeConfig = $config->get('lighthouse.route')) { /** - * Not using assert() as only one of those classes will actually be installed. + * Not using assert() as only one of those classes will be installed. * * @var Illuminate\Contracts\Routing\Registrar|\Laravel\Lumen\Routing\Router $router */ diff --git a/src/Pagination/ConnectionField.php b/src/Pagination/ConnectionField.php index 0edafcdd37..cc46096aea 100644 --- a/src/Pagination/ConnectionField.php +++ b/src/Pagination/ConnectionField.php @@ -90,8 +90,7 @@ public function edgeResolver(Paginator $paginator, array $args, GraphQLContext $ break; default: - // All other fields on the return type are assumed to be part - // of the edge, so we try to locate them in the pivot attribute + // All other fields on the return type are assumed to be part of the edge, so we try to locate them in the pivot attribute if (isset($item->pivot->{$field->name})) { $data[$field->name] = $item->pivot->{$field->name}; } diff --git a/src/Pagination/Cursor.php b/src/Pagination/Cursor.php index f4771497f5..1b1ffbe848 100644 --- a/src/Pagination/Cursor.php +++ b/src/Pagination/Cursor.php @@ -8,7 +8,7 @@ * Encode and decode pagination cursors. * * Currently, the underlying pagination query uses offset-based navigation. - * So this basically just encodes an offset. + * So this encodes an offset. * This is enough to satisfy the constraints that Relay has, but not a clean permanent solution. * * TODO Implement actual cursor pagination https://github.com/nuwave/lighthouse/issues/311 diff --git a/src/Pagination/PaginateDirective.php b/src/Pagination/PaginateDirective.php index 9521ccb7f6..9c1ad1e178 100644 --- a/src/Pagination/PaginateDirective.php +++ b/src/Pagination/PaginateDirective.php @@ -95,7 +95,8 @@ enum PaginateType { PAGINATOR """ - Offset-based pagination like the Laravel "Simple Pagination", which does not count the total number of records. + Offset-based pagination like Laravel "Simple Pagination". + It does not count the total number of records. """ SIMPLE diff --git a/src/Pagination/PaginationArgs.php b/src/Pagination/PaginationArgs.php index c4a732d6f7..9fed10633f 100644 --- a/src/Pagination/PaginationArgs.php +++ b/src/Pagination/PaginationArgs.php @@ -81,8 +81,8 @@ protected static function optimalPaginationType(PaginationType $proposedType, Re } // If the result may be used in a cache, we always want to retrieve and store the full pagination data. - // Even though the query that initially creates the cache may not need additional information such as - // the total counts, following queries may need them - and use the same cached value. + // The query that creates the cache may not need additional information such as the total counts. + // Following queries may need them and use the same cached value. $hasCacheDirective = $resolveInfo->argumentSet ->directives ->contains(static fn (Directive $directive): bool => $directive instanceof CacheDirective); diff --git a/src/Schema/AST/ASTBuilder.php b/src/Schema/AST/ASTBuilder.php index 45ff5b5b47..9f55ae4ed5 100644 --- a/src/Schema/AST/ASTBuilder.php +++ b/src/Schema/AST/ASTBuilder.php @@ -62,8 +62,7 @@ public function build(): DocumentAST $schemaString = $this->schemaSourceProvider->getSchemaString(); // Allow registering listeners that inject additional schema definitions. - // This can be used by plugins to hook into the schema building process - // while still allowing the user to define their schema as usual. + // This can be used by plugins to hook into the schema building process while still allowing the user to define their schema as usual. $additionalSchemas = (array) $this->eventsDispatcher->dispatch( new BuildSchemaString($schemaString), ); @@ -82,9 +81,8 @@ public function build(): DocumentAST $this->applyArgManipulators(); $this->applyInputFieldManipulators(); - // Listeners may manipulate the DocumentAST that is passed by reference - // into the ManipulateAST event. This can be useful for extensions - // that want to programmatically change the schema. + // Listeners may manipulate the DocumentAST that is passed by reference into the ManipulateAST event. + // This can be useful for extensions that want to programmatically change the schema. $this->eventsDispatcher->dispatch( new ManipulateAST($this->documentAST), ); @@ -109,16 +107,14 @@ protected function applyTypeExtensionManipulators(): void { foreach ($this->documentAST->typeExtensions as $typeName => $typeExtensionsList) { foreach ($typeExtensionsList as $typeExtension) { - // Before we actually extend the types, we apply the manipulator directives - // that are defined on type extensions themselves + // Before we extend the types, we apply the manipulator directives that are defined on type extensions themselves foreach ( $this->directiveLocator->associatedOfType($typeExtension, TypeExtensionManipulator::class) as $typeExtensionManipulator ) { $typeExtensionManipulator->manipulateTypeExtension($this->documentAST, $typeExtension); } - // After manipulation on the type extension has been done, - // we can merge them with the original type + // After manipulation on the type extension has been done, we can merge them with the original type if ( $typeExtension instanceof ObjectTypeExtensionNode || $typeExtension instanceof InputObjectTypeExtensionNode diff --git a/src/Schema/AST/ASTHelper.php b/src/Schema/AST/ASTHelper.php index f1382b3282..3168777f41 100644 --- a/src/Schema/AST/ASTHelper.php +++ b/src/Schema/AST/ASTHelper.php @@ -291,8 +291,7 @@ public static function addDirectiveToFields(DirectiveNode $directiveNode, Object $directiveDefinition = static::extractDirectiveDefinition($directive::definition()); foreach ($typeWithFields->fields as $fieldDefinition) { - // If the field already has the same directive defined, and it is not - // a repeatable directive, skip over it. + // If the field already has the same directive defined, and it is not a repeatable directive, skip over it. // Field directives are more specific than those defined on a type. if ( static::hasDirective($fieldDefinition, $name) @@ -310,7 +309,7 @@ public static function addDirectiveToFields(DirectiveNode $directiveNode, Object * * We have to make sure it is unique in the schema. * This name is a bit verbose. - * It is very unlikely to collide with a random user-defined type. + * It is unlikely to collide with a random user-defined type. * * @example ParentNameFieldNameArgName */ diff --git a/src/Schema/AST/DocumentAST.php b/src/Schema/AST/DocumentAST.php index 2c15d1a653..d393506643 100644 --- a/src/Schema/AST/DocumentAST.php +++ b/src/Schema/AST/DocumentAST.php @@ -61,8 +61,7 @@ class DocumentAST implements Arrayable /** * The type extensions within the parsed document. * - * Will NOT be kept after unserialization, as the type - * extensions are merged with the types before. + * Will NOT be kept after unserialization, as the type extensions are merged with the types before. * * @var array> */ @@ -104,8 +103,7 @@ public static function fromSource(string $schema): self ['noLocation' => true], ); } catch (SyntaxError $syntaxError) { - // Throw our own error class instead, since otherwise a schema definition - // error would get rendered to the Client. + // Throw our own error class instead, since otherwise a schema definition error would get rendered to the Client. throw new SchemaSyntaxErrorException($syntaxError); } @@ -137,9 +135,8 @@ public static function fromSource(string $schema): self throw new DefinitionException("Failed to find a model class {$modelName} in namespaces [{$consideredNamespaces}] referenced in @model on type {$name}."); } - // It might be valid to have multiple types that correspond to a single model - // in order to hide some fields in some scenarios, so we cannot decide on a - // single object type for a given class name unambiguously right here. + // Multiple types may correspond to a single model, e.g. to hide some fields in some scenarios. + // So we cannot pick a single object type for a given class name here. $instance->classNameToObjectTypeNames[$modelClass][] = $name; } } elseif ($definition instanceof TypeExtensionNode) { @@ -188,8 +185,7 @@ public function setDirectiveDefinition(DirectiveDefinitionNode $directive): self /** * Convert to a serializable array. * - * We exclude the type extensions stored in $typeExtensions, - * as they are merged with the actual types at this point. + * We exclude the type extensions stored in $typeExtensions, as they are merged with the actual types at this point. * * @return SerializableDocumentAST */ diff --git a/src/Schema/Directives/BelongsToDirective.php b/src/Schema/Directives/BelongsToDirective.php index 0b0a61ca3b..7a88b1a54e 100644 --- a/src/Schema/Directives/BelongsToDirective.php +++ b/src/Schema/Directives/BelongsToDirective.php @@ -12,8 +12,8 @@ public static function definition(): string """ directive @belongsTo( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String diff --git a/src/Schema/Directives/BelongsToManyDirective.php b/src/Schema/Directives/BelongsToManyDirective.php index c6d03c4477..c5916f10b3 100644 --- a/src/Schema/Directives/BelongsToManyDirective.php +++ b/src/Schema/Directives/BelongsToManyDirective.php @@ -14,8 +14,8 @@ public static function definition(): string """ directive @belongsToMany( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -44,8 +44,8 @@ public static function definition(): string maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -61,7 +61,8 @@ enum BelongsToManyType { PAGINATOR """ - Offset-based pagination like the Laravel "Simple Pagination", which does not count the total number of records. + Offset-based pagination like Laravel "Simple Pagination". + It does not count the total number of records. """ SIMPLE diff --git a/src/Schema/Directives/ConvertEmptyStringsToNullDirective.php b/src/Schema/Directives/ConvertEmptyStringsToNullDirective.php index ea0b9dfd53..2003137702 100644 --- a/src/Schema/Directives/ConvertEmptyStringsToNullDirective.php +++ b/src/Schema/Directives/ConvertEmptyStringsToNullDirective.php @@ -20,6 +20,8 @@ public static function definition(): string When used upon fields, empty strings for non-nullable inputs will pass unchanged. Only explicitly placing this on non-nullable inputs will force the conversion. + +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @convertEmptyStringsToNull on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION GRAPHQL; diff --git a/src/Schema/Directives/CreateDirective.php b/src/Schema/Directives/CreateDirective.php index e1ddee304b..3a3e822673 100644 --- a/src/Schema/Directives/CreateDirective.php +++ b/src/Schema/Directives/CreateDirective.php @@ -22,8 +22,7 @@ public static function definition(): string """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION diff --git a/src/Schema/Directives/CreateManyDirective.php b/src/Schema/Directives/CreateManyDirective.php index 8aed0ff428..03e912c2a4 100644 --- a/src/Schema/Directives/CreateManyDirective.php +++ b/src/Schema/Directives/CreateManyDirective.php @@ -22,8 +22,7 @@ public static function definition(): string """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION diff --git a/src/Schema/Directives/DeleteDirective.php b/src/Schema/Directives/DeleteDirective.php index 9765ad464d..bf4c177fca 100644 --- a/src/Schema/Directives/DeleteDirective.php +++ b/src/Schema/Directives/DeleteDirective.php @@ -34,8 +34,7 @@ public static function definition(): string """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String @@ -73,16 +72,14 @@ public function __invoke($model, $idOrIds): void $relation = $model->{$relationName}(); assert($relation instanceof Relation); - // Those types of relations may only have one related model attached to - // it, so we don't need to use an ID to know which model to delete. + // Those types of relations may only have one related model attached to it, so we don't need to use an ID to know which model to delete. $relationIsHasOneLike = $relation instanceof HasOne || $relation instanceof MorphOne; // This includes MorphTo, which is a subclass of BelongsTo $relationIsBelongsToLike = $relation instanceof BelongsTo; if ($relationIsHasOneLike || $relationIsBelongsToLike) { assert($relation instanceof HasOne || $relation instanceof MorphOne || $relation instanceof BelongsTo); // @phpstan-ignore instanceof.alwaysTrue, booleanOr.alwaysTrue - // Only delete if the given value is truthy, since - // the client might use a variable and always pass the argument. + // Only delete if the given value is truthy, since the client might use a variable and always pass the argument. // Deleting when `false` is given seems wrong. if ($idOrIds) { if ($relationIsBelongsToLike) { diff --git a/src/Schema/Directives/DropArgsDirective.php b/src/Schema/Directives/DropArgsDirective.php index 42a1adebb7..472240fb9f 100644 --- a/src/Schema/Directives/DropArgsDirective.php +++ b/src/Schema/Directives/DropArgsDirective.php @@ -15,6 +15,7 @@ public static function definition(): string return /** @lang GraphQL */ <<<'GRAPHQL' """ Apply the @drop directives on the incoming arguments. +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @dropArgs on FIELD_DEFINITION GRAPHQL; @@ -34,8 +35,7 @@ protected function drop(ArgumentSet &$argumentSet): ArgumentSet unset($argumentSet->arguments[$name]); } else { // Recursively remove nested inputs using @drop directive. - // We look for further ArgumentSet instances, they - // might be contained within an array. + // We look for further ArgumentSet instances, they might be contained within an array. Utils::applyEach( function ($value): void { if ($value instanceof ArgumentSet) { diff --git a/src/Schema/Directives/EnumDirective.php b/src/Schema/Directives/EnumDirective.php index 2638b98976..27a13d0f2e 100644 --- a/src/Schema/Directives/EnumDirective.php +++ b/src/Schema/Directives/EnumDirective.php @@ -9,8 +9,7 @@ public static function definition(): string return /** @lang GraphQL */ <<<'GRAPHQL' """ Assign an internal value to an enum key. -When dealing with the Enum type in your code, -you will receive the defined value instead of the string key. +Your code receives the internal value instead of the string key. """ directive @enum( """ diff --git a/src/Schema/Directives/HasManyDirective.php b/src/Schema/Directives/HasManyDirective.php index 4742dd2100..207a7247d5 100644 --- a/src/Schema/Directives/HasManyDirective.php +++ b/src/Schema/Directives/HasManyDirective.php @@ -14,8 +14,8 @@ public static function definition(): string """ directive @hasMany( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -44,8 +44,8 @@ public static function definition(): string maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -61,7 +61,8 @@ enum HasManyType { PAGINATOR """ - Offset-based pagination like the Laravel "Simple Pagination", which does not count the total number of records. + Offset-based pagination like Laravel "Simple Pagination". + It does not count the total number of records. """ SIMPLE diff --git a/src/Schema/Directives/HasManyThroughDirective.php b/src/Schema/Directives/HasManyThroughDirective.php index 093296aaed..34c8f1eb01 100644 --- a/src/Schema/Directives/HasManyThroughDirective.php +++ b/src/Schema/Directives/HasManyThroughDirective.php @@ -14,8 +14,8 @@ public static function definition(): string """ directive @hasManyThrough( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -32,18 +32,20 @@ public static function definition(): string """ Allow clients to query paginated lists without specifying the amount of items. Overrules the `pagination.default_count` setting from `lighthouse.php`. + Setting this to `null` means clients have to explicitly ask for the count. """ defaultCount: Int """ Limit the maximum amount of items that clients can request from paginated lists. Overrules the `pagination.max_count` setting from `lighthouse.php`. + Setting this to `null` means the count is unrestricted. """ maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -59,7 +61,8 @@ enum HasManyThroughType { PAGINATOR """ - Offset-based pagination like the Laravel "Simple Pagination", which does not count the total number of records. + Offset-based pagination like Laravel "Simple Pagination". + It does not count the total number of records. """ SIMPLE diff --git a/src/Schema/Directives/HasOneDirective.php b/src/Schema/Directives/HasOneDirective.php index 2daede7831..bba6c66cfc 100644 --- a/src/Schema/Directives/HasOneDirective.php +++ b/src/Schema/Directives/HasOneDirective.php @@ -12,8 +12,8 @@ public static function definition(): string """ directive @hasOne( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String diff --git a/src/Schema/Directives/HasOneThroughDirective.php b/src/Schema/Directives/HasOneThroughDirective.php index 0b2a875917..20047faa6a 100644 --- a/src/Schema/Directives/HasOneThroughDirective.php +++ b/src/Schema/Directives/HasOneThroughDirective.php @@ -12,8 +12,8 @@ public static function definition(): string """ directive @hasOneThrough( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String diff --git a/src/Schema/Directives/HideDirective.php b/src/Schema/Directives/HideDirective.php index 43b48a1cc1..fc1cdf894b 100644 --- a/src/Schema/Directives/HideDirective.php +++ b/src/Schema/Directives/HideDirective.php @@ -39,7 +39,8 @@ public static function definition(): string """ directive @hide( """ - Specify which environments must not use this field, e.g. ["production"]. + Specify which environments exclude this element, e.g. `["production"]`. + Compared against the value returned from `app()->environment()`. """ env: [String!]! ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION | OBJECT diff --git a/src/Schema/Directives/InjectDirective.php b/src/Schema/Directives/InjectDirective.php index 2a6b013fed..35cc993c28 100644 --- a/src/Schema/Directives/InjectDirective.php +++ b/src/Schema/Directives/InjectDirective.php @@ -19,17 +19,14 @@ public static function definition(): string directive @inject( """ A path to the property of the context that will be injected. - If the value is nested within the context, you may use dot notation - to get it, e.g. "user.id". + Use dot notation to get a nested value from the context, e.g. `user.id`. """ context: String! """ The target name of the argument into which the value is injected. - You can use dot notation to set the value at arbitrary depth - within the incoming argument. - Use an asterisk `*` as a path segment to inject the value into every - element of a list found at that position. + Use dot notation to set the value at any depth within the incoming arguments. + Use an asterisk `*` as a path segment to inject the value into every element of a list found at that position. """ name: String! ) repeatable on FIELD_DEFINITION diff --git a/src/Schema/Directives/LazyLoadDirective.php b/src/Schema/Directives/LazyLoadDirective.php index 862c6f6707..c1e58fcbce 100644 --- a/src/Schema/Directives/LazyLoadDirective.php +++ b/src/Schema/Directives/LazyLoadDirective.php @@ -19,8 +19,7 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -Perform a [lazy eager load](https://laravel.com/docs/eloquent-relationships#lazy-eager-loading) -on the relations of a list of models. +Perform a [lazy eager load](https://laravel.com/docs/eloquent-relationships#lazy-eager-loading) on the relations of a list of models. """ directive @lazyLoad( """ diff --git a/src/Schema/Directives/LikeDirective.php b/src/Schema/Directives/LikeDirective.php index b7748fa5ba..00b55d54c4 100644 --- a/src/Schema/Directives/LikeDirective.php +++ b/src/Schema/Directives/LikeDirective.php @@ -36,8 +36,7 @@ public static function definition(): string key: String """ - Fixate the positions of wildcards (`%`, `_`) in the LIKE comparison around the - placeholder `{}`, e.g. `%{}`, `__{}` or `%{}%`. + Fix the positions of wildcards (`%`, `_`) around the placeholder `{}` in the LIKE comparison, e.g. `%{}`, `__{}` or `%{}%`. If specified, wildcard characters in the client-given input are escaped. If not specified, the client can pass wildcards unescaped. """ diff --git a/src/Schema/Directives/LimitDirective.php b/src/Schema/Directives/LimitDirective.php index 41a2aa86bf..bdce03be4e 100644 --- a/src/Schema/Directives/LimitDirective.php +++ b/src/Schema/Directives/LimitDirective.php @@ -28,18 +28,17 @@ public static function definition(): string { return /* @lang GraphQL */ <<<'GRAPHQL' """ -Allow clients to specify the maximum number of results to return when used on an argument, -or statically limit them when used on a field. +On an argument, allow clients to specify the maximum number of results to return. +On a field, limit the number of results statically. -By default, this directive does not influence the number of results the resolver queries internally, -but limits how much of it is returned to clients. Use the `builder` argument to change this. +By default, this directive does not change how many results the resolver queries internally. +It only limits how many of them are returned to clients. +Use the `builder` argument to change this. """ directive @limit( """ - You may set this to `true` if the field uses a query builder, - then this directive will apply a LIMIT clause to it. - Typically, this option should only be used for root fields, - as it may cause wrong results with batched relation queries. + Set this to `true` to apply a LIMIT clause to the query builder of the field. + Only use this on root fields, as it may cause wrong results with batched relation queries. """ builder: Boolean! = false ) on ARGUMENT_DEFINITION | FIELD_DEFINITION diff --git a/src/Schema/Directives/MethodDirective.php b/src/Schema/Directives/MethodDirective.php index 0eee147767..b072c23c04 100644 --- a/src/Schema/Directives/MethodDirective.php +++ b/src/Schema/Directives/MethodDirective.php @@ -14,8 +14,7 @@ public static function definition(): string """ Resolve a field by calling a method on the parent object. -Use this if the data is not accessible through simple property access or if you -want to pass argument to the method. +Use this if the data is not accessible through simple property access, or to pass arguments to the method. """ directive @method( """ diff --git a/src/Schema/Directives/MorphManyDirective.php b/src/Schema/Directives/MorphManyDirective.php index 0e6d91a657..35df57f2a7 100644 --- a/src/Schema/Directives/MorphManyDirective.php +++ b/src/Schema/Directives/MorphManyDirective.php @@ -14,8 +14,8 @@ public static function definition(): string """ directive @morphMany( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -44,8 +44,8 @@ public static function definition(): string maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -61,7 +61,8 @@ enum MorphManyType { PAGINATOR """ - Offset-based pagination like the Laravel "Simple Pagination", which does not count the total number of records. + Offset-based pagination like Laravel "Simple Pagination". + It does not count the total number of records. """ SIMPLE diff --git a/src/Schema/Directives/MorphOneDirective.php b/src/Schema/Directives/MorphOneDirective.php index 8b259de66b..4461c6bdbb 100644 --- a/src/Schema/Directives/MorphOneDirective.php +++ b/src/Schema/Directives/MorphOneDirective.php @@ -12,8 +12,8 @@ public static function definition(): string """ directive @morphOne( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String diff --git a/src/Schema/Directives/MorphToDirective.php b/src/Schema/Directives/MorphToDirective.php index 7a4fd2307a..ea88a1dac3 100644 --- a/src/Schema/Directives/MorphToDirective.php +++ b/src/Schema/Directives/MorphToDirective.php @@ -12,8 +12,8 @@ public static function definition(): string """ directive @morphTo( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String diff --git a/src/Schema/Directives/MorphToManyDirective.php b/src/Schema/Directives/MorphToManyDirective.php index 5d0bedd445..0e2f8d3dd7 100644 --- a/src/Schema/Directives/MorphToManyDirective.php +++ b/src/Schema/Directives/MorphToManyDirective.php @@ -14,8 +14,8 @@ public static function definition(): string """ directive @morphToMany( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String @@ -44,8 +44,8 @@ public static function definition(): string maxCount: Int """ - Specify a custom type that implements the Edge interface - to extend edge object. + Name a custom object type to use for the edges instead of the generated one. + It needs the fields `node` and `cursor` and may add more fields. Only applies when using Relay style "connection" pagination. """ edgeType: String @@ -61,7 +61,8 @@ enum MorphToManyType { PAGINATOR """ - Offset-based pagination like the Laravel "Simple Pagination", which does not count the total number of records. + Offset-based pagination like Laravel "Simple Pagination". + It does not count the total number of records. """ SIMPLE diff --git a/src/Schema/Directives/NamespaceDirective.php b/src/Schema/Directives/NamespaceDirective.php index fe8733eb83..06b5308f56 100644 --- a/src/Schema/Directives/NamespaceDirective.php +++ b/src/Schema/Directives/NamespaceDirective.php @@ -15,8 +15,7 @@ * Redefine the default namespaces used in other directives. * * The args for this directive are a map from directive names to namespaces. - * For example `@namespace(field: "App\\GraphQL")` applies the namespace - * `App\GraphQL` to the `@field` directive. + * For example `@namespace(field: "App\\GraphQL")` applies the namespace `App\GraphQL` to the `@field` directive. */ class NamespaceDirective extends BaseDirective implements TypeManipulator, TypeExtensionManipulator { diff --git a/src/Schema/Directives/NestDirective.php b/src/Schema/Directives/NestDirective.php index 892e23f329..f507217965 100644 --- a/src/Schema/Directives/NestDirective.php +++ b/src/Schema/Directives/NestDirective.php @@ -26,8 +26,7 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -A no-op nested arg resolver that delegates all calls -to the ArgResolver directives attached to the children. +A no-op nested arg resolver that delegates all calls to the ArgResolver directives of its children. """ directive @nest on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION GRAPHQL; diff --git a/src/Schema/Directives/RelationDirective.php b/src/Schema/Directives/RelationDirective.php index 41917fe218..eeb86bc156 100644 --- a/src/Schema/Directives/RelationDirective.php +++ b/src/Schema/Directives/RelationDirective.php @@ -51,8 +51,7 @@ public function resolveField(FieldValue $fieldValue): callable $relation = $parent->{$relationName}(); assert($relation instanceof Relation); - // We can shortcut the resolution if the client only queries for a foreign key - // that we know to be present on the parent model. + // We can shortcut the resolution if the client only queries for a foreign key that we know to be present on the parent model. if ( $this->lighthouseConfig['shortcut_foreign_key_selection'] && (array_diff(array_keys($resolveInfo->getFieldSelection()), ['id', '__typename']) === []) diff --git a/src/Schema/Directives/RenameArgsDirective.php b/src/Schema/Directives/RenameArgsDirective.php index 8c4c0f825e..a1ee45f71d 100644 --- a/src/Schema/Directives/RenameArgsDirective.php +++ b/src/Schema/Directives/RenameArgsDirective.php @@ -15,6 +15,7 @@ public static function definition(): string return /** @lang GraphQL */ <<<'GRAPHQL' """ Apply the @rename directives on the incoming arguments. +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @renameArgs on FIELD_DEFINITION GRAPHQL; @@ -29,8 +30,7 @@ protected function rename(ArgumentSet &$argumentSet): ArgumentSet { foreach ($argumentSet->arguments as $name => $argument) { // Recursively apply the renaming to nested inputs. - // We look for further ArgumentSet instances, they - // might be contained within an array. + // We look for further ArgumentSet instances, they might be contained within an array. Utils::applyEach( function ($value): void { if ($value instanceof ArgumentSet) { diff --git a/src/Schema/Directives/SanitizeDirective.php b/src/Schema/Directives/SanitizeDirective.php index 317ce08ee8..3753f5db76 100644 --- a/src/Schema/Directives/SanitizeDirective.php +++ b/src/Schema/Directives/SanitizeDirective.php @@ -12,6 +12,7 @@ public static function definition(): string return /** @lang GraphQL */ <<<'GRAPHQL' """ Apply sanitization to the arguments of a field. +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @sanitize on FIELD_DEFINITION GRAPHQL; diff --git a/src/Schema/Directives/ScopeDirective.php b/src/Schema/Directives/ScopeDirective.php index acb3013eae..30994a9367 100644 --- a/src/Schema/Directives/ScopeDirective.php +++ b/src/Schema/Directives/ScopeDirective.php @@ -17,7 +17,7 @@ public static function definition(): string Adds a scope to the query builder. The scope method will receive the client-given value of the argument as the second parameter. -This also works with custom query builders, it simply calls its methods with the argument value. +This also works with custom query builders, it calls its methods with the argument value. """ directive @scope( """ diff --git a/src/Schema/Directives/ShowDirective.php b/src/Schema/Directives/ShowDirective.php index 63123e860f..f86054f555 100644 --- a/src/Schema/Directives/ShowDirective.php +++ b/src/Schema/Directives/ShowDirective.php @@ -12,7 +12,8 @@ public static function definition(): string """ directive @show( """ - Specify which environments may use this field, e.g. ["testing"]. + Specify which environments include this element, e.g. `["testing"]`. + Compared against the value returned from `app()->environment()`. """ env: [String!]! ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION | OBJECT diff --git a/src/Schema/Directives/SpreadDirective.php b/src/Schema/Directives/SpreadDirective.php index 88150f7635..d5948deef1 100644 --- a/src/Schema/Directives/SpreadDirective.php +++ b/src/Schema/Directives/SpreadDirective.php @@ -22,8 +22,7 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -Merge the fields of a nested input object into the arguments of its parent -when processing the field arguments given by a client. +Merge the fields of a nested input object into the arguments of its parent when processing the field arguments given by a client. """ directive @spread on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION GRAPHQL; diff --git a/src/Schema/Directives/ThrottleDirective.php b/src/Schema/Directives/ThrottleDirective.php index 7991d038ce..64e1074754 100644 --- a/src/Schema/Directives/ThrottleDirective.php +++ b/src/Schema/Directives/ThrottleDirective.php @@ -28,7 +28,8 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -Sets rate limit to access the field. Does the same as ThrottleRequests Laravel Middleware. +Limit the rate of access to the field. +Works like the Laravel middleware `ThrottleRequests`. """ directive @throttle( """ @@ -105,7 +106,7 @@ public function manipulateFieldDefinition(DocumentAST &$documentAST, FieldDefini { $name = $this->directiveArgValue('name'); if ($name !== null) { - // @phpstan-ignore-next-line limiter() can actually return null, some Laravel versions lie + // @phpstan-ignore-next-line limiter() can return null, some Laravel versions lie $this->limiter->limiter($name) ?? throw new DefinitionException("Named limiter {$name} is not found."); } diff --git a/src/Schema/Directives/TransformArgsDirective.php b/src/Schema/Directives/TransformArgsDirective.php index 3f08b5bffa..c17fd673d3 100644 --- a/src/Schema/Directives/TransformArgsDirective.php +++ b/src/Schema/Directives/TransformArgsDirective.php @@ -12,6 +12,7 @@ public static function definition(): string return /** @lang GraphQL */ <<<'GRAPHQL' """ Transform the arguments of a field. +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @transformArgs on FIELD_DEFINITION GRAPHQL; diff --git a/src/Schema/Directives/TrimDirective.php b/src/Schema/Directives/TrimDirective.php index 807c791728..4b72a50322 100644 --- a/src/Schema/Directives/TrimDirective.php +++ b/src/Schema/Directives/TrimDirective.php @@ -20,6 +20,8 @@ public static function definition(): string This can be used on: - a single argument or input field to sanitize that subtree - a field to trim all strings + +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @trim on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION GRAPHQL; diff --git a/src/Schema/Directives/UpdateDirective.php b/src/Schema/Directives/UpdateDirective.php index 2f30f6af84..43327de959 100644 --- a/src/Schema/Directives/UpdateDirective.php +++ b/src/Schema/Directives/UpdateDirective.php @@ -23,8 +23,7 @@ public static function definition(): string """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION diff --git a/src/Schema/Directives/UpdateManyDirective.php b/src/Schema/Directives/UpdateManyDirective.php index 3af93be4bc..7a26630b63 100644 --- a/src/Schema/Directives/UpdateManyDirective.php +++ b/src/Schema/Directives/UpdateManyDirective.php @@ -23,8 +23,7 @@ public static function definition(): string """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION diff --git a/src/Schema/Directives/UploadDirective.php b/src/Schema/Directives/UploadDirective.php index e2c8a9dd14..84f7991cad 100644 --- a/src/Schema/Directives/UploadDirective.php +++ b/src/Schema/Directives/UploadDirective.php @@ -13,8 +13,8 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -Uploads given file to storage, removes the argument and sets -the returned path to the attribute key provided. +Upload the given file to storage and remove the argument. +The returned path is set to the given attribute key. This does not change the schema from a client perspective. """ diff --git a/src/Schema/Directives/UpsertDirective.php b/src/Schema/Directives/UpsertDirective.php index 526ee860bc..901b4ded45 100644 --- a/src/Schema/Directives/UpsertDirective.php +++ b/src/Schema/Directives/UpsertDirective.php @@ -39,8 +39,7 @@ public static function definition(): string """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION diff --git a/src/Schema/Directives/UpsertManyDirective.php b/src/Schema/Directives/UpsertManyDirective.php index bc013293ce..cc98af6392 100644 --- a/src/Schema/Directives/UpsertManyDirective.php +++ b/src/Schema/Directives/UpsertManyDirective.php @@ -39,8 +39,7 @@ public static function definition(): string """ Specify the name of the relation on the parent model. - This is only needed when using this directive as a nested arg - resolver and if the name of the relation is not the arg name. + Only necessary when this directive is used as a nested arg resolver and the relation is named differently from the argument. """ relation: String ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION diff --git a/src/Schema/Directives/WhereBetweenDirective.php b/src/Schema/Directives/WhereBetweenDirective.php index 29294e1481..fcf9071803 100644 --- a/src/Schema/Directives/WhereBetweenDirective.php +++ b/src/Schema/Directives/WhereBetweenDirective.php @@ -15,8 +15,7 @@ public static function definition(): string """ Verify that a column's value is between two values. -The type of the input value this is defined upon should be -an `input` object with two fields. +The type of the argument or input field should be an `input` object with two fields. """ directive @whereBetween( """ diff --git a/src/Schema/Directives/WhereNotBetweenDirective.php b/src/Schema/Directives/WhereNotBetweenDirective.php index efd0edbd3b..429f2285b4 100644 --- a/src/Schema/Directives/WhereNotBetweenDirective.php +++ b/src/Schema/Directives/WhereNotBetweenDirective.php @@ -15,8 +15,7 @@ public static function definition(): string """ Verify that a column's value lies outside two values. -The type of the input value this is defined upon should be -an `input` object with two fields. +The type of the argument or input field should be an `input` object with two fields. """ directive @whereNotBetween( """ diff --git a/src/Schema/Directives/WithCountDirective.php b/src/Schema/Directives/WithCountDirective.php index d3a95cdc5c..7f91f84904 100644 --- a/src/Schema/Directives/WithCountDirective.php +++ b/src/Schema/Directives/WithCountDirective.php @@ -22,9 +22,9 @@ public static function definition(): string """ Eager-load the count of an Eloquent relation if the field is queried. -Note that this does not return a value for the field, the count is simply -prefetched, assuming it is used to compute the field value. Use `@count` -if the field should simply return the relation count. +This does not return a value for the field. +It only prefetches the count, assuming the field value is computed from it. +Use `@count` to return the relation count as the field value. """ directive @withCount( """ diff --git a/src/Schema/Directives/WithDirective.php b/src/Schema/Directives/WithDirective.php index 6eb3072eb1..5fadef9453 100644 --- a/src/Schema/Directives/WithDirective.php +++ b/src/Schema/Directives/WithDirective.php @@ -24,8 +24,8 @@ public static function definition(): string """ directive @with( """ - Specify the relationship method name in the model class, - if it is named different from the field in the schema. + Specify the relationship method name in the model class. + Only necessary if it is named differently from the field in the schema. """ relation: String diff --git a/src/Schema/ResolverProvider.php b/src/Schema/ResolverProvider.php index 4da836922c..a3af97b1b9 100644 --- a/src/Schema/ResolverProvider.php +++ b/src/Schema/ResolverProvider.php @@ -23,8 +23,7 @@ public function provideResolver(FieldValue $fieldValue): \Closure $this->throwMissingResolver($fieldValue); } - // Return any non-null value to continue nested field resolution - // when the root Query type is returned as part of the result. + // Return any non-null value to continue nested field resolution when the root Query type is returned as part of the result. if (ASTHelper::getUnderlyingTypeName($fieldValue->getField()) === RootType::QUERY) { return static fn (): bool => true; } @@ -53,8 +52,7 @@ protected function findResolverClass(FieldValue $fieldValue, string $methodName) /** @return never */ protected function throwMissingResolver(FieldValue $fieldValue): void { - // Since we already know we are on the root type, this is either - // query, mutation or subscription + // Since we already know we are on the root type, this is either query, mutation or subscription $parent = lcfirst($fieldValue->getParentName()); $fieldName = $fieldValue->getFieldName(); $proposedResolverClass = ucfirst($fieldName); diff --git a/src/Schema/SchemaBuilder.php b/src/Schema/SchemaBuilder.php index 0c8a950eab..ecce25bec1 100644 --- a/src/Schema/SchemaBuilder.php +++ b/src/Schema/SchemaBuilder.php @@ -45,8 +45,7 @@ protected function build(DocumentAST $documentAST): Schema assert($query instanceof ObjectType); $config->setQuery($query); - // Mutation and Subscription are optional, so only add them - // if they are present in the schema + // Mutation and Subscription are optional, so only add them if they are present in the schema if (isset($documentAST->types[RootType::MUTATION])) { $mutation = $this->typeRegistry->get(RootType::MUTATION); assert($mutation instanceof ObjectType); @@ -70,9 +69,8 @@ protected function build(DocumentAST $documentAST): Schema fn (): array => $this->typeRegistry->possibleTypes(), ); - // Passing scalar overrides explicitly prevents the first lookup of a built-in scalar - // from discovering them by resolving the lazy types callable, which would eagerly - // build every type in the schema, see https://github.com/nuwave/lighthouse/issues/2771. + // Passing scalar overrides explicitly keeps the first lookup of a built-in scalar from resolving the lazy types callable. + // That would eagerly build every type in the schema, see https://github.com/nuwave/lighthouse/issues/2771. // TODO remove this check when the minimum version of webonyx/graphql-php includes the method if (method_exists($config, 'setScalarOverrides')) { // @phpstan-ignore function.alreadyNarrowedType (backward compatibility with webonyx/graphql-php < 15.31) $config->setScalarOverrides($this->typeRegistry->scalarOverrides()); diff --git a/src/Schema/TypeRegistry.php b/src/Schema/TypeRegistry.php index 3919305eef..4f6a6bb37b 100644 --- a/src/Schema/TypeRegistry.php +++ b/src/Schema/TypeRegistry.php @@ -219,9 +219,8 @@ public function overwriteLazy(string $name, callable $type): self */ public function possibleTypes(): array { - // Make sure all the types from the AST are eagerly converted - // to find orphaned types, such as an object type that is only - // ever used through its association to an interface. + // Eagerly convert all types from the AST to find orphaned types. + // An example is an object type that is only ever used through its interface. foreach ($this->documentAST->types as $typeDefinition) { $name = $typeDefinition->getName()->value; @@ -238,8 +237,7 @@ public function possibleTypes(): array /** * Built-in scalar types that are overridden in this schema. * - * A scalar override is a type named after a built-in scalar such as `String`, - * defined in the schema or registered programmatically. + * A scalar override is a type named after a built-in scalar such as `String`, defined in the schema or registered programmatically. * * @return array */ diff --git a/src/Schema/Validator.php b/src/Schema/Validator.php index 2e0b45fc61..e43eb4174c 100644 --- a/src/Schema/Validator.php +++ b/src/Schema/Validator.php @@ -27,7 +27,7 @@ public function validate(): void $originalSchema = $this->schemaBuilder->schema(); $schemaConfig = $originalSchema->getConfig(); - // We add schema directive definitions only here, since it is very slow + // We add schema directive definitions only here, since it is slow $directiveFactory = new DirectiveFactory( new FallbackTypeNodeConverter($this->typeRegistry), ); diff --git a/src/Schema/Values/FieldValue.php b/src/Schema/Values/FieldValue.php index 3b290ca5c1..17a1e2b046 100644 --- a/src/Schema/Values/FieldValue.php +++ b/src/Schema/Values/FieldValue.php @@ -156,8 +156,8 @@ public function addArgumentSetTransformer(callable $argumentSetTransformer): sel */ public function finishResolver(callable $resolver): callable { - // We expect the wrapped resolvers to run in order, but nesting them causes the last - // applied wrapper to be run first. Thus, we reverse the wrappers before applying them. + // We expect the wrapped resolvers to run in order, but nesting them causes the last applied wrapper to be run first. + // Thus, we reverse the wrappers before applying them. foreach (array_reverse($this->resolverWrappers) as $wrapper) { $resolver = $wrapper($resolver); } diff --git a/src/SoftDeletes/SoftDeletesDirective.php b/src/SoftDeletes/SoftDeletesDirective.php index 5edb7d86b4..15f66dda7c 100644 --- a/src/SoftDeletes/SoftDeletesDirective.php +++ b/src/SoftDeletes/SoftDeletesDirective.php @@ -17,8 +17,7 @@ public static function definition(): string return /** @lang GraphQL */ <<<'GRAPHQL' """ Allows to filter if trashed elements should be fetched. -This manipulates the schema by adding the argument -`trashed: Trashed @trashed` to the field. +This adds the argument `trashed: Trashed @trashed` to the field. """ directive @softDeletes on FIELD_DEFINITION GRAPHQL; diff --git a/src/Subscriptions/Directives/BroadcastDirective.php b/src/Subscriptions/Directives/BroadcastDirective.php index 0d31ed0793..c8d4bca2a4 100644 --- a/src/Subscriptions/Directives/BroadcastDirective.php +++ b/src/Subscriptions/Directives/BroadcastDirective.php @@ -15,8 +15,7 @@ public static function definition(): string """ Broadcast the results of a mutation to subscribed clients. -Ensure you place this after other field middleware directives that may transform the -result to broadcast the final value. +Place this after other field middleware directives that may transform the result, so it broadcasts the final value. """ directive @broadcast( """ diff --git a/src/Subscriptions/Storage/RedisStorageManager.php b/src/Subscriptions/Storage/RedisStorageManager.php index 4bf2848580..5c5979fa99 100644 --- a/src/Subscriptions/Storage/RedisStorageManager.php +++ b/src/Subscriptions/Storage/RedisStorageManager.php @@ -69,8 +69,7 @@ public function subscribersByTopic(string $topic): Collection // Store all keys as missing keys to remove the ones which are expired later. $missingKeys = $subscriberIds; - // Since we store the individual subscribers with a prefix, - // but not in the set, we have to add the prefix here. + // Since we store the individual subscribers with a prefix, but not in the set, we have to add the prefix here. $subscriberIds = array_map([$this, 'channelKey'], $subscriberIds); // Using the mget command, we can retrieve multiple values from redis. @@ -116,8 +115,8 @@ public function storeSubscriber(Subscriber $subscriber, string $topic): void $subscriber->topic = $topic; // In contrast to the CacheStorageManager, we use redis sets. - // Instead of reading the entire list, adding the subscriber, and storing the list; - // we simply add the name of the subscriber to the set of subscribers of this topic using the sadd command... + // We do not read the entire list, add the subscriber and store the list. + // Instead, we add the name of the subscriber to the set of subscribers of this topic using the sadd command... $topicKey = $this->topicKey($topic); $this->connection->command('sadd', [ $topicKey, diff --git a/src/Subscriptions/SubscriptionResolverProvider.php b/src/Subscriptions/SubscriptionResolverProvider.php index 157f1be14f..5058783a08 100644 --- a/src/Subscriptions/SubscriptionResolverProvider.php +++ b/src/Subscriptions/SubscriptionResolverProvider.php @@ -51,8 +51,7 @@ public function provideSubscriptionResolver(FieldValue $fieldValue): \Closure assert(is_subclass_of($namespacedClassName, GraphQLSubscription::class)); $subscription = Container::getInstance()->make($namespacedClassName); - // Subscriptions can only be placed on a single field on the root - // query, so there is no need to consider the field path + // Subscriptions can only be placed on a single field on the root query, so there is no need to consider the field path $this->subscriptionRegistry->register($subscription, $fieldName); return function (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($subscription, $fieldName) { diff --git a/src/Support/AppVersion.php b/src/Support/AppVersion.php index 29696eac1e..190cd5e825 100644 --- a/src/Support/AppVersion.php +++ b/src/Support/AppVersion.php @@ -25,7 +25,7 @@ public static function below(float $version): bool protected static function version(): string { /** - * Not using assert() as only one of those classes will actually be installed. + * Not using assert() as only one of those classes will be installed. * * @var \Illuminate\Foundation\Application|\Laravel\Lumen\Application $container */ diff --git a/src/Support/Contracts/ArgResolver.php b/src/Support/Contracts/ArgResolver.php index 07b2bc4b09..96acdbf60f 100644 --- a/src/Support/Contracts/ArgResolver.php +++ b/src/Support/Contracts/ArgResolver.php @@ -5,8 +5,7 @@ /** * Resolve a slice of input arguments during mutation execution. * - * Arg resolvers compose like field resolvers: each handles only its own - * nested input, and Lighthouse orchestrates traversal of the argument tree. + * Arg resolvers compose like field resolvers: each handles only its own nested input, and Lighthouse orchestrates traversal of the argument tree. * * @see \Nuwave\Lighthouse\Support\Contracts\SaveAwareArgResolver * diff --git a/src/Support/Contracts/PreSaveArgumentsAware.php b/src/Support/Contracts/PreSaveArgumentsAware.php index 17033531e0..ca9be515b9 100644 --- a/src/Support/Contracts/PreSaveArgumentsAware.php +++ b/src/Support/Contracts/PreSaveArgumentsAware.php @@ -3,12 +3,10 @@ namespace Nuwave\Lighthouse\Support\Contracts; /** - * Implement this on ArgResolvers that can run pre-save arg resolvers - * lifted out of a @nest before persisting the model. + * Implement this on ArgResolvers that can run pre-save arg resolvers lifted out of a @nest before persisting the model. * * Lifted arguments are passed as an ordered list, not as a name-keyed map: - * field names are unique per input type, not across a whole input tree, - * so keying them would discard colliding arguments. + * field names are unique per input type, not across a whole input tree, so keying them would discard colliding arguments. */ interface PreSaveArgumentsAware { diff --git a/src/Support/Contracts/ProvidesCacheableValidationRules.php b/src/Support/Contracts/ProvidesCacheableValidationRules.php index 5ba53e5f48..e940e717c4 100644 --- a/src/Support/Contracts/ProvidesCacheableValidationRules.php +++ b/src/Support/Contracts/ProvidesCacheableValidationRules.php @@ -22,8 +22,7 @@ public function cacheableValidationRules(): array; * * These rules are always executed and their result is never cached. * - * Returning `null` enables all available rules, - * returning `[]` skips query validation entirely. + * Returning `null` enables all available rules, returning `[]` skips query validation entirely. * * @return array|null */ diff --git a/src/Support/Contracts/ProvidesValidationRules.php b/src/Support/Contracts/ProvidesValidationRules.php index 100fe13f50..a338ac41dd 100644 --- a/src/Support/Contracts/ProvidesValidationRules.php +++ b/src/Support/Contracts/ProvidesValidationRules.php @@ -7,8 +7,7 @@ interface ProvidesValidationRules /** * Rules to use for query validation. * - * Returning `null` enables all available rules, - * returning `[]` skips query validation entirely. + * Returning `null` enables all available rules, returning `[]` skips query validation entirely. * * @return array|null */ diff --git a/src/Support/Contracts/SaveAwareArgResolver.php b/src/Support/Contracts/SaveAwareArgResolver.php index c4f907da01..49e1426dd9 100644 --- a/src/Support/Contracts/SaveAwareArgResolver.php +++ b/src/Support/Contracts/SaveAwareArgResolver.php @@ -5,11 +5,10 @@ use Illuminate\Database\Eloquent\Model; /** - * Implement this on ArgResolver directives that need to control whether they - * run before or after the parent model is saved during mutation execution. + * Implement this on ArgResolver directives that need to control whether they run before or after the parent model is saved during mutation execution. * - * When `runBeforeSave()` returns true, `__invoke()` receives null as `$value` - * if the client sends null for a nullable input field. Guard accordingly. + * When `runBeforeSave()` returns true, `__invoke()` receives null as `$value` if the client sends null for a nullable input field. + * Guard accordingly. * * @api */ @@ -18,16 +17,14 @@ interface SaveAwareArgResolver extends ArgResolver /** * Should this resolver run before the parent model is persisted? * - * When true, the resolver is invoked before $model->save(), allowing it - * to set attributes or foreign keys on the model. - * When false, the resolver runs after the model is saved (the default - * for any ArgResolver that does not implement this interface). + * When true, the resolver is invoked before $model->save(), allowing it to set attributes or foreign keys on the model. + * When false, the resolver runs after the model is saved (the default for any ArgResolver that does not implement this interface). * * Only consulted when the root is a Model. * In non-Model contexts, this method is not called and the resolver executes normally. * - * Implementations must base the decision on the model class and its relations, - * not on instance state — the model may not yet be hydrated when this is called. + * Implementations must base the decision on the model class and its relations, not on instance state. + * The model may not yet be hydrated when this is called. */ public function runBeforeSave(Model $model): bool; } diff --git a/src/Support/DriverManager.php b/src/Support/DriverManager.php index b0a37668d4..b52fdf7d66 100644 --- a/src/Support/DriverManager.php +++ b/src/Support/DriverManager.php @@ -6,8 +6,8 @@ use Nuwave\Lighthouse\Exceptions\InvalidDriverException; /** - * NOTE: Implementation pulled from \Illuminate\Cache\CacheManager. Purpose is - * to serve as a base class to easily generate a manager that creates drivers with configuration options. + * NOTE: Implementation pulled from \Illuminate\Cache\CacheManager. + * Purpose is to serve as a base class to generate a manager that creates drivers with configuration options. * * @phpstan-type CustomCreator callable(\Illuminate\Container\Container $app, array $config): object */ diff --git a/src/Support/Utils.php b/src/Support/Utils.php index d5dbe7d383..d0ae344735 100644 --- a/src/Support/Utils.php +++ b/src/Support/Utils.php @@ -15,7 +15,7 @@ class Utils /** * Attempt to find a given class in the given namespaces. * - * If the class itself exists, it is simply returned as is. + * If the class itself exists, it is returned as is. * Else, the given namespaces are tried in order. * * @param array $namespacesToTry diff --git a/src/Testing/MakesGraphQLRequests.php b/src/Testing/MakesGraphQLRequests.php index 66441363ea..b900ae1474 100644 --- a/src/Testing/MakesGraphQLRequests.php +++ b/src/Testing/MakesGraphQLRequests.php @@ -25,8 +25,7 @@ trait MakesGraphQLRequests /** * Stores the result of the introspection query. * - * On the first call to introspect() this property is set to - * cache the result, as introspection is quite expensive. + * On the first call to introspect() this property is set to cache the result, as introspection is expensive. * * @var \Illuminate\Testing\TestResponse<\Symfony\Component\HttpFoundation\Response> */ @@ -65,8 +64,7 @@ protected function graphQL( /** * Send a POST request to the GraphQL endpoint. * - * Use this over graphQL() when you need more control or want to - * test how your server behaves on incorrect inputs. + * Use this over graphQL() when you need more control or want to test how your server behaves on incorrect inputs. * * @param array $data JSON-serializable payload * @param array $headers HTTP headers to pass to the POST request diff --git a/src/Testing/MakesGraphQLRequestsLumen.php b/src/Testing/MakesGraphQLRequestsLumen.php index 19320185d1..f484d2eda1 100644 --- a/src/Testing/MakesGraphQLRequestsLumen.php +++ b/src/Testing/MakesGraphQLRequestsLumen.php @@ -27,8 +27,7 @@ trait MakesGraphQLRequestsLumen // @phpstan-ignore trait.unused (hard to set up /** * Stores the result of the introspection query. * - * On the first call to introspect() this property is set to - * cache the result, as introspection is quite expensive. + * On the first call to introspect() this property is set to cache the result, as introspection is expensive. */ protected TestResponse $introspectionResult; @@ -66,8 +65,7 @@ protected function graphQL( /** * Send a POST request to the GraphQL endpoint. * - * Use this over graphQL() when you need more control or want to - * test how your server behaves on incorrect inputs. + * Use this over graphQL() when you need more control or want to test how your server behaves on incorrect inputs. * * @param array $data JSON-serializable payload * @param array $headers HTTP headers to pass to the POST request diff --git a/src/Testing/MockDirective.php b/src/Testing/MockDirective.php index 658f9b3e94..45d7e67a6e 100644 --- a/src/Testing/MockDirective.php +++ b/src/Testing/MockDirective.php @@ -17,7 +17,7 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -Allows you to easily hook up a resolver for an endpoint. +Resolve the field with a mock resolver registered in the test, see `MocksResolvers`. """ directive @mock( """ diff --git a/src/Testing/RefreshesSchemaCache.php b/src/Testing/RefreshesSchemaCache.php index 395363620e..ab8e516339 100644 --- a/src/Testing/RefreshesSchemaCache.php +++ b/src/Testing/RefreshesSchemaCache.php @@ -27,9 +27,8 @@ trait RefreshesSchemaCache protected function refreshSchemaCache(): void { if (! static::$schemaCacheWasRefreshed) { - // We use the filesystem as shared mutable state to coordinate between processes, - // since the tests might be run in parallel, and we want to ensure the schema cache - // is refreshed exactly once before all tests. + // Tests might run in parallel, so we coordinate processes through the filesystem. + // This refreshes the schema cache exactly once before all tests. \Safe\touch(self::$lockFilePath); $lockFile = \Safe\fopen(self::$lockFilePath, 'r'); diff --git a/src/Tracing/TracingDirective.php b/src/Tracing/TracingDirective.php index efbab6e070..6a71c9c4bc 100644 --- a/src/Tracing/TracingDirective.php +++ b/src/Tracing/TracingDirective.php @@ -19,8 +19,8 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -Do not use this directive directly, it is automatically added to the schema -when using the tracing extension. +Do not use this directive directly. +Lighthouse adds it to the schema when you use the tracing extension. """ directive @tracing on FIELD_DEFINITION GRAPHQL; diff --git a/src/Validation/BaseRulesDirective.php b/src/Validation/BaseRulesDirective.php index d84cb992ea..e859125120 100644 --- a/src/Validation/BaseRulesDirective.php +++ b/src/Validation/BaseRulesDirective.php @@ -21,10 +21,9 @@ public function rules(): array $rules = $this->directiveArgValue('apply'); // Custom rules may be referenced through their fully qualified class name. - // The Laravel validator expects a class instance to be passed, so we - // resolve any given rule where a corresponding class exists. - // Requiring a namespace separator keeps built-in rules such as `url` or `image` - // from matching global classes or facade aliases, as class names are case-insensitive. + // The Laravel validator expects a class instance to be passed, so we resolve any given rule where a corresponding class exists. + // Requiring a namespace separator keeps built-in rules such as `url` or `image` from matching global classes or facade aliases. + // This matters because class names are case-insensitive. foreach ($rules as $key => $rule) { if (str_contains($rule, '\\') && class_exists($rule)) { $rules[$key] = Container::getInstance()->make($rule); diff --git a/src/Validation/RulesDirective.php b/src/Validation/RulesDirective.php index d13301a60d..5a398f4069 100644 --- a/src/Validation/RulesDirective.php +++ b/src/Validation/RulesDirective.php @@ -15,8 +15,7 @@ public static function definition(): string directive @rules( """ Specify the validation rules to apply to the field. - This can either be a reference to [Laravel's built-in validation rules](https://laravel.com/docs/validation#available-validation-rules), - or the fully qualified class name of a custom validation rule. + Reference either one of [Laravel's built-in validation rules](https://laravel.com/docs/validation#available-validation-rules) or the fully qualified class name of a custom validation rule. Validation rules that mutate the given input value are _not_ supported: - `exclude_if` diff --git a/src/Validation/RulesForArrayDirective.php b/src/Validation/RulesForArrayDirective.php index 5ba317ee21..4d6712fb73 100644 --- a/src/Validation/RulesForArrayDirective.php +++ b/src/Validation/RulesForArrayDirective.php @@ -16,8 +16,7 @@ public static function definition(): string directive @rulesForArray( """ Specify the validation rules to apply to the field. - This can either be a reference to any of Laravel's built-in validation rules: https://laravel.com/docs/validation#available-validation-rules, - or the fully qualified class name of a custom validation rule. + Reference either one of [Laravel's built-in validation rules](https://laravel.com/docs/validation#available-validation-rules) or the fully qualified class name of a custom validation rule. Validation rules that mutate the given input values are _not_ supported: - `exclude_if` diff --git a/src/Validation/RulesGatherer.php b/src/Validation/RulesGatherer.php index 3749dde10e..e19a15914f 100644 --- a/src/Validation/RulesGatherer.php +++ b/src/Validation/RulesGatherer.php @@ -192,9 +192,8 @@ protected function wrap(array $rulesOrMessages, array $path): array /** * Prepend rule arguments that refer to other arguments with the full path. * - * This may be necessary to allow certain rules to be reusable when placed - * upon input arguments. For example, `required_with:foo` may be defined - * on an input value that is nested within the arguments under `input.0`. + * This may be necessary to allow certain rules to be reusable when placed upon input arguments. + * For example, `required_with:foo` may be defined on an input value that is nested within the arguments under `input.0`. * It is thus changed to the full reference `required_with:input.0.foo`. * * @param array $rules diff --git a/src/Validation/ValidateDirective.php b/src/Validation/ValidateDirective.php index 6e0c38e1fd..dcfa3f2e72 100644 --- a/src/Validation/ValidateDirective.php +++ b/src/Validation/ValidateDirective.php @@ -18,6 +18,7 @@ public static function definition(): string return /** @lang GraphQL */ <<<'GRAPHQL' """ Run validation on a field. +Lighthouse applies this to every field by default, through the `field_middleware` setting in `lighthouse.php`. """ directive @validate on FIELD_DEFINITION GRAPHQL; diff --git a/src/Validation/ValidatorDirective.php b/src/Validation/ValidatorDirective.php index a09990a1d3..4819d237d2 100644 --- a/src/Validation/ValidatorDirective.php +++ b/src/Validation/ValidatorDirective.php @@ -37,9 +37,8 @@ public static function definition(): string """ The name of the class to use. - If defined on an input, this defaults to a class called `{$inputName}Validator` in the - default validator namespace. For fields, it uses the namespace of the parent type - and the field name: `{$parent}\{$field}Validator`. + If defined on an input, this defaults to a class called `{$inputName}Validator` in the default validator namespace. + For fields, it uses the namespace of the parent type and the field name: `{$parent}\{$field}Validator`. """ class: String ) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION | INPUT_OBJECT diff --git a/src/WhereConditions/SQLOperator.php b/src/WhereConditions/SQLOperator.php index fe4a603874..7157c51eed 100644 --- a/src/WhereConditions/SQLOperator.php +++ b/src/WhereConditions/SQLOperator.php @@ -72,10 +72,10 @@ enum SQLOperator { "Whether a value is not in the JSON." JSON_DOESNT_CONTAIN @enum(value: "JsonDoesntContain") - "Whether the length of the JSON array is equals to the value." + "Whether the length of the JSON array equals the value." JSON_LENGTH_EQ @enum(value: "JsonLengthEq") - "Whether the length of the JSON array is not equals to the value." + "Whether the length of the JSON array does not equal the value." JSON_LENGTH_NEQ @enum(value: "JsonLengthNeq") "Whether the length of the JSON array is less than the value." @@ -84,10 +84,10 @@ enum SQLOperator { "Whether the length of the JSON array is greater than the value." JSON_LENGTH_GT @enum(value: "JsonLengthGt") - "Whether the length of the JSON array is less than or equals to the value." + "Whether the length of the JSON array is less than or equal to the value." JSON_LENGTH_LTE @enum(value: "JsonLengthLte") - "Whether the length of the JSON array is greater than or equals to the value." + "Whether the length of the JSON array is greater than or equal to the value." JSON_LENGTH_GTE @enum(value: "JsonLengthGte") } GRAPHQL; @@ -118,8 +118,7 @@ public function applyConditions(QueryBuilder|EloquentBuilder $builder, array $wh $arity = $this->operatorArity($operator); if ($arity === 3) { - // Usually, the operator is passed as the second argument to the condition - // method, e.g. ->where('some_col', '=', $value) + // Usually, the operator is passed as the second argument to the condition method, e.g. ->where('some_col', '=', $value) $args[] = match ($operator) { 'JsonLengthEq' => '=', 'JsonLengthNeq' => '!=', @@ -134,8 +133,7 @@ public function applyConditions(QueryBuilder|EloquentBuilder $builder, array $wh $method .= 'JsonLength'; } } else { - // We use the fact that the operators are named after Laravel's condition - // methods, so we can simply append the name, e.g. whereNull, whereNotBetween + // We use the fact that the operators are named after Laravel's condition methods, so we can append the name, e.g. whereNull, whereNotBetween $method .= $operator; } diff --git a/src/WhereConditions/WhereHasConditionsDirective.php b/src/WhereConditions/WhereHasConditionsDirective.php index 8b2d4ea94b..a1b9d8ddf5 100644 --- a/src/WhereConditions/WhereHasConditionsDirective.php +++ b/src/WhereConditions/WhereHasConditionsDirective.php @@ -13,16 +13,15 @@ public static function definition(): string { return /** @lang GraphQL */ <<<'GRAPHQL' """ -Allows clients to filter a query based on the existence of a related model, using -a dynamically controlled `WHERE` condition that applies to the relationship. +Allow clients to filter a query by the existence of a related model. +A dynamically controlled `WHERE` condition applies to the relationship. """ directive @whereHasConditions( """ The Eloquent relationship that the conditions will be applied to. - This argument can be omitted if the argument name follows the naming - convention `has{$RELATION}`. For example, if the Eloquent relationship - is named `posts`, the argument name must be `hasPosts`. + This argument can be omitted if the argument name follows the naming convention `has{$RELATION}`. + For example, if the Eloquent relationship is named `posts`, the argument name must be `hasPosts`. """ relation: String @@ -87,8 +86,7 @@ protected function relationName(): string { $relationName = $this->directiveArgValue('relation'); - // If the relation name is not set explicitly, we assume the argument - // name follows a convention and contains the relation name + // If the relation name is not set explicitly, we assume the argument name follows a convention and contains the relation name if (is_null($relationName)) { return lcfirst( Str::after($this->nodeName(), 'has'), diff --git a/src/lighthouse.php b/src/lighthouse.php index cd56d17277..7f4cba1010 100644 --- a/src/lighthouse.php +++ b/src/lighthouse.php @@ -7,8 +7,7 @@ |-------------------------------------------------------------------------- | | Controls the HTTP route that your GraphQL server responds to. - | You may set `route` => false, to disable the default route - | registration and take full control. + | You may set `route` => false, to disable the default route registration and take full control. | */ @@ -34,8 +33,8 @@ // Always set the `Accept: application/json` header. Nuwave\Lighthouse\Http\Middleware\AcceptJson::class, - // Logs in a user if they are authenticated. In contrast to Laravel's 'auth' - // middleware, this delegates auth and permission checks to the field level. + // Logs in a user if they are authenticated. + // In contrast to Laravel's 'auth' middleware, this delegates auth and permission checks to the field level. Nuwave\Lighthouse\Http\Middleware\AttemptAuthentication::class, // Logs every incoming GraphQL query. @@ -81,8 +80,7 @@ |-------------------------------------------------------------------------- | | A large part of schema generation consists of parsing and AST manipulation. - | This operation is very expensive, so it is highly recommended enabling - | caching of the final schema to optimize performance of large schemas. + | This operation is expensive, so enable caching of the final schema to optimize performance of large schemas. | */ @@ -182,8 +180,7 @@ |-------------------------------------------------------------------------- | | Should the source location be included in the AST nodes resulting from query parsing? - | Setting this to `false` improves performance, but omits the key `locations` from errors, - | see https://spec.graphql.org/October2021/#sec-Errors.Error-result-format. + | Setting this to `false` improves performance, but omits the key `locations` from errors, see https://spec.graphql.org/October2021/#sec-Errors.Error-result-format. | */ @@ -194,9 +191,8 @@ | Namespaces |-------------------------------------------------------------------------- | - | These are the default namespaces where Lighthouse looks for classes to - | extend functionality of the schema. You may pass in either a string - | or an array, they are tried in order and the first match is used. + | These are the default namespaces where Lighthouse looks for classes to extend functionality of the schema. + | You may pass in either a string or an array, they are tried in order and the first match is used. | */ @@ -236,8 +232,7 @@ | Pagination |-------------------------------------------------------------------------- | - | Set defaults for the pagination features within Lighthouse, such as - | the @paginate directive, or paginated relation directives. + | Set defaults for the pagination features within Lighthouse, such as the @paginate directive, or paginated relation directives. | */ @@ -290,8 +285,8 @@ | Error Handlers |-------------------------------------------------------------------------- | - | Register error handlers that receive the Errors that occur during execution - | and handle them. You may use this to log, filter or format the errors. + | Register error handlers that receive the Errors that occur during execution and handle them. + | You may use this to log, filter or format the errors. | The classes must implement \Nuwave\Lighthouse\Execution\ErrorHandler | */ @@ -342,8 +337,7 @@ | Persisted Queries |-------------------------------------------------------------------------- | - | Lighthouse supports Automatic Persisted Queries (APQ), compatible with the - | [Apollo implementation](https://www.apollographql.com/docs/apollo-server/performance/apq). + | Lighthouse supports Automatic Persisted Queries (APQ), compatible with the [Apollo implementation](https://www.apollographql.com/docs/apollo-server/performance/apq). | You may set this flag to either process or deny these queries. | */ @@ -355,10 +349,8 @@ | Transactional Mutations |-------------------------------------------------------------------------- | - | If set to true, the execution of built-in directives that mutate models - | will be wrapped in a transaction to ensure atomicity. - | The transaction is committed after the root field resolves, - | thus errors in nested fields do not cause a rollback. + | If set to true, the execution of built-in directives that mutate models will be wrapped in a transaction to ensure atomicity. + | The transaction is committed after the root field resolves, thus errors in nested fields do not cause a rollback. | */ @@ -369,9 +361,8 @@ | Mass Assignment Protection |-------------------------------------------------------------------------- | - | If set to true, mutations will use forceFill() over fill() when populating - | a model with arguments in mutation directives. Since GraphQL constrains - | allowed inputs by design, mass assignment protection is not needed. + | If set to true, mutations will use forceFill() over fill() when populating a model with arguments in mutation directives. + | Since GraphQL constrains allowed inputs by design, mass assignment protection is not needed. | */ @@ -382,8 +373,7 @@ | Batchload Relations |-------------------------------------------------------------------------- | - | If set to true, relations marked with directives like @hasMany or @belongsTo - | will be optimized by combining the queries through the BatchLoader. + | If set to true, relations marked with directives like @hasMany or @belongsTo will be optimized by combining the queries through the BatchLoader. | */ @@ -394,9 +384,8 @@ | Shortcut Foreign Key Selection |-------------------------------------------------------------------------- | - | If set to true, Lighthouse will shortcut queries where the client selects only the - | foreign key pointing to a related model. Only works if the related model's primary - | key field is called exactly `id` for every type in your schema. + | If set to true, Lighthouse will shortcut queries where the client selects only the foreign key pointing to a related model. + | Only works if the related model's primary key field is called exactly `id` for every type in your schema. | */ @@ -407,8 +396,7 @@ | GraphQL Subscriptions |-------------------------------------------------------------------------- | - | Here you can define GraphQL subscription broadcaster and storage drivers - | as well their required configuration options. + | Here you can define GraphQL subscription broadcaster and storage drivers as well their required configuration options. | */ @@ -434,8 +422,8 @@ * Default subscription storage time to live in seconds. * * Indicates how long a subscription can stay active before automatic removal from storage. - * Setting this to `null` means the subscriptions are stored forever. This may cause - * stale subscriptions to linger indefinitely in case cleanup fails for any reason. + * Setting this to `null` means the subscriptions are stored forever. + * This may cause stale subscriptions to linger indefinitely in case cleanup fails for any reason. */ 'storage_ttl' => env('LIGHTHOUSE_SUBSCRIPTION_STORAGE_TTL', null), diff --git a/tests/Integration/LifecycleEventsTest.php b/tests/Integration/LifecycleEventsTest.php index 661fb763c5..0b977714c9 100644 --- a/tests/Integration/LifecycleEventsTest.php +++ b/tests/Integration/LifecycleEventsTest.php @@ -27,8 +27,7 @@ public function testDispatchesProperLifecycleEvents(): void $eventsDispatcher->listen('*', static function (string $name, array $payload) use (&$events): void { if (str_starts_with($name, 'Nuwave\\Lighthouse')) { - // We only fire class-based events, so the payload - // always holds exactly a single class instance. + // We only fire class-based events, so the payload always holds exactly a single class instance. $events[] = $payload[0]; } }); diff --git a/tests/Integration/Validation/RulesDirectiveTest.php b/tests/Integration/Validation/RulesDirectiveTest.php index ec3518be65..7d157bc7cd 100644 --- a/tests/Integration/Validation/RulesDirectiveTest.php +++ b/tests/Integration/Validation/RulesDirectiveTest.php @@ -230,8 +230,7 @@ public function testCustomAttributes(): void public function testBuiltInRuleNotShadowedByGlobalClassWithMatchingName(): void { - // Like a facade alias such as `URL` or intervention/image's `Image`, - // which matches the built-in rule case-insensitively once loaded. + // Like a facade alias such as `URL` or intervention/image's `Image`, which matches the built-in rule case-insensitively once loaded. // The container then resolves its `url` binding, the UrlGenerator. if (! class_exists('Url')) { class_alias((new class {})::class, 'Url'); diff --git a/tests/Integration/Validation/RulesForArrayDirectiveTest.php b/tests/Integration/Validation/RulesForArrayDirectiveTest.php index a4f2eb60d7..d21a056cb1 100644 --- a/tests/Integration/Validation/RulesForArrayDirectiveTest.php +++ b/tests/Integration/Validation/RulesForArrayDirectiveTest.php @@ -59,8 +59,7 @@ public function testValidatesListSizeOfInputObjects(): void public function testBuiltInRuleNotShadowedByGlobalClassWithMatchingName(): void { - // Like a facade alias such as `URL` or intervention/image's `Image`, - // which matches the built-in rule case-insensitively once loaded. + // Like a facade alias such as `URL` or intervention/image's `Image`, which matches the built-in rule case-insensitively once loaded. if (! class_exists('Filled')) { class_alias((new class {})::class, 'Filled'); } diff --git a/tests/TestCase.php b/tests/TestCase.php index a34686617c..b1506d0a96 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -55,8 +55,7 @@ protected function setUp(): void { parent::setUp(); - // This default is only valid for testing Lighthouse itself and thus - // is not defined in the reusable test trait. + // This default is only valid for testing Lighthouse itself and thus is not defined in the reusable test trait. $this->schema ??= self::PLACEHOLDER_QUERY; $this->setUpTestSchema(); diff --git a/tests/Unit/Execution/Arguments/ArgumentSetTest.php b/tests/Unit/Execution/Arguments/ArgumentSetTest.php index fe03fae3cf..dd7b5bf3c3 100644 --- a/tests/Unit/Execution/Arguments/ArgumentSetTest.php +++ b/tests/Unit/Execution/Arguments/ArgumentSetTest.php @@ -185,8 +185,8 @@ public function testAddValueWithWildcardSkipsWhenNestedContainerIsMissing(): voi $set = new ArgumentSet(); $set->addValue('tasks.create.*.user_id', 123); - // The intermediary `tasks` input is created just like plain dot notation would, - // but nothing is injected because `create` was never provided by the client. + // The intermediary `tasks` input is created like plain dot notation would. + // Nothing is injected, because the client never provided `create`. $this->assertTrue($set->exists('tasks')); $tasks = $set->arguments['tasks']->value; diff --git a/tests/Unit/Rector/RootResolverSignatureRector/bootstrap.php b/tests/Unit/Rector/RootResolverSignatureRector/bootstrap.php index 9d10e91167..d83aef68d7 100644 --- a/tests/Unit/Rector/RootResolverSignatureRector/bootstrap.php +++ b/tests/Unit/Rector/RootResolverSignatureRector/bootstrap.php @@ -15,8 +15,7 @@ require_once __DIR__ . '/../../../../vendor/larastan/larastan/bootstrap.php'; -// Undo handlers registered by Laravel's HandleExceptions bootstrapper -// to avoid PHPUnit risky test warnings about leaked handlers. +// Undo handlers registered by Laravel's HandleExceptions bootstrapper to avoid PHPUnit risky test warnings about leaked handlers. for ($i = 0; $i < 10; ++$i) { if (set_error_handler(static fn (mixed ...$args): bool => false) === $errorHandler) { restore_error_handler();