I've added a static Customer Address attribute (for some reason, other didn't work, but whatever; another time):

$setup->addAttribute('customer_address', 'xxx', [
    'type' => 'static',
    'input' => 'text',
    'label' => 'XXX',
    'global' => 1,
    'visible' => 1,
    'required' => 0,
    'user_defined' => 1,
    'visible_on_front' => 1,
    'group' => 'General',
    // 'used_in_forms' => ['adminhtml_customer']
    'used_in_forms' => ['adminhtml_customer_address']

The attribute is showing up in the admin panel and, on load, the object is populated with the correct value.

But now I want to make sure this attribute gets correctly transferred to the Data model as well (\Magento\Customer\Api\Data\AddressInterface):

$x = \Magento\Framework\App\ObjectManager::getInstance()

/** @var \Magento\Customer\Api\Data\AddressInterface $addr */
$addr = $x->getById(1); // <-- "xxx" is not available here; others are

At first, I thought that only by having the static attribute, M2 would transfer its value to the Data model, or at least to its getCustomAttributes() or getExtensionAttribute(). It didn't. So I've created an extension_attrbutes.xml, telling it to do so:

<?xml version="1.0"?>
<config path="to.xsd">
    <extension_attributes for="Magento\Customer\Api\Data\AddressInterface">
        <attribute code="xxx" type="string" />

Damn it, that didn't work either, because I didn't specify a join directive and thus failing some conditions. But do I have to specify a join condition when my attribute is static/column? Furthermore, the Address Data interface is implemented (not auto-generated) so I think the only way is through extension attributes, right?

Do I really have to do it manually?

I'm really starting to hate those Data layers. There's not only many criterias to get an attribute functioning correctly, but, once you finally have made a valid attribute, some other find-them-if-you-can criteria need to be satisfied in order to have attributes into the Data layer.

1 Answer 1


Regarding saving/loading extension attribute

In general. The only correct way to make new attribute available in your data model is to populate it using plugin. The same relates to save, if you want have it saved to DB. For customer address you need "before" plugin for \Magento\Customer\Api\AddressRepositoryInterface::save() and "after" plugin for \Magento\Customer\Api\AddressRepositoryInterface::getById(). In that plugin you, as extension developer, know where your extension attribute is stored (may be anywhere, another table for example) and how it should be saved/retrieved.

In your particular case. This extension attribute can be loaded/saved using \Magento\Customer\Model\Address in plugins.

Is there a reason not to create new system EAV attribute? Then it will automatically be available in getCustomAttributes() array, and no need to deal with plugins.

Regarding other points in your question

Join directives are necessary only if you want to make this attribute available in the list of addresses, also you might want to declare them if there is a need to perform filtration by this attribute while using \Magento\Customer\Api\AddressRepositoryInterface::getList().

getCustomAttributes() will only return you EAV attributes.

Hopefully, you will love service contracts when your custom module will not be broken after the next releases of Magento 2 (of course if you do not bypass service contracts and use models/collections/resource models directly). And when you start consuming/exposing Magento 2 web API, which is now based on the same service contracts. So you have to make changes only in one place (e.g. via plugin) and they will be applied everywhere. This was impossible in Magento 1.

  • Thanks for the reply. Not saying the Data layer is bad. I know what it tries to do, it's just that it's kind of clunky and manual. For example, the Product Data layer actually has some of the custom attributes in the custom_attributes property. Which is what I was half-expecting Address Data to be able to do, too. Coupled with the custom-vs-extension attributes, and until I get the hang of it, it's quite a complicated system.
    – nevvermind
    Commented Nov 19, 2015 at 21:44
  • Sorry that I have to piggyback on this thread, but it seems that \Magento\Customer\Model\Address::getDataModel() is deprecated. I need to get to the extension attribute object, but I cannot through the Address model (as it's the case of the Product model of your github link), because of the deprecation. So it's \Magento\Customer\Api\Data\AddressInterface::getExtensionAttributes() instead of the preffered \Magento\Customer\Model\Address::getExtensionAttributes(). Er.. what now? Also, see what over-egineering gets you?
    – nevvermind
    Commented Nov 19, 2015 at 23:51
  • I understand what this comment says, but when you use an afterLoad plugin, you receive a model. But I cannot get to the extension attrs object through the model, but through its data model instead - which I'm forbidden to. I commented twice to give you the full view of things.
    – nevvermind
    Commented Nov 19, 2015 at 23:54
  • Please check my edited comment, should be clearer now what I mean (for which methods plugins should be created). Commented Nov 20, 2015 at 8:32
  • Thanks again for the follow-up. I would love to have the getCustomAttributes() return value pre-populated with my attribute, but it doesn't happen. When creating such an attribute (EAV, static or not) the system is not setting it. The attribute appears in backend, I set a value, I save the customer, but on refresh the value's not there. M2 checks the already implemented Address Data interface which has no setXxx or setIsXxx, thus failing this check: m2 link. So you end up with a valid EAV attribute, which is not saved in DB.
    – nevvermind
    Commented Nov 21, 2015 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.