New in Symplify 9: Composer Json Manipulator - In Object API

Found a typo? Edit me

Have you ever needed to modify composer.json with PHP code? Then you're family $json['require']['php'] ?? null structures. They're hell to work with as any other array - verify the value if it's null, how deeply nested it is, etc.

This is typical use case for a monorepo, where we need to merge many nested composer.json files into a root composer.json.

With an array, it's mission impossible. What about intuitive methods on simple value object? You'd expect such package to exist in PHP world - but there is none. So we made an object wrapper that handles all your worries:

/** @var \Symplify\ComposerJsonManipulator\ValueObject\ComposerJson $composerJson */
$composerJson = ...;

// get directories that should exists
$composerJson->getAbsoluteAutoloadDirectories();

// get minimum stability
$composerJson->getMinimumStability();

// it's ready for print
$composerJson->getJsonArray();

// change value
$composerJson->setLicense('MIT');

We've been testing the symplify/composer-json-manipulator package for a couple of weeks months, just to be sure it works well in practise.

It has over 240 000 downloads now.

3 Steps to Create ComposerJson object

1. Install the Package

composer require symplify/composer-json-manipulator --dev

Register bundle:

// config/bundles.php

declare(strict_types=1);

return [
    Symplify\ComposerJsonManipulator\ComposerJsonManipulatorBundle::class => [
        'all' => true,
    ],
];

2. Create ComposerJson with a Factory

declare(strict_types=1);

namespace App;

use Symplify\ComposerJsonManipulator\ComposerJsonFactory;
use Symplify\ComposerJsonManipulator\ValueObject\ComposerJson;
use Symplify\SmartFileSystem\SmartFileInfo;

final class SomeClass
{
    /**
     * @var ComposerJsonFactory
     */
    private $composerJsonFactory;

    public function __construct(ComposerJsonFactory $composerJsonFactory)
    {
        $this->composerJsonFactory = $composerJsonFactory;
    }

    public function createFromExisting(): ComposerJson
    {
        $fileInfo = new SmartFileInfo(getcwd() . '/composer.json');
        $composerJson = $this->composerJsonFactory->createFromFileInfo($fileInfo);

        // analyse/modify $composerJson

        return $composerJson;
    }

    public function createNew(): ComposerJson
    {
        $composerJson = $this->composerJsonFactory->createEmpty();
        $composerJson->setPreferStable(true);

        return $composerJson;
    }
}

3. Print modified ComposerJson

namespace App;

use Symplify\ComposerJsonManipulator\Printer\ComposerJsonPrinter;

class SomeClass
{
    /**
     * @var ComposerJsonPrinter
     */
    private $composerJsonPrinter;

    public function __construct(ComposerJsonPrinter $composerJsonPrinter)
    {
        $this->composerJsonPrinter = $composerJsonPrinter;
    }

    public function printAndReport(ComposerJson $composerJson)
    {
        // the file is saved + printed content returned
        $printedContent = $this->composerJsonPrinter->print(
            $composerJson,
            getcwd() . '/composer.json'
        );

        // show it to user $printedContent, so they know what was printed
    }
}

That's it! The ComposerJson is not 1:1 to full composer schema. That would be a mess full of methods and constants that are rarely used in practice. Instead, it has only the method we used.

Do you miss some method? No problem, send a pull-request to add it. That way, we'll know someone will use it and we'll be happy to merge it.


Happy coding!


Have you find this post useful? Do you want more?

Follow me on Twitter, RSS or support me on GitHub Sponsors.