9

I've added some custom fields to the form of customer group by using upgradeSchema.php.

After that I found that the original fields like customer group code and tax id are saved by using setter methods in the API provided. It is completely different from Magento 1.X that just use setXXX() to save.

Fabian Schmengler
  • 65,791
  • 25
  • 187
  • 421
Ricky.C
  • 2,182
  • 9
  • 33
  • 54
  • I've tried using \Magento\Customer\Api\Data\GroupInterface $customerGroup->setData('program_type',$programType); program_type is corresponding to the table column 'program_type' to save into database, but failed. – Ricky.C Nov 30 '15 at 05:29
  • Should I write a custom API with getter and setter to save the fields? – Ricky.C Nov 30 '15 at 05:38

2 Answers2

25

Extension attributes mechanism should be used in this case. It allows extension of core APIs by 3rd party modules. Generic steps for enabling new extension attribute:

  1. Declare extension attribute as described in the official docs. After clearing var and running <project_root>/bin/magento setup:di:compile, corresponding setter and getter for this new attribute should appear in \Magento\Customer\Api\Data\GroupExtensionInterface (this interface is auto-generated)
  2. Write plugins for \Magento\Customer\Api\GroupRepositoryInterface::save, \Magento\Customer\Api\GroupRepositoryInterface::getById (and any other service methods as necessary) to save/load new attribute. As an extension developer, only you know where this attribute should be stored, may be any table. See \Magento\Downloadable\Model\Plugin\AroundProductRepositorySave::aroundSave as an example
  3. If you need to make this attribute visible in collection (to make it searchable/filterable), declare join node. If not then just skip this
  4. Access your custom attribute as: $customerGroup->getExtensionAttributes()->getMyAttribute(), where customerGroup implements \Magento\Customer\Api\Data\GroupInterface. setMyAttribute() can be used as well

Below is the example of configuration which should be put to VendorName/ModuleName/etc/extension_attributes.xml

<?xml version="1.0"?>
<config>
    <extension_attributes for="Magento\Customer\Api\Data\GroupInterface">
        <!--Data interface can be used as a type of attribute, see example in CatalogInventory module-->
        <attribute code="name_of_attribute" type="string">
            <resources>
                <resource ref="VendorName_ModuleName::someAclNode"/>
            </resources>
            <!--Join is optional, only if you need to have added attribute visible in groups list-->
            <join reference_table="table_where_attribute_is_stored" reference_field="group_id_field_in_that_table" join_on_field="group_id">
                <field>name_of_added_attribute_field_in_that_table</field>
            </join>
        </attribute>
    </extension_attributes>
