Skip to content

5. Customizing Composer

Composer is a powerful tool that can be customized to fit your specific needs. This chapter will cover several ways to customize Composer, including using private repositories, using Composer with multiple environments, creating custom installers, creating Composer plugins, advanced Composer usage, using private packages, handling conflicts, and creating a package.

5.1 Using Private Repositories

If you are working on a project that requires packages that are not publicly available, you can use private repositories to store those packages. Composer supports several private repository options, including Satis and Packagist Private.

Private repositories can be used for a variety of reasons, such as proprietary code that cannot be shared publicly or internal packages that are not suitable for public release.

To use private repositories with Composer, you need to configure your composer.json file to include the repository URL, authentication credentials if needed, and the package name and version. The repository can be a git repository or a Composer repository.

Here is an example of a composer.json file with a private repository:

json
{
	"repositories":[
		{
			"type":"vcs",
			"url":"https://example.com/private-repo.git",
			"options":{
				"ssh2":{
					"username":"your-username",
					"pubkey_file":"/path/to/ssh/key.pub",
					"privkey_file":"/path/to/ssh/key"
				}
			}
		}
	],
	"require":{
		"your-vendor/your-package":"1.0.*"
	}
}

In this example, we have defined a private repository with the URL

"https://example.com/private-repo.git". We have also specified the authentication credentials using SSH, which require a username and public/private key pair. Finally, we have required the package "your-vendor/your-package" at version "1.0.*".

Once the composer.json file has been configured, you can run the following command to install the package:

bash
composer install

This will download the package from the private repository and install it in your project.

Private repositories can also be used to host packages that have been modified or customized for your project. In this case, you can fork the package repository, make the necessary changes, and then configure your composer.json file to use the forked repository instead of the original.

Using private repositories can help to keep your code secure and protect proprietary or sensitive information. It can also be used to manage internal packages and keep them separate from public packages.

5.1.1 Setting up a Satis Repository

Satis is a self-hosted repository that can be used to host private packages. To set up a Satis repository, you will need to have a web server and PHP installed on your system. Once you have those requirements met, you can follow these steps:

  1. Install Satis using Composer:
bash
composer create-project composer/satis --stability=dev --keep-vcs
  1. Create a Satis configuration file:
json
{
	"name":"My Private Repository",
	"homepage": "http://my-repo.com",
	"repositories":[
		{
			"type":"vcs",
			"url": "git@github.com:user/repo.git"
		}
	],
	"require-all":true
}
html
https://github.com/thusithawijethunga/satis/blob/main/satis.json
  1. Build the Satis repository:
bash
php bin/satis build satis.json web/
  1. Configure your project's composer.json file to use the Satis repository:
json
{
	"repositories":[
		{
			"type":"composer",
			"url":"https://my-repo.com"
		}
	],
	"require":{
		"my/package": "dev-master"
	}
}
bash
# My-Project, composer.json
https://github.com/thusithawijethunga/php-dependency-management/blob/main/satis-repository/my-project/composer.json
  1. Run composer install to install the private package.

image x

5.1.2 Using a Private Repository

If you prefer not to set up your own private repository, you can use Packagist Private to host your private packages. Packagist Private is a hosted solution that offers a private Composer repository. To use Packagist Private, you will need to sign up for an account and follow the instructions on the website to set up your private repository.

Once you have set up your private repository, you can add it to your composer.json file like this:

json
{
	"repositories":[
		{
			"type":"composer",
			"url":"https://<your-packagist-account>.packagist.com"
		}
	],
	"require":{
		"my/package":"dev-master"
	}
}

5.2 Using Composer with Multiple Environments

When developing a PHP project, it's common to have multiple environments, such as production, staging, and development. Each environment may have different requirements, such as different database credentials, API keys, and other settings.

To manage dependencies across multiple environments, Composer can be used with environment-specific configuration files. This allows you to easily switch between environments while using the same set of dependencies.

5.2.1 Creating Environment-Specific Configuration Files

To create environment-specific configuration files, you can create a separate composer.json file for each environment that specifies the dependencies and scripts for that environment.

For example:

