Skip to content

Commit 345f678

Browse files
Merge branch '2.4-develop' into L3-PR-2023-09-06
2 parents f273b70 + 0a834cc commit 345f678

File tree

58 files changed

+2159
-956
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2159
-956
lines changed

app/code/Magento/Catalog/Test/Fixture/Attribute.php

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
use Magento\Catalog\Api\ProductAttributeManagementInterface;
1212
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
1313
use Magento\Catalog\Model\Product;
14+
use Magento\Catalog\Model\ResourceModel\Attribute as ResourceModelAttribute;
15+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute as EavAttribute;
16+
use Magento\Eav\Model\AttributeFactory;
1417
use Magento\Eav\Setup\EavSetup;
1518
use Magento\Framework\DataObject;
19+
use Magento\TestFramework\Fixture\Api\DataMerger;
1620
use Magento\TestFramework\Fixture\Api\ServiceFactory;
1721
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;
1822
use Magento\TestFramework\Fixture\Data\ProcessorInterface;
@@ -30,12 +34,12 @@ class Attribute implements RevertibleDataFixtureInterface
3034
'is_filterable_in_grid' => true,
3135
'position' => 0,
3236
'apply_to' => [],
33-
'is_searchable' => '0',
34-
'is_visible_in_advanced_search' => '0',
35-
'is_comparable' => '0',
36-
'is_used_for_promo_rules' => '0',
37-
'is_visible_on_front' => '0',
38-
'used_in_product_listing' => '0',
37+
'is_searchable' => false,
38+
'is_visible_in_advanced_search' => false,
39+
'is_comparable' => false,
40+
'is_used_for_promo_rules' => false,
41+
'is_visible_on_front' => false,
42+
'used_in_product_listing' => false,
3943
'is_visible' => true,
4044
'scope' => 'store',
4145
'attribute_code' => 'product_attribute%uniqid%',
@@ -49,7 +53,6 @@ class Attribute implements RevertibleDataFixtureInterface
4953
'backend_type' => 'varchar',
5054
'is_unique' => '0',
5155
'validation_rules' => []
52-
5356
];
5457

