Skip to content

Commit 9852b08

Browse files
swnsmaal.kravchuk
authored and
al.kravchuk
committed
#23386: Copy Service does not works properly for Entities which extends Data Object and implements ExtensibleDataInterface.
Provide fallback to copy Extension Attributes for classes which extends Data Object.
1 parent 92118f5 commit 9852b08

File tree

1 file changed

+170
-87
lines changed
  • lib/internal/Magento/Framework/DataObject

1 file changed

+170
-87
lines changed

lib/internal/Magento/Framework/DataObject/Copy.php

Lines changed: 170 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,48 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

78
namespace Magento\Framework\DataObject;
89

10+
use Magento\Framework\Api\AbstractSimpleObject;
11+
use Magento\Framework\Api\ExtensibleDataInterface;
12+
use Magento\Framework\Api\ExtensionAttributesFactory;
13+
use Magento\Framework\DataObject;
14+
use Magento\Framework\DataObject\Copy\Config;
15+
use Magento\Framework\Event\ManagerInterface;
16+
917
/**
1018
* Utility class for copying data sets between objects
1119
*/
1220
class Copy
1321
{
1422
/**
15-
* @var \Magento\Framework\DataObject\Copy\Config
23+
* @var Config
1624
*/
1725
protected $fieldsetConfig;
1826

1927
/**
2028
* Core event manager proxy
2129
*
22-
* @var \Magento\Framework\Event\ManagerInterface
30+
* @var ManagerInterface
2331
*/
2432
protected $eventManager = null;
2533

2634
/**
27-
* @var \Magento\Framework\Api\ExtensionAttributesFactory
35+
* @var ExtensionAttributesFactory
2836
*/
2937
protected $extensionAttributesFactory;
3038

3139
/**
32-
* @param \Magento\Framework\Event\ManagerInterface $eventManager
33-
* @param \Magento\Framework\DataObject\Copy\Config $fieldsetConfig
34-
* @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionAttributesFactory
40+
* @param ManagerInterface $eventManager
41+
* @param Config $fieldsetConfig
42+
* @param ExtensionAttributesFactory $extensionAttributesFactory
3543
*/
3644
public function __construct(
37-
\Magento\Framework\Event\ManagerInterface $eventManager,
38-
\Magento\Framework\DataObject\Copy\Config $fieldsetConfig,
39-
\Magento\Framework\Api\ExtensionAttributesFactory $extensionAttributesFactory
45+
ManagerInterface $eventManager,
46+
Config $fieldsetConfig,
47+
ExtensionAttributesFactory $extensionAttributesFactory
4048
) {
4149
$this->eventManager = $eventManager;
4250
$this->fieldsetConfig = $fieldsetConfig;
@@ -51,10 +59,11 @@ public function __construct(
5159
*
5260
* @param string $fieldset
5361
* @param string $aspect
54-
* @param array|\Magento\Framework\DataObject $source
55-
* @param array|\Magento\Framework\DataObject $target
62+
* @param array|DataObject $source
63+
* @param array|DataObject $target
5664
* @param string $root
57-
* @return array|\Magento\Framework\DataObject|null the value of $target
65+
*
66+
* @return array|DataObject|null the value of $target
5867
* @throws \InvalidArgumentException
5968
*
6069
* @api
@@ -93,17 +102,18 @@ public function copyFieldsetToTarget($fieldset, $aspect, $source, $target, $root
93102
*
94103
* @param string $fieldset
95104
* @param string $aspect
96-
* @param array|\Magento\Framework\DataObject $source
97-
* @param array|\Magento\Framework\DataObject $target
105+
* @param array|DataObject $source
106+
* @param array|DataObject $target
98107
* @param string $root
99108
* @param bool $targetIsArray
100-
* @return \Magento\Framework\DataObject|mixed
109+
*
110+
* @return DataObject|mixed
101111
*/
102112
protected function dispatchCopyFieldSetEvent($fieldset, $aspect, $source, $target, $root, $targetIsArray)
103113
{
104114
$eventName = sprintf('core_copy_fieldset_%s_%s', $fieldset, $aspect);
105115
if ($targetIsArray) {
106-
$target = new \Magento\Framework\DataObject($target);
116+
$target = new DataObject($target);
107117
}
108118
$this->eventManager->dispatch(
109119
$eventName,
@@ -120,17 +130,19 @@ protected function dispatchCopyFieldSetEvent($fieldset, $aspect, $source, $targe
120130
*
121131
* @param string $fieldset
122132
* @param string $aspect a field name
123-
* @param array|\Magento\Framework\DataObject $source
133+
* @param array|DataObject $source
124134
* @param string $root
135+
*
125136
* @return array
126137
*
127138
* @api
128139
*/
129140
public function getDataFromFieldset($fieldset, $aspect, $source, $root = 'global')
130141
{
131-
if (!(is_array($source) || $source instanceof \Magento\Framework\DataObject)) {
142+
if ((!$this->isInputArgumentValid($source))) {
132143
return null;
133144
}
145+
134146
$fields = $this->fieldsetConfig->getFieldset($fieldset, $root);
135147
if ($fields === null) {
136148
return null;
@@ -155,18 +167,28 @@ public function getDataFromFieldset($fieldset, $aspect, $source, $root = 'global
155167
/**
156168
* Check if source and target are valid input for converting using fieldset
157169
*
158-
* @param array|\Magento\Framework\DataObject $source
159-
* @param array|\Magento\Framework\DataObject $target
170+
* @param array|DataObject $source
171+
* @param array|DataObject $target
172+
*
160173
* @return bool
161174
*/
162175
protected function _isFieldsetInputValid($source, $target)
163176
{
164-
return (is_array($source) || $source instanceof \Magento\Framework\DataObject ||
165-
$source instanceof \Magento\Framework\Api\ExtensibleDataInterface ||
166-
$source instanceof \Magento\Framework\Api\AbstractSimpleObject) && (
167-
is_array($target) || $target instanceof \Magento\Framework\DataObject ||
168-
$target instanceof \Magento\Framework\Api\ExtensibleDataInterface ||
169-
$target instanceof \Magento\Framework\Api\AbstractSimpleObject);
177+
return $this->isInputArgumentValid($source) && $this->isInputArgumentValid($target);
178+
}
179+
180+
/**
181+
* Verify that we can access data from input object.
182+
*
183+
* @param $object
184+
*
185+
* @return bool
186+
*/
187+
private function isInputArgumentValid($object): bool
188+
{
189+
return (is_array($object) || $object instanceof DataObject ||
190+
$object instanceof ExtensibleDataInterface ||
191+
$object instanceof AbstractSimpleObject);
170192
}
171193

172194
/**
@@ -180,20 +202,27 @@ protected function _isFieldsetInputValid($source, $target)
180202
*/
181203
protected function _getFieldsetFieldValue($source, $code)
182204
{
183-
if (is_array($source)) {
184-
$value = isset($source[$code]) ? $source[$code] : null;
185-
} elseif ($source instanceof \Magento\Framework\DataObject) {
186-
$value = $source->getDataUsingMethod($code);
187-
} elseif ($source instanceof \Magento\Framework\Api\ExtensibleDataInterface) {
188-
$value = $this->getAttributeValueFromExtensibleDataObject($source, $code);
189-
} elseif ($source instanceof \Magento\Framework\Api\AbstractSimpleObject) {
190-
$sourceArray = $source->__toArray();
191-
$value = isset($sourceArray[$code]) ? $sourceArray[$code] : null;
192-
} else {
193-
throw new \InvalidArgumentException(
194-
'Source should be array, Magento Object, ExtensibleDataInterface, or AbstractSimpleObject'
195-
);
205+
206+
switch (true) {
207+
case is_array($source):
208+
$value = isset($source[$code]) ? $source[$code] : null;
209+
break;
210+
case $source instanceof ExtensibleDataInterface:
211+
$value = $this->getAttributeValueFromExtensibleObject($source, $code);
212+
break;
213+
case $source instanceof DataObject:
214+
$value = $source->getDataUsingMethod($code);
215+
break;
216+
case $source instanceof AbstractSimpleObject:
217+
$sourceArray = $source->__toArray();
218+
$value = isset($sourceArray[$code]) ? $sourceArray[$code] : null;
219+
break;
220+
default:
221+
throw new \InvalidArgumentException(
222+
'Source should be array, Magento Object, ExtensibleDataInterface, or AbstractSimpleObject'
223+
);
196224
}
225+
197226
return $value;
198227
}
199228

@@ -209,20 +238,23 @@ protected function _getFieldsetFieldValue($source, $code)
209238
*/
210239
protected function _setFieldsetFieldValue($target, $targetCode, $value)
211240
{
212-
$targetIsArray = is_array($target);
213-
214-
if ($targetIsArray) {
215-
$target[$targetCode] = $value;
216-
} elseif ($target instanceof \Magento\Framework\DataObject) {
217-
$target->setDataUsingMethod($targetCode, $value);
218-
} elseif ($target instanceof \Magento\Framework\Api\ExtensibleDataInterface) {
219-
$this->setAttributeValueFromExtensibleDataObject($target, $targetCode, $value);
220-
} elseif ($target instanceof \Magento\Framework\Api\AbstractSimpleObject) {
221-
$target->setData($targetCode, $value);
222-
} else {
223-
throw new \InvalidArgumentException(
224-
'Source should be array, Magento Object, ExtensibleDataInterface, or AbstractSimpleObject'
225-
);
241+
switch (true) {
242+
case is_array($target):
243+
$target[$targetCode] = $value;
244+
break;
245+
case $target instanceof ExtensibleDataInterface:
246+
$this->setAttributeValueFromExtensibleObject($target, $targetCode, $value);
247+
break;
248+
case $target instanceof DataObject:
249+
$target->setDataUsingMethod($targetCode, $value);
250+
break;
251+
case $target instanceof AbstractSimpleObject:
252+
$target->setData($targetCode, $value);
253+
break;
254+
default:
255+
throw new \InvalidArgumentException(
256+
'Source should be array, Magento Object, ExtensibleDataInterface, or AbstractSimpleObject'
257+
);
226258
}
227259

228260
return $target;
@@ -231,68 +263,119 @@ protected function _setFieldsetFieldValue($target, $targetCode, $value)
231263
/**
232264
* Access the extension get method
233265
*
234-
* @param \Magento\Framework\Api\ExtensibleDataInterface $source
266+
* @param ExtensibleDataInterface $source
235267
* @param string $code
236268
*
237269
* @return mixed
238270
* @throws \InvalidArgumentException
271+
*
272+
* @deprecated
273+
* @see \Magento\Framework\DataObject\Copy::getAttributeValueFromExtensibleObject
239274
*/
240275
protected function getAttributeValueFromExtensibleDataObject($source, $code)
276+
{
277+
return $this->getAttributeValueFromExtensibleObject($source, $code);
278+
}
279+
280+
/**
281+
* Get Attribute Value from Extensible Object Data with fallback to DataObject or AbstractSimpleObject.
282+
*
283+
* @param ExtensibleDataInterface $source
284+
* @param string $code
285+
*
286+
* @return mixed|null
287+
*/
288+
private function getAttributeValueFromExtensibleObject(ExtensibleDataInterface $source, string $code)
241289
{
242290
$method = 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $code)));
243291

244292
$methodExists = method_exists($source, $method);
245-
if ($methodExists == true) {
246-
$value = $source->{$method}();
247-
} else {
248-
// If we couldn't find the method, check if we can get it from the extension attributes
249-
$extensionAttributes = $source->getExtensionAttributes();
250-
if ($extensionAttributes == null) {
251-
throw new \InvalidArgumentException('Method in extension does not exist.');
252-
} else {
253-
$extensionMethodExists = method_exists($extensionAttributes, $method);
254-
if ($extensionMethodExists == true) {
255-
$value = $extensionAttributes->{$method}();
256-
} else {
257-
throw new \InvalidArgumentException('Attribute in object does not exist.');
258-
}
293+
294+
if ($methodExists === true) {
295+
return $source->{$method}();
296+
}
297+
298+
$extensionAttributes = $source->getExtensionAttributes();
299+
300+
if ($extensionAttributes) {
301+
$methodExists = method_exists($extensionAttributes, $method);
302+
if ($methodExists) {
303+
return $extensionAttributes->{$method}();
259304
}
260305
}
261-
return $value;
306+
307+
if ($source instanceof DataObject) {
308+
return $source->getDataUsingMethod($code);
309+
}
310+
311+
if ($source instanceof AbstractSimpleObject) {
312+
$sourceArray = $source->__toArray();
313+
return isset($sourceArray[$code]) ? $sourceArray[$code] : null;
314+
}
315+
316+
throw new \InvalidArgumentException('Attribute in object does not exist.');
262317
}
263318

264319
/**
265320
* Access the extension set method
266321
*
267-
* @param \Magento\Framework\Api\ExtensibleDataInterface $target
322+
* @param ExtensibleDataInterface $target
268323
* @param string $code
269324
* @param mixed $value
270325
*
271-
* @return null
326+
* @return void
327+
* @throws \InvalidArgumentException
328+
*
329+
* @deprecated
330+
* @see \Magento\Framework\DataObject\Copy::setAttributeValueFromExtensibleObject
331+
*/
332+
protected function setAttributeValueFromExtensibleDataObject(ExtensibleDataInterface $target, $code, $value)
333+
{
334+
$this->setAttributeValueFromExtensibleObject($target, $code, $value);
335+
}
336+
337+
/**
338+
* Set Attribute Value for Extensible Object Data with fallback to DataObject or AbstractSimpleObject.
339+
*
340+
* @param ExtensibleDataInterface $target
341+
* @param string $code
342+
* @param $value
343+
*
344+
* @return void
272345
* @throws \InvalidArgumentException
273346
*/
274-
protected function setAttributeValueFromExtensibleDataObject($target, $code, $value)
347+
private function setAttributeValueFromExtensibleObject(ExtensibleDataInterface $target, string $code, $value): void
275348
{
276349
$method = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $code)));
277350

278351
$methodExists = method_exists($target, $method);
279-
if ($methodExists == true) {
352+
if ($methodExists) {
280353
$target->{$method}($value);
281-
} else {
282-
// If we couldn't find the method, check if we can set it from the extension attributes
283-
$extensionAttributes = $target->getExtensionAttributes();
284-
if ($extensionAttributes == null) {
285-
$extensionAttributes = $this->extensionAttributesFactory->create(get_class($target));
286-
}
287-
$extensionMethodExists = method_exists($extensionAttributes, $method);
288-
if ($extensionMethodExists == true) {
289-
$extensionAttributes->{$method}($value);
290-
$target->setExtensionAttributes($extensionAttributes);
291-
} else {
292-
throw new \InvalidArgumentException('Attribute in object does not exist.');
293-
}
354+
return;
355+
}
356+
357+
$extensionAttributes = $target->getExtensionAttributes();
358+
if ($extensionAttributes === null) {
359+
$extensionAttributes = $this->extensionAttributesFactory->create(get_class($target));
360+
}
361+
362+
if (method_exists($extensionAttributes, $method)) {
363+
$extensionAttributes->{$method}($value);
364+
$target->setExtensionAttributes($extensionAttributes);
365+
return;
366+
}
367+
368+
369+
if ($target instanceof DataObject) {
370+
$target->setDataUsingMethod($code, $value);
371+
return;
372+
}
373+
374+
if ($target instanceof AbstractSimpleObject) {
375+
$target->setData($code, $value);
376+
return;
294377
}
295378

296-
return null;
379+
throw new \InvalidArgumentException('Attribute in object does not exist.');
297380
}
298381
}

0 commit comments

Comments
 (0)