Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependency injecting callable objects #1487

Closed
danslo opened this issue Jul 14, 2015 · 9 comments
Closed

Dependency injecting callable objects #1487

danslo opened this issue Jul 14, 2015 · 9 comments
Labels
Fixed in 2.4.x The issue has been fixed in 2.4-develop branch Issue: Format is not valid Gate 1 Failed. Automatic verification of issue format is failed

Comments

@danslo
Copy link
Contributor

danslo commented Jul 14, 2015

Imagine having a third party library:

class MyLibrary {
    protected $callableClass;

    public function __construct(callable $callableClass) {
        $this->callableClass = $callableClass;
    }

    public function run() {
        call_user_func($this->callableClass);
    }
}

Now also imagine we define our own callable object:

class CallableClass {
    public function __invoke() {
        // We are now callable.
        echo 'Hello world';
    }
}

This works fine when injecting dependencies manually:

$lib = new MyLibrary(new CallableClass());
$lib->run();

However, this doesn't work when we use the Magento2 DI system:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <type name="MyLibrary">
        <arguments>
            <argument name="callableClass" xsi:type="object">CallableClass</argument>
        </arguments>
    </type>
</config>

Instead of an instance of CallableClass, Magento 2 will attempt to inject an array:

array (size=1)
      'instance' => string 'CallableClass' (length=13)

which obviously results in something bad:

Recoverable Error: Argument 1 passed to MyLibrary::__construct() must be callable, array given

I never gave you an array, I gave you an object!

I managed to fix this by checking for ReflectionParameter::isCallable in Magento\Framework\Code\Reader::getConstructor:

+++ lib/internal/Magento/Framework/Code/Reader/ClassReader.php
@@ -8,6 +8,23 @@ namespace Magento\Framework\Code\Reader;
 class ClassReader implements ClassReaderInterface
 {
     /**
+     * Determines type from reflection parameter.
+     *
+     * @param \ReflectionParameter $parameter
+     * @return string
+     */
+    protected function getParameterType(\ReflectionParameter $parameter)
+    {
+        $type = null;
+        if ($parameter->getClass() !== null) {
+            $type = $parameter->getClass()->getName();
+        } elseif ($parameter->isCallable()) {
+            $type = 'callable';
+        }
+        return $type;
+    }
+
+    /**
      * Read class constructor signature
      *
      * @param string $className
@@ -26,7 +43,7 @@ class ClassReader implements ClassReaderInterface
                 try {
                     $result[] = [
                         $parameter->getName(),
-                        $parameter->getClass() !== null ? $parameter->getClass()->getName() : null,
+                        $this->getParameterType($parameter),
                         !$parameter->isOptional(),
                         $parameter->isOptional()
                             ? ($parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null)

I am however having difficulties finding the appropriate place to create tests for this. Adding a unit test for this method will be easy, but the DI mechanism itself must be tested as well.

I also haven't exactly found why that object is being wrapped in an array. I assume this is default behavior for things it doesn't know (like callable)?

Input here would be much appreciated.

@antonkril
Copy link
Contributor

Yes it doesn't instantiate things that have unknown type hinting. I't should be fixed, but it should also be fixed in compiler.

Did you try to run compiler?

We have integration tests: dev/tests/integration/Magento/Framework/ObjectManager

@sshrewz sshrewz added the PS label Jul 14, 2015
@joanhe
Copy link
Contributor

joanhe commented Jul 15, 2015

@danslo Thanks for raising this issue. It will be great if you can submit a pull request. Unit test for this class can be added under directory: lib/internal/Magento/Framework/Code/Test/Unit/Reader.
Integration test can be added under directory: dev/tests/integration/testsuite/Magento/Framework/Code/Reader.

@danslo
Copy link
Contributor Author

danslo commented Jul 15, 2015

@joanhe @antonkril Yeah my diff was more meant as some insight, not as something expected to be merged. I need to do a bit more research before I feel confident to write some tests, maybe update the compiler, etc.

Give me a couple of days ;-)

@ilol
Copy link

ilol commented Aug 5, 2015

Hi @danslo, do you have some updates?

@danslo
Copy link
Contributor Author

danslo commented Aug 5, 2015

@ilol I have a module of mine that depends on this functionality but I haven't gotten around to fixing it in Magento2 yet. I definitely do intend to come back to this soon though.

@danslo
Copy link
Contributor Author

danslo commented Aug 25, 2015

I will close this for now as I'm currently not finding time to look into this and I worked around this by using wrapper classes that just instantiates $handler['instance']. I'll probably come back to this later.

@danslo danslo closed this as completed Aug 25, 2015
@ilol
Copy link

ilol commented Sep 7, 2015

Ok, thank you, @danslo

@adragus-inviqa
Copy link
Contributor

/cc #2026

magento-team pushed a commit that referenced this issue Sep 13, 2017
[EngCom] Public Pull Requests
 - MAGETWO-72486: response condition order changes. #10826
 - MAGETWO-72465: Enable livereload for watch: commands #10836
 - MAGETWO-72428: Close PayPal popup window in case of rejected request #10820
@gabrieldagama gabrieldagama added the Fixed in 2.4.x The issue has been fixed in 2.4-develop branch label Sep 11, 2020
@gabrieldagama
Copy link
Contributor

@magento-engcom-team magento-engcom-team added the Issue: Format is not valid Gate 1 Failed. Automatic verification of issue format is failed label Sep 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fixed in 2.4.x The issue has been fixed in 2.4-develop branch Issue: Format is not valid Gate 1 Failed. Automatic verification of issue format is failed
Projects
None yet
Development

No branches or pull requests

9 participants