Dependency Management in PHP

Better Late than Never

Overview

  • What it is dependency management & how it can help you
  • How to discover and use packages
  • How to write (and publish!) your own packages

About Me

  • Sequoia McDowell
  • Software Engineer at PTC
  • @_sequoia
  • sequoia.mcdowell@gmail.com

Package Management

  • What is a package manager?
    ...a collection of software tools to automate the process of installing, upgrading, configuring, and removing software packages for a computer's operating system in a consistent manner.

    dpkg/apt, rpm/yum, npm, rubygems

  • What is a package?
    A package is essentially just a directory containing something.

Example Package: zelenin/curl

www > tree Curl/
Curl/
├── composer.json
├── example.php
├── src
│   └── Zelenin
│       └── Curl.php
└── readme.md

2 directories, 4 files
					

Package Manager vs. Dependency Manager

  • Package Manager: installs packages globally and/or to be invoked independently
  • Dependency Manager: installs packages locally, relative to a project, for the project

Why Use a Dependency Manager?

  • Easier installation of application/library
  • Fewer version conflicts
  • Find problems faster (esp. for platform dependencies)
  • More consistency & transparency
  • $$$

Bad old days

  • "Go get library X from location Y..."
  • "Does this plugin even work with this version of the framework?"
  • "No, it doesn't... where do I find the old one"
  • "I didn't know this relied on PHP 5.4! :("
  • Authoring a new lib/framework: roll your own sanity checker

Installing Composer

  • Requires PHP 5.3.2 (Released Dec 20, 2012)
  • Install via curl (*nix):
    $ curl -sS https://getcomposer.org/installer | php
  • Move into your $PATH for easier access
    $ mv composer.phar /usr/local/bin/composer
    # now reachable via `composer [command]
    # rather than `php composer.phar [command]

Other Installation Methods

  • Without curl:
    $ php -r \
    "eval('?>'.file_get_contents('https://getcomposer.org/installer'));"
    	
  • Windows: Composer-Setup.exe
[499]$ composer
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 6a1262e675b5c1c2c7b1cc58a14028f67885b880

Usage:
  [options] command [arguments]

Options:
  --help           -h Display this help message.
  --quiet          -q Do not output any message.
  --verbose        -v|vv|vvv Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
  --version        -V Display this application version.
  --ansi              Force ANSI output.
  --no-ansi           Disable ANSI output.
  --no-interaction -n Do not ask any interactive question.
  --profile           Display timing and memory usage information
  --working-dir    -d If specified, use the given directory as working directory.

Available commands:
  about            Short information about Composer
  archive          Create an archive of this composer package
  config           Set config options
  create-project   Create new project from a package into given directory.
  depends          Shows which packages depend on the given package
  diagnose         Diagnoses the system to identify common errors.
  dump-autoload    Dumps the autoloader
  dumpautoload     Dumps the autoloader
  help             Displays help for a command
  init             Creates a basic composer.json file in current directory.
  install          Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.
  list             Lists commands
  require          Adds required packages to your composer.json and installs them
  run-script       Run the scripts defined in composer.json.
  search           Search for packages
  self-update      Updates composer.phar to the latest version.
  selfupdate       Updates composer.phar to the latest version.
  show             Show information about packages
  status           Show a list of locally modified packages
  update           Updates your dependencies to the latest version according to composer.json, and updates the composer.lock file.
  validate         Validates a composer.json

Getting Oriented

a few helpful commands

  • diagnose: system sanity check
    [499]$ composer diagnose
    Checking platform settings: OK
    Checking http connectivity: OK
    Checking composer.json: FAIL
    No license specified, it is recommended to do so. For closed-source software you
    may use "proprietary" as license.
    Checking disk free space: OK
    Checking composer version: OK
    
  • -V: version
    [500]$ composer -V
    Composer version 6a1262e675b5c1c2c7b1cc58a14028f67885b880
  • help [command name]: help output for commands
  • -v|vv|vvv: increase verbosity

Installing a Package Using Composer

  1. Start a new project from scratch
  2. Start a new project based on a framework
  3. Work on an existing library or project

Start a New Project

Create new composer.json

[501]$ cat composer.json
{
	"require": {
		"slim/slim":"*"
	}
}

[502]$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing slim/slim (2.3.1)
    Loading from cache

Writing lock file
Generating autoload files

