Formula9/Framework

View on GitHub
F9/Providers/TwigViewServiceProvider.php

Summary

Maintainability
C
1 day
Test Coverage
<?php namespace F9\Support\Provider;

/**
 * @package Nine
 * @version 0.4.2
 * @author  Greg Truesdell <odd.greg@gmail.com>
 */

use F9\Application\Application;
use F9\Contracts\BootableProvider;
use Nine\Containers\Forge;
use Nine\Views\TwigConfigurationSet;
use Nine\Views\TwigView;
use Nine\Views\TwigViewConfigurationInterface;
use Pimple\Container;
use Silex\Provider\TranslationServiceProvider;
use Symfony\Bridge\Twig\AppVariable;
use Symfony\Bridge\Twig\Extension\AssetExtension;
use Symfony\Bridge\Twig\Extension\DumpExtension;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Extension\HttpFoundationExtension;
use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
use Symfony\Bridge\Twig\Extension\RoutingExtension;
use Symfony\Bridge\Twig\Extension\SecurityExtension;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer;

class TwigViewServiceProvider extends ServiceProvider implements BootableProvider
{

    /**
     * @param Application|Container $app
     *
     */
    public function boot($app)
    {
        /** @var Forge $container */
        list($config, $container) = [$this->config, $this->container];

        // only boot if twig templates are enabled by the framework
        if ($this->config['view.twig.enabled']) {

            $app['twig.context'] = function ($app) {
                return new TwigConfigurationSet([
                    'events'   => $app['nine.events'],
                    'finder'   => $app['twig.finder'],
                    'global'   => $app['global.scope'],
                    'paths'    => $app['paths'],
                    'settings' => $app['twig.settings'],
                ]);
            };

            $app['twig.view'] = $app->factory(function ($app) { return new TwigView($app['twig.context']); });

            $container->singleton([TwigConfigurationSet::class, TwigViewConfigurationInterface::class],
                function () use ($app) { return $app['twig.context']; });

            $container->add([TwigView::class, 'TwigView'],
                function () use ($app) { return new TwigView($app['twig.context']); });

        }
    }

    /**
     * @param Container $app
     */
    public function register(Container $app)
    {
        // only register if twig templates are enabled by the framework
        if ($this->config['view.twig.enabled']) {

            $app['twig.settings'] = $settings = $this->config['view.twig.defaults'];
            $app['twig.options'] = $this->config['view.twig.defaults.options'];
            $app['twig.template.paths'] = $app['twig.settings']['filesystem'];
            $app['twig.form.templates'] = $app['twig.settings']['form']['templates']; # 'form_div_layout.html.twig'];
            $app['twig.templates'] = $app['twig.settings']['templates'];

            $app->register(new TranslationServiceProvider, [
                'locale_fallbacks' => ['en'],
            ]);

            $app['twig.app_variable'] = function ($app) {
                $var = new AppVariable();
                if (isset($app['security.token_storage'])) {
                    $var->setTokenStorage($app['security.token_storage']);
                }

                if (isset($app['request_stack'])) {
                    $var->setRequestStack($app['request_stack']);
                }

                $var->setDebug($app['debug']);

                return $var;
            };

            $app['twig.finder'] = $app->protect(function ($template) use ($app) {
                // try locating the
                $finder = new Finder();

                // add twig template paths
                foreach ($app['twig.template.paths'] as $dir) {
                    $finder->in(rtrim($dir, '/'));
                }

                // look for a match
                /** @var \SplFileInfo $file */
                foreach ($finder->files() as $file) {
                    if ($file->getFilename() === $template) {
                        return TRUE;
                    }
                }

                return FALSE;
            });

            $app['twig.loader.filesystem'] = function ($app) {
                return new \Twig_Loader_Filesystem($app['twig.template.paths']);
            };

            $app['twig.loader.array'] = function ($app) {
                return new \Twig_Loader_Array($app['twig.templates']);
            };

            $app['twig.loader'] = function ($app) {
                return new \Twig_Loader_Chain([
                    $app['twig.loader.array'],
                    $app['twig.loader.filesystem'],
                ]);
            };

            $app['twig.environment_factory'] = $app->protect(function ($app) {
                return new \Twig_Environment($app['twig.loader'], $app['twig.options']);
            });

            $app['twig'] = function ($app) {

                /** @var \Twig_Environment $twig */
                $twig = $app['twig.environment_factory']($app);

                // registered for BC, but should not be used anymore
                // deprecated and should probably be removed in Silex 3.0
                $twig->addGlobal('app', $app);

                if ($app['debug']) {
                    $twig->addExtension(new \Twig_Extension_Debug());
                }

                if (class_exists('Symfony\Bridge\Twig\Extension\RoutingExtension')) {
                    $twig->addGlobal('global', $app['twig.app_variable']);

                    if (isset($app['request_stack'])) {
                        $twig->addExtension(new HttpFoundationExtension($app['request_stack']));
                        $twig->addExtension(new RoutingExtension($app['url_generator']));
                    }

                    if (isset($app['translator'])) {
                        $twig->addExtension(new TranslationExtension($app['translator']));
                    }

                    if (isset($app['security.authorization_checker'])) {
                        $twig->addExtension(new SecurityExtension($app['security.authorization_checker']));
                    }

                    if (isset($app['fragment.handler'])) {
                        /** @type HIncludeFragmentRenderer */
                        $app['fragment.renderer.hinclude']->{'setTemplating'}($twig);

                        $twig->addExtension(new HttpKernelExtension($app['fragment.handler']));
                    }

                    if (isset($app['assets.packages'])) {
                        $twig->addExtension(new AssetExtension($app['assets.packages']));
                    }

                    if (isset($app['form.factory'])) {
                        $app['twig.form.engine'] = function ($app) {
                            return new TwigRendererEngine($app['twig.form.templates']);
                        };

                        $app['twig.form.renderer'] = function ($app) {
                            return new TwigRenderer($app['twig.form.engine'], $app['csrf.token_manager']);
                        };

                        $twig->addExtension(new FormExtension($app['twig.form.renderer']));

                        // add loader for Symfony built-in form templates
                        $reflected = new \ReflectionClass('Symfony\Bridge\Twig\Extension\FormExtension');
                        $path = dirname($reflected->getFileName()) . '/../Resources/views/Form';

                        /** @var \Twig_Loader_Chain */
                        $app['twig.loader']->{'addLoader'}(new \Twig_Loader_Filesystem($path));
                    }

                    if (isset($app['var_dumper.cloner'])) {
                        $twig->addExtension(new DumpExtension($app['var_dumper.cloner']));
                    }
                }

                return $twig;
            };
        }

    }
}