Skip to content

External DTOs should be usable as part of ExtensionAttributes system #34989

@MeCapron

Description

@MeCapron

Summary (*)

External classes such as DTO can not be used as part of extension attributes system if they are not arrays, because Magento2 will try to instantiate the object through the ObjectManager as if it was a \Magento\Framework\DataObject::class

Examples (*)

Example :

    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
        <attribute code="test1" type="MyVendor\Custom\DTO\MyDTOInterface[]"/>
        <attribute code="test2" type="MyVendor\Custom\DTO\AnotherDTO"/>
    </extension_attributes>

In this example, while calling :

       // $customerInformation = []; -> array with data information

        $this->dataObjectHelper->populateWithArray(
            $customer->getDataModel(),
            $customerInformation,
            CustomerInterface::class
        );

For the attribute test2 we will call :

As you see there, if the target type object is not part of the Magento "system" (i.e : not extending the DataObject class), it will not be created with the good data.

It leads the developer to duplicate the DTO class which is a non-sense because of the simplicity of such classes. Also, we could want to use direct DTO from external (vendor) modules such as SDK models.

Btw, it is counter-intuitive that we can define non DataObject extended objects in the extension_attributes.yml but they are not completely handled in the system. It made me think that this is just a specific (and marginal) forgotten case.

The same happens here : https://github.com/pepe1518/magento2/blob/master/vendor/magento/framework/Api/DataObjectHelper.php#L215

Proposed solution

We could implement this kind of solution which is what is done for array typed objects :

        if (is_subclass_of($extensionAttributeType, DataObject::class)) {
                $value[$extensionAttributeKey] = $this->objectFactory->create(
                        $extensionAttributeType,
                        ['data' => $extensionAttributeValue]
                );
        } else {
                $extensionAttributeInner = $this->objectFactory->create($extensionAttributeType, []);

                $this->populateWithArray(
                        $extensionAttributeInner,
                        $extensionAttributeValue,
                        $extensionAttributeType
                );

                $value[$extensionAttributeKey] = $extensionAttributeInner;
        }

Based on your suggestions/answers, I could make a PR for this.

Thanks,
Melvin

Below attached module helps in issue reproduction

Magz.zip


Please provide Severity assessment for the Issue as Reporter. This information will help during Confirmation and Issue triage processes.

  • Severity: S0 - Affects critical data or functionality and leaves users with no workaround.
  • Severity: S1 - Affects critical data or functionality and forces users to employ a workaround.
  • [ x] Severity: S2 - Affects non-critical data or functionality and forces users to employ a workaround.
  • Severity: S3 - Affects non-critical data or functionality and does not force users to employ a workaround.
  • Severity: S4 - Affects aesthetics, professional look and feel, “quality” or “usability”.

Metadata

Metadata

Labels

Area: FrameworkComponent: DtoIssue: ConfirmedGate 3 Passed. Manual verification of the issue completed. Issue is confirmedPriority: P2A defect with this priority could have functionality issues which are not to expectations.Progress: PR in progressReproduced on 2.4.xThe issue has been reproduced on latest 2.4-develop branchTriage: Dev.ExperienceIssue related to Developer Experience and needs help with Triage to Confirm or Reject it

Type

No type

Projects

Status

Pull Request In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions