3

For the sake of simplicity, let's say I want to echo out "Hello World" (in reality i want to do a lot more) directly after anyone runs php bin/magento setup:di:compile. In the latest version of Magento what is the correct way to do this without going directly in to vendor folders and modifying files? Observers are on their way out, interceptors seem to be the way forward but I cannot get an interceptor to run when basing it on the classes that perform the setup:di:compile action. Anyone know how to do this?

3 Answers 3

1
+50

Trying with overrides, plugins etc will not work, but there is a workaround.

You can create a shell script and do not use the php bin/magento setup:di:compile command directly.

EX: compile.sh

php bin/magento setup:di:compile
php yourscript.php

And you can execute ./compile.sh every time you need to run setup:di:compile

Another not way (not a good way though) is to directly bin/magento file.

After $application->run() you can execute your script by using exec php function and the content of the file would be somethign like this:

#!/usr/bin/env php
<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

if (PHP_SAPI !== 'cli') {
    echo 'bin/magento must be run as a CLI application';
    exit(1);
}

try {
    require __DIR__ . '/../app/bootstrap.php';
} catch (\Exception $e) {
    echo 'Autoload error: ' . $e->getMessage();
    exit(1);
}
try {
    $handler = new \Magento\Framework\App\ErrorHandler();
    set_error_handler([$handler, 'handler']);
    $application = new Magento\Framework\Console\Cli('Magento CLI');
    $application->run();
    if ($argv[1] == 'setup:di:compile' || $argv[1] == 'setup:upgrade') {
        // your code here
    }
} catch (\Exception $e) {
    while ($e) {
        echo $e->getMessage();
        echo $e->getTraceAsString();
        echo "\n\n";
        $e = $e->getPrevious();
    }
    exit(Magento\Framework\Console\Cli::RETURN_FAILURE);
}
5
  • I'm afraid it needs to be whenever specifically setup:di:compile is ran, not when a command running setup:di:compile is ran. This event also needs to trigger when setup:upgrade is ran or static-content:deploy is ran - but i figured if i found a way to run something after one command the infrastructure is there to be able to access the others. Additionally, it will not and never has been me running the setup:di:compile ect so i can't tell them to use my .sh file instead. Thank you for your answer though, out of interest why won't plugins/overrides work?
    – John
    Commented Jul 16, 2020 at 11:23
  • @John in that case you can try the second solution. If you put the execution of you script inside the if i added it will always run just for setup:di:compile. I am updating my answer and including both cases, setup:di:compile and setup:upgrade. Regarding why plugin/override won't work i do not have a precise answer, but it seems that magento does not allow overriding these files. Meanwhile for plugin there isn't any interceptor class generated so it won't work. Commented Jul 16, 2020 at 12:17
  • i'm going to research why magento doesn't allow overriding these files & see if that could be my path towards doing it, i'm going to give maybe a few more days to see if i get any more answers but if i don't i'm happy to give you the bounty for your work if you can edit your answer to list why it isn't possible with plugins or interceptors
    – John
    Commented Jul 17, 2020 at 7:52
  • Hi! Thanks for your answer - I have ended up in the scenario where I decided the best thing to do is to create my own Magento 2 command and have that run the code that I want it to rather than telling this company to run a shell script. In the scenario where I ask a question on how to do something that isn't (currently) technically possible, how should I award answers?
    – John
    Commented Jul 21, 2020 at 10:53
  • 1
    Modifying the bin/magento file will not cause troubles during the update so i think it is a solution. Doing another command of your own is of course another solution that in your case will work and do what you need. Regarding award of the question i think that you are the one to decide and you can see if the answers given are solutions to your problem :) Commented Jul 21, 2020 at 12:16
2

You may have seen the command bin/magento hits a Magento model Magento\Framework\Console\Cli from within magento script. However, this model is not instantiated with the objectmanager but rather using the raw php command new

then, following the code, you will find the function \Symfony\Component\Console\Application::doRunCommand. This function does not appear to have any interceptor (there is no plugins)

After you have run the command, this class is nowhere to be seen in generated folder with an interceptor. I have attempted to see why the class is not getting any interceptor and this is yet something to work out for me..

However, I don't how technical the above is to you, I'd say I am inclined to say the command-line system is not bootstrapped the same way as the magento framework is. Or more simply, the command-line environment is not triggering all the magento interception system.

As a conclusion, the best bet is indeed to trigger a script after the magento script or you may want to write a patch that would override the core function.

--> using a patch does not have the same problem as overriding the code directly. Next time you update the vendor folder, it gets updated and your patch will just need to be running again after each update.

3
  • Hi! Thanks for your answer - I have ended up in the scenario where I decided the best thing to do is to create my own Magento 2 command and have that run the code that I want it to rather than telling this company to run a shell script. In the scenario where I ask a question on how to do something that isn't (currently) technically possible, how should I award answers?
    – John
    Commented Jul 21, 2020 at 10:53
  • After thinking about it, I'm gonna accept the first answer I got but thank you again, especially for your work around \Symfony\Component\Console\Application::doRunCommand and noticing that Magento\Framework\Console\Cli's model is instantiated from new. Thank you again.
    – John
    Commented Jul 21, 2020 at 11:55
  • 1
    I also think the first answer does resolve your issue. Was just making sure you could see there was not much alternative in fact Commented Jul 21, 2020 at 12:33
0

The bottom line is that it isn't possible. Your best bet would be (as @Herve Tribouilloy @Zenel Rrushi have said) to either create a shell script that runs the command and then runs your custom code after or just to create an entire new Magento 2 command and have that run the code you want.

It seemingly isn't possible to setup an interceptor for the CLI commands because as Herve notes in his answer and i quote "the command-line system is not bootstrapped the same way as the magento framework is" resulting in the command-line environment not triggering the magento interception system.

Maybe it'll be possible one day to create an interceptor/plugin to run code after particular Magento 2 commands have been ran. But for now, in 2.3 it just can't be done.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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