diff --git a/implementations/php/composer.json b/implementations/php/composer.json index d16fa75dc..7593bca1f 100644 --- a/implementations/php/composer.json +++ b/implementations/php/composer.json @@ -2,8 +2,8 @@ "name": "apollo/php-implementation", "type": "project", "require": { - "webonyx/graphql-php": "^14.9", - "skillshare/apollo-federation-php": "^1.5" + "webonyx/graphql-php": "^14.11", + "skillshare/apollo-federation-php": "^1.6" }, "autoload": { "psr-4": { diff --git a/implementations/php/composer.lock b/implementations/php/composer.lock index 20655443c..85cb4e147 100644 --- a/implementations/php/composer.lock +++ b/implementations/php/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c12354097ba394904fa1842e150cd983", + "content-hash": "57d55804cbdc320f24d6bc24b7a3e347", "packages": [ { "name": "skillshare/apollo-federation-php", - "version": "v1.5", + "version": "v1.6", "source": { "type": "git", "url": "https://github.com/Skillshare/apollo-federation-php.git", - "reference": "2b418ba9c8d641df501b44e1876e9f91a12424d3" + "reference": "4f958ddb683c1fceb1d162f58a5dc2957e26fe5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Skillshare/apollo-federation-php/zipball/2b418ba9c8d641df501b44e1876e9f91a12424d3", - "reference": "2b418ba9c8d641df501b44e1876e9f91a12424d3", + "url": "https://api.github.com/repos/Skillshare/apollo-federation-php/zipball/4f958ddb683c1fceb1d162f58a5dc2957e26fe5d", + "reference": "4f958ddb683c1fceb1d162f58a5dc2957e26fe5d", "shasum": "" }, "require": { @@ -25,7 +25,7 @@ "webonyx/graphql-php": "^0.13.8 || ^14.0" }, "require-dev": { - "phpunit/phpunit": "^8.4", + "phpunit/phpunit": "^9.5", "psr/http-message": "^1.0", "react/promise": "^2.7", "spatie/phpunit-snapshot-assertions": "^4.2" @@ -43,39 +43,39 @@ "description": "A PHP port of the Apollo Federation specification.", "support": { "issues": "https://github.com/Skillshare/apollo-federation-php/issues", - "source": "https://github.com/Skillshare/apollo-federation-php/tree/v1.5" + "source": "https://github.com/Skillshare/apollo-federation-php/tree/v1.6" }, - "time": "2021-10-14T14:46:59+00:00" + "time": "2022-08-16T19:05:32+00:00" }, { "name": "webonyx/graphql-php", - "version": "v14.9.0", + "version": "v14.11.9", "source": { "type": "git", "url": "https://github.com/webonyx/graphql-php.git", - "reference": "36b83621deb5eae354347a2e86dc7aec81b32a82" + "reference": "ff91c9f3cf241db702e30b2c42bcc0920e70ac70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/36b83621deb5eae354347a2e86dc7aec81b32a82", - "reference": "36b83621deb5eae354347a2e86dc7aec81b32a82", + "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/ff91c9f3cf241db702e30b2c42bcc0920e70ac70", + "reference": "ff91c9f3cf241db702e30b2c42bcc0920e70ac70", "shasum": "" }, "require": { "ext-json": "*", "ext-mbstring": "*", - "php": "^7.1||^8.0" + "php": "^7.1 || ^8" }, "require-dev": { "amphp/amp": "^2.3", "doctrine/coding-standard": "^6.0", "nyholm/psr7": "^1.2", - "phpbench/phpbench": "^0.16.10", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "0.12.82", "phpstan/phpstan-phpunit": "0.12.18", "phpstan/phpstan-strict-rules": "0.12.9", - "phpunit/phpunit": "^7.2|^8.5", + "phpunit/phpunit": "^7.2 || ^8.5", "psr/http-message": "^1.0", "react/promise": "2.*", "simpod/php-coveralls-mirror": "^3.0", @@ -103,7 +103,7 @@ ], "support": { "issues": "https://github.com/webonyx/graphql-php/issues", - "source": "https://github.com/webonyx/graphql-php/tree/v14.9.0" + "source": "https://github.com/webonyx/graphql-php/tree/v14.11.9" }, "funding": [ { @@ -111,7 +111,7 @@ "type": "open_collective" } ], - "time": "2021-06-15T16:14:17+00:00" + "time": "2023-01-06T12:12:50+00:00" } ], "packages-dev": [], @@ -122,5 +122,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.3.0" } diff --git a/implementations/php/src/Data/CaseStudy.php b/implementations/php/src/Data/CaseStudy.php new file mode 100644 index 000000000..fc1ee5e9d --- /dev/null +++ b/implementations/php/src/Data/CaseStudy.php @@ -0,0 +1,19 @@ + 'support@apollographql.com', + 'name' => 'Jane Smith', + ]), + ]; + + self::$productResearch = [ + new ProductResearch([ + 'study' => new CaseStudy([ + 'caseNumber' => '1234', + 'description' => 'Federation Study', + ]), + ]), + new ProductResearch([ + 'study' => new CaseStudy([ + 'caseNumber' => '1235', + 'description' => 'Studio Study', + ]), + ]), + ]; + self::$products = [ new Product([ 'id' => 'apollo-federation', @@ -27,6 +52,14 @@ public static function init(): void 'variation' => 'platform', ]), ]; + + self::$deprecatedProducts = [ + new DeprecatedProduct([ + 'sku' => 'apollo-federation-v1', + 'package' => '@apollo/federation-v1', + 'reason' => 'Migrate to Federation V2', + ]), + ]; } public static function findProduct(string $id) { @@ -55,4 +88,38 @@ public static function findProductBySkuAndVariation(string $sku, string $variati return array_values($productsFound)[0] ?? null; } -} \ No newline at end of file + + public static function findDeprecatedProductBySkuAndPackage(string $sku, string $package) { + $deprecatedProductsFound = array_filter( + self::$deprecatedProducts, + static fn (DeprecatedProduct $product): bool => $product->sku === $sku && $product->package === $package + ); + + return array_values($deprecatedProductsFound)[0] ?? null; + } + + public static function findProductResearch(string $caseNumber) { + $researchFound = array_filter( + self::$productResearch, + static fn (ProductResearch $research): bool => $research->study->caseNumber === $caseNumber + ); + return array_values($researchFound)[0] ?? null; + } + + public static function findResearchForProduct(string $productId) { + $researchFound = array_filter( + self::$productResearch, + static fn (ProductResearch $research): bool => ($research->study->caseNumber === '1234' && $productId === 'apollo-federation') || ($research->study->caseNumber === '1235' && $productId === 'apollo-studio') + ); + return array_values($researchFound) ?? []; + } + + public static function findUser(string $email) { + $usersFound = array_filter( + self::$users, + static fn (User $user): bool => $user->email === $email + ); + + return array_values($usersFound)[0] ?? null; + } +} diff --git a/implementations/php/src/Data/DeprecatedProduct.php b/implementations/php/src/Data/DeprecatedProduct.php new file mode 100644 index 000000000..978e7a8f3 --- /dev/null +++ b/implementations/php/src/Data/DeprecatedProduct.php @@ -0,0 +1,21 @@ + 'CaseStudy', + 'fields' => [ + 'caseNumber' => [ 'type' => Types::nonNull(Types::id()) ], + 'description' => [ 'type' => Types::string() ] + ] + ]); + } +} diff --git a/implementations/php/src/Type/DeprecatedProductType.php b/implementations/php/src/Type/DeprecatedProductType.php new file mode 100644 index 000000000..9f7bad3b4 --- /dev/null +++ b/implementations/php/src/Type/DeprecatedProductType.php @@ -0,0 +1,51 @@ + 'DeprecatedProduct', + 'keyFields' => ['sku package'], + 'fields' => [ + 'sku' => [ 'type' => Types::nonNull(Types::string()) ], + 'package' => [ 'type' => Types::nonNull(Types::string()) ], + 'reason' => [ 'type' => Types::string() ], + 'createdBy' => [ + 'type' => Types::user(), + 'provides' => 'totalProductsCreated', + 'resolve' => static fn (): array => [ + 'email' => 'support@apollographql.com', + 'totalProductsCreated' => 1337, + ] + ], + ], + '__resolveReference' => function ($ref) { + $sku = $ref['sku']; + $package = $ref['package']; + + if ($sku !== null && $package !== null) { + return DataSource::findDeprecatedProductBySkuAndPackage($sku, $package); + } + }, + 'isTypeOf' => function ($value) { + if ($value instanceof DeprecatedProduct) { + return true; + } + }, + ]); + } + + static function getVariation(string $variation): array { + return [ 'id' => $variation ]; + } +} diff --git a/implementations/php/src/Type/ProductDimensionType.php b/implementations/php/src/Type/ProductDimensionType.php index b77c8c9b7..979474192 100644 --- a/implementations/php/src/Type/ProductDimensionType.php +++ b/implementations/php/src/Type/ProductDimensionType.php @@ -15,7 +15,8 @@ public function __construct() 'fields' => [ 'size' => [ 'type' => Types::string() ], 'weight' => [ 'type' => Types::float() ], + 'unit' => [ 'type' => Types::string() ] ] ]); } -} \ No newline at end of file +} diff --git a/implementations/php/src/Type/ProductResearchType.php b/implementations/php/src/Type/ProductResearchType.php new file mode 100644 index 000000000..af6d3d638 --- /dev/null +++ b/implementations/php/src/Type/ProductResearchType.php @@ -0,0 +1,37 @@ + 'ProductResearch', + 'keyFields' => ['study { caseNumber }'], + 'fields' => [ + 'study' => ['type' => Types::nonNull(Types::caseStudy())], + 'outcome' => [ 'type' => Types::string() ] + ], + '__resolveReference' => function ($ref) { + $study = $ref['study'] !== NULL ? $ref['study']['caseNumber'] : NULL; + + if($study !== null) { + return DataSource::findProductResearch($study); + } + }, + 'isTypeOf' => function ($value) { + if ($value instanceof ProductResearch) { + return true; + } + }, + ]); + } +} diff --git a/implementations/php/src/Type/ProductType.php b/implementations/php/src/Type/ProductType.php index 10157ebab..1455b23ec 100644 --- a/implementations/php/src/Type/ProductType.php +++ b/implementations/php/src/Type/ProductType.php @@ -35,28 +35,55 @@ public function __construct() 'resolve' => static fn (): array => [ 'size' => 'small', 'weight' => 1, + 'unit' => "kg" ] ], 'createdBy' => [ 'type' => Types::user(), 'provides' => 'totalProductsCreated', - 'resolve' => static fn (): array => [ + 'resolve' => static fn (): array => [ 'email' => 'support@apollographql.com', + 'name' => 'Jane Smith', 'totalProductsCreated' => 1337, ] + ], + 'notes' => [ 'type' => Types::string() ], + 'research' => [ + 'type' => Types::nonNull(Types::list(Types::nonNull(Types::productResearch()))), + 'resolve' => static function ($ref): array { + return DataSource::findResearchForProduct($ref->id); + } ] ], '__resolveReference' => function ($ref) { - $id = $ref['id']; - $sku = $ref['sku']; - $package = $ref['package']; - $variation = $ref['variation'] !== NULL ? $ref['variation']['id'] : NULL; + $id = NULL; + $sku = NULL; + $package = NULL; + $variation = NULL; + + if (array_key_exists('id', $ref)) { + $id = $ref['id']; + } + if (array_key_exists('sku', $ref)) { + $sku = $ref['sku']; + } + + if (array_key_exists('package', $ref)) { + $package = $ref['package']; + } + + if (array_key_exists('variation', $ref)) { + $tmp = $ref['variation']; + if (array_key_exists('id', $tmp)) { + $variation = $tmp['id']; + } + } if($id !== null) { return DataSource::findProduct($id); } else if ($sku !== null && $package !== null) { return DataSource::findProductBySkuAndPackage($sku, $package); - } else { + } else if ($sku !== null && $variation !== null) { return DataSource::findProductBySkuAndVariation($sku, $variation); } }, diff --git a/implementations/php/src/Type/QueryType.php b/implementations/php/src/Type/QueryType.php index 3c538f481..a762b6a65 100644 --- a/implementations/php/src/Type/QueryType.php +++ b/implementations/php/src/Type/QueryType.php @@ -24,7 +24,18 @@ public function __construct() return DataSource::findProduct($args['id']); } ], + 'deprecatedProduct' => [ + 'type' => Types::deprecatedProduct(), + 'args' => [ + 'sku' => Types::nonNull(Types::string()), + 'package' => Types::nonNull(Types::string()), + ], + 'deprecationReason' => 'Use product query instead', + 'resolve' => static function ($_, $args) { + return DataSource::findDeprecatedProductBySkuAndPackage($args['sku'], $args['package']); + } + ] ], ]); } -} \ No newline at end of file +} diff --git a/implementations/php/src/Type/UserType.php b/implementations/php/src/Type/UserType.php index 28a8b4d2d..44f7a1210 100644 --- a/implementations/php/src/Type/UserType.php +++ b/implementations/php/src/Type/UserType.php @@ -5,6 +5,8 @@ namespace GraphQL\Compatibility\Type; use GraphQL\Compatibility\Types; +use GraphQL\Compatibility\Data\User; +use GraphQL\Compatibility\Data\DataSource; use Apollo\Federation\Types\EntityRefObjectType; class UserType extends EntityRefObjectType { @@ -14,12 +16,47 @@ public function __construct() 'name' => 'User', 'keyFields' => [ 'email' ], 'fields' => [ + 'averageProductsCreatedPerYear' => [ + 'type' => Types::int(), + 'requires' => 'totalProductsCreated yearsOfEmployment', + 'resolve' => static function ($ref) { + if ($ref->totalProductsCreated !== null && $ref->yearsOfEmployment !== null) { + return round($ref->totalProductsCreated / $ref->yearsOfEmployment); + } + + return null; + } + ], 'email' => [ 'type' => Types::nonNull(Types::id()) ], + 'name' => [ 'type' => Types::string() ], 'totalProductsCreated' => [ 'type' => Types::int(), 'isExternal' => true ], - ] + 'yearsOfEmployment' => [ + 'type' => Types::nonNull(Types::int()), + 'isExternal' => true + ] + ], + '__resolveReference' => function ($ref) { + $email = $ref['email']; + if($email !== null) { + $user = DataSource::findUser($email); + if (array_key_exists('totalProductsCreated', $ref)) { + $user->{'totalProductsCreated'} = $ref['totalProductsCreated']; + } + + if (array_key_exists('yearsOfEmployment', $ref)) { + $user->{'yearsOfEmployment'} = $ref['yearsOfEmployment']; + } + return $user; + } + }, + 'isTypeOf' => function ($value) { + if ($value instanceof User) { + return true; + } + }, ]); } -} \ No newline at end of file +} diff --git a/implementations/php/src/Types.php b/implementations/php/src/Types.php index 3bdd509d3..e2ff39f14 100644 --- a/implementations/php/src/Types.php +++ b/implementations/php/src/Types.php @@ -10,10 +10,14 @@ use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\ScalarType; use GraphQL\Type\Definition\NonNull; +use GraphQL\Type\Definition\ListOfType; +use GraphQL\Compatibility\Type\CaseStudyType; +use GraphQL\Compatibility\Type\DeprecatedProductType; use GraphQL\Compatibility\Type\ProductType; use GraphQL\Compatibility\Type\ProductDimensionType; use GraphQL\Compatibility\Type\ProductVariationType; +use GraphQL\Compatibility\Type\ProductResearchType; use GraphQL\Compatibility\Type\UserType; use function class_exists; @@ -27,6 +31,16 @@ class Types { private static array $types = []; + public static function caseStudy(): callable + { + return static::get(CaseStudyType::class); + } + + public static function deprecatedProduct(): callable + { + return static::get(DeprecatedProductType::class); + } + public static function product(): callable { return static::get(ProductType::class); @@ -42,6 +56,11 @@ public static function productVariation(): callable return static::get(ProductVariationType::class); } + public static function productResearch(): callable + { + return static::get(ProductResearchType::class); + } + public static function user(): callable { return static::get(UserType::class); @@ -56,7 +75,7 @@ public static function id(): ScalarType { return Type::id(); } - + public static function int(): ScalarType { return Type::int(); @@ -72,6 +91,11 @@ public static function nonNull($type): NonNull return new NonNull($type); } + public static function list($type): ListOfType + { + return new ListOfType($type); + } + private static function get(string $classname): Closure { return static fn () => static::byClassName($classname); @@ -121,4 +145,4 @@ public static function byTypeName(string $shortName): Type return $type; } -} \ No newline at end of file +} diff --git a/implementations/php/src/server.php b/implementations/php/src/server.php index 538efc743..1ea787a84 100644 --- a/implementations/php/src/server.php +++ b/implementations/php/src/server.php @@ -18,6 +18,9 @@ use Apollo\Federation\FederatedSchema; +// turn off deprecation notices +error_reporting(E_ALL ^ E_DEPRECATED); + try { DataSource::init();