diff --git a/app/code/Magento/WishlistGraphQl/Model/Resolver/CustomerWishlistResolver.php b/app/code/Magento/WishlistGraphQl/Model/Resolver/CustomerWishlistResolver.php new file mode 100644 index 000000000000..e866b9cead03 --- /dev/null +++ b/app/code/Magento/WishlistGraphQl/Model/Resolver/CustomerWishlistResolver.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\WishlistGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Wishlist\Model\WishlistFactory; +use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; + +/** + * Fetches customer wishlist data + */ +class CustomerWishlistResolver implements ResolverInterface +{ + /** + * @var WishlistFactory + */ + private $wishlistFactory; + + /** + * @param WishlistFactory $wishlistFactory + */ + public function __construct(WishlistFactory $wishlistFactory) + { + $this->wishlistFactory = $wishlistFactory; + } + + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if (false === $context->getExtensionAttributes()->getIsCustomer()) { + throw new GraphQlAuthorizationException(__('The current customer isn\'t authorized.')); + } + $wishlist = $this->wishlistFactory->create()->loadByCustomerId($context->getUserId(), true); + return [ + 'id' => (string) $wishlist->getId(), + 'sharing_code' => $wishlist->getSharingCode(), + 'updated_at' => $wishlist->getUpdatedAt(), + 'items_count' => $wishlist->getItemsCount(), + 'model' => $wishlist, + ]; + } +} diff --git a/app/code/Magento/WishlistGraphQl/etc/module.xml b/app/code/Magento/WishlistGraphQl/etc/module.xml index 337623cc85a9..c2f5b3165b2a 100644 --- a/app/code/Magento/WishlistGraphQl/etc/module.xml +++ b/app/code/Magento/WishlistGraphQl/etc/module.xml @@ -6,5 +6,10 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_WishlistGraphQl" /> + <module name="Magento_WishlistGraphQl"> + <sequence> + <module name="Magento_Customer"/> + <module name="Magento_CustomerGraphQl"/> + </sequence> + </module> </config> diff --git a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls index 2aa5f03a787d..deaa66921ba7 100644 --- a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls +++ b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls @@ -2,13 +2,25 @@ # See COPYING.txt for license details. type Query { - wishlist: WishlistOutput @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistResolver") @doc(description: "The wishlist query returns the contents of a customer's wish list") @cache(cacheable: false) + wishlist: WishlistOutput @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistResolver") @deprecated(reason: "Moved under `Customer` `wishlist`") @doc(description: "The wishlist query returns the contents of a customer's wish list") @cache(cacheable: false) } -type WishlistOutput { +type Customer { + wishlist: Wishlist! @resolver(class:"\\Magento\\WishlistGraphQl\\Model\\Resolver\\CustomerWishlistResolver") @doc(description: "The wishlist query returns the contents of a customer's wish lists") @cache(cacheable: false) +} + +type WishlistOutput @doc(description: "Deprecated: `Wishlist` type should be used instead") { + items: [WishlistItem] @deprecated(reason: "Use field `items` from type `Wishlist` instead") @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistItemsResolver") @doc(description: "An array of items in the customer's wish list"), + items_count: Int @deprecated(reason: "Use field `items_count` from type `Wishlist` instead") @doc(description: "The number of items in the wish list"), + name: String @deprecated(reason: "This field is related to Commerce functionality and is always `null` in Open Source edition") @doc(description: "When multiple wish lists are enabled, the name the customer assigns to the wishlist"), + sharing_code: String @deprecated(reason: "Use field `sharing_code` from type `Wishlist` instead") @doc(description: "An encrypted code that Magento uses to link to the wish list"), + updated_at: String @deprecated(reason: "Use field `updated_at` from type `Wishlist` instead") @doc(description: "The time of the last modification to the wish list") +} + +type Wishlist { + id: ID @doc(description: "Wishlist unique identifier") items: [WishlistItem] @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\WishlistItemsResolver") @doc(description: "An array of items in the customer's wish list"), items_count: Int @doc(description: "The number of items in the wish list"), - name: String @doc(description: "When multiple wish lists are enabled, the name the customer assigns to the wishlist"), sharing_code: String @doc(description: "An encrypted code that Magento uses to link to the wish list"), updated_at: String @doc(description: "The time of the last modification to the wish list") } @@ -19,4 +31,4 @@ type WishlistItem { description: String @doc(description: "The customer's comment about this item"), added_at: String @doc(description: "The time when the customer added the item to the wish list"), product: ProductInterface @resolver(class: "\\Magento\\WishlistGraphQl\\Model\\Resolver\\ProductResolver") -} \ No newline at end of file +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/CustomerWishlistTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/CustomerWishlistTest.php new file mode 100644 index 000000000000..fbd9c53faf7f --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/CustomerWishlistTest.php @@ -0,0 +1,134 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Wishlist; + +use Magento\Integration\Api\CustomerTokenServiceInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\GraphQlAbstract; +use Magento\Wishlist\Model\Item; +use Magento\Wishlist\Model\ResourceModel\Wishlist\CollectionFactory; + +class CustomerWishlistTest extends GraphQlAbstract +{ + /** + * @var CustomerTokenServiceInterface + */ + private $customerTokenService; + + /** + * @var CollectionFactory + */ + private $wishlistCollectionFactory; + + protected function setUp() + { + $this->customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class); + $this->wishlistCollectionFactory = Bootstrap::getObjectManager()->get(CollectionFactory::class); + } + + /** + * @magentoApiDataFixture Magento/Wishlist/_files/wishlist.php + */ + public function testCustomerWishlist(): void + { + /** @var \Magento\Wishlist\Model\Wishlist $wishlist */ + $collection = $this->wishlistCollectionFactory->create()->filterByCustomerId(1); + + /** @var Item $wishlistItem */ + $wishlistItem = $collection->getFirstItem(); + $query = + <<<QUERY +{ + customer { + wishlist { + id + items_count + sharing_code + updated_at + items { + product { + sku + } + } + } + } +} +QUERY; + + $response = $this->graphQlQuery( + $query, + [], + '', + $this->getCustomerAuthHeaders('customer@example.com', 'password') + ); + $this->assertEquals((string)$wishlistItem->getId(), $response['customer']['wishlist']['id']); + $this->assertEquals($wishlistItem->getItemsCount(), $response['customer']['wishlist']['items_count']); + $this->assertEquals($wishlistItem->getSharingCode(), $response['customer']['wishlist']['sharing_code']); + $this->assertEquals($wishlistItem->getUpdatedAt(), $response['customer']['wishlist']['updated_at']); + $this->assertEquals('simple', $response['customer']['wishlist']['items'][0]['product']['sku']); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testCustomerAlwaysHasWishlist(): void + { + $query = + <<<QUERY +{ + customer { + wishlist { + id + } + } +} +QUERY; + + $response = $this->graphQlQuery( + $query, + [], + '', + $this->getCustomerAuthHeaders('customer@example.com', 'password') + ); + + $this->assertNotEmpty($response['customer']['wishlist']['id']); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage The current customer isn't authorized. + */ + public function testGuestCannotGetWishlist() + { + $query = + <<<QUERY +{ + customer { + wishlist { + items_count + sharing_code + updated_at + } + } +} +QUERY; + $this->graphQlQuery($query); + } + + /** + * @param string $email + * @param string $password + * @return array + * @throws \Magento\Framework\Exception\AuthenticationException + */ + private function getCustomerAuthHeaders(string $email, string $password): array + { + $customerToken = $this->customerTokenService->createCustomerAccessToken($email, $password); + return ['Authorization' => 'Bearer ' . $customerToken]; + } +}