Introducing Composer

As you might well know, Yii 1 was (initially) shipped as a standalone library that needed installation on the target environment, and from there you could use its CLI interface to create your web app. After that, the library would be sitting somewhere in your filesystem to be directly called by the web app upon loading it.

When Yii started, this was common practice; there wasn't a way to keep the code self-contained and you could easily get into several problems whenever you needed to ship the code to shared hosting environments (I'm looking at you Plesk/OpenBaseDir restriction).

Secondly, system-wide packages and dependencies were often restricting the developers to embrace new features and work around existing bugs, without even counting that these were (too) often overlooked. If you've been working on the web with PHP for quite a while, I'm pretty sure you've experienced the sense of lagging behind other big frameworks on the development scene (and not just in PHP-land).

Composer (http://getcomposer.org) solves the problem under many aspects, and thanks to the efforts of Nils Adermann, Jordi Boggiano, and many community contributions, it was first released in 2012.

Composer takes inspiration from Node.js' npm and Ruby's bundler. It provides a way to define and install dependencies (that is, libraries), and install web applications that are available from Packagist (https://packagist.org/) on a per-project basis.

Installing and using it

Let's start by following the installation guide proposed on the Composer website (https://getcomposer.org/doc/00-intro.md#installation-nix). Consider the following command:

$ curl -s https://getcomposer.org/installer | php

In the preceding command we are using curl to download the installer and php to parse it and output an executable PHP file called composer.phar. Be mindful that the installation under a different OS (in case you don't have a Linux box to play with) varies, for example, under OS X, Composer is part of the homebrew-php project at https://github.com/Homebrew/homebrew-php.

At this point, you can simply call Composer directly using a relative or absolute path, as shown in the following:

$ php composer.phar

Or move it into a more appropriate position for easier invocation, as you will see next.

If you can run sudo or log in as root, move it into a system wide bin folder, as shown in the following:

$ sudo mv composer.phar /usr/local/bin/composer

If the preceding option does not apply, you can install it in user-space, for example, ~/bin/, and then add the path to your PATH environment variable, as shown in the following:

$ mv composer.phar ~/bin/composer
$ PATH=$PATH:~/bin/; export PATH

The last command is adding the path to your terminal environment, so it can be invoked from anywhere you are in the filesystem. This specific command would need to be issued every time you open a terminal.

Otherwise, you can add it permanently, as shown in the following:

$ echo "export PATH=$PATH:~/bin/;" >> ~/.bashrc

By adding the export statement to your .bashrc (>> ~/.bashrc appends the output of echo to the end of the .bashrc file), you are simply making the directory searchable automatically every time you log in, given you are using BASH as shell interpreter.

If you're unsure which shell you're on, you can check using the following command:

$ echo $0

However, while this will work on most shells and it's quite easy to remember, it won't work if your shell is CSH, in which case, use the more complex but also more portable ps invocation, as shown in the following: command

$ ps -p $$ -o cmd=''

Once you have installed Composer, you can simply invoke it using the following command:

$ composer

The composer.json and composer.lock files

Composer works by reading the composer.json file found in the root of your project, which will contain all the requirements and dependencies:

composer.json

{
  "require": {
    "twig/twig": "1.16.*"
  }
}

The preceding snippet is quite clear: it's defining a dependency of our project on Twig (http://twig.sensiolabs.org/). This is a template engine with a clear and compact syntax. It's also defining a specific dependency on any version of Twig starting with 1.16.

Modifying the composer.json file by hand can be prone to human errors, and sometimes it might be necessary, as we will see later on, to add the packages to your require or require-dev section via the command line using the following command:

$ composer require "twig/twig:1.16.*"

This way the composer.json file will be automatically created if it does not already exist, and the package with its dependencies will be installed for you. Alternatively, if you've created the file yourself or if you've received the file as part of a project, you can invoke the install command as follows:

$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing twig/twig (1.6.5)
    Downloading: 100%         

Writing lock file
Generating autoload files

The normal behavior of the preceding command is to fetch the required packages as archives (called dist in composer jargon) for stable sources, or via repository if either the dist is not available or if the package is in some stage that is not stable (for example, beta or dev).

You can change this behavior by using the --prefer-dist option to force searching for the dist even for development packages, or --prefer-source to force the checkout from repository rather than dist for stable packages.

As you will see by listing the content of the directory, Composer will install all libraries into your project folder under the /vendor directory and create a composer.lock file in the root folder that will hold a snapshot of the current state of the installation, locking the installed libraries to the specific version defined in the lock file, as shown in the following:

$ tree -L 2
.
├── composer.json
├── composer.lock
└── vendor
    ├── autoload.php
    ├── composer
    └── twig

When sharing your code, you need to commit the composer.lock file, so everyone in your team and any other environment you will deploy to will run exactly the same version of the dependencies you have, mitigating the risk of bugs affecting only some environments. Composer will look for the lock file first before deciding to use the JSON file to download a more up-to-date version based on the definitions.

On the other hand, it is not recommended to commit the /vendor directory to your VCS as it can cause several problems, such as the following:

  • Difficulty in handling revisions and updates
  • Increased size of the repository without any benefit
  • In Git, it could cause problems if you're adding packages checked out via Git, as it will show them as submodules, while they're not.

This heavily depends on your deployment policy, but, in general, it will be better to have your environments and team mates run the composer install command on their own.

If you ever need to update the dependencies, you can simply issue the following command:

$ composer update

Or to update a specific package, the command will be the following:

$ composer update twig/twig [...]

The [...] means you can add as many packages to be updated with a single command.

Packages and Packagist

By creating the composer.json file, you are also defining your project as a package. This is a package that depends on other packages. The only difference is that your project is without a name, yet.

Composer can help you here in defining your project/package in a more consistent and clear way. Consider the following command:

$ composer init

This will start by asking you for some basic information regarding your project, including the requirements that you want for your project, and then create (or overwrite) the composer.json file, as shown in the following:

Package name (<vendor>/<name>) [peach/yii2composer]:
Description []: Installing Yii 2 from scratch with composer
Author [Matteo 'Peach' Pescarin <[email protected]>]:
Minimum Stability []: dev
License []: GPL-3.0

Among these, the one worth noticing is the Minimum Stability option: it provides a way to control the stability of the packages. By omitting it, it defaults to stable. This option combined with "prefer-stable": true (or false if you want to have the dev versions of your dependencies) will give you enough power to decide the policy of stability of the dependencies where this is not explicitly defined.

It will then move into setting the dependencies interactively, as shown in the following:

Define your dependencies.

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

Found 15 packages matching twig

   [0] twig/twig
   ...

Enter package # to add, or the complete package name if it is not listed []: 0
Enter the version constraint to require []: @dev

The search can be anything, and it works the same way as you would by searching on the website (https://packagist.org). If you want to have a more clear idea of what you're going to install, you probably want to have a look at the website: you need to be aware of the dependencies and browse the code to check it does what it says on the tin.

Knowing how to use the version constraints can be quite important in any project with just a few dependencies. According to https://getcomposer.org/doc/01-basic-usage.md#package-versions, the following are the possible keywords you need to be aware of:

  • Exact version: For example, 1.0.23
  • Range: For example, >=1.2 or >=1.0,<2.0 or use the pipe as a logical OR as >=1.0,<2.0 | >=3.0
  • Wildcard: For example, 1.2.*
  • Tilde operator: Here, ~1.2 is the same as >=1.2,<2.0; ~1.2.3 is the same as >=1.2.3,<1.3 (semantically: [[[[...]c.]b.]a.]x, where x is the only variable)

Composer provides further granularity when selecting specific packages, specifically you can filter by stability by adding @dev (or alpha, beta, RC or stable).

Sometimes, you are forced to use an unstable version, either because of the lack of a stable version or because the stable version ships with a bug that has been fixed in the master (dev)!

Together with require, which defines the list of fundamental packages that are a direct dependency, require-dev defines instead the secondary packages used for development, such as libraries for running tests, performing debugging, and so on. However, these are not fundamental for the application to work, as shown in the following:

Would you like to define your dev dependencies (require-dev) interactively [yes]?

You can also skip adding packages for require, and then add them later using the following command:

$ composer require

While for require-dev, at least with the version I've got installed at the time of writing this book, you need to add them manually as seen at the beginning.

At this point of the process, you'll be able to review the JSON that will be written before confirming it, as shown in the following:

{
    "name": "peach/composer",
    "description": "A Composer project",
    "require": {
        "twig/twig": "@dev"
    },
    "license": "GPL-3.0",
    "authors": [
        {
            "name": "Matteo 'Peach' Pescarin",
            "email": "[email protected]"
        }
    ],
    "minimum-stability": "dev"
}

Do you confirm generation [yes]?
Would you like the vendor directory added to your .gitignore [yes]?
$

Once you've got your composer.json file created, you can edit it and tweak it to your liking. There are many other options that can be specified. Refer to https://getcomposer.org/doc/04-schema.md.

By compiling your composer.json file, you are actually creating a package yourself that could be shared on Packagist with other developers.

The process itself is not particularly difficult, as you just need to add a few additional options, as defined in the JSON schema documentation (https://getcomposer.org/doc/04-schema.md#the-composer-json-schema), and publish your code using a Git, subversion or mercurial repository. You can also decide to publish just a dist package. Refer to the documentation at https://getcomposer.org/doc/ for more information if you want to take a step in this direction.

Once you've created your composer.json file, you can start installing all the dependencies as follows:

$ composer install --prefer-dist

Composer lets you decide how to fetch all the requirements and, in this particular case, we gave preference to dist files when available. The result is the following:

Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing twig/twig (dev-master 72aa82b)
    Downloading: 100%         

Writing lock file
Generating autoload files
$

Creating your first web app

At this point, you should have gained enough confidence with Composer to be able to undertake the next step. But before doing this, forget what you've learned!

Creating a composer.json file and requiring a bunch of packages can be done by anyone. With Composer, you can create a project from a given package. This means that the package will be extracted into a specified directory (not /vendor anymore). This new project will have all its dependencies checked out and saved within its scope, that is, within its own directory.

The syntax for the command we're going to use to install Yii 2 and start working with it is the following:

composer create-project vendor/project target-directory

Here, vendor/project is the Packagist name of the project, in our case, the name will be yiisoft/yii2-app-basic, as we will see later, and target-directory is where you want to install it. This command won't create a composer.json file, so you can run it from anywhere in your environment, just be sure to specify the correct target path.

Yii 2 developers have shared two packages that contain an initial application you can start working with: a basic and an advanced one.

The difference between the two is the type of dependencies and what's already been implemented.

Both projects come with a README.md file in Markdown format, which you can read to understand the details. To keep it short:

  • Basic: As the name says, it's a basic implementation, very close to what you would get by installing Yii 1, ready to be used with a default Apache or Nginx installation.
  • Advanced: This is a very basic configuration if you need to build a multitiered application. The one you will get with the advanced app consists of a frontend, a backend, and a console application, all as separate Yii applications with some common components. It would require a specific initialization, so refer to the README.md file for details.

Note

The advanced application features an additional script called init, which wraps Composer and enables or disables the installation of require-dist.

For a more detailed guide, check out the documentation at http://www.yiiframework.com/doc-2.0/guide-tutorial-advanced-app.html.

Consider the following command:

$ composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic

We are now installing into /basic the yiisoft/yii2-app-basic package. There are other ways to get you started, but this is definitely the most clean way I can think of, as you won't be tied to a repository nor anything else.

There is no interaction required after this command, as it would carry on installing the required packages including require-dev.

It might be that at this point, Composer will fail in installing some dependencies, or you can fall in some runtime errors later on, so it's probably better if you check your requirements are met by opening the requirement script in your browser, which will check that everything is all right. The file is found in the root of the project and it's called requirements.php.

In Ubuntu, there are some packages you might want to install, which are going to be needed, such as php5-mcrypt, php5-xsl, and php5-xdebug. Each Linux distribution ships these PHP extensions in different ways and their naming might be different; please consult your Linux distro documentation if you're having problems on how to find, install, or configure them.

At the end of the installation process, you will note some additional work being done, as shown in the following:

Generating autoload files
Setting writable: runtime ...done
Setting writable: web/assets ...done
Setting executable: yii ...done
$

If you had memory of the previous version of Yii, this was something many were looking for.

Note

Please note that these steps need to be replicated manually if you're running Composer on a freshly checked out application, or you would need to run the init tool if you've got the advanced application installed.

The CLI command line

In Yii 2, Composer is used both as a way to install the basic skeleton of your web app, something you would have done with Yii 1 using the CLI interface instead, as shown in the following sequence of commands, and as a way to manage the dependencies of your projects:

$ cd protected/
$ ./yiic webapp ~/public_html/myproject

As you can imagine, the scope and functionality of the command line is now quite different and has been expanded.

First of all, the CLI is now found in the root of the project and it's called yii, as shown here:

$ ./yii

By just running the preceding command, you will get a list of possible commands, as shown in the following:

- asset     Allows you to combine and compress your JavaScript and CSS files.
- cache     Allows you to flush cache.
- fixture   Manages loading and unloading fixtures.
- hello     This command echoes the first argument that you have entered.
- help      Provides help information about console commands.
- message   Extracts messages to be translated from source files.
- migrate   Manages application migrations.

To see the help of each command, enter:

  yii help <command-name>
$

The ones you will recognize from Yii 1 are migrate and message, which accomplish the same operations you were used to, albeit some have been improved. The only real difference is the way you'll be calling its specific actions (for example, migrate/create).

The shell and web app commands have now been replaced with a cache management tool called cache, a fixtures creation tool called fixture, which we'll see later on, and a demo command called hello, which you can use as inspiration to code one yourself (for example, to create cronjob tasks).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset