aimeos-laravel icon indicating copy to clipboard operation
aimeos-laravel copied to clipboard

Lighthouse-php GraphQL compatibility?

Open binaryfire opened this issue 3 years ago • 3 comments

Hi guys

Will the Laravel Aimeos package work with the lighthouse-php GraphQL package?

Thanks!

binaryfire avatar Oct 11 '21 03:10 binaryfire

Lighthouse-php requires Eloquent models which we don't use for performance reasons. Thus, the package isn't compatible with Aimeos if you don't implement models for the tables Aimeos is using.

GraphQL is very good for write-heavy applications but as frontend for read-heavy e-commerce applications it's not suited and we recommend the JSON:API which scales infinitely compared to GraphQL.

aimeos avatar Oct 11 '21 06:10 aimeos

@aimeos Sorry, just to clarify, this would be used for a custom admin panel. Not for the storefront API.

GraphQL could be quite good for this use case :)

binaryfire avatar Oct 11 '21 07:10 binaryfire

Yes, for the admin backend we are already working on a GraphQL interface. We've already played around with graphql-php package (https://webonyx.github.io/graphql-php/) to test the best way for relations and filtering but we lack some time at the moment. If you want to help, you are heartly invited to join :-)

<?php

require_once( '../vendor/autoload.php' );


use GraphQL\GraphQL;
use GraphQL\Type\Schema;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\InputObjectField;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;


class Registry
{
	private $types = [];
	private $resolve = [];
	private $args = [];


	public function add( $name, $type, $args, $resolve ) : self
	{
		$this->resolve[$name] = $resolve;
		$this->types[$name] = $type;
		$this->args[$name] = $args;

		return $this;
	}


	public function type( $name ) : ?Type
	{
		return $this->types[$name] ?? null;
	}


	public function args( $name ) : array
	{
		return $this->args[$name] ?? [];
	}


	public function resolve( $name ) : ?callable
	{
		return $this->resolve[$name] ?? null;
	}
}

$registry = new Registry();
$types = $support = [];

$support['media'] =  [
	'type' => new ObjectType( [
		'name' => 'media',
		'fields' => function() use ( $registry ) {
			return [
				'id' => Type::string(),
				'siteid' => Type::string(),
				'domain' => Type::string(),
				'type' => Type::string(),
				'url' => Type::string(),
				'preview' => Type::string(),
				'previews' => Type::listOf( new ObjectType( [
					'name' => 'previews',
					'fields' => [
						'width' => Type::int(),
						'url' => Type::string()
					],
					'resolveField' => function( $entry, $args, $context, ResolveInfo $info ) {
						switch( $info->fieldName ) {
							case 'width': return key( $entry );
							case 'url': return current( $entry );
						}
						return null;
					}
				] ) ),
				'status' => Type::int(),
				'ctime' => Type::string(),
				'mtime' => Type::string(),
				'editor' => Type::string(),
			];
		},
		'resolveField' => function( $mediaItem, $args, $context, ResolveInfo $info ) {
			// return $mediaItem->get( 'media.' . $info->fieldName );
			return $mediaItem['media.' . $info->fieldName] ?? null;
		}
	] ),
	'args' => [
		'type' => Type::string(),
	],
	'resolve' => function( $listItem, $args, $context, ResolveInfo $info ) {
		// return $listItem->getRefItem();
		return $listItem['media'] ?? [];
	}
];

$support['lists'] = [
	'type' => Type::listOf( new ObjectType( [
		'name' => 'lists',
		'fields' => function() use ( $registry ) {
			return [
				'id' => Type::string(),
				'siteid' => Type::string(),
				'domain' => Type::string(),
				'type' => Type::string(),
				'refid' => Type::string(),
				'datestart' => Type::string(),
				'dateend' => Type::string(),
				'status' => Type::int(),
				'ctime' => Type::string(),
				'mtime' => Type::string(),
				'editor' => Type::string(),
				'media' => [
					'type' => $registry->type( 'media' ),
					'args' => $registry->args( 'media' ),
					'resolve' => $registry->resolve( 'media' ),
				]
			];
		},
		'resolveField' => function( $listItem, $args, $context, ResolveInfo $info ) {
			$prefix = join( '.', array_slice( $info->path, -4, 2 ) );
			// return $listItem->get( $prefix . '.' . $info->fieldName );
			return $listItem[$prefix . '.' . $info->fieldName] ?? null;
		}
	] ) ),
	'args' => [
		'domain' => Type::string(),
		'type' => Type::string(),
	],
	'resolve' => function( $item, $args, $context, ResolveInfo $info ) {
		// return $item->getListItems()
		return $item['lists'] ?? [];
	}
];

