tapestry-cloud/tapestry

View on GitHub
src/Tapestry.php

Summary

Maintainability
A
0 mins
Test Coverage
A
90%
<?php

namespace Tapestry;

use ArrayAccess;
use League\Event\Emitter;
use League\Container\Container;
use League\Container\ContainerInterface;
use League\Container\ReflectionContainer;
use League\Container\ContainerAwareInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Tapestry\Exceptions\InvalidConsoleInputException;
use League\Container\ServiceProvider\ServiceProviderInterface;
use Tapestry\Exceptions\InvalidCurrentWorkingDirectoryException;

class Tapestry implements ContainerAwareInterface, ArrayAccess
{
    /**
     * The current globally available instance of Tapestry.
     *
     * @var static
     */
    protected static $instance;

    /**
     * @var \League\Container\ContainerInterface|\League\Container\Container
     */
    protected $container;

    /**
     * Version Number.
     *
     * @var string
     */
    const VERSION = '1.0.12';

    /**
     * Storage of data used by --stopwatch flag.
     *
     * @var Profiler
     */
    public static $profiler;

    /**
     * Tapestry constructor.
     *
     * InputInterface need only contain the command line options; this is because some of the service providers need to
     * know options such as --site-dir but do not need to know command arguments.
     *
     * @param InputInterface $input
     */
    public function __construct(InputInterface $input)
    {
        static::$profiler = new Profiler();

        $this->setInput($input);
        $this['events'] = new Emitter();
        $this->boot();
    }

    /**
     * @param array $options
     */
    private function parseOptions(array $options = [])
    {
        $this['cmd_options'] = $options;
        $this['environment'] = 'local';
        $this['currentWorkingDirectory'] = getcwd();

        if (isset($options['env'])) {
            $this['environment'] = $options['env'];
        }

        if (isset($options['site-dir'])) {
            $this['currentWorkingDirectory'] = $options['site-dir'];
        }

        $this['destinationDirectory'] = $this['currentWorkingDirectory'].DIRECTORY_SEPARATOR.'build_'.$this['environment'];

        if (isset($options['dist-dir'])) {
            $this['destinationDirectory'] = $options['dist-dir'];
        }
    }

    /**
     * @throws InvalidConsoleInputException
     */
    public function validateInput()
    {
        if (! file_exists($this['currentWorkingDirectory'])) {
            throw new InvalidCurrentWorkingDirectoryException('The site directory ['.$this['currentWorkingDirectory'].'] does not exist.');
        }

        if (! realpath($this['currentWorkingDirectory'])) {
            throw new InvalidConsoleInputException('There was an error while identifying the site directory, do you have read/write permissions?');
        }
    }

    /**
     * @param InputInterface $input
     */
    public function setInput(InputInterface $input)
    {
        $this->parseOptions($input->getOptions());
        $this->getContainer()->add(InputInterface::class, $input);
    }

    /**
     * @param OutputInterface $output
     */
    public function setOutput(OutputInterface $output)
    {
        $this->getContainer()->add(OutputInterface::class, $output);
    }

    /**
     * Register/Boot Providers.
     *
     * @return void
     */
    public function boot()
    {
        $this->register(\Tapestry\Providers\CommandServiceProvider::class);
        $this->register(\Tapestry\Providers\ProjectConfigurationServiceProvider::class);
        $this->register(\Tapestry\Providers\ProjectServiceProvider::class);
        $this->register(\Tapestry\Providers\CompileStepsServiceProvider::class);
        $this->register(\Tapestry\Providers\PlatesServiceProvider::class);
        $this->register(\Tapestry\Providers\ProjectKernelServiceProvider::class);
    }

    /**
     * Set a container.
     *
     * @param \League\Container\ContainerInterface $container
     */
    public function setContainer(ContainerInterface $container)
    {
        $this->container = $container;
        $this->container->delegate(
            new ReflectionContainer()
        );
        $this->container->add(self::class, $this);
        self::setInstance($this);
    }

    /**
     * Get the container.
     *
     * @return \League\Container\ContainerInterface
     */
    public function getContainer()
    {
        if (! isset($this->container)) {
            $this->setContainer(new Container());
        }

        return $this->container;
    }

    /**
     * Register a service provider.
     *
     * @param string|ServiceProviderInterface $serviceProvider
     *
     * @return void
     */
    public function register($serviceProvider)
    {
        $this->getContainer()->addServiceProvider($serviceProvider);
    }

    /**
     * @return Tapestry
     */
    public static function getInstance()
    {
        return static::$instance;
    }

    /**
     * @param Tapestry $tapestry
     */
    public static function setInstance(self $tapestry)
    {
        static::$instance = $tapestry;
    }

    /**
     * @param string $name
     */
    public static function addProfile($name)
    {
        static::$profiler->addItem($name);
    }

    /**
     * @return Emitter
     */
    public function getEventEmitter()
    {
        return $this['events'];
    }

    /**
     * Whether a offset exists.
     *
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
     * @param mixed $offset
     * @return bool
     */
    public function offsetExists($offset)
    {
        return $this->getContainer()->has($offset);
    }

    /**
     * Offset to retrieve.
     *
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
     * @param mixed $offset
     * @return mixed
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function offsetGet($offset)
    {
        return $this->getContainer()->get($offset);
    }

    /**
     * Offset to set.
     *
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
     * @param mixed $offset
     * @param mixed $value
     * @return void
     */
    public function offsetSet($offset, $value)
    {
        $this->getContainer()->add($offset, $value);
    }

    /**
     * Offset to unset.
     *
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
     * @param mixed $offset
     * @throws \Exception
     */
    public function offsetUnset($offset)
    {
        throw new \Exception("The container doesn't support removal of registered containers.");
    }
}