0

I know I can achieve this with object Manager - but just wanted to see if there is a better way. Perhaps this case is a good candidate for using the object Manager; however, I would like to do things properly so it'd be good to get some feedback from more experienced developers.

I want to inject an object via a class constructor - and then within the body of the constructor decide what type of object it is.

I will use the Module Manager to check if a module exists - if so then I'd like to use one of its classes. Otherwise, I'd like to use another class in core.

The reason it is possible is because both the classes (the one that might not be available and the one in the core) have the same class name and method that I need to use).

Obviously I can't inject the class that might not exist directly. Here is some code as an example:

/**
 * MyClass constructor.
 *
 * @param {unsure how to define it} $object
 * @param \Magento\Framework\Module\Manager $moduleManager
 */
public function __construct({unsure how to define it} $object,
                            \Magento\Framework\Module\Manager $moduleManager,
)
{
    $this->_moduleManager = $moduleManager;

    if ($this->_moduleManager->isEnabled('ThirdPartyExtension_PerhapsNotInstalled')) {
        $object =  $classThatMightNotExist;
    } else {
        $object = $coreClass;
    }

    $this->_object = $object;
}
7

First Approach:
The cleanest way is to not take decisions in the constructor.
Let the di.xml do that for you.
Let's say the core class you are using if a module is not present is Some\Core\ClassName.
And the class that should use this core class us My\Custom\ClassName.

And the class that might not exist is MyExtension\PerhapsNotInstalled\ClassThatMightNotExist

Make your class constructor like this:

public function __construct(
    \Some\Core\ClassName $object 
) {
    $this->_object = $object;
}

Now, in your module MyExtension_PerhapsNotInstalled di.xml file add this:

<type name="My\Custom\ClassName">
    <arguments>
        <argument name="object" xsi:type="object">MyExtension\PerhapsNotInstalled\ClassThatMightNotExist</argument>
    </arguments>
</type>

just make sure that MyExtension\PerhapsNotInstalled\ClassThatMightNotExist extends the core class Some\Core\ClassName.

This way, if the module MyExtension_PerhapsNotInstalled is not installed, the original core class Some\Core\ClassName will be used, otherwise MyExtension\PerhapsNotInstalled\ClassThatMightNotExist will be used.

Second Approach:
If your extension that might not exist, is a third party extension that you cannot control, and you want your code to work with it and without it, you can do this (using the same notations as above):

Create your own class that acts as a factory:
Let's call it My\Module\Factory

<?php

namespace My\Module;

class Factory
{
    protected $moduleManager;
    protected $objectManager;

    public function __construct(
        \Magento\Framework\Module\Manager $moduleManager,
        \Magento\Framework\ObjectManagerInterface $objectManager
    ) {
        $this->moduleManager = $moduleManager;
        $this->objectManager = $objectManager;
    }

    public function create(array $data = array())
    {
        if ($this->moduleManager->isEnabled('ThirdPartyExtension_PerhapsNotInstalled')) {
            $instanceName =  'MyExtension\PerhapsNotInstalled\ClassThatMightNotExist';
        } else {
            $instanceName = 'Some\Core\ClassName';
        }
        return $this->objectManager->create($instanceName, $data);
    }
}

You should inject this new class in the constructor of your My\Custom\ClassName class and call the create method from it to determine the class instance you need.

public function __construct(
    \My\Module\Factory $factory 
) {
    $this->_object = $factory->create();
}

Note: This second approach is not really clean, because in theory your dependencies should be explicit and the composition should be done via di.xml but I certainly understand the need.
Second Note: You are not violating any guidelines of not using the object manager, because OM is allowed in factories and you just created a factory.
And your class does not depend on the OM directly.
I didn't test the code, so watch out for syntax errors.

| improve this answer | |
  • Looks like a good solution. +1. – Kingshuk Deb May 8 '17 at 13:27
  • @marius - Thanks, definitely getting closer - only thing is I might have confused the situation by saying 'myExtensionPerhapsNotInstalled' - it's actually a third part extension that might not be installed. It resembles a core class, has similar functionality, but does not override the core. So they're separate - but with the same methods, classes, etc. Sorry for misunderstanding – BAF May 8 '17 at 13:28
  • @BAF. I see. In this case you have a dependency problem. I will edit the answer with a solution that might work in your case also. – Marius May 8 '17 at 13:34
  • @BAF. See my edit (second approach). I didn't test, but I think it should work. – Marius May 8 '17 at 13:45
  • @marius - makes sense, thanks for this it has been very helpful – BAF May 8 '17 at 13:48
0

I would suggest using instanceof. You can check if the class is available like this. A class would be available if the module is enabled only. So

if ($pagerBlock instanceof \Magento\Framework\DataObject) {

And example implication can be something like this. // Taken from this.

if ( ($obj instanceof MyClass) != true ) {
    $obj = new MyClass();
}

No, i wont try to DI it. Just a speculation. Suggestions are welcome !!

Also a core php type solution can be like this.

| improve this answer | |
  • Thanks @Kingshuk, I understand - although would you load $pagerBlock in the first place using DI if \Magento\Framework\DataObject didn't exist? You would get a compilation error, so what would the type be to load in $object? – BAF May 8 '17 at 12:50
  • True. I wont try to use DI to make it. – Kingshuk Deb May 8 '17 at 13:08
  • Thanks, I think instead of going through all of the extra steps to instantiate the classes, probably object manager can be used in this case? – BAF May 8 '17 at 13:15

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.