cancel
Showing results for 
Search instead for 
Did you mean: 

extension_attributes join reference_table bug?

extension_attributes join reference_table bug?

Hi, I made custom module using extension attributes, as described in doc: http://devdocs.magento.com/guides/v2.2/extension-dev-guide/attributes.html

 

When I use in extension_attributes.xml join table, like this:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
<extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
<attribute code="loyalty_programs" type="Sprii\LoyaltyProgram\Api\Data\LoyaltyProgramInterface[]" >
<join reference_table="sprii_loyalty" reference_field="customer_id" join_on_field="entity_id">
<field>card_number</field>
<field>valid_from</field>
</join>
</attribute>
</extension_attributes>
</config>

 

I get following error:

"

join directives cannot be processed for attribute (loyalty_programs) of extensible entity (Magento\Customer\Api\Data\CustomerInterface) which has an Array type (Sprii\LoyaltyProgram\Api\Data\LoyaltyProgramInterface[])

"

When I delete this join, module works fine. And Customer module works fine too, and my attributes are visible and searchable in Customer module.

According to http://devdocs.magento.com/guides/v2.2/extension-dev-guide/attributes.html#search , what for is this join if system works without it?

1 REPLY 1

Re: extension_attributes join reference_table bug?

Per the documentation:

 

The system uses a join directive to add external attributes to a collection and to make the collection filterable.

Because your attribute is an array of LoyaltyProgramInterface objects, this tells me that you have a one to many relationship between the `customer_entity` and `sprii_loyalty` table, and a customer can have more than one card saved at a time (I state "card" just assuming here based off your field name you've given in your question).

Due to this, a select query that returns a single row per customer, cannot reliably also return the dataset for this table in the same query, as that dataset could contain multiple rows per customer. Take for example the following:

 

/** @var \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory $collectionFactory */
$collection = $collectionFactory->create();
$collection->addAttributeToSelect('loyalty_programs');

The SQL query for the above, if using the instructions of the `join` XML from your question, would yield something along the lines of the following:

SELECT
e.*,
at_loyalty_programs.card_number,
at_loyalty_programs.valid_from
FROM customer_entity AS e
JOIN sprii_loyalty AS attr_loyalty_programs
ON e.customer_id = at_loyalty_programs.entity_id

Using the SQL query above, if a customer were to have more than one card on file in the `sprii_loyalty` table, the query would return more than one row for that customer. The `Collection` object however, expects and needs to have only one row per return per record in `customer_entity`.

 


When I delete this join, module works fine. And Customer module works fine too, and my attributes are visible and searchable in Customer module.

I cannot know for certain without seeing the rest of the code in your extension. It is possible that you've added other code, which appends the array of `LoyaltyProgramInterface` objects to each item of the collection. Also, when you state "collection" I'm curious to know of you mean you're gathering customers truly by using a `\Magento\Customer\Model\ResourceModel\Customer\Collection` object, or if you're utilizing `\Magento\Customer\Model\ResourceModel\CustomerRepository` to return an array of customers. As these two different approaches can have different outcomes depending on how each are used.

 

Reviewing the source code of the `magento/customer-module` (v2.4.0 here) I can see that attributes are handled somewhat differently than they are from the `magento/module-catalog` extension. In my current project, I have a similar situation, where my extension attribute is an array of objects. These are being appended to items by configuring adding `di.xml` configuration to append an instance of a `\Magento\Framework\EntityManager\Operation\ExtensionInterface` object I've written to the `\Magento\Framework\EntityManager\Operation\ExtensionPool`. Example:

 

<type name="Magento\Framework\EntityManager\Operation\ExtensionPool">
<arguments>
<argument name="extensionActions" xsi:type="array">
<item name="Magento\Catalog\Api\Data\ProductInterface" xsi:type="array">
<item name="create" xsi:type="array">
<item name="add_my_attr" xsi:type="string">VendorName\ModelName\Model\Product\CreateHandler</item>
</item>
<item name="update" xsi:type="array">
<item name="update_my_attr" xsi:type="string">VendorName\ModelName\Model\Product\UpdateHandler</item>
</item>
<item name="read" xsi:type="array">
<item name="read_my_attr" xsi:type="string">VendorName\ModelName\Model\Product\ReadHandler</item>
</item>
</item>
</argument>
</arguments>
</type>

 

I looked to try and find in `module-customer` where an `ExtensionPool` is used, but it is nowhere to be found. So I guess that answers... "half" your question. As to why the join cannot be applied in your scenario. How it is working anyway, I am at a loss, and Magento has increased from 2.2 to 2.4 since your question was originally asked so things may have changed within `magento/module-catalog` and `magento/module-customer` since then.