Categories


Archives


Recent Posts


Categories


Composer Plugins and Installers

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

I’m planning to take a look at options for installing OpenMage — but before we do that we need to do a quick primer on the plugin system for PHP’s package management system, composer. We’ll be talking briefly about plugins, custom installers, and the composer/installer package.

Composer Plugins

Composer has a plugin system. Plugins allow you to create a composer package that registers a PHP class as a plugin. The syntax for registering this class in your composer.json file doesn’t actually use the word plugin — instead its full json path is extra/class

{
    /* ... */
    "extra": {
        "class": "Your\\Full\\Plugin\\Class\\Name"
    }
    /* ... */
}

This PHP class can listen for events that composer emits during its normal operation. A plugin author can then take programatic actions when composer emits these events. The composer docs cover the syntax for using this class to setup event listeners, and also provides a list of events you can listen for.

In addition to this event listener system, plugins also allow you to register a separate class as a composer command provider. Once registered, your command will be available next to all the other commands in $ composer.phar list. The plugin docs contain information on how to register your plugin with this command provider capability.

Custom Installers

Composer has a custom installer system. This system is adjacent to the plugin system, but it’s not fully part of the plugin system. A custom installer is a special class that you instantiate and then register in the constructor of a composer plugin class. However, despite working via the plugin system, customer installers are not a formal capability of the plugin system.

Installer classes implement a specific PHP interface. These methods comprise the logic needed for adding code to a user’s system somewhere other than the vendor folder. Composer invokes them automatically whenever a user runs certain composer commands (install, update, etc.).

Composer Non-Custom Installers

Composer also has a package named composer/installers. This is a composer plugin package. This composer plugin package adds a single custom installer to the system. The intention behind this package is if a package author requires it into their own package and their own package has a specific type, composer will automatically install files outside of vendor whenever anyone uses this author’s package.

If you look at the composer/installers README, it contains a long list of package types that it supports. Let’s use our old friends at Concrete5 as an example. There’s five different package types listed in the README for Concrete5.

concrete5-core
concrete5-package
concrete5-theme
concrete5-block
concrete5-update

If a third party developer creates a composer package that has composer/installers required and categorizes itself with one of these types

{
    "name": "some/concrete5-package",
    "type": "concrete5-core",
    "require": {
        "composer/installers": "~1.0"
    }
}

then whenever a — fourth? — party installs this package, the some/concrete5-package package’s files will be automatically added to the right place outside of vendor.

The works because for each supported type the composer/installer packages has a class suffix configured via code. When composer/installer‘s installer class needs to determine where to install files, it uses these suffixes to generate a full class name, and then uses an object instantiated via this new class. For our Concrete5 friends, those paths live in Composer\Installers\Concrete5Installer.

In addition to these hard coded paths, each vendor can choose to customize where things end up by using the installer-paths configuration in their own composer.json files. This extra configuration is covered in more detail by the composer/installers README.

Wrap Up

The customer installer and composer/installers package both exist to solve the vendor vs. bootstrap problem. While managing your code through composer is a no-brainer in 2020, even the simplest project still needs a single PHP file (or a symlink to a file in vendor) in order to run.

At a gut level I don’t like these installers. I prefer a stricter separation between “other people’s code I’m installing and using”, and code I can edit myself. Composer custom installers blur those lines by moving code from vendor (or another source) into your project. The implicit contracts around how this code should be updated or treated don’t seem to exist. That is to say, the customer installer system does nothing to enforce what happens during a package update, and what should happen isn’t always clear.

All that said — these installers acknowledge the reality that many popular PHP frameworks predate composer, and aren’t well suited to run strictly via the vendor folder. In our next article we’ll take a look at how the Open Mage project uses composer installers and, if we’re lucky, talk about ways they might be able to improve the experience for folks working with the platform.

Series Navigation<< Checking in on OpenMage and Magento in 2020Installing OpenMage: Bridging a Generational Gap >>

Copyright © Alan Storm 1975 – 2020 All Rights Reserved

Originally Posted: 21st September 2020