json
{
	"require":{
		"monolog/monolog":"^2.0"
	},
	"scripts":{
		"prod":[
			"echo 'Running production build'",
			"composer install --no-dev"
		],
		"dev":[
			"echo 'Running development build'",
			"composer install"
		],
		"test":[
			"echo 'Running test build'",
			"composer install --no-dev"
		],
	}
}

In this example, we're using the monolog/monolog package and defining scripts for each environment (prod, dev, and test). (composer.prod.json, composer. dev.json, and composer.test.json)

bash
# My-Project, composer.json
https://github.com/thusithawijethunga/php-dependency-management/blob/main/satis-repository/my-project/composer.json

5.2.2 Creating Environment-Specific Configuration Files on Windows

To create environment-specific configuration files on Windows, you can create batch files for each environment that sets the COMPOSER environment variable to the path of the environment-specific configuration file, like this:

bash
@echo off

REM Set the path to the Composer
set COMPOSER_HOME=.\prod\cache

REM Set the path to the environment-specific Composer configuration file
set COMPOSER=composer.prod.json

REM Run the prod script
composer run-script prod

Note that the set command is used to set the value of the COMPOSER environment variable to the path of the environment-specific Composer configuration file.

Also note that the @echo off command is used at the beginning of each file to suppress the output of each command in the batch file, making the output cleaner and easier to read.

In this example, we're setting the COMPOSER_HOME environment variable to the .\prod\cache directory, which will be used by Composer to cache packages and other data.

By using a separate cache directory for each environment, you can prevent conflicts between different versions of packages and other data that may be used in different environments.

Note that you'll need to create the .\ prod \cache directory before running the dev.bat file, and you'll need to create separate cache directories for each environment if you're using multiple environments.

Also note that you can customize the path to the cache directory as needed, depending on your project's directory structure and the requirements of your development environment.

bash
# My-Project, prod.bat
https://github.com/thusithawijethunga/php-dependency-management/blob/main/satis-repository/my-project/prod.bat

5.2.3 Running Environment-Specific Scripts

To run environment-specific scripts, simply execute the appropriate shell script or batch file for the environment you want to use.

For example, on Linux or macOS, you can run:

bash
#!/bin/bash
export COMPOSER_HOME=./prod/cache
export COMPOSER=composer.prod.json
composer run-script prod

On Linux or macOS, you can run: ./prod.sh, ./dev.sh or ./test.sh

On Windows 10, you can run: prod.bat, dev.bat or test.bat

This will run the prod, dev, or test script using the environment-specific composer.json file.

By using Composer with environment-specific configuration files, you can easily switch between environments while using the same set of dependencies. This can make it easier to manage your project's dependencies and ensure that your project works correctly in each environment.

5.3 Creating Custom Installers

Composer allows you to define custom installers for your packages. Custom installers are classes that can be used to install packages in a non-standard way, such as installing packages into a specific directory or configuring them in a particular way.

To create a custom installer, you need to create a class that extends Composer's Installer class and implement its methods. The installer should be registered in your composer.json file.

Here's an example of a custom installer class:

php

<?php

namespace MyNamespace;

use Composer\Installer\LibraryInstaller;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;

class MyInstaller extends LibraryInstaller
{
    public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
    {
        parent::install($repo, $package);
        // Custom installation logic goes here
    }

    public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
    {
        parent::uninstall($repo, $package);
        // Custom uninstallation logic goes here
    }

    public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
    {
        parent::update($repo, $initial, $target);
        // Custom update logic goes here
    }

    public function supports($packageType)
    {
        return $packageType === 'my-package-type';
    }
}

In this example, MyInstaller extends Composer's LibraryInstaller class, which provides a basic installation implementation. The supports() method specifies the package type that this installer should handle.

bash
# Custom Installer, MyInstaller.php
https://github.com/thusithawijethunga/template-installer-plugin/blob/main/src/TemplateInstaller.php

Once you've created your custom installer class, you can register it in your composer.json file like this:

json
{
	"name": "my/package",
	"type": "my-package-type",
	"require": {},
	"extra": {
		"installer-paths":{
			"path/to/install": ["my/package"]
		},
		"class": "MyInstaller"
	}
}

