pug-php/installer

View on GitHub
src/Pug/Installer/Installer.php

Summary

Maintainability
A
2 hrs
Test Coverage
A
100%
<?php

namespace Pug\Installer;

use Composer\Composer;
use Composer\EventDispatcher\Event;
use Composer\Json\JsonFile;

class Installer
{
    /**
     * @var Event
     */
    protected $event;

    public function __construct(Event $event)
    {
        $this->event = $event;
    }

    public function install($repository, $version = null)
    {
        $vendorDirectory = static::fallbackVendorDir(static::getComposerVendorDir($this->event->getComposer()));
        $composer = $vendorDirectory . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'composer';

        return shell_exec($composer . ' require --no-interaction ' . $repository . ($version ? ' ' . $version : '') . ' 2>&1');
    }

    protected static function looksVendorDir($vendorDirectory)
    {
        return is_dir($vendorDirectory . DIRECTORY_SEPARATOR . 'bin') ||
            file_exists($vendorDirectory . DIRECTORY_SEPARATOR . 'autoload.php');
    }

    public static function fallbackVendorDir($vendorDirectory, $vendorName = 'vendor')
    {
        if (!static::looksVendorDir($vendorDirectory)) {
            $vendorDirectory = __DIR__;

            for ($i = 0; $i < 10; $i++) {
                $vendorDirectory = dirname($vendorDirectory);

                foreach (array('', DIRECTORY_SEPARATOR . $vendorName) as $directory) {
                    if (static::looksVendorDir($vendorDirectory . $directory)) {
                        return $vendorDirectory . $directory;
                    }
                }
            }
        }

        return $vendorDirectory;
    }

    protected static function appendConfig(&$installers, $directory)
    {
        $json = new JsonFile($directory . DIRECTORY_SEPARATOR . 'composer.json');

        try {
            $dependencyConfig = $json->read();
        } catch (\RuntimeException $e) {
            $dependencyConfig = null;
        }
        if (is_array($dependencyConfig) && isset($dependencyConfig['extra'], $dependencyConfig['extra']['installer'])) {
            $installers = array_merge($installers, (array) $dependencyConfig['extra']['installer']);
        }
    }

    protected static function getComposerVendorDir(Composer $composer)
    {
        return realpath($composer->getConfig()->get('vendor-dir'));
    }

    protected static function getInstallerConfig(Composer $composer)
    {
        $vendorDir = static::getComposerVendorDir($composer);

        $installers = array();

        foreach (scandir($vendorDir) as $namespace) {
            if ($namespace === '.' || $namespace === '..' || !is_dir($directory = $vendorDir . DIRECTORY_SEPARATOR . $namespace)) {
                continue;
            }
            foreach (scandir($directory) as $dependency) {
                if ($dependency === '.' || $dependency === '..' || !is_dir($subDirectory = $directory . DIRECTORY_SEPARATOR . $dependency)) {
                    continue;
                }
                static::appendConfig($installers, $subDirectory);
            }
        }
        static::appendConfig($installers, dirname($vendorDir));

        return $installers;
    }

    public static function onAutoloadDump(Event $event)
    {
        $composer = $event->getComposer();
        $installers = static::getInstallerConfig($composer);

        if (!count($installers)) {
            $event->getIO()->write(
                "Warning: in order to use Pug\\Installer, you should add an \"extra\": {\"installer\": \"YourInstallerClass\"}' setting in your composer.json"
            );

            return;
        }

        include_once static::fallbackVendorDir(static::getComposerVendorDir($composer)) . DIRECTORY_SEPARATOR . 'autoload.php';

        foreach ($installers as $installer) {
            call_user_func($installer, $event, new static($event));
        }
    }

    public function __toString()
    {
        return get_class();
    }
}