This looks like an older thread, but the following worked for me.
You can also add your own extension attribute with its own data model/table, and use the db_schema.xml
file instead of an install/upgrade script.
Something like the following:
- extension_attributes.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
<extension_attributes for="Magento\Company\Api\Data\CompanyInterface">
<attribute code="your_attribute_code" type="string">
<join reference_table="your_custom_table" reference_field="reference_in_new_table" join_on_field="entity_id">
<field>extension_attribute_field</field>
</join>
</attribute>
</extension_attributes>
</config>
Mind the join
in the above code. It will make Magento add your extension attribute getters and setters to the generated extension classes upon code generation (also worth mentioning the vendor/magento/framework/Model/AbstractExtensibleModel.php
class, it helps a lot with understanding how the extension attributes work). This is pretty neat.
- You can add your custom table to the db with a
db_schema.xml
(don't forget to generate a schema whitelist!):
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="custom_table_name" resource="default" engine="innodb" comment="Company Custom Table">
<column xsi:type="int" name="id" padding="10" unsigned="true" nullable="false" identity="true" comment="Id"/>
<column xsi:type="varchar" name="extension_attribute_field" length="255" nullable="true" comment="YOUR EXTENSION ATTRIBUTE"/>
<column xsi:type="int" name="company_id" padding="10" unsigned="true" nullable="false" comment="Company Id"/>
<constraint xsi:type="primary" referenceId="PRIMARY">
<column name="id"/>
</constraint>
<constraint xsi:type="foreign" referenceId="CUSTOM_TABLE_ID_COMPANY_ENTITY_ID"
table="custom_table_name" column="company_id" referenceTable="company"
referenceColumn="entity_id" onDelete="CASCADE"/>
</table>
</schema>
Then you can add your interfaces and model+resource model to retrieve the data from this table. I won't provide that code here.
Following the above link, you can add your plugins in your module's di.xml
:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Company\Api\CompanyRepositoryInterface">
<plugin name="company_extension_attribute" type="MyCompany\MyModule\Plugin\CompanyRepository" />
</type>
<type name="Magento\Company\Model\SaveHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="customHandler" xsi:type="object">MyCompany\MyModule\Model\SaveHandler\CustomHandler</item>
</argument>
</arguments>
</type>
<type name="Magento\Company\Model\Company\DataProvider">
<plugin name="company_data_provider_information" type="MyCompany\MyModule\Plugin\CompanyDataProvider" />
</type>
</config>
For the CompanyRepository
plugin, please find the code on that link above that I provided (except for the afterSave method).
There are two things here that need some explanation. First, since the Company object uses a handler pool for saving different type of information, we are adding another saveHandler that will take care of our extra piece of info. If you take a look at the vendor/magento/module-company/etc/di.xml
file, you should find this code:
<type name="Magento\Company\Model\SaveHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="defaultRole" xsi:type="object">\Magento\Company\Model\SaveHandler\DefaultRole</item>
<item name="superUser" xsi:type="object">\Magento\Company\Model\SaveHandler\SuperUser</item>
<item name="salesRepresentative" xsi:type="object">\Magento\Company\Model\SaveHandler\SalesRepresentative</item>
<item name="companyStatus" xsi:type="object">\Magento\Company\Model\SaveHandler\CompanyStatus</item>
<item name="customerGroup" xsi:type="object">\Magento\Company\Model\SaveHandler\CustomerGroup</item>
</argument>
</arguments>
</type>
So instead of creating a plugin method to do an afterSave, it makes more sense to create another handler that will save the new information (you will just need to implement the execute
method there, take one of the already present handlers as an example). For me it looked like this:
MyCompany/MyModule/Model/SaveHandler/CustomHandler
class CustomHandler implements \Magento\Company\Model\SaveHandlerInterface
{
private $customDataFactory;
private $customDataRepository;
public function __construct(
MyCompany\MyModule\Model\CustomDataFactory $customDataFactory,
MyCompany\MyModule\Model\CustomDataRepository $customDataRepository
)
{
$this->customDataFactory = $customDataFactory;
$this->customDataRepository = $customDataRepository;
}
public function execute(\Magento\Company\Api\Data\CompanyInterface $company, \Magento\Company\Api\Data\CompanyInterface $initialCompany)
{
if (!$initialCompany->getId()) {
$customData = $this->customDataFactory->create();
$customData->setCompanyId($company->getId());
} else {
$customData = $this->customDataRepository->getByCompanyId($initialCompany->getId());
}
$customData->setCustomAttribute($company->getExtensionAttributes()->getCustomAttribute());
$this->customDataRepository->save($customData);
}
}
- b. The other thing that would need some explanation is the
MyCompany\MyModule\Plugin\CompanyDataProvider
. This is where you give the data to your ui component. You can override the default Magento data provider for the company (as stated in the previous answers) or hook into the save function with a plugin or find another method to add the relevant information to the data provider. I used an after plugin, there might be (probably is) a better way to do this. However, it would look something like this:
class CompanyDataProvider
{
protected $customDataRepository;
public function __construct(
\MyCompany\MyModule\Api\CustomDataRepository $customDataRepository
)
{
$this->customDataRepository = $customDataRepository;
}
public function afterGetInformationData(
\Magento\Company\Model\Company\DataProvider $subject, $result, \Magento\Company\Api\Data\CompanyInterface $company){
$data = $this->customDataRepository->getByCompanyId($company->getId());
if ($company->getId() && $data->getId()){
$result['extension_attributes']['custom_attribute'] = $data->getCustomAttribute();
return $result;
}
$result['extension_attributes']['custom_attribute'] = '';
return $result;
}
- And finally you can add your field to the information fieldset on the company form in the
MyCompany/MyModule/view/base/ui_component/company_form.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<fieldset name="information" sortOrder="20">
<field name="extension_attributes.custom_attribute" formElement="input" sortOrder="10">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="source" xsi:type="string">custom_attribute</item>
</item>
</argument>
<settings>
<dataType>text</dataType>
<label translate="true">Custom Attribute Value</label>
</settings>
</field>
</fieldset>
</form>