Thanks to some late, post merchant beta changes made to Magento, distributing modules via Composer (PHP’s de-facto package/dependency manager) has never been easier. While we’re all interested to see how the new Marketplace turns out, thanks to Magento 2’s architecture changes we should all be able to distribute our modules without needing to buy into whatever tradeoffs will be involved with official distribution channels.
As a module developer, the bare minimum composer.json
file you’ll want for your module should look something like this
{
"name": "pulsestorm/module-name",
"description": "A description of your extension",
"authors": [
{
"name": "Robert Hoffner",
"email": "rhoffner@example.com"
}
],
"require": {},
"autoload": {
"psr-4": {
"Package\Module\": "src/path/to/Package/Module/Package/Module",
},
"files": [
"src/path/to/Package/Module/registration.php",
]
}
}
The name
property uniquely identifies your package across a composer repository. It has nothing to do with Magento, but should be globally unique. The convention is for a word identifying the package maintainer/creator (pulsestorm
above) be followed by a name identifying the individual composer package (module-name
above)
The description
and authors
properties are self explanatory and should not impact the behavior of your package.
The require
property would normally be a key/value pair of other composer packages your project/module uses. In this bare minimum file this is empty.
The meat of the functionality here is in the autoload
property. This is normally where you provide information to ensure PHP’s class autoloading works. Magento uses teh autoload
section for autoloading, but also for something a bit clever.
The psr-4
property sets up composer’s PSR-4 compatible autoloader. The first sub-key should match your Magento module’s Package
name and Module
name. The second key points to the physical folder in the source repository (i.e. GitHub) where your module resides (traditionally app/code/Package/Module
, but src/path/to/Package/Module/Package/Module
above)
This is a significant, and welcome, change. Magento modules no longer rely on a built-in autoloader function. Instead they’re using the standard set and used in the global PHP community. It also means you can put your module files wherever you want in your git repository.
The files
property is where things get a little clever. Normally, the files
autoload is a composer’s autoloader of last resort. It’s meant to provide composer package developers with a way to setup PHP autoloaders that aren’t PSR compatible.
The core team, however, have hijacked this functionality. The GA release of Magento 2.0 introduced a registration.php
file. These files tell Magento that your module (or theme) is part of Magento 2. By pointing a files
autoloader at your module’s registration.php
file, you ensure that Magento knows about your module, and will recognize your module when you try to enable it.
Both of these changes mean something else: Modules no longer need to be located in the app/code/
folder. You can put there whereever you want within your repository.
If the composer autoloader stuff flew a little over your head and you want to know more, you may be interested in my Laravel, Composer, and the State of Autoloading article. While foisted on Laravel, the composer articles are geared towards general PHP development.
Using Someone’s Module in your File
Assuming a module developer has setup a composer.json
file, and you can access their source code repository, you’ll be able to use it in your project.
If the module developer has listed their package in packagist, the only thing you’ll need to add to your project’s composer.json file is the following
require:{
//...
"pulsestorm/module-name":"dev-master"
//...
}
The above code says “add the version of pulsestorm/module-name
that’s in the master
branch of the repository. If you want a specific version of the module, swap that version out for dev-master
. Composer package versions are equivalent to git tags. i.e. a branch tagged with a version number becomes that version. Also, if the package is listed in packagist
, its listing page should have the correct require
syntax. You can also read more about composer versioning in composer’s module.
If a module developer has not listed their package in packagist, you’ll still be able to install it via composer. The only difference is you’ll need to add the module developer’s GitHub repository as a packagist repository.
For example, if you wanted to add Fooman’s same invoice number extension to your project, first you’d add the composer package to your composer.json
file.
require:{
//...
"fooman/sameorderinvoicenumber-m2":"2.0.1"
//...
}
However, since there’s no package on packagist with the fooman/sameorderinvoicenumber-m2 package name, you also need to add the GitHub repository as packagist repository
require:{
//...
"fooman/sameorderinvoicenumber-m2":"2.0.1"
//...
},
"repositories": {
"fooman/sameorderinvoicenumber-m2":{
"type": "git",
"url": "git@github.com:fooman/sameorderinvoicenumber-m2.git"
}
}
In case it’s not clear from context, the fooman/sameorderinvoicenumber-m2
name comes from the composer.json file, the 2.01
version comes from the GitHub repository’s tags, and the url
comes from the git ssh URL included on the GitHub repository’s main page.