Extending a type
In case you need to add fields to data types provided by another module (even OXID’s GraphQL modules) you can just use the Extending a type feature in GraphQLite.
Every data type can be extended via the @ExtendType
annotation multiple times, even in the same module.
Important
Types, Controllers, Services, … can not be extended through OXID’s module chain!
In case you wonder, see description about why we made classes final.
Extend the product type
Given that you have
a custom module that
adds a custom
subtitle
field to theoxarticle
database tableextends the
OxidEsales\Eshop\Application\Model\Article
model with asubtitle()
method
want this field exposed via the GraphQL API
have installed the
oxid-esales/graphql-storefront
module
Create the extend type
The @ExtendType
annotation has a class
argument which has to be the data type you want to extend. That being the PHP class with the @Type
annotation.
<?php
declare(strict_types=1);
namespace Full\Qualified\Namespace\Service;
use OxidEsales\GraphQL\Storefront\Product\DataType\Product;
use TheCodingMachine\GraphQLite\Annotations\Field;
use TheCodingMachine\GraphQLite\Annotations\ExtendType;
/**
* @ExtendType(class=Product::class)
*/
final class ProductExtendType
{
/**
* @Field()
*/
public function subtitle(Product $product): string
{
return $product->getEshopModel()->subtitle();
}
}
The first argument is always the class you are extending. When a client asks for your field, you’ll get the original data type and can then fetch the OXID eShop model from it in case needed.
This results in the following GraphQL schema
type Product {
id: ID!
# all other fields from data type
# ...
# plus now your field:
subtitle: String!
}
Register type
For GraphQLite to find your newly created extend type
it must be registered via the namespace mappers
getTypeNamespaceMapping()
needs to exist in the DI container and the container identifier MUST be the fully qualified class name
Namespace mapper
<?php
declare(strict_types=1);
namespace Full\Qualified\Namespace\Shared\Service;
use OxidEsales\GraphQL\Base\Framework\NamespaceMapperInterface;
final class NamespaceMapper implements NamespaceMapperInterface
{
public function getTypeNamespaceMapping(): array
{
return [
'\\Full\\Qualified\\Namespace\\Service' => __DIR__ . '/../../Service';
];
}
}
services.yaml
services:
Full\Qualified\Namespace\Service\ProductExtendType:
class: Full\Qualified\Namespace\Service\ProductExtendType
Full\Qualified\Namespace\Shared\Service\NamespaceMapper:
class: Full\Qualified\Namespace\Shared\Service\NamespaceMapper
tags: ['graphql_namespace_mapper']
Best practice
Try to withstand the urge to create another module for this case and integrate the GraphQL type mapping into your existing module. That way you do not end up with an invalid state when activating/deactivating a module. Otherwise you might deactivate the module that adds the subtitle()
method to the OxidEsales\Eshop\Application\Model\Article
class. The subtitle
field is still in your GraphQL schema, but requesting that field will result in a PHP Fatal Error.