How to craft a PHP package

Kpicaza
PHP FAD
Published in
5 min readJun 14, 2020

In the next lines, I will try to explain how to make a PHP package following some recommended rules. Then I’ll show you how to host the recently created library at Packagist.

For that task, I will go with a real use case. I want to have Doctrine DBAL running out of the box inside Antidot Framework applications. Furthermore, I want someone with the same requirement to have the chance to download and use it in its project.

Step 1

I will start making a new git repository, come on, and let’s start coding.

In the initial commit, I will add standard boilerplate files for Antidot Framework packages.

Concretely, the README file with a small explanation of the package intentions, the CODE_OF_CONDUCT file describing the code of conduct to contribute on the package development community, the LICENSE file, the PULL_REQUEST_TEMPLATE and the Github ISSUE_TEMPLATES defining the workflow for contributors, and at last but not less important the FUNDING file to allow sponsoring the project developers.

Look at the Github repository at the step-1 branch to see in more detail the content of files. The big picture will look like this.

Step 2

Now I am going to add the new composer.json file. This file describes how to autoload classes, the required dependencies, some info about utility and developer, and so on. It looks as follows:

At the top of the file, were the package name, description, license, keywords, type, and authors. Then it has the requirements definition for production and development environments, the autoloading namespaces for the classes and test classes in the library. And at the end of the file, it has the definition of the scripts with some util scripts to run tests, code sniffer, and PHPStan the code static analysis tool.

For the mentioned scripts, I added the development dependencies as you observed on the composer.json file and I attached some config files that you can find in the Github repository in the step-2 branch.

Step 3

At this point, I have to install the package dependencies with Composer to start creating the needed code for the package. To integrate the DBAL library inside the Antidot Framework, we will need two things:

  • First, we need to make a PSR-11 Container compatible factory that will be responsible for instantiating new DBAL connections.
  • And then, a config class to tell Antidot Framework how to load provided instances inside its DI container.

We Start by installing dependencies with Composer:

cd dbal-adapter
composer install
composer require doctrine/dbal

With the required dependencies installed, we are going to take a TDD approach to create our code. I start by creating the DBALConnectionFactoryTest PHPUnit test class inside the AntidotTest\Persistence\DBAL\Container namespace. I defined before namespace resolution in the composer.json file.

I created a minimal test with the DBALConnectionFactory class instantiation. To run tests you will execute thevendor/bin/phpunit command.

This test must fail because the DBALConnectionFactory class does not exist yet.

Now the tests are yellow because we don’t make any assertion yet, update the test to assert something, in this case, we need to ensure to pass the dependency container as a factory method’s first parameter.

This change broke tests because we don’t have any method implemented inside the factory. To instantiate a Connection, we need to pass the connection config to DBAl’s DriverManagerclass.

The tests continue being broken because we defined here a config structure for the framework. We need to mock it.

Now we are on the green. I have to iterate some more times by completing the different allowed casuistics. If you want to see the complete sources finished, look to the Github repository in the step-3 branch.

Step 4

Once we have the factory created, tested, and documented the current code behavior. We need a ConfigProvider class to integrate our class inside Antidot Framework’s DI container. To do that task, Antidot uses the Laminas component installer package. Let see how it works.

First, I have to create a ConfigProvider class. This class is an invokable class that returns the container config array.

The Laminas Component installer is a Composer plugin that injects the given config provider inside The Laminas Config Aggregator class. To enable it, we need to tell Composer where to find the recently created ConfigProvider.

Job done, we have all the code we need, see the progress in the Github repository on the step-4 branch.

Now is the time to publish the package on Packagist. Doing this allows us to install the library using the Composer command-line tool. Login in Packagist with your chosen sign-in method and find the “Submit” button in the top right of the screen. Finally, propose a new package.

To install the package, you can use the following command inside Antidot Framework or Mezzio application.

composer require antidot-fw/dbal-adapter

Conclusion:

To finish this long post, I want to thank you so much for getting here and tell you that if you want to contribute to this library or the Antidot Framework development in some manner, you are welcome. Look at the Github project site, or open chat at Gitter, I will be glad to talk.

On the other hand, we saw how to design and publish a well-tested PHP package only with four steps.

--

--