5558
private const DEFAULT_ATTRIBUTE_SET_DATA = [
@@ -78,29 +81,59 @@ class Attribute implements RevertibleDataFixtureInterface
7881
*/
7982
private $productAttributeManagement;
8083

84+
/**
85+
* @var AttributeFactory
86+
*/
87+
private AttributeFactory $attributeFactory;
88+
89+
/**
90+
* @var DataMerger
91+
*/
92+
private DataMerger $dataMerger;
93+
94+
/**
95+
* @var ResourceModelAttribute
96+
*/
97+
private ResourceModelAttribute $resourceModelAttribute;
98+
8199
/**
82100
* @param ServiceFactory $serviceFactory
83101
* @param ProcessorInterface $dataProcessor
84102
* @param EavSetup $eavSetup
103+
* @param ProductAttributeManagementInterface $productAttributeManagement
104+
* @param AttributeFactory $attributeFactory
105+
* @param DataMerger $dataMerger
106+
* @param ResourceModelAttribute $resourceModelAttribute
85107
*/
86108
public function __construct(
87109
ServiceFactory $serviceFactory,
88110
ProcessorInterface $dataProcessor,
89111
EavSetup $eavSetup,
90-
ProductAttributeManagementInterface $productAttributeManagement
112+
ProductAttributeManagementInterface $productAttributeManagement,
113+
AttributeFactory $attributeFactory,
114+
DataMerger $dataMerger,
115+
ResourceModelAttribute $resourceModelAttribute
91116
) {
92117
$this->serviceFactory = $serviceFactory;
93118
$this->dataProcessor = $dataProcessor;
94119
$this->eavSetup = $eavSetup;
95120
$this->productAttributeManagement = $productAttributeManagement;
121+
$this->attributeFactory = $attributeFactory;
122+
$this->dataMerger = $dataMerger;
123+
$this->resourceModelAttribute = $resourceModelAttribute;
96124
}
97125

98126
/**
99127
* {@inheritdoc}
100128
* @param array $data Parameters. Same format as Attribute::DEFAULT_DATA.
129+
* @return DataObject|null
101130
*/
102131
public function apply(array $data = []): ?DataObject
103132
{
133+
if (array_key_exists('additional_data', $data)) {
134+
return $this->applyAttributeWithAdditionalData($data);
135+
}
136+
104137
$service = $this->serviceFactory->create(ProductAttributeRepositoryInterface::class, 'save');
105138

106139
/**
@@ -139,6 +172,26 @@ public function revert(DataObject $data): void
139172
);
140173
}
141174

175+
/**
176+
* @param array $data Parameters. Same format as Attribute::DEFAULT_DATA.
177+
* @return DataObject|null
178+
*/
179+
private function applyAttributeWithAdditionalData(array $data = []): ?DataObject
180+
{
181+
$defaultData = array_merge(self::DEFAULT_DATA, ['additional_data' => null]);
182+
/** @var EavAttribute $attr */
183+
$attr = $this->attributeFactory->createAttribute(EavAttribute::class, $defaultData);
184+
$mergedData = $this->dataProcessor->process($this, $this->dataMerger->merge($defaultData, $data));
185+
186+
$attributeSetData = $this->prepareAttributeSetData(
187+
array_intersect_key($data, self::DEFAULT_ATTRIBUTE_SET_DATA)
188+
);
189+
190+
$attr->setData(array_merge($mergedData, $attributeSetData));
191+
$this->resourceModelAttribute->save($attr);
192+
return $attr;
193+
}
194+
142195
/**
143196
* Prepare attribute data
144197
*

app/code/Magento/CatalogGraphQl/Model/Output/AttributeMetadata.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,32 @@ public function execute(
5252
}
5353

5454
$metadata = [
55-
'is_searchable' => $attribute->getIsSearchable() === "1",
56-
'is_filterable' => $attribute->getIsFilterable() === "1",
5755
'is_comparable' => $attribute->getIsComparable() === "1",
56+
'is_filterable' => $attribute->getIsFilterable() === "1",
57+
'is_filterable_in_search' => $attribute->getIsFilterableInSearch() === "1",
58+
'is_searchable' => $attribute->getIsSearchable() === "1",
5859
'is_html_allowed_on_front' => $attribute->getIsHtmlAllowedOnFront() === "1",
5960
'is_used_for_price_rules' => $attribute->getIsUsedForPriceRules() === "1",
60-
'is_filterable_in_search' => $attribute->getIsFilterableInSearch() === "1",
61-
'used_in_product_listing' => $attribute->getUsedInProductListing() === "1",
62-
'is_wysiwyg_enabled' => $attribute->getIsWysiwygEnabled() === "1",
6361
'is_used_for_promo_rules' => $attribute->getIsUsedForPromoRules() === "1",
64-
'apply_to' => null,
62+
'is_visible_in_advanced_search' => $attribute->getIsVisibleInAdvancedSearch() === "1",
63+
'is_visible_on_front' => $attribute->getIsVisibleOnFront() === "1",
64+
'is_wysiwyg_enabled' => $attribute->getIsWysiwygEnabled() === "1",
65+
'used_in_product_listing' => $attribute->getUsedInProductListing() === "1",
66+
'apply_to' => null
6567
];
6668

6769
if (!empty($attribute->getApplyTo())) {
6870
$metadata['apply_to'] = array_map('strtoupper', $attribute->getApplyTo());
6971
}
7072

73+
if (!empty($attribute->getAdditionalData())) {
74+
$additionalData = json_decode($attribute->getAdditionalData(), true);
75+
$metadata = array_merge(
76+
$metadata,
77+
array_map('strtoupper', $additionalData)
78+
);
79+
}
80+
7181
return $metadata;
7282
}
7383
}

app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductCustomAttributes.php

Lines changed: 25 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@
1212
use Magento\Catalog\Model\Product;
1313
use Magento\CatalogGraphQl\Model\ProductDataProvider;
1414
use Magento\Eav\Api\Data\AttributeInterface;
15-
use Magento\Eav\Model\AttributeRepository;
1615
use Magento\EavGraphQl\Model\Output\Value\GetAttributeValueInterface;
17-
use Magento\EavGraphQl\Model\Resolver\AttributeFilter;
18-
use Magento\Framework\Api\SearchCriteriaBuilder;
16+
use Magento\EavGraphQl\Model\Resolver\GetFilteredAttributes;
1917
use Magento\GraphQl\Model\Query\ContextInterface;
2018
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
2119
use Magento\Framework\GraphQl\Config\Element\Field;
@@ -27,16 +25,6 @@
2725
*/
2826
class ProductCustomAttributes implements ResolverInterface
2927
{
30-
/**
31-
* @var AttributeRepository
32-
*/
33-
private AttributeRepository $attributeRepository;
34-
35-
/**
36-
* @var SearchCriteriaBuilder
37-
*/
38-
private SearchCriteriaBuilder $searchCriteriaBuilder;
39-
4028
/**
4129
* @var GetAttributeValueInterface
4230
*/
@@ -48,36 +36,30 @@ class ProductCustomAttributes implements ResolverInterface
4836
private ProductDataProvider $productDataProvider;
4937

5038
/**
51-
* @var AttributeFilter
39+
* @var GetFilteredAttributes
5240
*/
53-
private AttributeFilter $attributeFilter;
41+
private GetFilteredAttributes $getFilteredAttributes;
5442

5543
/**
5644
* @var FilterProductCustomAttribute
5745
*/
5846
private FilterProductCustomAttribute $filterCustomAttribute;
5947

6048
/**
61-
* @param AttributeRepository $attributeRepository
62-
* @param SearchCriteriaBuilder $searchCriteriaBuilder
6349
* @param GetAttributeValueInterface $getAttributeValue
6450
* @param ProductDataProvider $productDataProvider
65-
* @param AttributeFilter $attributeFilter
51+
* @param GetFilteredAttributes $getFilteredAttributes
6652
* @param FilterProductCustomAttribute $filterCustomAttribute
6753
*/
6854
public function __construct(
69-
AttributeRepository $attributeRepository,
70-
SearchCriteriaBuilder $searchCriteriaBuilder,
7155
GetAttributeValueInterface $getAttributeValue,
7256
ProductDataProvider $productDataProvider,
73-
AttributeFilter $attributeFilter,
57+
GetFilteredAttributes $getFilteredAttributes,
7458
FilterProductCustomAttribute $filterCustomAttribute
7559
) {
76-
$this->attributeRepository = $attributeRepository;
77-
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
7860
$this->getAttributeValue = $getAttributeValue;
7961
$this->productDataProvider = $productDataProvider;
80-
$this->attributeFilter = $attributeFilter;
62+
$this->getFilteredAttributes = $getFilteredAttributes;
8163
$this->filterCustomAttribute = $filterCustomAttribute;
8264
}
8365

@@ -99,25 +81,18 @@ public function resolve(
9981
array $value = null,
10082
array $args = null
10183
) {
102-
$filterArgs = $args['filter'] ?? [];
84+
$filtersArgs = $args['filters'] ?? [];
10385

104-
$searchCriteriaBuilder = $this->attributeFilter->execute($filterArgs, $this->searchCriteriaBuilder);
105-
106-
$searchCriteriaBuilder = $searchCriteriaBuilder
107-
->addFilter('is_visible', true)
108-
->addFilter('backend_type', 'static', 'neq')
109-
->create();
110-
111-
$productCustomAttributes = $this->attributeRepository->getList(
112-
ProductAttributeInterface::ENTITY_TYPE_CODE,
113-
$searchCriteriaBuilder
114-
)->getItems();
86+
$productCustomAttributes = $this->getFilteredAttributes->execute(
87+
$filtersArgs,
88+
ProductAttributeInterface::ENTITY_TYPE_CODE
89+
);
11590

11691
$attributeCodes = array_map(
11792
function (AttributeInterface $customAttribute) {
11893
return $customAttribute->getAttributeCode();
11994
},
120-
$productCustomAttributes
95+
$productCustomAttributes['items']
12196
);
12297

12398
$filteredAttributeCodes = $this->filterCustomAttribute->execute(array_flip($attributeCodes));
@@ -141,15 +116,18 @@ function (AttributeInterface $customAttribute) {
141116
];
142117
}
143118

144-
return array_map(
145-
function (array $customAttribute) {
146-
return $this->getAttributeValue->execute(
147-
ProductAttributeInterface::ENTITY_TYPE_CODE,
148-
$customAttribute['attribute_code'],
149-
$customAttribute['value']
150-
);
151-
},
152-
$customAttributes
153-
);
119+
return [
120+
'items' => array_map(
121+
function (array $customAttribute) {
122+
return $this->getAttributeValue->execute(
123+
ProductAttributeInterface::ENTITY_TYPE_CODE,
124+
$customAttribute['attribute_code'],
125+
$customAttribute['value']
126+
);
127+
},
128+
$customAttributes
129+
),
130+
'errors' => $productCustomAttributes['errors']
131+
];
154132
}
155133
}

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

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\
125125
categories: [CategoryInterface] @doc(description: "The categories assigned to a product.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Categories") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoriesIdentity")
126126
canonical_url: String @doc(description: "The relative canonical URL. This value is returned only if the system setting 'Use Canonical Link Meta Tag For Products' is enabled.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\CanonicalUrl")
127127
media_gallery: [MediaGalleryInterface] @doc(description: "An array of media gallery objects.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\MediaGallery")
128-
custom_attributes(filter: AttributeFilterInput): [AttributeValueInterface] @doc(description: "Product custom attributes.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductCustomAttributes")
128+
custom_attributesV2(filters: AttributeFilterInput): ProductCustomAttributes @doc(description: "Product custom attributes.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductCustomAttributes")
129129
}
130130

