6

How can I get, code wise, the list of the installed modules and their version listed in composer?

I need something like this (format is just as an example. It's not really important):

array(
    array(
        'name' => 'magento/module-catalog',
        'version' => '101.1.0'
    ),
    array(
        'name' => 'magento/module-cms',
        'version' => '101.1.0'
    ),
....
)

I tried \Magento\Framework\Composer\ComposerInformation::getInstalledMagentoPackages() and getSystemPackages(), but both return and empty array.

I suspect this might happen because I didn't install Magento 2 via composer. I just cloned the guthub repo.

But this is not a solution. I need something that will work on both install methods (composers and clone repo).

0

2 Answers 2

9

Maybe my code can be useful for you (tested in the observer):

/**
 * @var \Magento\Framework\App\DeploymentConfig
 */
protected $deploymentConfig;

/**
 * @var \Magento\Framework\Component\ComponentRegistrarInterface
 */
protected $componentRegistrar;

/**
 * @var \Magento\Framework\Filesystem\Directory\ReadFactory
 */
protected $readFactory;

/**
 * @param \Magento\Framework\App\DeploymentConfig $deploymentConfig
 * @param \Magento\Framework\Component\ComponentRegistrarInterface $componentRegistrar
 * @param \Magento\Framework\Filesystem\Directory\ReadFactory $readFactory
 */
public function __construct(
    \Magento\Framework\App\DeploymentConfig $deploymentConfig,
    \Magento\Framework\Component\ComponentRegistrarInterface $componentRegistrar,
    \Magento\Framework\Filesystem\Directory\ReadFactory $readFactory
) {
    $this->deploymentConfig = $deploymentConfig;
    $this->componentRegistrar = $componentRegistrar;
    $this->readFactory = $readFactory;
}

/**
 * Get module composer version
 *
 * @param $moduleName
 * @return \Magento\Framework\Phrase|string|void
 */
public function getModuleVersion($moduleName)
{
    $path = $this->componentRegistrar->getPath(
        \Magento\Framework\Component\ComponentRegistrar::MODULE,
        $moduleName
    );
    $directoryRead = $this->readFactory->create($path);
    $composerJsonData = $directoryRead->readFile('composer.json');
    $data = json_decode($composerJsonData);

    return !empty($data->version) ? $data->version : __('Read error!');
}

/**
 * Collect enabled modules version
 *
 * @param Observer $observer
 */
public function execute(Observer $observer)
{
    $modules = $this->deploymentConfig->get('modules');
    $modulesWithVersion = [];
    foreach ($modules as $moduleName => $isEnabled) {
        if (!$isEnabled) {
            continue;
        }

        $modulesWithVersion[$moduleName] = $this->getModuleVersion($moduleName);
    }
}
  1. Collects all enabled module names from the config
  2. Reads their composer.json one-by-one and saves version

Result (in debug):

Result

4
  • this looks clean. I'll give it a shot and come back.
    – Marius
    Commented May 12, 2017 at 9:25
  • 1
    I can confirm this works. I had to do some changes, because some (custom) modules might not have composer.json and it gives an error. But it was easy to work around it. I also used $data->name instead of $moduleName in the return array, because that's what I needed. Thanks.
    – Marius
    Commented May 12, 2017 at 12:56
  • @Marius I'm glad to help you. Feel free to improve my answer if you could make it more helpful for others. Commented May 12, 2017 at 13:15
  • I have nothing to improve. The idea is there. If someone needs a really custom thing, let them work for it.
    – Marius
    Commented May 12, 2017 at 13:25
4

I need something that will work on both install methods (composers and clone repo).

That's probably the tricky part as you said because you can't use the Composer packages classes directly when installed via GitHub.

My suggestion would be to loop through the modules folder and use a mix of the following:

  • Magento\Framework\Composer\ComposerJsonFinder::findComposerJson() to find the composer.json file
  • then use \Composer\Factory::create(new BufferIo(), $composerJsonFile) to create a composer instance.
  • once you have that , I'm pretty sure you can call getConfig() on the Composer file to get the details of that file.

NB: all I'm saying here is highly theorical based on my assumptions

2
  • This sounds like a lot of work. I could simply do a glob and turn JSON into array and read it from there, but I was hoping for a clean solution. +1 though. It looks like a valid solution, at least theoretically.
    – Marius
    Commented May 12, 2017 at 8:21
  • @Marius yeah as I said I don't think there's a quick and clean solution when you have a non composer M2 install unfortunately :( Commented May 12, 2017 at 8:27

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.