Search code examples
phpcomposer-php

PHP Namespaces with Composer autoload


I want to move a couple of libraries to Composer/Packagist and am struggling with php namespace mapping.

  • Classfiles are in a folder Csp under /src. They have a PHP namespace Csp.
  • The composer.json generated by compose init contains (not sure if that is correct though)
    "autoload": {
        "psr-4": {
            "Theking2\\Csp\\": "src/"
        }
    },
  • The package is registered on Packagist https://packagist.org/packages/theking2/
  • In a test project I require the package
  • In the index.php I have as per documentation
require_once __DIR__ . '/vendor/autoload.php';
  • and
$csp = new Csp\Builder(true);

But I get a class not found error.

EDIT also with this in composer.json:

    "autoload": {
        "psr-4": { "Csp\\": "src/Csp" }
    },

or this

    "autoload": {
        "psr-0": { "Csp\\": "src/Csp" }
    },

same results. The files sit in the folder src/Csp directly under vendor/Theking2/csp-builder as compose update created it.

And just before anyone askes: Yes there is a namespace Csp; in every file.


Solution

  • There are a couple of things to consider when using composer init. The first question (<vendor><name>) defines quite a lot and defaults to whatever user is logged on (?) and what folder she is working in. Of course this can be changed but it needs some thinking ahead. Therefor take this step by step.

    Setting up the package

    What we want

    Lets assume these prerequisites:

    entity value
    vendor kingsoft
    package under development csp-builder
    developer/logged on user joking
    github user developing theking2
    Packagist name kingsoft
    PHP namespace Kingsoft\Csp
    source root src/

    Lets assume the package is not dependent on anything and has a MIT license, all of which are not relevant. Also your code resides in a folder called /src which is kind of the standard for composer packages but really it might as well be called /source.

    Let's compose!

    Answer to the first question of composer init has to be changed kingsoft/csp-builder. The answer to the 9th question (PSR-4 autoload mapping) can be answered yes but we have to change the effect of that answer later on. After generating, observe the last couple of lines:

    Generating autoload files
    Generated autoload files
    PSR-4 autoloading configured. Use "namespace Kingsoft\CspBuilder;" in src/
    Include the Composer autoloader with: require 'vendor/autoload.php';
    

    Autoloader adjustment

    A good guess for the namespace but we want to change it to Kingsoft\Csp. Do this in the generated composer.json

        "autoload": {
            "psr-4": {
                "Kingsoft\\Csp\\": "src/"
            }
        },
    

    This now will assume the source files in the folder src/ and those directly within have a

    namespace Kingsoft\Csp;
    

    close to the top. (Probably directly after a <?php declare(strict_types=1);.)

    Commit and push

    Now commit this and sync it with a repo on whatever git provider you use. Maybe before that tag it with:

    git tag 1.0.0
    

    Packagist

    On Packagist set up a new package (csp-builder) under account kingsoft and add the relevant hooks to for instance GitHub after connecting the Packagist account with the GitHub account. (not sure how to this on other git hosters, leave a message in the comments).

    Small changes (typos etc.) not involving code during the setup might need commits and retagging with

    git tag 1.0.1 --force && git push -f --tags
    

    Of course later on after code changes you might (must) add tags to newer versions.

    That is most of the work. Now to ..

    Use the package

    That is easy. Create a composer.json with this minimal content:

    {
        "require": {
            "kingsoft/csp-builder": "*"
        }
    }
    

    or even easier type composer require kingsoft/csp-builder in a termibal at the root of your project. After that type this

    composer update
    

    and use whatever is contained in Kingsoft\Csp. Like

    $csp = new Kingsoft\Csp\Builder(true);
    $csp-> setCspHeader();
    

    Or shorten the names of imports a bit by importing the namespace: use Kingsoft\Csp; and leave out the vendor name on classnames etc. (but do include namespace Csp\!) like new Csp\Builder(true);.

    I'm writing this quite elaborate answer for my own future reference.