131131
interface PhysicalProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\\ProductInterfaceTypeResolverComposite") @doc(description: "Contains attributes specific to tangible products.") {
@@ -540,16 +540,18 @@ enum AttributeEntityTypeEnum {
540540
}
541541

542542
type CatalogAttributeMetadata implements CustomAttributeMetadataInterface @doc(description: "Catalog attribute metadata.") {
543-
is_filterable_in_search: Boolean! @doc(description: "Whether a product or category attribute can be filtered in search or not.")
544-
used_in_product_listing: Boolean! @doc(description: "Whether a product or category attribute is used in product listing or not.")
545-
is_searchable: Boolean! @doc(description: "Whether a product or category attribute can be searched or not.")
546-
is_filterable: Boolean! @doc(description: "Whether a product or category attribute can be filtered or not.")
547-
is_comparable: Boolean! @doc(description: "Whether a product or category attribute can be compared against another or not.")
548-
is_html_allowed_on_front: Boolean! @doc(description: "Whether a product or category attribute can use HTML on front or not.")
549-
is_used_for_price_rules: Boolean! @doc(description: "Whether a product or category attribute can be used for price rules or not.")
550-
is_wysiwyg_enabled: Boolean! @doc(description: "Whether a product or category attribute has WYSIWYG enabled or not.")
551-
is_used_for_promo_rules: Boolean! @doc(description: "Whether a product or category attribute is used for promo rules or not.")
552543
apply_to: [CatalogAttributeApplyToEnum] @doc(description: "To which catalog types an attribute can be applied.")
544+
is_comparable: Boolean @doc(description: "Whether a product or category attribute can be compared against another or not.")
545+
is_filterable: Boolean @doc(description: "Whether a product or category attribute can be filtered or not.")
546+
is_filterable_in_search: Boolean @doc(description: "Whether a product or category attribute can be filtered in search or not.")
547+
is_html_allowed_on_front: Boolean @doc(description: "Whether a product or category attribute can use HTML on front or not.")
548+
is_searchable: Boolean @doc(description: "Whether a product or category attribute can be searched or not.")
549+
is_used_for_price_rules: Boolean @doc(description: "Whether a product or category attribute can be used for price rules or not.")
550+
is_used_for_promo_rules: Boolean @doc(description: "Whether a product or category attribute is used for promo rules or not.")
551+
is_visible_in_advanced_search: Boolean @doc(description: "Whether a product or category attribute is visible in advanced search or not.")
552+
is_visible_on_front: Boolean @doc(description: "Whether a product or category attribute is visible on front or not.")
553+
is_wysiwyg_enabled: Boolean @doc(description: "Whether a product or category attribute has WYSIWYG enabled or not.")
554+
used_in_product_listing: Boolean @doc(description: "Whether a product or category attribute is used in product listing or not.")
553555
}
554556

