Type mapping
As explained in the queries section, the job of GraphQLite is to create GraphQL types from PHP types.
Scalar mapping
Scalar PHP types can be type-hinted to the corresponding GraphQL types:
string
int
bool
float
For instance:
namespace App\Controller;
use TheCodingMachine\GraphQLite\Annotations\Query;
class MyController
{
#[Query]
public function hello(string $name): string
{
return 'Hello ' . $name;
}
}
Class mapping
When returning a PHP class in a query, you must annotate this class using #[Type]
and #[Field]
attributes:
namespace App\Entities;
use TheCodingMachine\GraphQLite\Annotations\Field;
use TheCodingMachine\GraphQLite\Annotations\Type;
#[Type]
class Product
{
// ...
#[Field]
public function getName(): string
{
return $this->name;
}
#[Field]
public function getPrice(): ?float
{
return $this->price;
}
}
Note: The GraphQL output type name generated by GraphQLite is equal to the class name of the PHP class. So if your
PHP class is App\Entities\Product
, then the GraphQL type will be named "Product".
In case you have several types with the same class name in different namespaces, you will face a naming collision. Hopefully, you can force the name of the GraphQL output type using the "name" attribute:
#[Type(name: "MyProduct")]
class Product { /* ... */ }
#[Type]
attribute on a PHP interface to map your code to a GraphQL interface.Array mapping
You can type-hint against arrays (or iterators) as long as you add a detailed @return
statement in the PHPDoc.
/**
* @return User[] <=== we specify that the array is an array of User objects.
*/
#[Query]
public function users(int $limit, int $offset): array
{
// Some code that returns an array of "users".
}
ID mapping
GraphQL comes with a native ID
type. PHP has no such type.
There are two ways with GraphQLite to handle such type.
Force the outputType
#[Field(outputType: "ID")]
public function getId(): string
{
// ...
}
Using the outputType
attribute of the #[Field]
attribute, you can force the output type to ID
.
You can learn more about forcing output types in the custom types section.
ID class
use TheCodingMachine\GraphQLite\Types\ID;
#[Field]
public function getId(): ID
{
// ...
}
Note that you can also use the ID
class as an input type:
use TheCodingMachine\GraphQLite\Types\ID;
#[Mutation]
public function save(ID $id, string $name): Product
{
// ...
}
Date mapping
Out of the box, GraphQL does not have a DateTime
type, but we took the liberty to add one, with sensible defaults.
When used as an output type, DateTimeImmutable
or DateTimeInterface
PHP classes are
automatically mapped to this DateTime
GraphQL type.
#[Field]
public function getDate(): \DateTimeInterface
{
return $this->date;
}
The date
field will be of type DateTime
. In the returned JSON response to a query, the date is formatted as a string
in the ISO8601 format (aka ATOM format).
DateTime
type is not supported.Union types
Union types for return are supported in GraphQLite as of version 6.0:
#[Query]
public function companyOrContact(int $id): Company|Contact
{
// Some code that returns a company or a contact.
}
Enum types
PHP 8.1 introduced native support for Enums. GraphQLite now also supports native enums as of version 5.1.
#[Type]
enum Status: string
{
case ON = 'on';
case OFF = 'off';
case PENDING = 'pending';
}
/**
* @return User[]
*/
#[Query]
public function users(Status $status): array
{
if ($status === Status::ON) {
// Your logic
}
// ...
}
query users($status: Status!) {}
users(status: $status) {
id
}
}
By default, the name of the GraphQL enum type will be the name of the class. If you have a naming conflict (two classes
that live in different namespaces with the same class name), you can solve it using the name
property on the #[Type]
attribute:
namespace Model\User;
#[Type(name: "UserStatus")]
enum Status: string
{
// ...
}
Enum types with myclabs/php-enum
Prior to version 5.1, GraphQLite only supported Enums through the 3rd party library, myclabs/php-enum. If you'd like to use this implementation you'll first need to add this library as a dependency to your application.
$ composer require myclabs/php-enum
Now, any class extending the MyCLabs\Enum\Enum
class will be mapped to a GraphQL enum:
use MyCLabs\Enum\Enum;
class StatusEnum extends Enum
{
private const ON = 'on';
private const OFF = 'off';
private const PENDING = 'pending';
}
/**
* @return User[]
*/
#[Query]
public function users(StatusEnum $status): array
{
if ($status == StatusEnum::ON()) {
// Note that the "magic" ON() method returns an instance of the StatusEnum class.
// Also, note that we are comparing this instance using "==" (using "===" would fail as we have 2 different instances here)
// ...
}
// ...
}
query users($status: StatusEnum!) {}
users(status: $status) {
id
}
}
By default, the name of the GraphQL enum type will be the name of the class. If you have a naming conflict (two classes
that live in different namespaces with the same class name), you can solve it using the #[EnumType]
attribute:
use TheCodingMachine\GraphQLite\Annotations\EnumType;
#[EnumType(name: "UserStatus")]
class StatusEnum extends Enum
{
// ...
}
Deprecation of fields
You can mark a field as deprecated in your GraphQL Schema by just annotating it with the @deprecated
PHPDoc annotation. Note that a description (reason) is required for the annotation to be rendered.
namespace App\Entities;
use TheCodingMachine\GraphQLite\Annotations\Field;
use TheCodingMachine\GraphQLite\Annotations\Type;
#[Type]
class Product
{
// ...
#[Field]
public function getName(): string
{
return $this->name;
}
/**
* @deprecated use field `name` instead
*/
#[Field]
public function getProductName(): string
{
return $this->name;
}
}
This will add the @deprecated
directive to the field in the GraphQL Schema which sets the isDeprecated
field to true
and adds the reason to the deprecationReason
field in an introspection query. Fields marked as deprecated can still be queried, but will be returned in an introspection query only if includeDeprecated
is set to true
.
query {
__type(name: "Product") {
 fields(includeDeprecated: true) {
 name
 isDeprecated
 deprecationReason
 }
 }
}
Promise mapping
GraphQL includes a native \GraphQL\Deferred type.
You can map the return type by adding a detailed @return
statement in the PHPDoc.
An alternative to the @return
statement is using #[Field(outputType: SomeGQLType)]
.
All the previously mentioned mappings work with Promises, except when a return type is explicitly declared in the method signature.
This allows you to use \Overblog\DataLoader\DataLoader as an alternative for resolving N+1 query issues and caching intermediate results.
#[Type]
class Product
{
// ...
/**
* @return string
*/
#[Field]
public function getName(): Deferred
{
return new Deferred(fn() => $this->name);
}
#[Field(outputType: "Float")]
public function getPrice(): Deferred
{
return new Deferred(fn() => $this->price);
}
#[Field(outputType: "[String!]!")]
public function getCategories(#[Autowire('categoryDataLoader')] DataLoader $categoryDataLoader): SyncPromise
{
return $categoryDataLoader->load($this->id)->adoptedPromise;
}
}
More scalar types
Available in GraphQLite 4.0+GraphQL supports "custom" scalar types. GraphQLite supports adding more GraphQL scalar types.
If you need more types, you can check the GraphQLite Misc. Types library. It adds support for more scalar types out of the box in GraphQLite.
Or if you have some special needs, you can develop your own scalar types.