Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Composer: Managing Product Dependencies

Composer: Managing Product Dependencies

There's a lot of awesome libraries out there that you can use with your projects. What's the best way to manage those dependencies and keep everyone using the same version? Commit them to your repository? Use git submodules?

Try Composer. It's an extremely easy way to document dependencies, lock them down to specific versions, and then help to ensure every developer on the project is using the same versions of the included dependencies.

Learn how to use Composer to manage dependencies and then learn how to share your libraries with others by publishing your own composer compatible projects.

Russell Ahlstrom

January 17, 2014
Tweet

Other Decks in Programming

Transcript

  1. Introduction
    Managing Project Dependencies
    Russell S. Ahlstrom
    @janiv2

    View Slide

  2. VP of Web Development at Scan, Inc.
    Scan’s goal is to make it easy to connect the digital and physical worlds. Currently, we’re doing that with QR Codes. We have QR codes for business cards, following or liking
    people on social networks, connecting to wi-fi networks, contacting people, or just showing plain text. We’re currently beta testing two new types of QR Codes.
    One, which we’re calling Scan to Pay, allows for collecting mobile payments or donating to charities. For example, you see something in the Sky Mall magazine you want to buy.
    You scan the QR code and buy it immediately. Or maybe someone hands you a flyer from the Red Cross asking for help in the Philippines due to the recent typhoon. You can scan
    the qr code on the flyer to donate to the Red Cross.
    The second, called Scan to Market, encourages customers of business to share something on social networks to receive some kind of incentive from the business--such as free
    chips or a 5% discount, etc.
    Personally, I’ve been doing PHP for over 13 years and professionally for over 10. I’m a sucker for the Symfony 2 framework. I love writing all my CSS in SASS. And if I need to do
    something fancy in JavaScript, I love doing it in Ember.
    I’m a huge board game fan and I spend all my hard earned money on Kickstarter. You can scan my QR code to see my board game collection or view some of the things I’ve
    pledged for on Kickstarter.

    View Slide

  3. The Problems
    What Problems Are We Solving?
    We’re talking about Composer today and how we can use it to manage project dependencies. Let’s talk about some of the problems project dependencies can
    cause.

    View Slide

  4. The Problems
    Project Setup
    Let’s say you’re the new guy at work. Your first day is spent getting your environment all setup so you can start developing on the company’s website. The senior
    developer tells you you’ll need to clone the repo down from github and then install some libraries the site depends on. You need to go download Guzzle,
    Monolog, Doctrine, the Zend Framework, some company specific libraries, PHPUnit, a Selenium WebDrive for PHP, etc.
    You have to go find where to download all these libraries, figure out where to put them, and then how to hook them all up correctly. It takes you an hour or so
    and then you try to run the website. Nothing works. You’re getting these errors about method definitions not being defined or wrong arguments being passed,
    etc. You go and bug the senior developer. He comes and talks a look at your setup and starts debugging. After a while, he figures it out. You downloaded the
    latest version of the Zend Framework and Doctrine while the company is still a few versions behind. You delete the newer libraries, download the older ones, and
    things seem to be working.
    And then you run your unit tests. Looks like the PHPUnit version you installed is wrong too. You have to figure out which version you need to be using and install
    that one instead.

    View Slide

  5. $ cd ~/projects/companyWebsite
    $ wget https://github.com/guzzle/guzzle/archive/
    master.zip
    $ unzip master -d vendor
    $ git add ./
    $ git commit -m ‘Adds Guzzle Library’
    You decide to make this easier for the next new guy. Instead of having to download all the 3rd party libraries, let’s just commit them to our project. That way the
    next time someone clones down the project, they already have everything.
    This seems look a good idea, right? You do this with all the libraries and pretty soon have them all committed and push your changes up.
    The senior developer stops by. Hah. He’s not too happy. You’ve added all this code to the repo that’s not yours. Your repo is huge, if a new version of the library
    comes out, you have to download it, overwrite all the old files, and commit it. You no longer have the commit history of the libraries. Instead you have the commit
    history of ‘Updates guzzle”, “Updates guzzle to latest version”, “Updating libraries”.
    And now that the libraries are committed to the repo, it won’t be long before someone decides they can just modify something in a library to fix an issue they’re
    having and commit it. Now you’ve forked the library and upgrading will either become a lot harder or someone will overwrite the library and not notice the
    customizations your company has made to it.
    It’s a bad idea. Don’t do this.

    View Slide

  6. $ cd ~/projects/companyWebsite
    $ git submodule add [email protected]:guzzle/guzzle.git
    $ git commit -m ‘Adds Guzzle Library’
    Okay, so scratch committing these libraries directly to our repo. Googling around, you find out about git submodules and decide to use those. You add
    submodules to your repo for each library and commit those up.

    View Slide

  7. $ cd ~/projects/companyWebsite
    $ git submodule init
    $ git submodule update
    A new developer comes along and is setting up his project. He clones out the repo and he gets all these blank folders with no code in them. Oh, you explain to
    him he needs to do a git submodule init, and then a git submodule update and that’ll clone everything down. Perfect.

    View Slide

  8. $ cd ~/projects/companyWebsite
    $ cd guzzle
    $ git checkout master
    $ git pull
    $ cd ../
    $ git add ./
    $ git commit -m ‘Updates Guzzle Library’
    New versions of all the libraries you use come out. Now you need to figure out how to update all your submodules. You google around. Ah, you have to go inside
    of each folder, and do a git checkout master, git pull, and then go back to the root of the project, and commit the submodule update. Not a huge deal.
    If you have a ton of libraries you can either do each library by hand one at a time as above, or you can google around until you find out that you can also do, “git
    submodule foreach git pull origin master”. Problem solved.
    Things seem to be working well. Why not just use submodules? Sure there’s a little training required and updating submodules is a little weird but no big deal,
    right.

    View Slide

  9. The Problems
    What About Non-Git Libraries?
    What are you going to do when you find a non-git library you want to do? You find some cool library using subversion or you need to use something from pear.
    Now what? Are you going to keep a git mirror of that svn project you want to use? It’s a pain.

    View Slide

  10. A Better Way
    There Has to be a Better Way!

    View Slide

  11. A Better Way
    There Has to be a Better Way!

    View Slide

  12. What is Composer?
    What is Composer?

    View Slide

  13. What is Composer?
    Tool for Dependency
    Management
    Composer is a tool for dependency management in PHP. It allows for you to declare the dependent libraries your project needs and it will install them in your
    project for you.
    From getcomposer.org

    View Slide

  14. What is Composer?
    Not a Package Manager
    Composer is not a package manager. Yes, it deals with “packages” or libraries, but it manages them on a per-project basis, install them in a directory (e.g vendor)
    inside your project. By default it will never install anything globally. Thus, it is a dependency manager.
    From getcomposer.org
    This isn’t a new idea. Composer is strongly inspired by Node’s NPM or Ruby’s bundler. There wasn’t a similar tool for PHP until Composer.

    View Slide

  15. What is Composer?
    What does Composer do?
    • You have a project that depends on a number of libraries
    • Some of those libraries depend on other libraries.
    • You declare the things you depend on.
    • Composer finds out which versions of which packages need
    to be installed, and installs them (meaning it downloads
    them into your project).
    Composer not only downloads the libraries you’ve asked for but also any libraries that those libraries depend on as well. It also figures out what versions of all
    those libraries to use to get them all working happily together.
    From getcomposer.org

    View Slide

  16. $ curl -sS https://getcomposer.org/installer | php
    $ php composer.phar --version
    Composer version
    b20021cc6aa113069e4223b78d0074a1fc7dd4e8 2014-01-14
    16:22:09
    Installing locally.

    View Slide

  17. $ curl -Ss https://getcomposer.org/installer | php
    $ mv composer.phar /usr/local/bin/composer
    $ composer --version
    Composer version
    b20021cc6aa113069e4223b78d0074a1fc7dd4e8 2014-01-14
    16:22:09
    Installing globally. This is what I usually do and it’s worked well for me.

    View Slide

  18. $ brew tap josegonzalez/homebrew-php
    $ brew install josegonzalez/php/composer
    $ composer --version
    Composer version
    b20021cc6aa113069e4223b78d0074a1fc7dd4e8 2014-01-14
    16:22:09
    I just learned about this and haven’t tried it? Has anyone? How does it handle updating composer? Do you do composer self update still or brew upgrade?
    If I was installing new, I’d probably try it this way.

    View Slide

  19. $ cd ~/projects/companyWebsite
    $ vim composer.json
    {
    “require”: {
    “guzzle/guzzle”: “~3.8”,
    “monolog/monlog”: “~1.7”
    }
    }
    You create a composer.json and then minimally list your required dependencies and versions.

    View Slide

  20. $ cd ~/projects/companyWebsite
    $ composer init
    Welcome to the Composer config generator
    This command will guide you through creating your composer.json config.
    Package name (/) [scan/company-website]:
    Description []: The website for our company
    Author [Russell Ahlstrom ]:
    Minimum Stability []:
    License []: MIT
    Define your dependencies.
    Would you like to define your dependencies (require) interactively [yes]?
    Search for a package []: guzzle/guzzle
    Found 15 packages matching guzzle/guzzle
    [0] guzzle/guzzle
    Enter package # to add, or the complete package name if it is not listed []: 0
    Enter the version constraint to require []: ~3.8
    Search for a package []:
    Would you like to define your dev dependencies (require-dev) interactively [yes]? no
    {
    "name": "scan/company-website",
    "description": "The website for our company",
    "require": {
    "guzzle/guzzle": "~3.8",
    "monolog/monolog": "~1.7"
    },
    "license": "MIT",
    "authors": [
    {
    "name": "Russell Ahlstrom",
    "email": "[email protected]"
    }
    ]
    }
    Do you confirm generation [yes]?
    If you have a hard time remembering the basic format, you can also do composer init and it’ll walk you through creating a composer.json. It’ll ask you a bunch of
    questions.

    View Slide

  21. {
    "name": "scan/company-website",
    "description": "The website for our company",
    "require": {
    "guzzle/guzzle": "~3.8",
    "monolog/monolog": "~1.7"
    },
    "license": "MIT",
    "authors": [
    {
    "name": "Russell Ahlstrom",
    "email": "[email protected]"
    }
    ]
    }
    Here’s the end result from the script but bigger.

    View Slide

  22. Versioning
    guzzle/guzzle: “3.4.3”
    You’re using this version and this version only.

    View Slide

  23. Versioning
    guzzle/guzzle: “3.4.*”
    3.4.* means 3.4.1, 3.4.2, 3.4.3, etc.

    View Slide

  24. Versioning
    guzzle/guzzle: “>=3.4,<4”
    This means anything 3.4 but less than 4.

    View Slide

  25. Versioning
    guzzle/guzzle: “>=3.4,<3.6|>=4”
    You can also do an “or” with a pipe. “And” has higher precedence.

    View Slide

  26. Versioning
    guzzle/guzzle: “~3.4”
    Most useful with semantic versioning and this is the one I try to use if possible.
    Semantic versioning works like this. x.y.z
    Z is changed if it’s just a simple bug fix. Everything is still backwards compatible and no new public API’s are introduced.
    Y is changed if new public API’s are introduced and everything is still backwards compatible. Z is reset to 0. Y is also changed if some public API’s are deprecated.
    It can also be changed if there is substantial changes in the private code.
    X is changed when you break backwards compatibility. Y and Z are reset to 0.

    View Slide

  27. Versioning
    guzzle/guzzle: “~3.4.2”
    This is the same as >=3.4.2,<3.5

    View Slide

  28. Versioning
    guzzle/guzzle: “3.9.*@dev”
    You can also do @alpha, @beta, @RC

    View Slide

  29. Versioning
    guzzle/guzzle: “dev-branch”
    Branch can be any branch name in your repo. You see dev-master a lot.

    View Slide

  30. Versioning
    guzzle/guzzle: “dev-branch#0a66”
    You really shouldn’t do this. If you are doing it, it should be for a very short time only. You want to move off to a version as soon as possible.

    View Slide

  31. $ composer update
    Loading composer repositories with package
    information
    Installing dependencies
    - Installing psr/log (1.0.0)
    Downloading: 100%
    - Installing monolog/monolog (1.7.0)
    Loading from cache
    ...
    Writing lock file
    Generating autoload files
    Composer update writes a lock file.

    View Slide

  32. Version Control
    • Commit
    - composer.json
    - composer.lock
    • Add to .gitignore
    - vendor/
    Version Control

    View Slide

  33. $ git clone [email protected]:scaninc/website.git
    $ composer install
    Loading composer repositories with package information
    Installing dependencies from lock file
    - Installing psr/log (1.0.0)
    Downloading: 100%
    - Installing monolog/monolog (1.7.0)
    Downloading: 100%
    - Installing symfony/event-dispatcher (v2.4.1)
    Downloading: 100%
    - Installing guzzle/guzzle (v3.8.0)
    Downloading: 100%
    Generating autoload files
    New developer comes on and all they need to do now is clone down the project and run composer install. All the dependencies with all the right versions are
    automatically downloaded and installed in the correct places.
    People who aren’t managing dependencies should also use composer install. Do not do composer update.
    composer install reads the lock file and installs the versions specifically mentioned in that file. It does not use composer.json and find versions meeting the rules
    specified there.

    View Slide

  34. {
    “require”: {
    “guzzle/guzzle”: “~3.8”,
    “monolog/monolog”: “~1.7”
    },
    “require-dev”: {
    “phpunit/phpunit”: “~3.7”
    }
    }
    $ composer install --dev
    Loading composer repositories with package information
    Installing dependencies (including require-dev)
    - Installing phpunit/phpunit (3.7.28)
    Downloading: 100%
    Writing lock file
    Generating autoload files
    You can also have dev requirements that are only installed if you pass the dev flag.

    View Slide

  35. {
    “require”: {
    “php”: “~5.4”,
    “ext-intl”: “*”,
    “lib-curl”: “*”,
    “guzzle/guzzle”: “~3.8”,
    “monolog/monolog”: “~1.7”
    },
    “require-dev”: {
    “phpunit/phpunit”: “~3.7”
    }
    }
    You can also require platform packages. They won’t be installed by composer but composer will check to see if they are met and error out with messages about
    what platform packages are missing.

    View Slide

  36. $ composer update
    Loading composer repositories with package
    information
    Updating dependencies (including require-dev)
    - Removing guzzle/guzzle (v3.8.0)
    - Installing guzzle/guzzle (v3.8.1)
    Loading from cache
    Writing lock file
    Generating autoload files
    $ git add composer.json
    $ git add composer.lock
    $ git commit -m ‘Updates guzzle to newest version’
    When a new version of a library you use comes out, you can update to that new version by running composer update. This updates the composer lock file.

    View Slide

  37. $ composer install
    Loading composer repositories with package
    information
    Updating dependencies from lock file
    - Removing guzzle/guzzle (v3.8.0)
    - Installing guzzle/guzzle (v3.8.1)
    Loading from cache
    Other developers can then just run composer install and get the updates specified in the lock file.

    View Slide

  38. $ composer update
    Loading composer repositories with package
    information
    Updating dependencies (including require-dev)
    Nothing to install or update
    Generating autoload files
    Let’s say Guzzle 4.0 comes out and want to upgrade. We run composer update but nothing happens.

    View Slide

  39. $ composer update
    Loading composer repositories with package
    information
    Updating dependencies (including require-dev)
    Nothing to install or update
    Generating autoload files
    {
    “require”: {
    “guzzle/guzzle”: “~3.8”,
    “monolog/monolog”: “~1.7”
    }
    }
    What’s wrong? guzzle is ~3.8 which means >=3.8,<4. Guzzle 4.0 doesn’t match.

    View Slide

  40. {
    “require”: {
    “guzzle/guzzle”: “~4.0”,
    “monolog/monolog”: “~1.7”
    }
    }
    $ composer update
    Loading composer repositories with package information
    Updating dependencies (including require-dev)
    - Removing guzzle/guzzle (v3.8.0)
    - Installing guzzle/guzzle (v4.0.0)
    Loading from cache
    Writing lock file
    Generating autoload files
    Update the min version in the composer.json and re-run composer update. Dependencies now update correctly.

    View Slide

  41. require: {
    “guzzle/guzzle”: “~4.0”
    “monolog/monolog”: “~1.7”
    }
    Checks to make sure composer.json is a valid format.

    View Slide

  42. require: {
    “guzzle/guzzle”: “~4.0”
    “monolog/monolog”: “~1.7”
    }
    $ composer validate
    ./composer.json is invalid, the following errors/
    warnings were found:
    "./composer.json" does not contain valid JSON
    Parse error on line 3:
    ...le": "~4.0" "monolog/monolog": "
    ----------------------^
    Expected one of: 'EOF', '}', ':', ',', ']'
    Checks to make sure composer.json is a valid format.

    View Slide

  43. namespace Scan\BoardGameInfo;
    use Guzzle\Http\Client;
    require_once 'vendor/autoload.php';
    $client = new Client('http://boardgamegeek.com/
    xmlapi2/');
    $request = $client->get('thing?id=34119');
    $response = $request->send();
    echo $response->getBody();
    The composer autoloader supports psr-0, psr-4, class maps, and file including. Most libraries are going to be using psr-0 or psr-4.
    All you have to do to use the autoloader is include it in and then you can start using all your dependencies automatically.

    View Slide

  44. $ composer dumpautoload -o
    Generating autoload files
    return array(
    'Guzzle\\Http\\Client' => $vendorDir . '/guzzle/
    guzzle/src/Guzzle/Http/Client.php',
    );
    Class maps are the fastest autoloading type. You can user composer to automatically convert PSR-0 or PSR-4 autoloaders into class maps.

    View Slide

  45. Packagist is where you can go to search for packages you can install through composer. This also where you’d go to submit your own packages.

    View Slide

  46. {
    “repositories”: [
    {
    “type”: “vcs”,
    “url”: “[email protected]:scaninc/topsecret.git”
    }
    ],
    “require”: {
    “guzzle/guzzle”: “~3.8”,
    “monolog/monolog”: “~1.7”,
    “scan/topsecret”: “~0.5”
    }
    }
    The url can point to an hg or svn. This will only work though if the repository already has a composer.json file. Good for private repositories that you cannot put
    up on packagist, etc.

    View Slide

  47. {
    "repositories": [
    {
    "type": "package",
    "package": {
    "name": "chibimagic/webdriver",
    "version": "dev-master",
    "dist": {
    "url": "https://github.com/chibimagic/WebDriver-PHP/archive/master.zip",
    "type": "zip"
    },
    "autoload": {
    "psr-0": {
    "WebDriver": ""
    }
    }
    }
    }
    ],
    “require-dev”: {
    “chibimagic/webdriver”: “dev-master”
    }
    }
    If the project doesn’t have a composer.json file at all and you can’t get one added, you can still use the library by manually specifying all the information for the
    repository.

    View Slide

  48. {
    "repositories": [
    {
    "type": "pear",
    "url": "http://pear2.php.net"
    }
    ],
    "require": {
    "pear-pear2.php.net/PEAR2_Text_Markdown": "*",
    "pear-pear2/PEAR2_HTTP_Request": "*"
    }
    }
    Composer can also manage pear dependencies. Package name becomes pear-{channelName} or pear-{channelAlias}. Still installed in vendor.

    View Slide

  49. Conclusion
    Share Your Libraries
    Upload them to packagist. Control your version numbers via tags or branches in the repo. Don’t try specifying your version manually in the composer.json file.

    View Slide

  50. Conclusion
    • You can suggest, replace, or conflict with other packages.
    • Composer can run scripts before and after the command
    runs or before/after a package is installed.
    • There’s a global config file if you need to tweak things.
    • You can install packages globally if you really want to.
    • A whole bunch of command line stuff.
    • You can host your own private packagist-like site.
    Things I Didn’t Tell You

    View Slide

  51. Conclusion
    Questions?
    More info also at http://getcomposer.org

    View Slide