Skip to content

Commit d865701

Browse files
committed
Merge branch 'eav-graphql' of github.com:magento-lynx/magento2ce into eav-graphql
2 parents f0928f2 + 5e6e0ef commit d865701

File tree

17 files changed

+791
-387
lines changed

17 files changed

+791
-387
lines changed

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

Lines changed: 55 additions & 2 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;
@@ -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: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,21 @@ public function execute(
6161
'used_in_product_listing' => $attribute->getUsedInProductListing() === "1",
6262
'is_wysiwyg_enabled' => $attribute->getIsWysiwygEnabled() === "1",
6363
'is_used_for_promo_rules' => $attribute->getIsUsedForPromoRules() === "1",
64-
'apply_to' => null,
64+
'apply_to' => null
6565
];
6666

6767
if (!empty($attribute->getApplyTo())) {
6868
$metadata['apply_to'] = array_map('strtoupper', $attribute->getApplyTo());
6969
}
7070

71+
if (!empty($attribute->getAdditionalData())) {
72+
$additionalData = json_decode($attribute->getAdditionalData(), true);
73+
$metadata = array_merge(
74+
$metadata,
75+
array_map('strtoupper', $additionalData)
76+
);
77+
}
78+
7179
return $metadata;
7280
}
7381
}

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: 4 additions & 18 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_attributes(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.") {
@@ -562,21 +562,7 @@ enum CatalogAttributeApplyToEnum {
562562
CATEGORY
563563
}
564564

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.")
565+
type ProductCustomAttributes @doc(description: "Product custom attributes") {
566+
items: [AttributeValueInterface!]! @doc(description: "Requested custom attributes")
567+
errors: [AttributeMetadataError!]! @doc(description: "Errors when retrieving custom attributes metadata.")
582568
}

app/code/Magento/Customer/Test/Fixture/CustomerAttribute.php

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,6 @@
1919

2020
class CustomerAttribute implements RevertibleDataFixtureInterface
2121
{
22-
private const DEFAULT_DATA = [
23-
'entity_type_id' => null,
24-
'attribute_id' => null,
25-
'attribute_code' => 'attribute%uniqid%',
26-
'default_frontend_label' => 'Attribute%uniqid%',
27-
'frontend_labels' => [],
28-
'frontend_input' => 'text',
29-
'backend_type' => 'varchar',
30-
'is_required' => false,
31-
'is_user_defined' => true,
32-
'note' => null,
33-
'backend_model' => null,
34-
'source_model' => null,
35-
'default_value' => null,
36-
'is_unique' => '0',
37-
'frontend_class' => null,
38-
'used_in_forms' => [],
39-
'sort_order' => 0,
40-
'attribute_set_id' => null,
41-
'attribute_group_id' => null,
42-
'input_filter' => null,
43-
'multiline_count' => 0,
44-
'validate_rules' => null,
45-
'website_id' => null,
46-
'is_visible' => 1,
47-
'scope_is_visible' => 1,
48-
];
49-
5022
/**
5123
* @var DataMerger
5224
*/
@@ -72,32 +44,41 @@ class CustomerAttribute implements RevertibleDataFixtureInterface
7244
*/
7345
private AttributeRepositoryInterface $attributeRepository;
7446

47+
/**
48+
* @var CustomerAttributeDefaultData
49+
*/
50+
private CustomerAttributeDefaultData $customerAttributeDefaultData;
51+
7552
/**
7653
* @param DataMerger $dataMerger
7754
* @param ProcessorInterface $processor
7855
* @param AttributeRepositoryInterface $attributeRepository
7956
* @param AttributeFactory $attributeFactory
8057
* @param ResourceModelAttribute $resourceModelAttribute
58+
* @param CustomerAttributeDefaultData $customerAttributeDefaultData
8159
*/
8260
public function __construct(
8361
DataMerger $dataMerger,
8462
ProcessorInterface $processor,
8563
AttributeRepositoryInterface $attributeRepository,
8664
AttributeFactory $attributeFactory,
87-
ResourceModelAttribute $resourceModelAttribute
65+
ResourceModelAttribute $resourceModelAttribute,
66+
CustomerAttributeDefaultData $customerAttributeDefaultData
8867
) {
8968
$this->dataMerger = $dataMerger;
9069
$this->processor = $processor;
9170
$this->attributeFactory = $attributeFactory;
9271
$this->resourceModelAttribute = $resourceModelAttribute;
9372
$this->attributeRepository = $attributeRepository;
73+
$this->customerAttributeDefaultData = $customerAttributeDefaultData;
9474
}
9575

9676
/**
9777
* @inheritdoc
9878
*/
9979
public function apply(array $data = []): ?DataObject
10080
{
81+
$defaultData = $this->customerAttributeDefaultData->getData();
10182
if (empty($data['entity_type_id'])) {
10283
throw new InvalidArgumentException(
10384
__(
@@ -110,8 +91,8 @@ public function apply(array $data = []): ?DataObject
11091
}
11192

11293
/** @var Attribute $attr */
113-
$attr = $this->attributeFactory->createAttribute(Attribute::class, self::DEFAULT_DATA);
114-
$mergedData = $this->processor->process($this, $this->dataMerger->merge(self::DEFAULT_DATA, $data));
94+
$attr = $this->attributeFactory->createAttribute(Attribute::class, $defaultData);
95+
$mergedData = $this->processor->process($this, $this->dataMerger->merge($defaultData, $data));
11596
$attr->setData($mergedData);
11697
if (isset($data['website_id'])) {
11798
$attr->setWebsite($data['website_id']);

0 commit comments

Comments
 (0)