Better dependency management: leverage composer to the limit

Can I use composer to do this?

A talk by Rodrigo Aguilera / @marinero

Norok!

Ymbra
Focused on processes, workflows and shared tools

Agenda

  • The PHP reinassance
  • The old days of drush make and the Drupal island
  • Composer is awesome
  • Your drupal project has dependencies too
  • Compose all the things!

The PHP reinassance

elephant

We had too much code

Took less time to write (or copypaste) a solution yourself than to find a component you can reuse.

Reusability

Sharing must be easy or it won't happen.

Free software as a feature.

First attemps, aka: the way there

  • Pear (PHP 4, required root, lots of includes)
  • Class autoloading (PHP 5.0)
  • Github (As replacement of Sourceforge)
  • Namespaces (PHP 5.3)
  • PHP standards (PSR-x) from PHP-FIG

The drupal island

Drupal diver

Drush make (2010)

The shopping list

api = 2
core = 7.*
projects[views] = 3.1
projects[ctools] = 1.0-rc1
projects[media] = 2.x-dev

projects[nodequeue][subdir] = contrib
projects[nodequeue][version] = 2.0-alpha1
projects[nodequeue][patch][] = "http://drupal.org/files/issues/1023606-qid-to-name-6.patch"
projects[nodequeue][patch][] = "http://drupal.org/files/issues/nodequeue_d7_autocomplete-872444-6.patch"

libraries[jquery.cycle][download][type] = get
libraries[jquery.cycle][download][url] = http://malsup.com/jquery/cycle/release/jquery.cycle.zip?v2.99
libraries[jquery.cycle][destination] = libraries
            

Problems

  • Downloads all the code everytime
  • All dependencies listed
  • You have to be specific about the versions
  • Only remote patches
  • Different make files for different purposes

Some brave sailors

Drupal diver Sailorwoman

Drupal makes some friends out there

Just by looking at the composer.json in drupal core

  • A lot of symfony components(dependency injection, events, routing, yaml, etc)
  • Twig
  • Guzzle
  • Composer
  • And much more

Introducing Composer - 2012

Director

Director

The main goals

  • Reuse third party libraries.
  • Avoid dependency hell.
  • Standarization among PHP projects

Definition

Composer is a tool for dependency management in PHP. It allows you to declare the dependent libraries your project needs and it will install them in your project for you.

What it means

  • No more Copy/Paste of libraries
  • Resolves dependencies
  • Each project defines its own requirements
  • Performs build tasks
  • Autoloading: all code under the same roof

Similar to composer in diferent programming languages

  • npm (javascript)
  • pip (python)
  • rubygems (with bundler)

Get Composer


# Quick-n-easy:
$ curl -sS https://getcomposer.org/installer | php

# Global
$ curl -sS https://getcomposer.org/installer | php -- --install-dir=bin
            

Structure of composer.json

Base manifest file for your project


{
    "name": "rodrigoaguilera/mydrupalsite",
    "description": "This site is awesome.",
    "require": {
        "drupal/honeypot": "1.*"
    },
    "require-dev": {
        "drupal/devel": "1.*"
    },
    "config": {},
    "extra": {}
}
            

Composer.json and composer.lock

  • The lock file has the dependencies already solved.
  • The key to get everyone same versions is the lock file.
  • Always commit your lock file.

Basic Commands

Install

            
composer install
            
            

Reads composer.lock and downloads all your dependencies in the /vendor directory.

Update

            
composer update [<vendor>/<package>]
            
            

Writes a new composer.lock based on what is on composer.json and downloads only what is missing.
You can update only one package to do more atomic updates.

Require

            
composer require <vendor>/<package>:"<version-constrain>"
            
            

Origin of libraries, modules, tools, etc.

The concept of repositories.

Packagist.org

Main repository for packages.
There is also https://packages.drupal.org/8 as a mirror of the modules and themes on drupal.org

Execute binaries

            
vendor/bin/drush
            
            

            
composer exec drush
            
            

Global vs local

  • The power of composer comes from having per project dependencies.
  • But you can also install composer plugins or tools shared by all the projects in your machine.
  • Use "composer global" before commands. (needs environment variable $COMPOSER_HOME to be set)

Simulating environments

            
"config": {
    "platform": {
       "php": "5.6.2",
       "ext-mongodb": "1.1"
    }
}
            
            

Semantic versioning

Versioning

Composer in production

            
composer install --prefer-dist --no-dev --optimize-autoloader
            
            
  • No git repository files
  • The require-dev section is ignored
  • Faster autoloader

Component vs. project

The composer.json for a project (the root package) has more capabalities like:

  • Use your own repos
  • Define hook scripts (post-install, pre-update, etc.)
  • Configuration

Patches

              
{
  "require": {
    "cweagans/composer-patches": "~1.0",
    "drupal/drupal": "8.5.*@dev"
  },
  "config": {
    "preferred-install": "source"
  },
  "extra": {
    "patches": {
      "drupal/drupal": {
        "Add startup configuration for PHP server": "https://www.drupal.org/files/issues/add_a_startup-1543858-30.patch"
      }
    }
  }
}
              
            

Dawg

Quiz: install or update

  • Be sure you have the last updates from your team: composer install
  • Deploying a new release of your application to production. composer install
  • Checked out with git a new project and want to start coding. composer install
  • Fetch new versions for the dependencies of your project. composer update

But... How do I use composer in my drupal project?

Composer template for drupal projects comes to the rescue.
https://github.com/drupal-composer/drupal-project

What does the template do?

  • Drupal will be downloaded with correct permissions ready for install.
  • Declaring a new depencency and downloading is one semantic command.
  • Modules, themes, and profiles (packages of type drupal-[module|theme|profile]) will be placed in web/[module|theme|profile]/contrib/

What does the template do?

  • Creates default writable version of settings.php.
  • Latest version of drush is installed locally for use at vendor/bin/drush.
  • Latest version of DrupalConsole is installed locally for use at vendor/bin/drupal.

Profit :D

  • Now everyone can have not only the same modules but also drush and console
  • Updating all your modules to the stable versions is just a couple of words away
  • Your continous integration system can become much more simple
Dawg

Frontend libraries are also dependencies

  • Not in packagist (npmjs.org or bower)
  • Different locations than modules

asset-packagist.org

  • Add one repository to your root composer.json
  • Collects both packages from npm and bower under 2 vendors
  • Enables the ability to do composer require npm-asset/bootstrap-sass:"^3"
  • Needs oomphinc/composer-installers-extender to define custom paths

Binary tools are also dependencies

  • Generally found in distribution's repositories (apt-get, yum, etc)
  • Usually compiled for a certain arquitecture and operating system
  • Specific packages for each binary
  • Available on vendor/bin/
  • Examples: mouf/nodejs-installer, jakoch/phantomjs-installer
Dawg

Recommendations

Minimum stability for all the dependencies or one by one

For example:

              "minimum-stability": "dev"
            

You can be more semantic and declare it for each package like

               composer require "drupal/webform":"^5@beta",
            

Config options


"config": {
    "sort-packages": true,
    "discard-changes": true,
    "process-timeout": 600,
    "platform": {
      "php": "7.1.0"
    }
  }
            

Vendoring

Committing dependencies in the repo

Versioning

The future

  • Better user experience
  • Best practices
  • Make parts of Drupal reusable for other PHP projects

Questions

THE END

Multumesc.
- https://getcomposer.org/