$types['product'] = [
	'type' => new ObjectType( [
		'name' => 'product',
		'fields' => function() use ( $registry ) {
			return [
				['name' => 'id', 'type' => Type::string(), 'description' => 'Unique ID'],
				'siteid' => Type::string(),
				'code' => Type::string(),
				'label' => Type::string(),
				'datestart' => Type::string(),
				'dateend' => Type::string(),
				'status' => Type::int(),
				'ctime' => Type::string(),
				'mtime' => Type::string(),
				'editor' => Type::string(),
				'rating' => Type::string(),
				'ratings' => Type::int(),
				'lists' => [
					'type' => $registry->type( 'lists' ),
					'args' => $registry->args( 'lists' ),
					'resolve' => $registry->resolve( 'lists' )
				]
			];
		},
		'resolveField' => function( $productItem, $args, $context, ResolveInfo $info ) {
			// return $productItem->get( $info->parentType->name . '.' . $info->fieldName );
			return $productItem[$info->parentType->name . '.' . $info->fieldName] ?? null;
		}
	] ),
	'args' => [
		['name' => 'filter', 'type' => Type::string(), 'defaultValue' => '{}', 'description' => 'Filter description'],
		['name' => 'include', 'type' => Type::string(), 'defaultValue' => '{}', 'description' => 'Include description'],
		['name' => 'sort', 'type' => Type::listOf(Type::string()), 'defaultValue' => [], 'description' => 'Sort description'],
		['name' => 'offset', 'type' => Type::int(), 'defaultValue' => 0, 'description' => 'Offset description'],
		['name' => 'limit', 'type' => Type::int(), 'defaultValue' => 0, 'description' => 'Limit description'],
	],
	'resolve' => function( $root, $args, $context, ResolveInfo $info ) {
		return [
			'product.id' => '1',
			'product.siteid' => '1.',
			'product.code' => 'test',
			'product.label' => 'Test product',
			'product.datestart' => null,
			'product.dateend' => null,
			'product.status' => 0,
			'product.ctime' => '2000-01-01 00:00:00',
			'product.mtime' => '2000-01-01 00:00:00',
			'product.editor' => 'aimeos',
			'product.rating' => '5.00',
			'product.ratings' => 1,
			'lists' => [[
				'product.lists.id' => '1',
				'product.lists.siteid' => '1.',
				'product.lists.domain' => 'media',
				'product.lists.type' => 'default',
				'product.lists.refid' => '123',
				'product.lists.datestart' => null,
				'product.lists.dateend' => null,
				'product.lists.status' => 1,
				'product.lists.ctime' => '2000-01-01 00:00:00',
				'product.lists.mtime' => '2000-01-01 00:00:00',
				'product.lists.editor' => 'aimeos',
				'media' => [
					'media.id' => '1',
					'media.siteid' => '1.',
					'media.domain' => 'media',
					'media.type' => 'default',
					'media.url' => 'path/to/image1.jpg',
					'media.preview' => 'path/to/image2.jpg',
					'media.previews' => [
						[250 => 'path/to/image3.jpg'],
						[500 => 'path/to/image4.jpg'],
					],
					'media.status' => 1,
					'media.ctime' => '2000-01-01 00:00:00',
					'media.mtime' => '2000-01-01 00:00:00',
					'media.editor' => 'aimeos',
				]
			]]
		];
	}
];

foreach( $support as $name => $entry) {
	$registry->add( $name, $entry['type'], $entry['args'] ?? [], $entry['resolve'] ?? null );
}

foreach( $types as $name => $entry) {
	$registry->add( $name, $entry['type'], $entry['args'] ?? [], $entry['resolve'] ?? null );
}


$schema = new Schema([
    'query' => new ObjectType( [
		'name' => 'query',
		'fields' => $types
	] ),
]);

try
{
	$rawInput = file_get_contents('php://input');

	$input = json_decode($rawInput, true);
	$query = $input['query'] ?? null;
	$root = [];
	$context = null;
	$variableValues = $input['variables'] ?? null;
	$operationName = $input['operationName'] ?? null;

	$output = GraphQL::executeQuery( $schema, $query, $root, $context, $variableValues, $operationName )->toArray();
}
catch (\Exception $e)
{
	$output = [
		'errors' => [[
			'message' => $e->getMessage()
		]]
	];
}

header('Content-Type: application/json');
echo json_encode($output);

aimeos avatar Oct 11 '21 07:10 aimeos

A GraphQL API for administration is now included in Aimeos 2022.10.1+

aimeos avatar Oct 13 '22 08:10 aimeos