Let's poke with Magento 2 runtime

Posted on June 10, 2016

One of my favorite way of learning Magento framework was that of initializing a Magento runtime and poking with it through the command line.

I usually recommend writing shell scripts as best practice for Magento 1 instead of using bare minimum PHP scripts.

Since shell scripts in Magento 2 left space to Command Line Interface (CLI) commands, PHP scripts come back in handy.

Here is a first example of a PHP script that can be put in Magento 2 installation directory (the one that contains the pub subdirectory):

try {
    require __DIR__ . '/app/bootstrap.php';
} catch (\Exception $e) {
    echo $e->getMessage() . PHP_EOL;
    exit(1);
}

$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
/** @var \Magento\Framework\App\Http $app */
$app = $bootstrap->createApplication('Magento\Framework\App\Http');
$app->launch();

// YOUR CODE HERE

What can we do with that piece of script?

Well, what follows is a step-by-step example of how to retrieve a collection of products; we should place the following code after the // YOUR CODE HERE comment.

First of all: we don’t have any more static methods to invoke on a Mage class; neither are we encouraged to use the new statement to instantiate objects.

There are several new ways of instantiating objects within Magento 2 and I warmly recommend to read this quickie by Alan Storm to get an idea.

For our example let’s use the object manager, provided by our $bootstrap object:

$objectManager = $bootstrap->getObjectManager();

Now that we have our shiny object manager, we can instantiate a product factory.

Wait what? We use an object to instantiate a factory object which in turn will be used to instantiate objects? Yes, remember: we are poking around, we aren’t doing things according to best practices.

In an ideal world we would write our code in a class; that class will be injected needed dependencies through its constructor; the object manager will do that work under the hood without any need for us to use it directly. But that’s not the scenario that occurs here in our PHP script.

So let’s ask the object manager to provide a product factory:

$productFactory = $objectManager->create('Magento\Catalog\Model\ProductFactory');

Note: factory classes are dynamically generated by Magento 2. For example, we won’t find the ProductFactory class under the Magento_Catalog module; if we want to find it we have to dig into var/generation/Magento/Catalog/Model path.

Once we have our $productFactory we can get a product collection and count results:

$collection = $productFactory->create()->getCollection();
echo 'Total products:', $collection->count(), PHP_EOL;

That’s it!

Here is the complete code snippet in case you want to download it.

Note that what I’ve shown is still a work in progress script, lacking things like initialization of application area and user session; I will post updates here in the future, so stay tuned and enjoy!

EDIT

Many thanks to my beloved mentor Vinai Kopp who, after reading this post gave me some useful advices.

First advice: from PHP 5.5 we can use the ::class directive to get the fully qualified class name:

$objectManager->create(\Magento\Catalog\Model\ProductFactory::class);`

instead of:

$objectManager->create('Magento\Catalog\Model\ProductFactory');`

Second advice: we can instantiate the product collection factory directly instead of using the product factory and then get the collection:

$productCollectionFactory = $objectManager->create(\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class);
$collection = $productCollectionFactory->create();

Another interesting thought triggered by Vinai reading my post is that there is no \Magento\Framework\AppInterface implementation for CLI applications; indeed the bin/magento is a SymfonyApplication and doesn’t implement the AppInterface.

He pushed me to open an issue asking the Magento 2 team for such an implementation.


Photo credits: bambe1964 - Creative Commons license


Posted with : Magento2, Runtime