Skip to content

Commit ebbe813

Browse files
committed
1 parent 2863caa commit ebbe813

File tree

14 files changed

+900
-15
lines changed

14 files changed

+900
-15
lines changed

app/code/Magento/CustomerGraphQl/Model/Customer/ValidateCustomerData.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
namespace Magento\CustomerGraphQl\Model\Customer;
99

1010
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
11+
use Magento\Framework\Validator\EmailAddress as EmailAddressValidator;
1112

1213
/**
13-
* Class ValidateCustomerData
14+
* Customer data validation used during customer account creation and updating
1415
*/
1516
class ValidateCustomerData
1617
{
@@ -21,14 +22,23 @@ class ValidateCustomerData
2122
*/
2223
private $getAllowedCustomerAttributes;
2324

25+
/**
26+
* @var EmailAddressValidator
27+
*/
28+
private $emailAddressValidator;
29+
2430
/**
2531
* ValidateCustomerData constructor.
2632
*
2733
* @param GetAllowedCustomerAttributes $getAllowedCustomerAttributes
34+
* @param EmailAddressValidator $emailAddressValidator
2835
*/
29-
public function __construct(GetAllowedCustomerAttributes $getAllowedCustomerAttributes)
30-
{
36+
public function __construct(
37+
GetAllowedCustomerAttributes $getAllowedCustomerAttributes,
38+
EmailAddressValidator $emailAddressValidator
39+
) {
3140
$this->getAllowedCustomerAttributes = $getAllowedCustomerAttributes;
41+
$this->emailAddressValidator = $emailAddressValidator;
3242
}
3343

3444
/**
@@ -59,5 +69,11 @@ public function execute(array $customerData): void
5969
__('Required parameters are missing: %1', [implode(', ', $errorInput)])
6070
);
6171
}
72+
73+
if (isset($customerData['email']) && !$this->emailAddressValidator->isValid($customerData['email'])) {
74+
throw new GraphQlInputException(
75+
__('"%1" is not a valid email address.', $customerData['email'])
76+
);
77+
}
6278
}
6379
}
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
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\SwatchesGraphQl\Model\Resolver\Product\Options\DataProvider;
9+
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Catalog\Model\Product\Image\UrlBuilder;
12+
use Magento\Framework\Exception\LocalizedException;
13+
use Magento\Framework\Exception\NoSuchEntityException;
14+
use Magento\Framework\Exception\RuntimeException;
15+
use Magento\Framework\GraphQl\Query\EnumLookup;
16+
use Magento\Swatches\Helper\Data as SwatchData;
17+
use Magento\Swatches\Helper\Media as SwatchesMedia;
18+
use Magento\Swatches\Model\Swatch;
19+
20+
/**
21+
* Swatch data provider
22+
*/
23+
class SwatchDataProvider
24+
{
25+
/**
26+
* @var SwatchData
27+
*/
28+
private $swatchHelper;
29+
30+
/**
31+
* @var SwatchesMedia
32+
*/
33+
private $swatchMediaHelper;
34+
35+
/**
36+
* @var UrlBuilder
37+
*/
38+
private $imageUrlBuilder;
39+
40+
/**
41+
* @var EnumLookup
42+
*/
43+
private $enumLookup;
44+
45+
/**
46+
* SwatchDataProvider constructor.
47+
*
48+
* @param SwatchData $swatchHelper
49+
* @param SwatchesMedia $swatchMediaHelper
50+
* @param UrlBuilder $imageUrlBuilder
51+
* @param EnumLookup $enumLookup
52+
*/
53+
public function __construct(
54+
SwatchData $swatchHelper,
55+
SwatchesMedia $swatchMediaHelper,
56+
UrlBuilder $imageUrlBuilder,
57+
EnumLookup $enumLookup
58+
) {
59+
$this->swatchHelper = $swatchHelper;
60+
$this->swatchMediaHelper = $swatchMediaHelper;
61+
$this->imageUrlBuilder = $imageUrlBuilder;
62+
$this->enumLookup = $enumLookup;
63+
}
64+
65+
/**
66+
* Get swatch data
67+
*
68+
* @param string $optionId
69+
* @param ProductInterface $product
70+
*
71+
* @return array
72+
*
73+
* @throws LocalizedException
74+
* @throws NoSuchEntityException
75+
* @throws \LogicException
76+
*/
77+
public function getData(string $optionId, ProductInterface $product): array
78+
{
79+
$swatches = $this->swatchHelper->getSwatchesByOptionsId([$optionId]);
80+
if (!isset($swatches[$optionId], $swatches[$optionId]['type'], $swatches[$optionId]['value'])) {
81+
return null;
82+
}
83+
84+
$type = (int)$swatches[$optionId]['type'];
85+
$value = $swatches[$optionId]['value'];
86+
$thumbnail = null;
87+
88+
// change value & thumbnail if type is 'visual'
89+
if ($type === Swatch::SWATCH_TYPE_VISUAL_IMAGE) {
90+
$thumbnail = $this->swatchMediaHelper->getSwatchAttributeImage(Swatch::SWATCH_THUMBNAIL_NAME, $value);
91+
$value = $this->swatchMediaHelper->getSwatchAttributeImage(Swatch::SWATCH_IMAGE_NAME, $value);
92+
}
93+
94+
$attributeData = $this->getSwatchAttributeDataByOptionId($product, $optionId);
95+
// check if swatch value should be getting from related product image
96+
if (!$this->isUseProductImageForSwatch($attributeData)) {
97+
return $this->getResultArray($value, $type, $thumbnail);
98+
}
99+
100+
// get product with existing image
101+
$variationProduct = $this->getVariationProduct($attributeData, $optionId, $product);
102+
if (null === $variationProduct) {
103+
return $this->getResultArray($value, $type, $thumbnail);
104+
}
105+
106+
// set 'visual' type, because the product image is using as swatch value
107+
$type = Swatch::SWATCH_TYPE_VISUAL_IMAGE;
108+
109+
// get image from child product
110+
$productImage = $this->getSwatchProductImage($variationProduct, Swatch::SWATCH_IMAGE_NAME);
111+
if (null !== $productImage) {
112+
$value = $productImage;
113+
}
114+
115+
// get thumbnail from child product
116+
$productThumbnail = $this->getSwatchProductImage($variationProduct, Swatch::SWATCH_THUMBNAIL_NAME);
117+
if (null !== $productThumbnail) {
118+
$thumbnail = $productThumbnail;
119+
}
120+
121+
return $this->getResultArray($value, $type, $thumbnail);
122+
}
123+
124+
/**
125+
* Get result array
126+
*
127+
* @param string $value
128+
* @param int $type
129+
* @param null|string $thumbnail
130+
*
131+
* @return array
132+
*
133+
* @throws RuntimeException
134+
*/
135+
private function getResultArray(string $value, int $type, ?string $thumbnail)
136+
{
137+
return [
138+
'value' => $value,
139+
'type' => $this->enumLookup->getEnumValueFromField('SwatchTypeEnum', (string)$type),
140+
'thumbnail' => $thumbnail
141+
];
142+
}
143+
144+
/**
145+
* Is swatch images should be getting from related simple products
146+
*
147+
* @param array $attributeData
148+
*
149+
* @return bool
150+
*/
151+
private function isUseProductImageForSwatch(array $attributeData) : bool
152+
{
153+
return isset($attributeData['use_product_image_for_swatch']) && $attributeData['use_product_image_for_swatch'];
154+
}
155+
156+
/**
157+
* Get simple product with first variation swatch image or image
158+
*
159+
* @param array $attributeData
160+
* @param string $optionId
161+
* @param ProductInterface $product
162+
*
163+
* @return ProductInterface|null
164+
*/
165+
private function getVariationProduct(array $attributeData, string $optionId, ProductInterface $product) : ?ProductInterface
166+
{
167+
$attributeCode = $attributeData['attribute_code'];
168+
$requiredAttributes = [
169+
$attributeCode => $optionId
170+
];
171+
172+
$variationProduct = $this->swatchHelper->loadFirstVariationWithSwatchImage($product, $requiredAttributes);
173+
if ($variationProduct instanceof ProductInterface) {
174+
return $variationProduct;
175+
}
176+
177+
$variationProduct = $this->swatchHelper->loadFirstVariationWithImage($product, $requiredAttributes);
178+
if ($variationProduct instanceof ProductInterface) {
179+
return $variationProduct;
180+
}
181+
182+
return null;
183+
}
184+
185+
/**
186+
* Get swatch product image
187+
*
188+
* @param ProductInterface $product
189+
* @param string $imageType
190+
*
191+
* @return string|null
192+
*/
193+
private function getSwatchProductImage(ProductInterface $product, $imageType) : ?string
194+
{
195+
if ($this->isProductHasImage($product, Swatch::SWATCH_IMAGE_NAME)) {
196+
$swatchImageId = $imageType;
197+
$imageAttributes = ['type' => Swatch::SWATCH_IMAGE_NAME];
198+
} elseif ($this->isProductHasImage($product, 'image')) {
199+
$swatchImageId = $imageType == Swatch::SWATCH_IMAGE_NAME ? 'swatch_image_base' : 'swatch_thumb_base';
200+
$imageAttributes = ['type' => 'image'];
201+
}
202+
203+
if (empty($swatchImageId) || empty($imageAttributes['type'])) {
204+
return null;
205+
}
206+
207+
return $this->imageUrlBuilder->getUrl($product->getData($imageAttributes['type']), $swatchImageId);
208+
}
209+
210+
/**
211+
* Is product has image
212+
*
213+
* @param ProductInterface $product
214+
* @param string $imageType
215+
*
216+
* @return bool
217+
*/
218+
private function isProductHasImage(ProductInterface $product, string $imageType) : bool
219+
{
220+
return $product->getData($imageType) !== null && $product->getData($imageType) != SwatchData::EMPTY_IMAGE_VALUE;
221+
}
222+
223+
/**
224+
* Get swatch attribute data by option id
225+
*
226+
* @param ProductInterface $product
227+
* @param string $optionId
228+
*
229+
* @return array
230+
*
231+
* @throws LocalizedException
232+
* @throws \LogicException
233+
* @throws NoSuchEntityException
234+
*/
235+
private function getSwatchAttributeDataByOptionId(ProductInterface $product, string $optionId) : array
236+
{
237+
$attributesData = $this->swatchHelper->getSwatchAttributesAsArray($product);
238+
foreach ($attributesData as $attributeData) {
239+
if (!isset($attributeData['options']) || !is_array($attributeData['options'])) {
240+
continue;
241+
}
242+
243+
if (array_key_exists($optionId, $attributeData['options'])) {
244+
return $attributeData;
245+
}
246+
}
247+
248+
throw new LocalizedException(__(sprintf('Cannot find the attribute with option id "%1".', $optionId)));
249+
}
250+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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\SwatchesGraphQl\Model\Resolver\Product\Options;
9+
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Framework\GraphQl\Config\Element\Field;
13+
use Magento\Framework\GraphQl\Query\ResolverInterface;
14+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
15+
use Magento\SwatchesGraphQl\Model\Resolver\Product\Options\DataProvider\SwatchDataProvider;
16+
17+
/**
18+
* Class SwatchData
19+
*
20+
* Product swatch data resolver, used for GraphQL request processing
21+
*/
22+
class SwatchData implements ResolverInterface
23+
{
24+
/**
25+
* @var SwatchDataProvider
26+
*/
27+
private $swatchDataProvider;
28+
29+
/**
30+
* SwatchData constructor.
31+
*
32+
* @param SwatchDataProvider $swatchDataProvider
33+
*/
34+
public function __construct(
35+
SwatchDataProvider $swatchDataProvider
36+
) {
37+
$this->swatchDataProvider = $swatchDataProvider;
38+
}
39+
40+
/**
41+
* @inheritdoc
42+
*/
43+
public function resolve(
44+
Field $field,
45+
$context,
46+
ResolveInfo $info,
47+
array $value = null,
48+
array $args = null
49+
) {
50+
if (!array_key_exists('model', $value) || !$value['model'] instanceof ProductInterface) {
51+
throw new LocalizedException(__('"model" value should be specified'));
52+
}
53+
54+
return $this->swatchDataProvider->getData($value['value_index'], $value['model']);
55+
}
56+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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\SwatchesGraphQl\Model\Resolver\Product\Options;
9+
10+
use Magento\Framework\GraphQl\Query\Resolver\TypeResolverInterface;
11+
use Magento\Swatches\Model\Swatch;
12+
13+
/**
14+
* Resolver for swatch data interface.
15+
*/
16+
class SwatchDataTypeResolver implements TypeResolverInterface
17+
{
18+
/**
19+
* {@inheritdoc}
20+
*/
21+
public function resolveType(array $data): string
22+
{
23+
switch ($data['type']) {
24+
case Swatch::SWATCH_TYPE_TEXTUAL:
25+
return 'TextSwatchData';
26+
case Swatch::SWATCH_TYPE_VISUAL_COLOR;
27+
return 'ColorSwatchData';
28+
case Swatch::SWATCH_TYPE_VISUAL_IMAGE;
29+
return 'ImageSwatchData';
30+
default:
31+
return '';
32+
}
33+
}
34+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
</argument>
1717
</arguments>
1818
</type>
19-
</config>
19+
</config>

0 commit comments

Comments
 (0)