Skip to content

Commit 3c6b65e

Browse files
authored
Merge branch '2.4-develop' into MCP-412
2 parents a127c71 + ccdb2a7 commit 3c6b65e

File tree

24 files changed

+779
-4925
lines changed

24 files changed

+779
-4925
lines changed

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/AttributeOptionProvider.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public function getOptions(array $optionIds, ?int $storeId, array $attributeCode
6363
'attribute_id' => 'a.attribute_id',
6464
'attribute_code' => 'a.attribute_code',
6565
'attribute_label' => 'a.frontend_label',
66+
'position' => 'attribute_configuration.position'
6667
]
6768
)
6869
->joinLeft(
@@ -72,6 +73,11 @@ public function getOptions(array $optionIds, ?int $storeId, array $attributeCode
7273
'attribute_store_label' => 'attribute_label.value',
7374
]
7475
)
76+
->joinLeft(
77+
['attribute_configuration' => $this->resourceConnection->getTableName('catalog_eav_attribute')],
78+
'a.attribute_id = attribute_configuration.attribute_id',
79+
[]
80+
)
7581
->joinLeft(
7682
['options' => $this->resourceConnection->getTableName('eav_attribute_option')],
7783
'a.attribute_id = options.attribute_id',
@@ -131,6 +137,7 @@ private function formatResult(Select $select): array
131137
'attribute_code' => $option['attribute_code'],
132138
'attribute_label' => $option['attribute_store_label']
133139
? $option['attribute_store_label'] : $option['attribute_label'],
140+
'position' => $option['position'],
134141
'options' => [],
135142
];
136143
}

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Builder/Attribute.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ public function build(AggregationInterface $aggregation, ?int $storeId): array
8383
$result[$bucketName] = $this->layerFormatter->buildLayer(
8484
$attribute['attribute_label'] ?? $bucketName,
8585
\count($bucket->getValues()),
86-
$attribute['attribute_code'] ?? $bucketName
86+
$attribute['attribute_code'] ?? $bucketName,
87+
isset($attribute['position']) ? $attribute['position'] : null
8788
);
8889

