The Driver class is the gateway to much of the functionality of this library. It has many options and top-level functions, detailed here.
use ApiSkeletons\Doctrine\ORM\GraphQL\Config;
use ApiSkeletons\Doctrine\ORM\GraphQL\Driver;
use ApiSkeletons\Doctrine\ORM\GraphQL\Filter\Filters;
use ApiSkeletons\Doctrine\ORM\GraphQL\Type\JsonFormat;
$driver = new Driver($entityManager, new Config([
'batchAssociations' => true,
'batchLimit' => 1000,
'entityPrefix' => 'App\\ORM\\Entity\\',
'group' => 'customGroup',
'groupSuffix' => 'customGroupSuffix',
'extractByValue' => true,
'limit' => 500,
'sortFields' => true,
'useHydratorCache' => true,
'useNonNullTypes' => true,
'useQueryResultCache' => true,
'excludeFilters' => [Filters::CONTAINS],
'filterConditions' => 100,
'filterDepth' => 3,
'formatJsonAs' => JsonFormat::Object,
]);
The Driver takes a second, optional, argument of type
ApiSkeletons\Doctrine\ORM\GraphQL\Config. The constructor of Config takes
an array parameter. An unknown option, or a value of the wrong type or out of
range, throws ApiSkeletons\Doctrine\ORM\GraphQL\Exception\Configuration
naming the option.
The parameter options are:
When set to true, associations are loaded in batches rather than once for
each row. Default is true.
The unloaded to-one associations of a field are loaded with one query per entity class.
The identifiers of the rows of a one-to-many or many-to-many collection
field are fetched with one query for all the rows it is resolved for,
within the batchLimit. They give each row’s count and page, and one more
query loads only the entities on a page.
A query then costs a fixed number of queries however many rows it returns. The results are the same as without batching.
A collection is not batched when its association has an eventName, so its
QueryBuilder event is still dispatched for each row, or when
its source or target entity has a composite identifier, or an association as
its identifier, as a derived identity has.
The most row identifiers a batched collection field fetches with one query. When the rows of all the sources a collection field is resolved for number more than this, each source’s page is queried separately, and the rows are counted with one query only when a page needs the count. It must be at least 0; 0 queries each source’s page separately. Default is 1000.
This is a common namespace prefix for all entities in a group. When specified,
the entityPrefix such as, ‘App\ORM\Entity\’, will be stripped from driver name. So
App_ORM_Entity_Artist_groupName
becomes
Artist_groupName
See also groupSuffix
An array of filters to exclude from all available filters for all fields and associations for all entities.
This overrides the extractByValue entity attribute globally. When set to true
all hydrators will extract by value. When set to false all hydrators will
extract by reference. When not set the individual entity attribute value
is used and that is, by default, extract by value.
The most filters the branches of a filter’s _or may have
in all, including those of nested _or. A filter given null is not
counted, nor are a computed field’s args; neither are the filters outside
_or, so a filter without one is never limited. An in list is one
filter whatever its length. Beyond it, the query is a client error. It must
be at least 0; 0 or null is unlimited. Default is 100.
How deeply a filter’s _or may nest: an _or of the
filter is at depth 1, and an _or of one of its branches at depth 2.
Beyond it, the query is a client error. It must be at least 0; 0 or null
is unlimited. Default is 3.
GraphQL’s query depth and complexity rules count the fields a query selects, not its arguments, so they do not limit a filter.
How the Json scalar exchanges a JSON value with a client, a
ApiSkeletons\Doctrine\ORM\GraphQL\Type\JsonFormat case or its value.
JsonFormat::String, the default: as a string containing a JSON document,
such as "{\"to\":\"json\"}". A client decodes it, and sends a JSON value
as such a string.
JsonFormat::Object: as the value itself, such as {"to": "json"}. A
client sends a JSON value as a variable or as a GraphQL literal, such as
{ to: "json", tags: [1, 2] }.
It applies to every field, argument and input field of the Json type,
which includes the json, json_object, jsonb and jsonb_object
Doctrine types. With JsonFormat::Object, an empty PHP array is sent as
[], as PHP cannot tell an empty object from an empty list; a
json_object or jsonb_object field, which Doctrine reads as an object,
is sent as {}.
Each attribute has an optional group parameter that allows
for multiple configurations within the entities. Specify the group in the
Config to load only those attributes with the same group.
If no group is specified the group value is default.
By default, the group name is appended to GraphQL types. You may specify
a different suffix or an empty suffix. When used in combination with
entityPrefix your type names can be changed from
App_ORM_Entity_Artist_groupname
to
Artist
The most rows a connection returns, whatever pagination is requested. Use this to prevent abuse of GraphQL. It must be at least 1. Default is 1000. It caps each connection, not a query of nested connections; see Limiting Query Cost.
This is the default limit. An entity’s limit replaces it for queries of
that entity, and an association’s limit replaces both for that
association, even when larger. See attributes.
When entity types are created, and after the definition event, the fields will be sorted alphabetically when set to true. This can aid reading of the documentation created by GraphQL. The default is false.
When set to true hydrator results will be cached for as long as the entity
they were extracted from exists, thereby saving possible multiple extracts for
the same entity. An entity is normally kept by Doctrine until the entity
manager is cleared, so clear it between requests in a long running process.
Values of an entity changed after it was extracted are not seen until it is
freed. Default is false
When set to true, a field which always has a value is a non-null type in the
entity’s type: its identifier, a field whose column is not nullable, and a
to-one association on the owning side whose join columns are not nullable. So
performanceDate of a datetime column which is not nullable is
DateTime!. Default is false, and every field is nullable.
A field keeps a nullable type when its column or a join column is nullable, as a join column is by default, and so does the inverse side of a one-to-one association, a collection and a computed field. A field of a custom type is made non-null in the same way, unless its type already is. Input and filter types do not change.
A null value for a non-null field is an error, which GraphQL reports in the
result’s errors with null for the nearest nullable field above it. A
field’s value can be null although its column is not nullable when a hydrator
strategy returns null, when a property of an entity extracted by reference is
not initialized, or when a row’s join column refers to a row which does not
exist.
When set to true query results will be cached, thereby preventing duplicate database queries with identical SQL and parameters. This is particularly useful for:
Circular references in the graph
Queries accessing the same entity multiple times
Duplicate association queries
The results are entities of the entity manager, so the cache is cleared whenever the entity manager is cleared or flushed. A mutation that flushes therefore does not leave stale results. Clear the entity manager between requests in a long running process, or the cache, like the entity manager, keeps results from earlier requests. Changes made outside the entity manager, such as by another process, are not seen until the cache is cleared. The cache can also be cleared directly:
use ApiSkeletons\Doctrine\ORM\GraphQL\Cache\QueryResultCache;
$driver->get(QueryResultCache::class)->clear();
Performance benefits are most noticeable with complex, nested GraphQL queries that may execute the same database query multiple times.
Default is false
Note: This caches the query results, not the hydrated entities.
For entity caching, see useHydratorCache.
This is a short cut to using connection(), pagination(), resolve(), and filter(). There are three parameters:
Doctrine entity class name, required,
entityDefinitionEvent name, optional.
queryBuilderEvent name, optional.
use ApiSkeletons\Doctrine\ORM\GraphQL\Driver; $driver = new Driver($this->getEntityManager()); $schema = new Schema([ 'query' => new ObjectType([ 'name' => 'query', 'fields' => [ 'artists' => $driver->completeConnection(Artist::class), ], ]), ]);
The connection function returns a wrapper for an entity type. This wrapper,
in combination with the resolve and pagination functions, implements the
GraphQL Complete Connection Model.
You may pass a second parameter to the connection function to specify the
custom event name to fire for the entity definition event.
use ApiSkeletons\Doctrine\ORM\GraphQL\Driver; $driver = new Driver($this->getEntityManager()); $schema = new Schema([ 'query' => new ObjectType([ 'name' => 'query', 'fields' => [ 'artists' => [ 'type' => $driver->connection(Artist::class), 'args' => $driver->pagination(), 'resolve' => $driver->resolve(Artist::class), ], ], ]), ]);
This is a short cut to using dbalConnection(), pagination(), and dbalResolve(). There are two parameters:
A GraphQL ObjectType describing one row of the result, required,
A Doctrine\DBAL\Query\QueryBuilder, required.
use ApiSkeletons\Doctrine\ORM\GraphQL\Driver; $driver = new Driver($this->getEntityManager()); $queryBuilder = $entityManager->getConnection()->createQueryBuilder() ->select('id', 'name') ->from('artist') ->orderBy('name', 'ASC') ->addOrderBy('id', 'ASC'); $artistRow = new ObjectType([ 'name' => 'artistRow', 'fields' => [ 'id' => Type::int(), 'name' => Type::string(), ], ]); $schema = new Schema([ 'query' => new ObjectType([ 'name' => 'query', 'fields' => [ 'artistRows' => $driver->dbalCompleteConnection($artistRow, $queryBuilder), ], ]), ]);
These functions implement the GraphQL Complete Connection Model for a DBAL QueryBuilder. They are for queries which are not backed by an entity such as reports and aggregates.
The dbalConnection function takes a GraphQL ObjectType describing one
row of the result and returns that type wrapped in a connection. The
dbalResolve function takes a Doctrine\DBAL\Query\QueryBuilder and
returns the resolve closure for that connection. The pagination arguments
must be added to the args.
use ApiSkeletons\Doctrine\ORM\GraphQL\Driver; $driver = new Driver($this->getEntityManager()); $schema = new Schema([ 'query' => new ObjectType([ 'name' => 'query', 'fields' => [ 'artistRows' => [ 'type' => $driver->dbalConnection($artistRow), 'args' => $driver->pagination(), 'resolve' => $driver->dbalResolve($queryBuilder), ], ], ]), ]);
When the query is resolved the QueryBuilder is given the offset and limit
calculated from the pagination arguments. They replace any the QueryBuilder
was given with setFirstResult() and setMaxResults(), and the
totalCount counts the query without them, so a QueryBuilder’s own offset
and limit are ignored. To cap the rows of a query, such as a top ten, limit it
in the query itself, for example with a subquery, or use the pagination
arguments; the connection’s rows are also capped by the limit.
Each page is a separate query with its own offset, so the rows must be in the
same order every time the query runs. Give the QueryBuilder an ORDER BY
which orders every row, ending with a column or columns which are unique, such
as a primary key. A database returns rows in no particular order without an
ORDER BY, and in no particular order within a tie, so rows may be repeated
or skipped from one page to the next. An entity connection is ordered by its
identifier for this reason, but a DBAL query has no identifier the driver can
use.
Rows are returned as associative arrays so the fields of the given type are resolved by their column name or alias. Filters are not available because there is no entity metadata to build them from. The QueryBuilder is cloned for each resolution so it is not modified by a query.
The totalCount is computed by counting the rows of the QueryBuilder’s
query, without its offset, limit and ordering, as a subquery, so a query using
GROUP BY, DISTINCT or HAVING is counted by the rows it returns. As
for an entity connection, the rows are counted only when totalCount is
requested or a last or before argument needs the count.
The limit from the Config applies to these functions.
Based on the attribute configuration of an entity, this function adds a
filter argument to a connection. See filters for a list of
available filters per field. The args field must be filter.
Filters are applied to a connection. It is also possible to use them ad-hoc
as detailed in tips.
'args' => ['filter' => $driver->filter(Artist::class)] + $driver->pagination(),
This function creates an InputObjectType for the given entity. There are four parameters: The entity class name, an array of required fields, an array of optional fields, and an optional name for the type. See mutations.
This function returns GraphQL types for all Doctrine types, any custom types, and Doctrine entity types.
There are two type containers: TypeContainer and EntityTypeContainer.
Types from each of these containers are returned from this type() function.
See types for details on custom types and using the TypeContainer.
The EntityTypeContainer is used only for Doctrine entities and is populated
though the metadata. This class is used internally for generating ObjectType types for entities.
Though a connection is a type, it is not
available through this function. Use the connection function of the Driver.
This is documentation for API-Skeletons/doctrine-orm-graphql. Please add your ★ star to the project.