Formula9/Framework

View on GitHub
Nine/Views/TwigView.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php namespace Nine\Views;

/**
 * F9 (Formula Nine) Personal PHP Framework
 *
 * Copyright (c) 2010-2016, Greg Truesdell (<odd.greg@gmail.com>)
 * License: MIT (reference: https://opensource.org/licenses/MIT)
 *
 * Acknowledgements:
 *  - The code provided in this file (and in the Framework in general) may include
 * open sourced software licensed for the purpose, refactored code from related
 * packages, or snippets/methods found on sites throughout the internet.
 *  - All originator copyrights remain in force where applicable, as well as their
 *  licenses where obtainable.
 *
 * @package Noid
 * @version 0.1.0
 * @author  Greg Truesdell <odd.greg@gmail.com>
 */

use Twig_Environment;
use Twig_Error_Runtime;
use Twig_Loader_Filesystem;

/**
 * **TwigView is an implementation of the Illuminate View component.**
 *
 * Requires that `TwigViewServiceProvider` has been previously registered.
 *
 * Usage:
 *
 *      $tv = app('twig.view');
 *      - or -
 *      $tv = new TwigView(new TwigConfigurationSet([...]));
 *
 *      $tv['data'] = 'test data';
 *      $tv->render('template');
 *      - or -
 *      $tv->with('data','test data')->render('template');
 *      - or -
 *      $tv->template('test')->with('data','testing')->render();
 *      - or -
 *      app('twig.view')->template('test')->with('data','testing')->render();
 *
 * @see `view()` function.
 */
class TwigView extends AbstractView
{
    const TWIG_LOADER_ARRAY  = 1;
    const TWIG_LOADER_STRING = 2;
    const TWIG_LOADER_CHAIN  = 3;
    const TWIG_LOADER_FILE   = 4;
    const TWIG_LOADER_RADIUM = 5;

    /** @var TwigConfigurationSet */
    protected $context;

    /** @var array */
    protected $defaults;

    /** @var array */
    protected $environment;

    /** @var array */
    protected $filesystem;

    /** @var string */
    protected $template;

    /** @var int */
    protected $template_type;

    /** @var Twig_Environment */
    protected $twig;

    /** @var Twig_Loader_Filesystem */
    protected $twig_loader;

    public function __construct(TwigViewConfigurationInterface $context)
    {
        $this->context = $context;
        $this->defaults = $context->settings();

        $this->templatePaths = $this->defaults['filesystem'];
        $this->events = $context->events();
        parent::__construct($context);

        $this->configure();

    }

    /**
     * @param $templateDir
     *
     * @return mixed|void
     */
    public function addPath($templateDir)
    {
        $this->twig_loader->addPath(realpath($templateDir));

        return $this;
    }

    /**
     * @param array $template_paths
     *
     * @return mixed|void
     * @throws \Twig_Error_Loader
     */
    public function addPaths($template_paths)
    {
        foreach ($template_paths as $template_path) {
            $this->twig_loader->addPath($template_path);
        }

        return $this;
    }

    /**
     * @return \Twig_Loader_Filesystem
     */
    public function getTwigLoader()
    {
        return $this->twig_loader;
    }

    /**
     * get the array of paths from the BladeView view finder.
     *
     * @return array
     */
    public function getViewPaths() : array
    {
        return $this->getTwigLoader()->getPaths();
    }

    /**
     * @param string $template_name
     *
     * @return mixed
     * @throws Twig_Error_Runtime
     */
    public function hasView($template_name) : bool
    {
        throw new \Twig_Error_Runtime('hasView not implemented.');
    }

    /**
     * Template Service Load Interface
     *
     * @param $template_file
     *
     * @return mixed
     */
    public function loadTemplate($template_file)
    {
        try {
            $this->twig->loadTemplate($template_file);

            return $this;
        } catch (\Twig_Error_Loader $e) {
            return FALSE;
        }
    }

    /**
     * @param $templateDir
     *
     * @return mixed|void
     */
    public function prependPath($templateDir)
    {
        $this->twig_loader->prependPath(realpath($templateDir));

        return $this;
    }

