General Context
When adding custom attributes to EAV-storage data types such as customer
s and customer_address
es, two seemingly redundant configuration values are allowed to be passed in:
// File: InstallData.php
public function install(...) {
/** @var Magento\Eav\Setup\EavSetup */
$eavSetup = $this->eavSetupFactory->create(...);
$eavSetup->addAttribute(
Magento\Customer\Model\Indexer\Address\AttributeProvider::ENTITY,
'my_custom_attr',
[
'system' => true,
'user_defined' => false
]
);
}
Other questions have addressed the question of what exactly a user_defined
custom attribute means: the attribute is considered a "system" attribute (note the ambiguous terminology here), and as such it will not appear on the admin as removable because it is considered essential to the operation of Magento.
Specific Context
However, when omitting the system
and user_defined
configuration values altogether, I found that the attributes I defined defaulted to 'system' => true
and 'user_defined' => false
. This behavior seems to be due to the following two lines of code in PropertyMapper.php
files:
// File: Magento/Customer/Model/ResourceModel/Setup/PropertyMapper.php
// Line: 27
'is_system' => $this->_getValue($input, 'system', 1),
// ...
// File: Magento/Eav/Model/Entity/Setup/PropertyMapper.php
// Line: 35
'is_user_defined' => $this->_getValue($input, 'user_defined', 0),
Based on the location of the two aforementioned files, I would predict that is_system
relates specifically to customer attributes, and is_user_defined
relates to attributes of any entity type.
When I later attempted to set and save those attributes via a repository, as such:
/** @var \Magento\Customer\Api\Data\AddressInterface */
$address = $this->addressRepository->getById(...);
$address->setCustomAttribute('my_custom_attr', 'my_custom_value');
$this->addressRepository->save($address);
...I found that my custom attribute was not even exposed by the engine, due to the following lines of code:
// File: Magento/Customer/Model/Metadata/AddressMetadata.php
// Lines: 121-143
public function getCustomAttributesMetadata($dataObjectClassName = AddressMetadataInterface::DATA_INTERFACE_NAME)
{
...
foreach ($this->getAllAttributesMetadata() as $attributeMetadata) {
...
if (!$isDataObjectMethod && !$attributeMetadata->isSystem()) {
$customAttributes[] = $attributeMetadata;
}
}
}
(The link to the Magento source is here.)
I had to set 'system' => false
in my InstallData.php
script in order for the custom attribute to be accessible via the program, yet I left user_defined
untouched.
Question
What is the difference between these two configuration values from a human perspective? How do they affect each other, if at all?