[503]$ ls -l vendor
total 12
-rw-rw-r-- 1 diamonds diamonds  182 Aug  9 22:50 autoload.php
drwxrwxr-x 2 diamonds diamonds 4096 Aug  9 22:50 composer
drwxrwxr-x 3 diamonds diamonds 4096 Aug  9 22:50 slim

Create a site/project based on a framework

create-project

[500]$ composer create-project laravel/laravel
Installing laravel/laravel (v4.0.6)
  - Installing laravel/laravel (v4.0.6)
    Downloading: 100%

Created project in /tmp/laravel
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing filp/whoops (1.0.7)
    Downloading: 100%

  - Installing doctrine/lexer (dev-master bc0e1f0)
    Loading from cache	
...
  - Installing laravel/framework (4.0.x-dev e943b3d)
    Cloning e943b3da84ab556f0176eea73387cd14fa07933e

symfony/translation suggests installing symfony/config ()
symfony/translation suggests installing symfony/yaml ()
...
monolog/monolog suggests installing ext-amqp (Allow sending log messages to an AMQP server (1.0+ required))
monolog/monolog suggests installing ext-mongo (Allow sending log messages to a Mongoserver)
Writing lock file
Generating autoload files
Generating optimized class loader
Application key [3keZh90lTVfdiyQ1aw5zwUvwY7w5OXBt] set successfully.

Work on an existing project or Library

git clone && composer install
[499]$ git clone https://github.com/Seldaek/monolog.git
Cloning into 'monolog'...
remote: Counting objects: 3810, done.
remote: Compressing objects: 100% (2109/2109), done.
remote: Total 3810 (delta 1560), reused 3519 (delta 1313)
Receiving objects: 100% (3810/3810), 744.90 KiB | 759 KiB/s, done.
Resolving deltas: 100% (1560/1560), done.
[500]$ cd monolog/ 
[501]$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing psr/log (1.0.0)
    Downloading: 100%

  - Installing mlehner/gelf-php (v1.0)
    Downloading: 100%

  - Installing raven/raven (0.5.1)
    Downloading: 100%

  - Installing doctrine/common (2.3.0)
    Downloading: 100%

  - Installing doctrine/couchdb (dev-master 44f0b79)
    Cloning 44f0b7926926aa77431591c6debf3004ce13ddfa

Writing lock file
Generating autoload files

Interactive Project Setup

composer init


[501]$ composer init

                                            
  Welcome to the Composer config generator  
                                            

This command will guide you through creating your composer.json config.

Package name (<vendor>/<name>) [diamonds/foo]: sequoia/clientSite
Description []: site for client X
Author [Sequoia McDowell <sequoia.mcdowell@gmail.com>]: 
Minimum Stability []: stable 
License []: proprietary

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]?
Search for a package []: slim

Search for a package []: slim

Found 15 packages matching slim

   [0] slim/slim
   [1] slim/slim-skeleton
   [2] slim/extras
   [3] slim/views
   [4] slim/strong
   [5] slim/shady
   [6] flynsarmy/slim-monolog
   [7] zeuxisoo/slim-whoops
   [8] entomb/slim-json-api
   [9] hellogerard/less-slim-middleware
  [10] petebrowne/slim-layout-view
  [11] rtablada/slim-post
  [12] slimcontroller/slimcontroller
  [13] mikehaertl/phpwkhtmltopdf
  [14] voodoophp/voodoo

Enter package # to add, or the complete package name if it is not listed []: 0
Enter the version constraint to require []: 2
Search for a package []:
Would you like to define your dev dependencies (require-dev) interactively [yes]? no


{
    "name": "sequoia/clientSite",
    "description": "site for client X",
    "require": {
        "slim/slim": "2"
    },
    "license": "proprietary",
    "authors": [
        {
            "name": "Sequoia McDowell",
            "email": "sequoia.mcdowell@gmail.com"
        }
    ],
    "minimum-stability": "stable"
}

Do you confirm generation [yes]?

Installing

[502]$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing slim/slim (2.0.0)
    Downloading: 100%

Writing lock file
Generating autoload files

Using the Dependencies

<?php
//index.php

require 'vendor/autoload.php';
$app = new \Slim\Slim();

$app->get("/",function(){
    echo "you should probably copy the .htaccess file to this dir...";
});

$app->run();