    /**
     * Renders a Blade template with passed and stored symbol data.
     *
     * @param null|string $view
     * @param array       $data
     *
     * @return string
     * @internal param string $name
     */
    public function render($view = NULL, array $data = []) : string
    {
        // use the template supplied with ->using() if one is not provided
        $view = $view ?: $this->template;

        // one way or the other, there must be a template to render
        if (NULL === $view) {
            throw new \InvalidArgumentException('No twig view template supplied.');
        }

        $name = empty(pathinfo($view, PATHINFO_EXTENSION)) ? $view . '.twig' : $view;
        $data = $this->collectScope($data);

        return $this->twig->render($name, $data);
    }

    /**
     * @param string $view
     *
     * @return TwigView
     */
    public function using($view = 'default') : TwigView
    {
        $this->template = $view;

        return $this;
    }

    /**
     * Sends configuration data to the template engine
     *
     * for twig, this should include ['filesystem'=>['',],'environment'=>'',]
     *
     */
    protected function configure()
    {
        // set the twig environment (templates and loaders)
        $this->set_environment($this->defaults);

        // make twig and install extensions and globals
        $this->make_twig();
    }

    /**
     * @param $configuration
     *
     * @return mixed
     */
    private function get_template_type($configuration)
    {
        // the 'type' parameter determines which loader is used
        /** @noinspection NullCoalescingOperatorCanBeUsedInspection */
        $this->template_type = isset($configuration['type']) ? $configuration['type'] : static::TWIG_LOADER_FILE;

        return $configuration;
    }

    /**
     *  creates the twig environment, sets globals and installs extensions
     */
    private function make_twig()
    {
        // \Twig_Autoloader::register();
        $this->twig = new \Twig_Environment($this->twig_loader, array_merge($this->environment, ['debug' => TRUE]));

        // globals
        $this->set_globals();

        // extensions
        $this->twig->addExtension(new \Twig_Extension_Debug());
    }

    /**
     * @param $configuration
     */
    private function set_environment($configuration)
    {
        $configuration = $this->get_template_type($configuration);

        // get the loader
        $configuration = $this->set_loader($configuration);

        // assign the environment
        /** @noinspection NullCoalescingOperatorCanBeUsedInspection */
        $this->environment = isset($configuration['environment']) ? $configuration['environment'] : [];
    }

    private function set_globals()
    {
        $this->twig->addGlobal('forge', forge());
        $this->twig->addGlobal('context', forge('context'));
    }

    /**
     * @param $configuration
     *
     * @return mixed
     *
     * @throws \InvalidArgumentException
     */
    private function set_loader($configuration)
    {
        switch (TRUE) {

            case ($this->template_type === static::TWIG_LOADER_ARRAY):

                if ( ! array_key_exists('array', $configuration)) {
                    throw new \InvalidArgumentException(
                        'Twig Service Configuration Error: TWIG_LOADER_ARRAY `array` setting is missing.');
                }

                $this->twig_loader = new \Twig_Loader_Array($configuration['array']);
                break;

            case ($this->template_type === static::TWIG_LOADER_STRING):

                throw new \InvalidArgumentException('Twig template type `TWIG_LOADER_STRING` is deprecated.');
                //$this->twig_loader = new \Twig_Loader_String();
                break;

            case ($this->template_type === static::TWIG_LOADER_CHAIN):

                if ( ! array_key_exists('chain', $configuration)) {
                    throw new \InvalidArgumentException(
                        'Twig Service Configuration Error: TWIG_LOADER_CHAIN `chain` setting is missing.');
                }

                $loaders = [];
                array_map(
                    function ($loader) use (&$loaders) {
                        $loaders[] = new \Twig_Loader_Array($loader);
                    },
                    $configuration['chain']
                );

                $this->twig_loader = new \Twig_Loader_Chain($loaders);
                break;

            case ($this->template_type === static::TWIG_LOADER_FILE):

                if ( ! array_key_exists('filesystem', $configuration)) {
                    new \InvalidArgumentException(
                        'Twig Service Configuration Error: TWIG_LOADER_FILE "filesystem" setting is missing.');
                }

                /** @noinspection NullCoalescingOperatorCanBeUsedInspection */
                $this->filesystem = isset($configuration['filesystem']) ? $configuration['filesystem'] : [];
                $this->twig_loader = new \Twig_Loader_Filesystem($this->filesystem);
                break;

            case ($this->template_type === static::TWIG_LOADER_RADIUM):
                throw new \InvalidArgumentException('Twig Service Error: TWIG_LOADER_RADIUM not implemented.');
                break;
        }

        return $configuration;
    }
}