Skip to content

Commit 77b636e

Browse files
committed
Mutation for adding bundled products to cart
Partial resolution for magento/graphlql-ce#143
1 parent 8b56ad0 commit 77b636e

File tree

8 files changed

+471
-0
lines changed

8 files changed

+471
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\BundleGraphQl\Model\Cart;
9+
10+
use Magento\Bundle\Helper\Catalog\Product\Configuration;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\Quote\Model\Quote\Item;
13+
use Magento\Framework\Pricing\Helper\Data;
14+
use Magento\Framework\Serialize\SerializerInterface;
15+
16+
class BundleOptionDataProvider
17+
{
18+
/**
19+
* @var Data
20+
*/
21+
private $pricingHelper;
22+
23+
/**
24+
* @var SerializerInterface
25+
*/
26+
private $serializer;
27+
28+
/**
29+
* @var Configuration
30+
*/
31+
private $configuration;
32+
33+
/**
34+
* @param Data $pricingHelper
35+
* @param SerializerInterface $serializer
36+
* @param Configuration $configuration
37+
*/
38+
public function __construct(
39+
Data $pricingHelper,
40+
SerializerInterface $serializer,
41+
Configuration $configuration
42+
) {
43+
$this->pricingHelper = $pricingHelper;
44+
$this->serializer = $serializer;
45+
$this->configuration = $configuration;
46+
}
47+
48+
/**
49+
* @param Item $item
50+
* @return array
51+
*/
52+
public function getData(Item $item): array
53+
{
54+
$options = [];
55+
$product = $item->getProduct();
56+
57+
/** @var \Magento\Bundle\Model\Product\Type $typeInstance */
58+
$typeInstance = $product->getTypeInstance();
59+
60+
$optionsQuoteItemOption = $item->getOptionByCode('bundle_option_ids');
61+
$bundleOptionsIds = $optionsQuoteItemOption
62+
? $this->serializer->unserialize($optionsQuoteItemOption->getValue())
63+
: [];
64+
65+
if ($bundleOptionsIds) {
66+
/** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */
67+
$optionsCollection = $typeInstance->getOptionsByIds($bundleOptionsIds, $product);
68+
69+
$selectionsQuoteItemOption = $item->getOptionByCode('bundle_selection_ids');
70+
71+
$bundleSelectionIds = $this->serializer->unserialize($selectionsQuoteItemOption->getValue());
72+
73+
if (!empty($bundleSelectionIds)) {
74+
$selectionsCollection = $typeInstance->getSelectionsByIds($bundleSelectionIds, $product);
75+
$bundleOptions = $optionsCollection->appendSelections($selectionsCollection, true);
76+
77+
$options = $this->buildBundleOptions($bundleOptions, $item);
78+
}
79+
}
80+
81+
return $options;
82+
}
83+
84+
/**
85+
* @param \Magento\Bundle\Model\Option[] $bundleOptions
86+
* @param Item $item
87+
* @return array
88+
*/
89+
private function buildBundleOptions(array $bundleOptions, Item $item): array
90+
{
91+
$options = [];
92+
foreach ($bundleOptions as $bundleOption) {
93+
if (!$bundleOption->getSelections()) {
94+
continue;
95+
}
96+
97+
$options[] = [
98+
'id' => $bundleOption->getId(),
99+
'label' => $bundleOption->getTitle(),
100+
'type' => $bundleOption->getType(),
101+
'values' => $this->buildBundleOptionValues($bundleOption->getSelections(), $item),
102+
];
103+
}
104+
105+
return $options;
106+
}
107+
108+
/**
109+
* @param Product[] $selections
110+
* @param Item $item
111+
* @return array
112+
*/
113+
private function buildBundleOptionValues(array $selections, Item $item): array
114+
{
115+
$values = [];
116+
117+
$product = $item->getProduct();
118+
foreach ($selections as $selection) {
119+
$qty = (float) $this->configuration->getSelectionQty($product, $selection->getSelectionId());
120+
if (!$qty) {
121+
continue;
122+
}
123+
124+
$selectionPrice = $this->configuration->getSelectionFinalPrice($item, $selection);
125+
126+
$values[] = [
127+
'id' => $selection->getSelectionId(),
128+
'label' => $selection->getName(),
129+
'quantity' => $qty,
130+
'price' => $this->pricingHelper->currency($selectionPrice, false, false),
131+
];
132+
}
133+
134+
return $values;
135+
}
136+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\BundleGraphQl\Model\Cart\BuyRequest;
9+
10+
use Magento\Framework\Stdlib\ArrayManager;
11+
use Magento\QuoteGraphQl\Model\Cart\BuyRequest\BuyRequestDataProviderInterface;
12+
13+
class BundleDataProvider implements BuyRequestDataProviderInterface
14+
{
15+
/**
16+
* @var ArrayManager
17+
*/
18+
private $arrayManager;
19+
20+
/**
21+
* @param ArrayManager $arrayManager
22+
*/
23+
public function __construct(
24+
ArrayManager $arrayManager
25+
) {
26+
$this->arrayManager = $arrayManager;
27+
}
28+
29+
/**
30+
* @inheritdoc
31+
*/
32+
public function execute(array $cartItemData): array
33+
{
34+
$bundleOptions = [];
35+
$bundleInputs = $this->arrayManager->get('bundle_options', $cartItemData) ?? [];
36+
foreach ($bundleInputs as $bundleInput) {
37+
$bundleOptions['bundle_option'][$bundleInput['id']] = $bundleInput['value'];
38+
$bundleOptions['bundle_option_qty'][$bundleInput['id']] = $bundleInput['quantity'];
39+
}
40+
41+
return $bundleOptions;
42+
}
43+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\BundleGraphQl\Model\Resolver;
9+
10+
use Magento\BundleGraphQl\Model\Cart\BundleOptionDataProvider;
11+
use Magento\Framework\GraphQl\Config\Element\Field;
12+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
13+
use Magento\Framework\GraphQl\Query\ResolverInterface;
14+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
15+
16+
class BundleOption implements ResolverInterface
17+
{
18+
/**
19+
* @var BundleOptionDataProvider
20+
*/
21+
private $dataProvider;
22+
23+
/**
24+
* @param BundleOptionDataProvider $bundleOptionDataProvider
25+
*/
26+
public function __construct(
27+
BundleOptionDataProvider $bundleOptionDataProvider
28+
) {
29+
$this->dataProvider = $bundleOptionDataProvider;
30+
}
31+
32+
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
33+
{
34+
if (!isset($value['model'])) {
35+
throw new GraphQlInputException(__('Value must contain "model" property.'));
36+
}
37+
return $this->dataProvider->getData($value['model']);
38+
}
39+
}

app/code/Magento/BundleGraphQl/composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"magento/module-catalog": "*",
88
"magento/module-bundle": "*",
99
"magento/module-catalog-graph-ql": "*",
10+
"magento/module-quote": "*",
11+
"magento/module-quote-graph-ql": "*",
1012
"magento/module-store": "*",
1113
"magento/framework": "*"
1214
},

app/code/Magento/BundleGraphQl/etc/di.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,11 @@
1616
</argument>
1717
</arguments>
1818
</type>
19+
<type name="Magento\QuoteGraphQl\Model\Resolver\CartItemTypeResolver">
20+
<arguments>
21+
<argument name="supportedTypes" xsi:type="array">
22+
<item name="bundle" xsi:type="string">BundleCartItem</item>
23+
</argument>
24+
</arguments>
25+
</type>
1926
</config>

app/code/Magento/BundleGraphQl/etc/graphql/di.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
</argument>
1414
</arguments>
1515
</type>
16+
<type name="Magento\QuoteGraphQl\Model\Cart\BuyRequest\BuyRequestBuilder">
17+
<arguments>
18+
<argument name="providers" xsi:type="array">
19+
<item name="bundle" xsi:type="object">Magento\BundleGraphQl\Model\Cart\BuyRequest\BundleDataProvider</item>
20+
</argument>
21+
</arguments>
22+
</type>
1623
<type name="Magento\Framework\GraphQl\Schema\Type\Enum\DefaultDataMapper">
1724
<arguments>
1825
<argument name="map" xsi:type="array">

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,50 @@
11
# Copyright © Magento, Inc. All rights reserved.
22
# See COPYING.txt for license details.
33

4+
type Mutation {
5+
addBundleProductsToCart(input: AddBundleProductsToCartInput): AddBundleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart")
6+
}
7+
8+
input AddBundleProductsToCartInput {
9+
cart_id: String!
10+
cartItems: [BundleProductCartItemInput!]!
11+
}
12+
13+
input BundleProductCartItemInput {
14+
data: CartItemInput!
15+
bundle_options:[BundleOptionInput!]!
16+
customizable_options:[CustomizableOptionInput!]
17+
}
18+
19+
input BundleOptionInput {
20+
id: Int!
21+
quantity: Float!
22+
value: [String!]!
23+
}
24+
25+
type AddBundleProductsToCartOutput {
26+
cart: Cart!
27+
}
28+
29+
type BundleCartItem implements CartItemInterface {
30+
customizable_options: [SelectedCustomizableOption]! @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CustomizableOptions")
31+
bundle_options: [SelectedBundleOption!]! @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\BundleOption")
32+
}
33+
34+
type SelectedBundleOption {
35+
id: Int!
36+
label: String!
37+
type: String!
38+
values: [SelectedBundleOptionValue!]!
39+
}
40+
41+
type SelectedBundleOptionValue {
42+
id: Int!
43+
label: String!
44+
quantity: Float!
45+
price: Float!
46+
}
47+
448
type BundleItem @doc(description: "BundleItem defines an individual item in a bundle product") {
549
option_id: Int @doc(description: "An ID assigned to each type of item in a bundle product")
650
title: String @doc(description: "The display name of the item")

0 commit comments

Comments
 (0)