89-
$options = $this->getSortedOptions($bucket,$attribute['options'] ?: []);
90+
$options = $this->getSortedOptions($bucket, isset($attribute['options']) ? $attribute['options'] : []);
9091
foreach ($options as $option) {
9192
$result[$bucketName]['options'][] = $this->layerFormatter->buildItem(
9293
$option['label'],

app/code/Magento/CatalogGraphQl/DataProvider/Product/LayeredNavigation/Formatter/LayerFormatter.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@ class LayerFormatter
1818
* @param string $layerName
1919
* @param string $itemsCount
2020
* @param string $requestName
21+
* @param int $position
2122
* @return array
2223
*/
23-
public function buildLayer($layerName, $itemsCount, $requestName): array
24+
public function buildLayer($layerName, $itemsCount, $requestName, $position = null): array
2425
{
2526
return [
2627
'label' => $layerName,
2728
'count' => $itemsCount,
28-
'attribute_code' => $requestName
29+
'attribute_code' => $requestName,
30+
'position' => isset($position) ? (int)$position : null
2931
];
3032
}
3133

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ type Aggregation @doc(description: "A bucket that contains information for each
474474
label: String @doc(description: "The aggregation display name.")
475475
attribute_code: String! @doc(description: "Attribute code of the aggregation group.")
476476
options: [AggregationOption] @doc(description: "Array of options for the aggregation.")
477+
position: Int @doc(description: "The relative position of the attribute in a layered navigation block")
477478
}
478479

479480
interface AggregationOptionInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\\AggregationOptionTypeResolverComposite") {

app/code/Magento/EavGraphQl/Model/Resolver/CustomAttributeMetadata.php

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99

1010
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1111
use Magento\EavGraphQl\Model\Resolver\Query\Type;
12-
use Magento\EavGraphQl\Model\Resolver\Query\FrontendType;
12+
use Magento\EavGraphQl\Model\Resolver\Query\Attribute;
1313
use Magento\Framework\Exception\InputException;
1414
use Magento\Framework\Exception\LocalizedException;
1515
use Magento\Framework\GraphQl\Config\Element\Field;
1616
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
1717
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
1818
use Magento\Framework\GraphQl\Query\ResolverInterface;
19+
use Magento\Eav\Api\Data\AttributeInterface;
1920

2021
/**
2122
* Resolve data for custom attribute metadata requests
@@ -28,18 +29,18 @@ class CustomAttributeMetadata implements ResolverInterface
2829
private $type;
2930

3031
/**
31-
* @var FrontendType
32+
* @var Attribute
3233
*/
33-
private $frontendType;
34+
private $attribute;
3435

3536
/**
3637
* @param Type $type
37-
* @param FrontendType $frontendType
38+
* @param Attribute $attribute
3839
*/
39-
public function __construct(Type $type, FrontendType $frontendType)
40+
public function __construct(Type $type, Attribute $attribute)
4041
{
4142
$this->type = $type;
42-
$this->frontendType = $frontendType;
43+
$this->attribute = $attribute;
4344
}
4445

4546
/**
@@ -54,27 +55,30 @@ public function resolve(
5455
) {
5556
$attributes['items'] = null;
5657
$attributeInputs = $args['attributes'];
57-
foreach ($attributeInputs as $attribute) {
58-
if (!isset($attribute['attribute_code']) || !isset($attribute['entity_type'])) {
59-
$attributes['items'][] = $this->createInputException($attribute);
58+
foreach ($attributeInputs as $attributeInput) {
59+
if (!isset($attributeInput['attribute_code']) || !isset($attributeInput['entity_type'])) {
60+
$attributes['items'][] = $this->createInputException($attributeInput);
6061
continue;
6162
}
6263
try {
63-
$frontendType = $this->frontendType->getType($attribute['attribute_code'], $attribute['entity_type']);
64-
$type = $this->type->getType($attribute['attribute_code'], $attribute['entity_type']);
64+
$attribute = $this->attribute->getAttribute(
65+
$attributeInput['attribute_code'],
66+
$attributeInput['entity_type']
67+
);
68+
$type = $this->type->getType($attributeInput['attribute_code'], $attributeInput['entity_type']);
6569
} catch (InputException $exception) {
6670
$attributes['items'][] = new GraphQlNoSuchEntityException(
6771
__(
6872
'Attribute code %1 of entity type %2 not configured to have a type.',
69-
[$attribute['attribute_code'], $attribute['entity_type']]
73+
[$attributeInput['attribute_code'], $attributeInput['entity_type']]
7074
)
7175
);
7276
continue;
7377
} catch (LocalizedException $exception) {
7478
$attributes['items'][] = new GraphQlInputException(
7579
__(
7680
'Invalid entity_type specified: %1',
77-
[$attribute['entity_type']]
81+
[$attributeInput['entity_type']]
7882
)
7983
);
8084
continue;
@@ -85,16 +89,48 @@ public function resolve(
8589
}
8690

8791
$attributes['items'][] = [
88-
'attribute_code' => $attribute['attribute_code'],
89-
'entity_type' => $attribute['entity_type'],
92+
'attribute_code' => $attributeInput['attribute_code'],
93+
'entity_type' => $attributeInput['entity_type'],
9094
'attribute_type' => ucfirst($type),
91-
'input_type' => $frontendType
95+
'input_type' => isset($attribute) ? $attribute->getFrontendInput() : null,
96+
'storefront_properties' => isset($attribute) ?$this->getStorefrontProperties($attribute) : null
9297
];
9398
}
9499

95100
return $attributes;
96101
}
97102

103+
/**
104+
* Format storefront properties
105+
*
106+
* @param AttributeInterface $attribute
107+
* @return array
108+
*/
109+
private function getStorefrontProperties(AttributeInterface $attribute)
110+
{
111+
return [
112+
'position'=> $attribute->getPosition(),
113+
'visible_on_catalog_pages'=> $attribute->getIsVisibleOnFront(),
114+
'use_in_search_results_layered_navigation' => $attribute->getIsFilterableInSearch(),
115+
'use_in_product_listing'=> $attribute->getUsedInProductListing(),
116+
'use_in_layered_navigation'=>
117+
$this->getLayeredNavigationPropertiesEnum()[$attribute->getisFilterable()] ?? null
118+
];
119+
}
120+
121+
/**
122+
* Return enum for resolving use in layered navigation
123+
*
124+
* @return string[]
125+
*/
126+
private function getLayeredNavigationPropertiesEnum() {
127+
return [
128+
0 => 'NO',
129+
1 => 'FILTERABLE_WITH_RESULTS',
130+
2 => 'FILTERABLE_NO_RESULT'
131+
];
132+
}
133+
98134
/**
99135
* Create GraphQL input exception for an invalid attribute input
100136
*

app/code/Magento/EavGraphQl/Model/Resolver/Query/FrontendType.php renamed to app/code/Magento/EavGraphQl/Model/Resolver/Query/Attribute.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
namespace Magento\EavGraphQl\Model\Resolver\Query;
99

1010
use Magento\Eav\Api\AttributeRepositoryInterface;
11+
use Magento\Eav\Api\Data\AttributeInterface;
1112
use Magento\Framework\Exception\NoSuchEntityException;
1213
use Magento\Framework\Webapi\ServiceTypeToEntityTypeMap;
1314

1415
/**
1516
* Get frontend input type for EAV attribute
1617
*/
17-
class FrontendType
18+
class Attribute
1819
{
1920
/**
2021
* @var AttributeRepositoryInterface
@@ -43,9 +44,9 @@ public function __construct(
4344
*
4445
* @param string $attributeCode
4546
* @param string $entityType
46-
* @return null|string
47+
* @return null | AttributeInterface
4748
*/
48-
public function getType(string $attributeCode, string $entityType): ?string
49+
public function getAttribute(string $attributeCode, string $entityType): ?AttributeInterface
4950
{
5051
$mappedEntityType = $this->serviceTypeMap->getEntityType($entityType);
5152
if ($mappedEntityType) {
@@ -56,6 +57,6 @@ public function getType(string $attributeCode, string $entityType): ?string
5657
} catch (NoSuchEntityException $e) {
5758
return null;
5859
}
59-
return $attribute->getFrontendInput();
60+
return $attribute;
6061
}
6162
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,21 @@ type Attribute @doc(description: "Attribute contains the attribute_type of the s
1515
attribute_type: String @doc(description: "The data type of the attribute")
1616
input_type: String @doc(description: "The frontend input type of the attribute")
1717
attribute_options: [AttributeOption] @resolver(class: "Magento\\EavGraphQl\\Model\\Resolver\\AttributeOptions") @doc(description: "Attribute options list.")
18+
storefront_properties: StorefrontProperties @doc(description: "Contains details about the storefront properties configured for the attribute")
19+
}
20+
21+
type StorefrontProperties {
22+
use_in_product_listing: Boolean @doc(description: "Indicates whether the attribute is displayed in product listings")
23+
position: Int @doc(description: "The relative position of the attribute in the layered navigation block")
24+
visible_on_catalog_pages: Boolean @doc(description: "Indicates whether the attribute is displayed on product pages")
25+
use_in_layered_navigation: UseInLayeredNavigationOptions @doc(description: "Indicates whether the attribute is filterable with results, without results, or not at all")
26+
use_in_search_results_layered_navigation: Boolean @doc(description: "Indicates whether the attribute can be used in layered navigation on search results pages")
27+
}
28+
29+
enum UseInLayeredNavigationOptions {
30+
NO
31+
FILTERABLE_WITH_RESULTS
32+
FILTERABLE_NO_RESULT
1833
}
1934

2035
type AttributeOption @doc(description: "Attribute option.") {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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\QuoteGraphQl\Model\Cart\MergeCarts;
9+
10+
11+
use Magento\CatalogInventory\Api\StockRegistryInterface;
12+
use Magento\Framework\Exception\CouldNotSaveException;
13+
use Magento\Framework\Exception\NoSuchEntityException;
14+
use Magento\Quote\Api\CartItemRepositoryInterface;
15+
use Magento\Quote\Api\Data\CartInterface;
16+
use Magento\Quote\Api\Data\CartItemInterface;
17+
18+
class CartQuantityValidator implements CartQuantityValidatorInterface
19+
{
20+
/**
21+
* @var CartItemRepositoryInterface
22+
*/
23+
private $cartItemRepository;
24+
25+
/**
26+
* @var StockRegistryInterface
27+
*/
28+
private $stockRegistry;
29+
30+
/**
31+
* @param CartItemRepositoryInterface $cartItemRepository
32+
* @param StockRegistryInterface $stockRegistry
33+
*/
34+
public function __construct(
35+
CartItemRepositoryInterface $cartItemRepository,
36+
StockRegistryInterface $stockRegistry
37+
) {
38+
$this->cartItemRepository = $cartItemRepository;
39+
$this->stockRegistry = $stockRegistry;
40+
}
41+
42+
/**
43+
* Validate combined cart quantities to make sure they are within available stock
44+
*
45+
* @param CartInterface $customerCart
46+
* @param CartInterface $guestCart
47+
* @return bool
48+
*/
49+
public function validateFinalCartQuantities(CartInterface $customerCart, CartInterface $guestCart): bool
50+
{
51+
$modified = false;
52+
/** @var CartItemInterface $guestCartItem */
53+
foreach ($guestCart->getAllVisibleItems() as $guestCartItem) {
54+
foreach ($customerCart->getAllItems() as $customerCartItem) {
55+
if ($customerCartItem->compare($guestCartItem)) {
56+
$product = $customerCartItem->getProduct();
57+
$stockCurrentQty = $this->stockRegistry->getStockStatus(
58+
$product->getId(),
59+
$product->getStore()->getWebsiteId()
60+
)->getQty();
61+
if ($stockCurrentQty < $guestCartItem->getQty() + $customerCartItem->getQty()) {
62+
try {
63+
$this->cartItemRepository->deleteById($guestCart->getId(), $guestCartItem->getItemId());
64+
$modified = true;
65+
} catch (NoSuchEntityException $e) {
66+
continue;
67+
} catch (CouldNotSaveException $e) {
68+
continue;
69+
}
70+
}
71+
}
72+
}
73+
}
74+
return $modified;
75+
}
76+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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\QuoteGraphQl\Model\Cart\MergeCarts;
9+
10+
use Magento\Quote\Api\Data\CartInterface;
11+
12+
interface CartQuantityValidatorInterface
13+
{
14+
/**
15+
* Validate cart quantities when merging
16+
*
17+
* @param CartInterface $customerCart
18+
* @param CartInterface $guestCart
19+
* @return bool
20+
*/
21+
public function validateFinalCartQuantities(CartInterface $customerCart, CartInterface $guestCart): bool;
22+
}

0 commit comments

Comments
 (0)