6

It's pretty easy to replace a class in Magento 2 using dependency injection. However, let's say I have two modules that want to replace the same class. For example, the dotmailer Magento2 extension sets a preference for Magento\Customer\Model\AccountManagement but my own team's modules already override that class with one of our own. How do we resolve this conflict?

  • 1
    Use plugins and observers :) – Siarhey Uchukhlebau May 31 '17 at 14:41
  • @SiarheyUchukhlebau That doesn't work when the methods that need changing are private or protected - which is, unfortunately, a lot of the time. – Mr. Shiny and New 安宇 May 31 '17 at 14:42
  • If the method is private you should not change it anyway. – Siarhey Uchukhlebau May 31 '17 at 14:44
  • 1
    @SiarheyUchukhlebau Private and protected methods can be wrong/inappropriate/buggy/defective just as much as public methods. – Mr. Shiny and New 安宇 May 31 '17 at 14:59
9

It's the same problem like in M1 if modules overwrite the same class. You've to implement your own class which consolidate the changes of all conflicting modules in order to resolve it.

Your basic module structure

- app/code/YourNamespace
   |- ConflictResolver
        |- etc
        |   |- module.xml
        |   |- di.xml
        |- Model
        |   |- YourClass.php
        |- composer.json
        |- registration.php

Your module structure should look something like this. The third party and Magento modules are located in vendor directory... If not see here for how to setup a Magento 2 project: http://devdocs.magento.com/guides/v2.0/install-gde/prereq/integrator_install_ce.html

In the module.xml you have to define the sequence for your module loading

<?xml version="1.0"?>   
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> 
    <module name="YourNamespace_ConflictResolver" setup_version="1.0.0"> 
        <sequence>
            <module name="ThirdParty_ModuleA" />
            <module name="ThirdParty_ModuleB" />
            <module name="Magento_ModuleA" />
        </sequence>
    </module> 
</config>

In this example your module would be loaded after the three modules listed in the sequence node and your DI config will overrule the previous loaded...

See this page for more details: http://devdocs.magento.com/guides/v2.0/extension-dev-guide/build/module-load-order.html

However this is not the preferred way of the Magento Engineers. Plugins have better compatibility and if a module overwrites by using preferences this is a sign for less quality... Of course I understand, that there is in some cases no other way because the core it self does not follow Magento 2 standards in most modules.

The Future...

I've told with some core developers about further engineering ideas and concepts. The new way to go will be that all modules will be separate into API / service contracts and (final; final is not really possible because of the autogenerated classes) implementation so there will be interfaces for everything, but you can't extend from core and have to implement your own logic... For your problem this would mean that you have to implement an own class which includes the right interface(s) anyway...

Edit: Alan Kent just published something about this: https://community.magento.com/t5/Magento-DevBlog/Service-Contracts-in-Separate-Packages/ba-p/68129

  • "Implement your own class to consolidate the changes of all conflicting modules" - that sounds reasonable - a conflict-resolution module that resolves conflicts between two fighting modules? Am I reading you correctly? – Mr. Shiny and New 安宇 May 31 '17 at 19:14
  • Yes, you do. I updated my answer in order to be more concrete, so I hope... – Vadim Justus May 31 '17 at 19:22
  • I'm new to Magento - is it possible for you to expand in your answer how to structure the module so that its consolidation class gets loaded instead of the two classes it's mediating? Or should I post that as a new question? – Mr. Shiny and New 安宇 May 31 '17 at 19:25
  • I'll try :) But currently I've only my smartphone, so you have to way till tomorrow... – Vadim Justus May 31 '17 at 19:30
  • Wow, excellent edit to this answer! Thanks! – Mr. Shiny and New 安宇 Jun 1 '17 at 13:29
3

Make your class extend the dot mailer one. And declare your module to be loaded after the dot mailer module in module.xml.

  • Okay, I guess that works in the simple example I posted, but what about if I have two third-party modules overriding the same class? Or if extending a third-party module's class isn't feasible? – Mr. Shiny and New 安宇 May 31 '17 at 18:19
  • 1
    Then I guess the modules are not compatible. – Marius May 31 '17 at 18:21
  • So short of making one module depend on the other, there's no other solution for this? – Mr. Shiny and New 安宇 May 31 '17 at 18:22
  • Not that I know of. But there might be. Wait for an other answer. Don't take mine for granted. – Marius May 31 '17 at 18:24
  • Thanks. I was going to wait anyway, since your answer's just bad news :) – Mr. Shiny and New 安宇 May 31 '17 at 18:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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