Creating a Composer Package Tutorial

This is a simple step-by-step guide to making a PHP composer package that can be listed publicly on packagist.org for anyone in the world to install. We’ll be using Github to update the package. We’ll also add some testing with PHPUnit.

Creating a Composer Package

The basic steps to creating a new composer package are as follows.

  1. Create a Github Repo for the project
  2. Clone the Github repo locally
  3. composer init
  4. composer install
  5. Write the PHP composer package, put the PHP into a src directory.
  6. Commit and push to Github
  7. Give the package a version by using git tag 0.0.1 then git push --tags
  8. Login to Packagist and add the new Github repo to your packagist account.
  9. Make sure all the info packagist.org needs is in your composer.json

After following these steps, your package should now be published on packagist. Any future changes you make should be pushed to Github and make a new tag like this… git tag 0.0.2 and git push --tags. You can list all the tags with git tag. Every time you update in this way, Github will get updated, and packagist will also get updated automatically.

Our class is called Bar, so our main PHP file has to be Bar.php (upper/lowercase matters!). We’ll put it in a directory called “src”…

<?php 
namespace Foo;
class Bar {
    public function helloworld(){
        return 'Hello, World!';
    }
}

Here is a sample composer.json file. Our namespace is “Foo” so we say that Foo is in the src directory in the composer.json…

{
    "name": "foo/bar",
    "license": "MIT",
    "require": {
        "php": "^7.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^5.7"
    },
    "autoload": {
        "psr-4": {
            "Foo\\": "src/"
        }
    }
}

To use the package, import it by copy/pasting the command line instructions from Packagist. It’ll be something like this… composer require foo/bar. Then, once the package has been installed into the vendor directory, you can start using it, like this, for example…

<?php

require_once 'vendor/autoload.php';

$test = new Foo\Bar();

$test->helloworld();

Updating the Package

For testing purposes. Each time you update you need to make sure the latest version is downloaded from Packagist.

Make sure the composer.json of the project you’re inporting the package into has a composer.json like this. You’ll need to make sure the package you’re testing is greater than or equals to >= instead of ^which specifies an exact version.

{
    "name": "neil/test",
    "authors": [
        {
            "name": "neil",
            "email": "[email protected]"
        }
    ],
    "require": {
        "foo/bar": ">=0.4.3",
        "phpunit/phpunit": "^6.5"
    }
}

But, even then composer update may still not do anything when you update the package. You may need to composer clearcache first, then update composer. Also, sometimes there is a short lag in Packagist updating so don’t get too worried if it doesn’t update straight away first time.

Testing the Package

To add testing you might want to use something like PHPUnit or PHPSpec. This is using PHPUnit 6.5 which runs with PHP 7.0…

composer require --dev phpunit/phpunit

Make a directory called tests and make a file called BarTest.php…

<?php
declare(strict_types=1);

use PHPUnit\Framework\TestCase;
use Foo\Bar;

final class BarTest extends TestCase
{

    public function testOutputsExpectedTestString()
    {
        $this->assertEquals(
            'Hello, World!',
            Bar::helloworld()
        );
    }
}

Then, making sure you’re using the “dev” packages you can run the test in the command line like so…

vendor/bin/phpunit --bootstrap vendor/foo/bar/src/Bar.php vendor/foo/bar/tests/BarTest

Unit tests will only work on public functions, not private functions.

Troubleshooting

The name of the class must be exactly the same as the filename, and vice versa. If your class is called SomeClass, the file must be SomeClass.php.

Errors can also come from not using git tag to create a version or not having all the info packagist needs in the composer.json.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.