555557
enum CatalogAttributeApplyToEnum {
@@ -562,21 +564,7 @@ enum CatalogAttributeApplyToEnum {
562564
CATEGORY
563565
}
564566

565-
input AttributeFilterInput @doc(description: "An input object that specifies the filters used for product.") {
566-
is_comparable: Boolean @doc(description: "Whether a product or category attribute can be compared against another or not.")
567-
is_filterable_in_search: Boolean @doc(description: "Whether a product or category attribute can be filtered in search or not.")
568-
is_searchable: Boolean @doc(description: "Whether a product or category attribute can be searched or not.")
569-
is_filterable: Boolean @doc(description: "Whether a product or category attribute can be filtered or not.")
570-
is_html_allowed_on_front: Boolean @doc(description: "Whether a product or category attribute can use HTML on front or not.")
571-
is_used_for_price_rules: Boolean @doc(description: "Whether a product or category attribute can be used for price rules or not.")
572-
is_visible_in_advanced_search: Boolean @doc(description: "Whether a product or category attribute is visible in advanced search or not.")
573-
is_wysiwyg_enabled: Boolean @doc(description: "Whether a product or category attribute has WYSIWYG enabled or not.")
574-
is_used_for_promo_rules: Boolean @doc(description: "Whether a product or category attribute is used for promo rules or not.")
575-
used_in_product_listing: Boolean @doc(description: "Whether a product or category attribute is used in product listing or not.")
576-
is_visible_on_front: Boolean @doc(description: "Whether a product or category attribute is visible on front or not.")
577-
used_for_sort_by: Boolean @doc(description: "Whether a product or category attribute is used for sort or not.")
578-
is_required_in_admin_store: Boolean @doc(description: "Whether a product or category attribute is required in admin store or not.")
579-
is_used_in_grid: Boolean @doc(description: "Whether a product or category attribute is used in grid or not.")
580-
is_visible_in_grid: Boolean @doc(description: "Whether a product or category attribute is visible in grid or not.")
581-
is_filterable_in_grid: Boolean @doc(description: "Whether a product or category attribute is filterable in grid or not.")
567+
type ProductCustomAttributes @doc(description: "Product custom attributes") {
568+
items: [AttributeValueInterface!]! @doc(description: "Requested custom attributes")
569+
errors: [AttributeMetadataError!]! @doc(description: "Errors when retrieving custom attributes metadata.")
582570
}

app/code/Magento/Customer/Model/Metadata/AttributeMetadataCache.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public function clean()
156156
$this->cache->clean(
157157
[
158158
Type::CACHE_TAG,
159-
Attribute::CACHE_TAG,
159+
Attribute::CACHE_TAG
160160
]
161161
);
162162
}

0 commit comments

Comments
 (0)