composer.json

  • List package information
  • Define dependencies
  • Declare where the files for your package are
  • Constrain what types of dependencies are installed
  • ...and more
{
    "name": "monolog/monolog",
    "description": "Sends your logs to files, sockets, inboxes, databases and various...",
    "keywords": ["log", "logging", "psr-3"],
    "homepage": "http://github.com/Seldaek/monolog",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "Jordi Boggiano",
            "email": "j.boggiano@seld.be",
            "homepage": "http://seld.be"
        }
    ],
    "require": {
        "php": ">=5.3.0",
        "psr/log": "~1.0"
    },
    "require-dev": {
        "mlehner/gelf-php": "1.0.*",
        "raven/raven": "0.5.*",
        "doctrine/couchdb": "dev-master"
    },
    "suggest": {
        "mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
        "raven/raven": "Allow sending log messages to a Sentry server",
        "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
        "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
        "ext-mongo": "Allow sending log messages to a MongoDB server"
    },
    "autoload": {
        "psr-0": {"Monolog": "src/"}
    },
    "extra": {
        "branch-alias": {
            "dev-master": "1.6.x-dev"
        }
    }
}

Root-only properties

  • require-dev
  • minimum-stability
  • repositories
  • config
  • scripts

composer.lock

  • Record which dependency versions are currently installed
  • Check this into your VCS (unless it's a library)
  • Exact same libs (from same location) across all servers
  • Clone & install 12 months later: all same lib versions
  • Update lockfile with composer update [packagename]

Finding and Adding Packages

  • Packagist.com
  • composer search
  • composer require
a screenshot of packagist.org with 'twitter bootstrap' in the search box and search results displayed below
a screenshot of the twitter/bootstrap package page on packagist.org. Available releases/versions are listed below the package metadata
[501]$ composer search bootstrap
twitter/bootstrap Sleek, intuitive, and powerful front-end framework for faster and easier...
twbs/bootstrap Sleek, intuitive, and powerful front-end framework for faster and easier we...
components/bootstrap Sleek, intuitive, and powerful front-end framework for faster and eas...
mopa/bootstrap-bundle Easy integration of twitters bootstrap into symfony2
braincrafted/bootstrap-bundle Twitter Bootstrap for Symfony2
qubes/bootstrap Bootstrap Helper
phundament/p3bootstrap Bootstrap Theme for Phundament
typo3/twitter-bootstrap Simple and flexible HTML, CSS, and Javascript for popular user int...
jasny/bootstrap Sleek, intuitive, and powerful front-end framework for faster and easier w...
jlong/sass-twitter-bootstrap A sass port of the sleek, intuitive, and powerful front-end f...
nervo/bootstrap Simple and flexible HTML, CSS, and Javascript for popular user interface c...
naturalweb/bootstrap Simple Module to allow facilitate use of Twitter Bootstrap Zend Frame...
komola/bootstrap-zend-framework Twitter bootstrap for ZF1
kdyby/bootstrap-form-renderer Nette forms renderer with bootstrap
mwillbanks/zfc-twitter-bootstrap A module that assists in implementing Twitter Bootstrap f...

[502]$ composer require twitter/bootstrap
Please provide a version constraint for the twitter/bootstrap requirement: 2.*
composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing twitter/bootstrap (v2.3.2)
    Loading from cache

Generating autoload files

[503]$ cat composer.json 
{
    "require": {
        "twitter/bootstrap": "2.*"
    }
}

Publishing to Packagist.org

screenshot of packagist.org: submit package page. Form contains a single input field for VCS repo location and a large green button labeled 'check'.

How Packagist Works

  • Gets package metadata from composer.json
  • Lists release versions based on tag names (or comparable branch name)
  • Users may also require branches directly using dev-branchname
  • Scans repo once per day for new code

CI with Travis

Travis CI is a hosted continuous integration service for the open source community.
  • Runs when you push to github
  • Can test against multiple PHP versions
  • Notifications on build failure
  • Has common tools (xdebug, phpunit, composer)
  • .travis.yml tells travis how to run your build
  • Best part: 'build: passing' badge from travis-ci.org

.travis.yml

language: php

php:
  - 5.3.3
  - 5.3
  - 5.4
  - 5.5

before_script:
  - composer install --dev --prefer-source

script: phpunit

What about PEAR?

  • Only one channel for a long time
  • Language features (namespaces)
  • Frameworks
  • Many packages not updated to PHP5
  • Github filled many of the same needs, better
  • vs. Composer: PEAR requires server software, Composer can install from git repo
  • Successes: PEAR installer itself, DB, MDB2; many projects have channels still
  • Still used for: PHP extensions

Summary

  • What & Why of Package Management
  • How to Package Your Application
  • How to Share
  • How to Test

Go forth & package! :)