In this example, the "installer-paths" key specifies the installation path for this package, and the "class" key specifies the name of the custom installer class.

bash
# Custom Installer, composer.json
https://github.com/thusithawijethunga/template-installer-plugin/blob/main/composer.json

By using custom installers, you can customize the installation process of your packages and make them easier to use for your users.

This can be useful if your package requires additional steps to install, such as running database migrations or copying files to a specific location.

5.4 Creating Composer Plugins

Composer plugins are PHP classes that can be used to extend Composer's functionality. You can use plugins to add custom commands, modify the Composer installation process, or perform other custom tasks.

5.4.1 Creating a Custom Plugin

To create a custom plugin, you will need to create a PHP class that extends the Composer\Plugin\PluginInterface interface.

Here's an example plugin class:

php
<?php

namespace Thusitha;

use Composer\Plugin\PluginInterface;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Plugin\Capability\CommandProvider;
use Composer\Plugin\Capable;

class MyPlugin implements PluginInterface, Capable, CommandProvider
{

    public function activate(Composer $composer, IOInterface $io)
    {
        $this->createLogFile($composer, $io);

        $io->write("MyPlugin activated!");
    }

    public function deactivate(Composer $composer, IOInterface $io)
    {
        $io->write("MyPlugin deactivated!");
    }

    public function uninstall(Composer $composer, IOInterface $io)
    {
        $io->write("MyPlugin uninstalled!");
    }

    private function createLogFile(Composer $composer, IOInterface $io)
    {

        $payload = [];

    }

}
bash
# Composer Custom Installer, MyPlugin.php
https://github.com/thusithawijethunga/composer-custom-installer/blob/main/src/MyPlugin.php

Once you have created your plugin class, you will need to register it with Composer. When Composer runs, it will load and activate your plugin.

Here's an example composer.json file for a Sample Application it using your plugin:

