Skip to content

Commit 94f014f

Browse files
authored
Merge pull request #162 from magento-lynx/2.4-gl-graphql-v1
LYNX-258 & LYNX-259
2 parents 53769f6 + bac4885 commit 94f014f

File tree

7 files changed

+591
-40
lines changed

7 files changed

+591
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2023 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\Quote\Test\Fixture;
20+
21+
use Magento\Framework\DataObject;
22+
use Magento\Framework\Exception\InvalidArgumentException;
23+
use Magento\Quote\Api\CartRepositoryInterface;
24+
use Magento\Quote\Model\QuoteFactory;
25+
use Magento\Quote\Model\ResourceModel\Quote as QuoteResource;
26+
use Magento\TestFramework\Fixture\DataFixtureInterface;
27+
28+
/**
29+
* Mark cart as inactive
30+
*/
31+
class MakeCartInactive implements DataFixtureInterface
32+
{
33+
private const FIELD_CART_ID = 'cart_id';
34+
35+
/**
36+
* @var CartRepositoryInterface
37+
*/
38+
private CartRepositoryInterface $cartRepository;
39+
40+
/**
41+
* @var QuoteFactory
42+
*/
43+
private QuoteFactory $quoteFactory;
44+
45+
/**
46+
* @var QuoteResource
47+
*/
48+
private QuoteResource $quoteResource;
49+
50+
/**
51+
* @param CartRepositoryInterface $cartRepository
52+
* @param QuoteFactory $quoteFactory
53+
* @param QuoteResource $quoteResource
54+
*/
55+
public function __construct(
56+
CartRepositoryInterface $cartRepository,
57+
QuoteFactory $quoteFactory,
58+
QuoteResource $quoteResource
59+
) {
60+
$this->cartRepository = $cartRepository;
61+
$this->quoteFactory = $quoteFactory;
62+
$this->quoteResource = $quoteResource;
63+
}
64+
65+
/**
66+
* @param array $data
67+
* @return void
68+
* @throws InvalidArgumentException
69+
*/
70+
public function apply(array $data = []): ?DataObject
71+
{
72+
if (empty($data[self::FIELD_CART_ID])) {
73+
throw new InvalidArgumentException(__('"%field" is required', ['field' => self::FIELD_CART_ID]));
74+
}
75+
76+
$quote = $this->quoteFactory->create();
77+
$this->quoteResource->load($quote, $data[self::FIELD_CART_ID]);
78+
$quote->setIsActive(false);
79+
$this->cartRepository->save($quote);
80+
81+
return $quote;
82+
}
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2023 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\QuoteGraphQl\Model\Cart;
20+
21+
use Magento\Framework\Exception\NoSuchEntityException;
22+
use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException;
23+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
24+
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
25+
26+
/**
27+
* Validates a pre-defined masked quote id
28+
*/
29+
class ValidateMaskedQuoteId
30+
{
31+
/**
32+
* @var MaskedQuoteIdToQuoteIdInterface
33+
*/
34+
private MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId;
35+
36+
/**
37+
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
38+
*/
39+
public function __construct(
40+
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
41+
) {
42+
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
43+
}
44+
45+
/**
46+
* Validate masked id
47+
*
48+
* @param string $maskedId
49+
* @throws GraphQlAlreadyExistsException
50+
* @throws GraphQlInputException
51+
*/
52+
public function execute(string $maskedId): void
53+
{
54+
if (mb_strlen($maskedId) != 32) {
55+
throw new GraphQlInputException(__('Cart ID length should to be 32 symbols.'));
56+
}
57+
58+
if ($this->isQuoteWithSuchMaskedIdAlreadyExists($maskedId)) {
59+
throw new GraphQlAlreadyExistsException(__('Cart with ID "%1" already exists.', $maskedId));
60+
}
61+
}
62+
63+
/**
64+
* Check is quote with such maskedId already exists
65+
*
66+
* @param string $maskedId
67+
* @return bool
68+
*/
69+
private function isQuoteWithSuchMaskedIdAlreadyExists(string $maskedId): bool
70+
{
71+
try {
72+
$this->maskedQuoteIdToQuoteId->execute($maskedId);
73+
return true;
74+
} catch (NoSuchEntityException $e) {
75+
return false;
76+
}
77+
}
78+
}

app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php

+11-39
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@
77

88
namespace Magento\QuoteGraphQl\Model\Resolver;
99

10-
use Magento\Framework\Exception\NoSuchEntityException;
1110
use Magento\Framework\GraphQl\Config\Element\Field;
12-
use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException;
13-
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
1411
use Magento\Framework\GraphQl\Query\ResolverInterface;
1512
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1613
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
1714
use Magento\QuoteGraphQl\Model\Cart\CreateEmptyCartForCustomer;
1815
use Magento\QuoteGraphQl\Model\Cart\CreateEmptyCartForGuest;
16+
use Magento\QuoteGraphQl\Model\Cart\ValidateMaskedQuoteId;
1917

2018
/**
2119
* @inheritdoc
@@ -37,19 +35,27 @@ class CreateEmptyCart implements ResolverInterface
3735
*/
3836
private $maskedQuoteIdToQuoteId;
3937

38+
/**
39+
* @var ValidateMaskedQuoteId
40+
*/
41+
private ValidateMaskedQuoteId $validateMaskedQuoteId;
42+
4043
/**
4144
* @param CreateEmptyCartForCustomer $createEmptyCartForCustomer
4245
* @param CreateEmptyCartForGuest $createEmptyCartForGuest
4346
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
47+
* @param ValidateMaskedQuoteId $validateMaskedQuoteId
4448
*/
4549
public function __construct(
4650
CreateEmptyCartForCustomer $createEmptyCartForCustomer,
4751
CreateEmptyCartForGuest $createEmptyCartForGuest,
48-
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
52+
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
53+
ValidateMaskedQuoteId $validateMaskedQuoteId
4954
) {
5055
$this->createEmptyCartForCustomer = $createEmptyCartForCustomer;
5156
$this->createEmptyCartForGuest = $createEmptyCartForGuest;
5257
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
58+
$this->validateMaskedQuoteId = $validateMaskedQuoteId;
5359
}
5460

5561
/**
@@ -62,46 +68,12 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
6268
$predefinedMaskedQuoteId = null;
6369
if (isset($args['input']['cart_id'])) {
6470
$predefinedMaskedQuoteId = $args['input']['cart_id'];
65-
$this->validateMaskedId($predefinedMaskedQuoteId);
71+
$this->validateMaskedQuoteId->execute($predefinedMaskedQuoteId);
6672
}
6773

6874
$maskedQuoteId = (0 === $customerId || null === $customerId)
6975
? $this->createEmptyCartForGuest->execute($predefinedMaskedQuoteId)
7076
: $this->createEmptyCartForCustomer->execute($customerId, $predefinedMaskedQuoteId);
7177
return $maskedQuoteId;
7278
}
73-
74-
/**
75-
* Validate masked id
76-
*
77-
* @param string $maskedId
78-
* @throws GraphQlAlreadyExistsException
79-
* @throws GraphQlInputException
80-
*/
81-
private function validateMaskedId(string $maskedId): void
82-
{
83-
if (mb_strlen($maskedId) != 32) {
84-
throw new GraphQlInputException(__('Cart ID length should to be 32 symbols.'));
85-
}
86-
87-
if ($this->isQuoteWithSuchMaskedIdAlreadyExists($maskedId)) {
88-
throw new GraphQlAlreadyExistsException(__('Cart with ID "%1" already exists.', $maskedId));
89-
}
90-
}
91-
92-
/**
93-
* Check is quote with such maskedId already exists
94-
*
95-
* @param string $maskedId
96-
* @return bool
97-
*/
98-
private function isQuoteWithSuchMaskedIdAlreadyExists(string $maskedId): bool
99-
{
100-
try {
101-
$this->maskedQuoteIdToQuoteId->execute($maskedId);
102-
return true;
103-
} catch (NoSuchEntityException $e) {
104-
return false;
105-
}
106-
}
10779
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2023 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\QuoteGraphQl\Model\Resolver;
20+
21+
use Magento\Framework\GraphQl\Config\Element\Field;
22+
use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException;
23+
use Magento\Framework\GraphQl\Query\ResolverInterface;
24+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
25+
use Magento\Quote\Api\CartRepositoryInterface;
26+
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
27+
use Magento\QuoteGraphQl\Model\Cart\CreateEmptyCartForGuest;
28+
use Magento\QuoteGraphQl\Model\Cart\ValidateMaskedQuoteId;
29+
30+
/**
31+
* Creates a guest cart
32+
*/
33+
class CreateGuestCart implements ResolverInterface
34+
{
35+
/**
36+
* @var CreateEmptyCartForGuest
37+
*/
38+
private CreateEmptyCartForGuest $createEmptyCartForGuest;
39+
40+
/**
41+
* @var MaskedQuoteIdToQuoteIdInterface
42+
*/
43+
private MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId;
44+
45+
/**
46+
* @var CartRepositoryInterface
47+
*/
48+
private CartRepositoryInterface $cartRepository;
49+
50+
/**
51+
* @var ValidateMaskedQuoteId
52+
*/
53+
private ValidateMaskedQuoteId $validateMaskedQuoteId;
54+
55+
/**
56+
* @param CreateEmptyCartForGuest $createEmptyCartForGuest
57+
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
58+
* @param CartRepositoryInterface $cartRepository
59+
* @param ValidateMaskedQuoteId $validateMaskedQuoteId
60+
*/
61+
public function __construct(
62+
CreateEmptyCartForGuest $createEmptyCartForGuest,
63+
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
64+
CartRepositoryInterface $cartRepository,
65+
ValidateMaskedQuoteId $validateMaskedQuoteId
66+
) {
67+
$this->createEmptyCartForGuest = $createEmptyCartForGuest;
68+
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
69+
$this->cartRepository = $cartRepository;
70+
$this->validateMaskedQuoteId = $validateMaskedQuoteId;
71+
}
72+
73+
/**
74+
* @inheritdoc
75+
*/
76+
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
77+
{
78+
$customerId = $context->getUserId();
79+
80+
$predefinedMaskedQuoteId = null;
81+
if (isset($args['input']['cart_uid'])) {
82+
$predefinedMaskedQuoteId = $args['input']['cart_uid'];
83+
$this->validateMaskedQuoteId->execute($predefinedMaskedQuoteId);
84+
}
85+
86+
if ($customerId === 0 || $customerId === null) {
87+
$maskedQuoteId = $this->createEmptyCartForGuest->execute($predefinedMaskedQuoteId);
88+
$cartId = $this->maskedQuoteIdToQuoteId->execute($maskedQuoteId);
89+
$cart = $this->cartRepository->get($cartId);
90+
} else {
91+
throw new GraphQlAlreadyExistsException(
92+
__('Use `Query.customerCart` for logged in customer.')
93+
);
94+
}
95+
96+
return [
97+
'cart' => [
98+
'model' => $cart,
99+
],
100+
];
101+
}
102+
}

app/code/Magento/QuoteGraphQl/etc/schema.graphqls

+10-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ type Query {
88
}
99

1010
type Mutation {
11-
createEmptyCart(input: createEmptyCartInput @doc(description: "An optional input object that assigns the specified ID to the cart.")): String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Create an empty shopping cart for a guest or logged in user")
11+
createGuestCart(input: CreateGuestCartInput): CreateGuestCartOutput @doc(description: "Create a new shopping cart") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateGuestCart")
12+
createEmptyCart(input: createEmptyCartInput @doc(description: "An optional input object that assigns the specified ID to the cart.")): String @deprecated(reason: "Use `Mutation.createGuestCart` or `Query.customerCart` for logged in customer") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Create an empty shopping cart for a guest or logged in user")
1213
addSimpleProductsToCart(input: AddSimpleProductsToCartInput @doc(description: "An input object that defines which simple products to add to the cart.")): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more simple products to the specified cart. We recommend using `addProductsToCart` instead.")
1314
addVirtualProductsToCart(input: AddVirtualProductsToCartInput @doc(description: "An input object that defines which virtual products to add to the cart.")): AddVirtualProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more virtual products to the specified cart. We recommend using `addProductsToCart` instead.")
1415
applyCouponToCart(input: ApplyCouponToCartInput @doc(description: "An input object that defines the coupon code to apply to the cart.")): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") @doc(description:"Apply a pre-defined coupon code to the specified cart.")
@@ -29,6 +30,10 @@ type Mutation {
2930
addProductsToCart(cartId: String! @doc(description: "The cart ID of the shopper."), cartItems: [CartItemInput!]! @doc(description: "An array that defines the products to add to the cart.")): AddProductsToCartOutput @doc(description:"Add any type of product to the cart.") @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddProductsToCart")
3031
}
3132

33+
input CreateGuestCartInput {
34+
cart_uid: ID @doc(description: "Optional client-generated ID")
35+
}
36+
3237
input createEmptyCartInput @doc(description: "Assigns a specific `cart_id` to the empty cart.") {
3338
cart_id: String @doc(description: "The ID to assign to the cart.")
3439
}
@@ -186,6 +191,10 @@ type CartDiscount @doc(description: "Contains information about discounts applie
186191
label: [String!]! @doc(description: "The description of the discount.")
187192
}
188193

194+
type CreateGuestCartOutput {
195+
cart: Cart @doc(description: "The newly created cart.")
196+
}
197+
189198
type SetPaymentMethodOnCartOutput @doc(description: "Contains details about the cart after setting the payment method.") {
190199
cart: Cart! @doc(description: "The cart after setting the payment method.")
191200
}

0 commit comments

Comments
 (0)