</config>
Alex Paliarush
  • 13,751
  • 5
  • 51
  • 55
  • I tried to add the extension_attributes.xml, but no new interface is generated. p.s I've deleted the generation folder and invoked some operation..... – Ricky.C Dec 01 '15 at 05:41
  • My extension_attribute.xml: – Ricky.C Dec 01 '15 at 06:03
  • File should be called extension_attributes.xml (plural). Try to invoke generation of all autogenerated entities using CLI. – Alex Paliarush Dec 01 '15 at 07:35
  • sorry for the typo on the above comment, the file I have actually is extension_attributes.xml – Ricky.C Dec 01 '15 at 07:37
  • I've googled but found nothing. Can you let me know which command should be used? I'm a new comer that not familiar to the cli. Thanks. – Ricky.C Dec 01 '15 at 08:33
  • Added this command to the first step, please try if. – Alex Paliarush Dec 01 '15 at 08:38
  • Oh, I've tried setup:di:compile before, but it seems there are some bugs in the Magento, error occurs: [ErrorException] Declaration of Magento\Newsletter\Test\Unit\Model\Queue\TransportBuilderTes t::testGetTransport() should be compatible with Magento\Framework\Mail\Test \Unit\Template\TransportBuilderTest::testGetTransport($templateType, $messa geType, $bodyText, $templateNamespace) – Ricky.C Dec 01 '15 at 08:45
  • Not sure why you are getting this error because of unit test, on my installation compilation just completed successfully. Just remove \Magento\Newsletter\Test\Unit\Model\Queue\TransportBuilderTest::testGetTransport (or add 4th missing argument, like in parent) and run again. – Alex Paliarush Dec 01 '15 at 08:54
  • Unfortunately, still no new interface generated after re-compilation. – Ricky.C Dec 01 '15 at 10:03
  • Looks like your module is not enabled. I took your extension_attributes.xml content, put in Magento/Captcha/etc/extension_attributes.xml (just for testing) and got \Magento\Customer\Api\Data\GroupExtensionInterface::getGroupDomain and \Magento\Customer\Api\Data\GroupExtensionInterface::setGroupDomain generated by compiler. – Alex Paliarush Dec 01 '15 at 10:55
  • Alex, thanks for your help. I'm sure that my module is enabled, because the custom fields added by the module showed. Besides, I also put the extension_attributes.xml into Magento/Captcha/etc/. Still got nothing. But when I made some mistakes deliberately like removing the "for" inside <extension_attributes>, the system could give out an error. – Ricky.C Dec 01 '15 at 15:14
  • Try to delete <project>/var/di if exists before running compiler. Its existence may prevent compiler from successful execution. – Alex Paliarush Dec 01 '15 at 15:19
  • Do you have \Magento\Customer\Api\Data\GroupExtensionInterface generated? If yes, try to delete it and regenerate once again. Do you see expected methods after regeneration? – Alex Paliarush Dec 01 '15 at 20:39
  • /var/di not exists and \Magento\Customer\Api\Data\GroupExtensionInterface not generated. Magento has read the extension_attributes.xml but does not generate the GroupExtensionInterface – Ricky.C Dec 02 '15 at 01:15
  • Can you share what was the problem with generation? It is not expected to be instantiated using object manager (it even does not have a preference). Instead you should do $customerGroup->getExtensionAttributes() and it will return you extension object with getters/setters for your extension attributes (see step 4 in my answer) – Alex Paliarush Dec 02 '15 at 09:11
  • The problem due to my misunderstanding, I misunderstand the file location of GroupExtensionInterface.php. Besides, I've tried using $customerGroup->getExtensionAttributes() but it return null. Then I can't set or get values of the custom attributes. Thanks for your great help. – Ricky.C Dec 02 '15 at 09:14
  • Looks like you have not implemented plugin yet (step 2), see example here \Magento\Bundle\Model\Plugin\BundleLoadOptions::aroundLoad – Alex Paliarush Dec 02 '15 at 09:27
  • I find it difficult for me to write the plugins by modifying the examples you provided.In the AroundProductRepositorySave.php, there is a function called 'saveLinks', it uses linkRepository to save attribute 'link'. Should I write a 'regUrlRepository' for my custom attribute 'regUrl'? I'm confused why Magento Team could make Magento 2 so complicated when comparing with Magento 1.X. Could you give me more details how to write the plugins? I've worked on it for a whole day, but no result. Thanks – Ricky.C Dec 03 '15 at 09:24
  • Take a look at http://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html if haven't seen it yet. – Alex Paliarush Dec 03 '15 at 09:52
  • Thanks Alex. Sorry for my misleading words. My actual meaning is could you give me more details about how to modify the example you provided. I've learnt how to write a plugin thanks to your answer at another question post I created. Thanks – Ricky.C Dec 03 '15 at 09:57
  • Current discussion is pretty long already. How about closing it, if the original question is answered, and posting here link to a new question about this particular plugin creation? I will help when have time, if no one helps earlier. – Alex Paliarush Dec 04 '15 at 08:08
  • I'm getting this error while using this example: Fatal error: Uncaught Error: Call to a member function getCustomAttr() on null Could you please help me? – VIPIN A ROY Apr 26 '20 at 07:51
2

Don't forget that a module needs a register.php file in it, and you must use bin/magento module:enable VendorName_ModuleName before it will show up!

GuruBob
  • 131
  • 3