json
{
    "name": "sample/app",
    "require": {
        "thusitha/my-plugin": "*",
        "monolog/monolog": "^2.0",
        "thusitha/composer-plugin": "dev-main",
        "thusitha/php-plugin": "dev-main"
    },
    "repositories": [
        {
            "type": "git",
            "url": "https://github.com/thusithawijethunga/composer-custom-installer.git"
        },
        {
            "type": "composer",
            "url": "https://satis.mydomain.com",
            "options": {
                "ssl": {
                    "verify_peer": false
                }
            }
        }
    ],
    "config": {
        "allow-plugins": {
            "thusitha/my-plugin": true
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true
}
bash
# Sample Application, composer.json
https://github.com/thusithawijethunga/php-dependency-management/blob/main/sample-app/composer.json

Here's an example Console Output after composer update in Sample Application.

bash
PS D:\www\book\php-dependency-management\sample-app> composer update
Username: Thusitha Avinda
Email: thusithawijethunga@gmail.com
MyPlugin activated!

Here this plugin read your Current Git Username and Email address. its create sample.json file in your project directory.

json
{
	"name": "Thusitha Avinda",
	"email": "thusithawijethunga@gmail.com",
	"app": "sample\/app",
	"requires": {
		"thusitha\/my-plugin": "*",
		"monolog\/monolog": "^2.0",
		"thusitha\/composer-plugin": "dev-main",
		"thusitha\/php-plugin": "dev-main"
	}
}

5.4.2 Best Practices for Creating Composer Plugins

When creating Composer plugins, it's important to follow best practices to ensure that your plugins are reliable and easy to use. Here are some best practices to keep in mind:

  • Use Composer's autoloader to load your plugin classes
  • Keep your plugin code simple and easy to understand
  • Use Composer's events system to hook into the installation process
  • Document your plugin's functionality and usage

5.4.3 Publishing a Composer Plugin

If you have created a useful Composer plugin, you may want to share it with the Composer community by publishing it to Packagist. To publish a Composer plugin, you will need to create a new package on Packagist and add the necessary information to your composer.json file.

Here's an example composer.json file for a Composer plugin:

json
{
    "name": "thusitha/my-plugin",
    "description": "My Composer plugin",
    "type": "composer-plugin",
    "require": {
        "composer-plugin-api": "^2.3.0",
        "composer/composer": "^2.5.0"
    },
    "autoload": {
        "psr-4": {
            "Thusitha\\": "src/"
        }
    },
    "extra": {
        "class": "Thusitha\\MyPlugin"
    },
    "minimum-stability": "dev",
    "prefer-stable": true
}

Once you have added this information to your composer.json file, you can publish your plugin to Packagist by running composer update and then composer publish.

bash
# Composer Custom Installer, composer.json
https://github.com/thusithawijethunga/composer-custom-installer/blob/main/composer.json

5.5 Advanced Composer Usage

In addition to the basic usage of Composer, there are several advanced techniques you can use to customize and optimize your Composer workflow.

5.5.1 Using Composer with Docker

If you work in a Docker environment, you can use Composer with Docker to ensure that your dependencies are installed consistently across all of your Docker containers. To use Composer with Docker, you will need to create a custom Docker image that includes Composer and your project dependencies.

Here's an example Dockerfile for a PHP project that uses Composer:

yaml
# syntax=docker/dockerfile:1

FROM php:7.4-fpm-alpine
RUN apk add --no-cache git
WORKDIR /var/www/html
COPY composer.json composer.lock ./
RUN composer install --prefer-dist --no-dev --no-scripts --no-progress --no-suggest
COPY . .
CMD ["php-fpm"]

In this example, we start with a base PHP image, install Git, and set the working directory to /var/www/html.

We then copy the composer.json and composer.lock files to the container and run composer install to install the project dependencies.

Finally, we copy the rest of the project files to the container and start the PHP-FPM process.

To build and run this Docker image, you can use the following commands:

bash
docker build -t myproject . docker run -p 8080:9000 myproject

This will build the Docker image and start a container that exposes port 8080 and maps it to port 9000 in the container.

5.5.2 Using Composer with Continuous Integration

If you use a continuous integration (CI) system to build and test your code, you can use Composer with your CI system to ensure that your dependencies are installed correctly and consistently across all of your build environments.

Many CI systems have built-in support for Composer, such as Travis CI and CircleCI. To use Composer with your CI system, you will typically need to create a composer.json file that lists your project dependencies and a script that runs composer install.

Here's an example .travis.yml file for a PHP project that uses Composer:

yaml
language: php
php: - 7.4 - 8.0
before_script: - composer install --prefer-dist --no-dev --no-scripts --no-progress --no-suggest
script: - phpunit tests/

In this example,

We define two PHP versions to test against (7.4 and 8.0), and use the before_script section to run composer install to install the project dependencies. We then use the script section to run our test suite using PHPUnit.

When working on a project with multiple developers, it is important to have a continuous integration (CI) system in place to ensure that changes to the codebase do not introduce any issues. Composer can be integrated into the CI system to ensure that the correct dependencies are installed for the project.

Here are the general steps to use Composer with a CI system:

  1. Configure the CI system to check out the latest codebase from the repository.
  2. Install Composer on the CI system if it is not already installed.
  3. Run the composer install command to install the dependencies for the project.
  4. Run the project's tests to ensure that the dependencies are working correctly.
  5. If the tests pass, deploy the codebase to the production environment.

Many CI systems, such as Travis CI, GitLab CI/CD, and CircleCI, have built-in support for Composer and can automatically run the composer install command as part of the build process.

These systems can also be configured to run the project's tests and deploy the codebase to the production environment.

By using Composer with a CI system, you can ensure that your project's dependencies are always up to date and that changes to the codebase do not introduce any issues.

5.6 Using Private Packages

If you have private packages that are not available on Packagist or other public repositories, you can use Composer with private repositories to manage these packages.

There are several ways to use Composer with private repositories, but one common approach is to use a tool called Satis to create a private Composer repository. Satis is a simple static Composer repository generator that you can use to create a repository that contains your private packages.

To use Satis, you will need to create a satis.json configuration file that lists your private packages and the URLs of the repositories that contain them. You can then use Satis to generate a static repository that you can host on a web server or in a private Git repository.

Once you have created your private repository, you can use Composer's config command to configure Composer to use your private repository. Here's an example composer.json file that shows how to use a private repository:

json
{
	"repositories":[
		{
			"type": "composer",
			"url": "https://packagist.org"
		},
		{
			"type": "composer",
			"url": "https://my.private.repository.com"
		}
	],
	"require":{
		"my/private-package": "dev-master"
	}
}

In this example,

We define two repositories, one for Packagist and one for our private repository. We then use the require section to list our private package, my/private-package, and specify that we want to use the dev-master branch.

To configure Composer to use our private repository, we can run the following command:

bash
composer config repositories.my-repo composer https://my.private.repository.com

This command adds our private repository to Composer's configuration, under the name my-repo.

To use private packages with Composer, you need to define the private package repository in the composer.json file. You can use several types of private package repositories, such as Satis, Toran Proxy, or Private Packagist.

Here is an example of how to use Private Packagist to install a private package in your project:

  1. First, you need to create an account on Private Packagist and create a new repository for your private packages.
  2. Once you have created a new repository, you can add your private package to it. You can either upload your package directly or connect it to a version control system like GitHub.
  3. Next, you need to authenticate with Private Packagist to access your private packages. You can do this by setting your Private Packagist token in the COMPOSER_AUTH environment variable or in your global Composer configuration file.
  4. Finally, you can require your private package in your project's composer.json file like you would with any other package:
json
{
	"require":{
		"private-packagist-username/private-package": "1.0.0"
	},
	"repositories":[
		{
			"type": "composer",
			"url": "https://repo.packagist.com/private-packagist-username/"
		}
	]
}

In this example,

Replace "private-packagist-username" with your Private Packagist username and "private-package" with the name of your private package. You can also specify the version of your package that you want to use.

The "repositories" section specifies the URL of your Private Packagist repository. You can also use other types of repositories, such as Satis or Toran Proxy, by replacing the URL with the appropriate repository URL.

Once you have added your private package to the composer.json file, you can run the "composer install" or "composer update" command to install your private package and its dependencies. Composer will automatically download your private package from your private repository and install it in your project.

5.7 Creating a Package

If you want to share your code with others or use it in multiple projects, you can create a Composer package. A Composer package is a reusable piece of code that can be installed and managed using Composer.

To create a Composer package, you will need to create a directory that contains the package code and a composer.json file that describes the package dependencies and metadata.

Here's an example composer.json file for a simple package:

json
{
	"name": "my/package",
	"description": "My package",
	"type": "library",
	"license": "MIT",
	"authors": [
		{
			"name": "Thusitha Avinda",
			"email": "thusithawijethunga@gmail.com"
		}
	],
	"require":{
		"php": "^7.4"
	},
	"autoload": {
		"psr-4": {
			"My\\Package\\": "src/"
		}
	}
}

In this example, we define the package name, description, type, license, authors, and dependencies. We also define an autoload section that tells Composer how to autoload the package code.

To create the package code, you can create a directory structure that corresponds to the autoload section of the composer.json file. In this example, we would create a src directory and a My/Package subdirectory.

Once you have created the package code and composer.json file, you can publish the package to a repository, such as Packagist, or host it in a private repository. To publish a package to Packagist, you will need to create an account on the Packagist website and follow the instructions for publishing a package.

Once your package is published, other developers can install it using Composer by adding it to their composer.json file, like this:

json
{
	"require":{
		"my/package": "^1.0"
	},
}

This will tell Composer to download and install the my/package package and its dependencies.

Conclusion

Composer is a powerful tool for managing dependencies in PHP projects. It simplifies the process of installing and updating packages and makes it easy to manage dependencies across multiple projects.

In this chapter, we covered several advanced features of Composer, including using private repositories, customizing Composer with environment variables, creating custom installers and plugins, and handling conflicts.

We also covered the basics of creating a Composer package and publishing it to a repository.

By mastering these advanced features of Composer, you can take your PHP development to the next level and build more complex and robust applications with ease.

All content, including books, text, and media, on this website is the intellectual property of the author and is protected by copyright laws. Unauthorized copying, distribution, or use of any material on this site is strictly prohibited without explicit written permission from the author W G T Avinda.