Formula9/Framework

View on GitHub
F9/Providers/F9WebProfilerServiceProvider.php

Summary

Maintainability
F
3 days
Test Coverage
<?php

/*
 * This file is part of the Silex framework.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Silex\Provider;

use F9\Contracts\BootableProvider;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Silex\Api\BootableProviderInterface;
use Silex\Api\ControllerProviderInterface;
use Silex\Api\EventListenerProviderInterface;
use Silex\Application;
use F9\Application\Application as NineApplication;
use Silex\ServiceControllerResolver;
use Symfony\Bridge\Twig\DataCollector\TwigDataCollector;
use Symfony\Bridge\Twig\Extension\CodeExtension;
use Symfony\Bridge\Twig\Extension\ProfilerExtension;
use Symfony\Bundle\WebProfilerBundle\Controller\ExceptionController;
use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController;
use Symfony\Bundle\WebProfilerBundle\Controller\RouterController;
use Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener;
use Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\DataCollector\FormDataCollector;
use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor;
use Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeFactoryDataCollectorProxy;
use Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension;
use Symfony\Component\HttpKernel\DataCollector\AjaxDataCollector;
use Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector;
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\HttpKernel\DataCollector\EventDataCollector;
use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector;
use Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector;
use Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector;
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector;
use Symfony\Component\HttpKernel\DataCollector\RouterDataCollector;
use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector;
use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher;
use Symfony\Component\HttpKernel\EventListener\DumpListener;
use Symfony\Component\HttpKernel\EventListener\ProfilerListener;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\Profiler\FileProfilerStorage;
use Symfony\Component\HttpKernel\Profiler\Profiler;
use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\Yaml\Yaml;

/**
 * Symfony Web Profiler provider.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class F9WebProfilerServiceProvider implements ServiceProviderInterface, ControllerProviderInterface, BootableProvider, EventListenerProviderInterface
{
    public function boot($app)
    {
        $app->mount($app['profiler.mount_prefix'], $this->connect($app));
    }

    public function connect(Application $app)
    {
        if ( ! $app['resolver'] instanceof ServiceControllerResolver) {
            // using RuntimeException crashes PHP?!
            throw new \LogicException('You must enable the ServiceController service provider to be able to use the WebProfiler.');
        }

        $controllers = $app['controllers_factory'];

        $controllers->get('/router/{token}', 'web_profiler.controller.router:panelAction')->bind('_profiler_router');
        $controllers->get('/exception/{token}.css', 'web_profiler.controller.exception:cssAction')->bind('_profiler_exception_css');
        $controllers->get('/exception/{token}', 'web_profiler.controller.exception:showAction')->bind('_profiler_exception');
        $controllers->get('/search', 'web_profiler.controller.profiler:searchAction')->bind('_profiler_search');
        $controllers->get('/search_bar', 'web_profiler.controller.profiler:searchBarAction')->bind('_profiler_search_bar');
        $controllers->get('/purge', 'web_profiler.controller.profiler:purgeAction')->bind('_profiler_purge');
        $controllers->get('/info/{about}', 'web_profiler.controller.profiler:infoAction')->bind('_profiler_info');
        $controllers->get('/phpinfo', 'web_profiler.controller.profiler:phpinfoAction')->bind('_profiler_phpinfo');
        $controllers->get('/{token}/search/results', 'web_profiler.controller.profiler:searchResultsAction')->bind('_profiler_search_results');
        $controllers->get('/{token}', 'web_profiler.controller.profiler:panelAction')->bind('_profiler');
        $controllers->get('/wdt/{token}', 'web_profiler.controller.profiler:toolbarAction')->bind('_wdt');
        $controllers->get('/', 'web_profiler.controller.profiler:homeAction')->bind('_profiler_home');

        return $controllers;
    }

    public function register(Container $app)
    {
        $app['profiler.mount_prefix'] = '/_profiler';
        $app->extend('dispatcher', function ($dispatcher, $app) {
            return new TraceableEventDispatcher($dispatcher, $app['stopwatch'], $app['logger']);
        });

        $app['data_collector.templates'] = function ($app) {
            $templates = [
                ['config', '@WebProfiler/Collector/config.html.twig'],
                ['request', '@WebProfiler/Collector/request.html.twig'],
                ['exception', '@WebProfiler/Collector/exception.html.twig'],
                ['events', '@WebProfiler/Collector/events.html.twig'],
                ['logger', '@WebProfiler/Collector/logger.html.twig'],
                ['time', '@WebProfiler/Collector/time.html.twig'],
                ['router', '@WebProfiler/Collector/router.html.twig'],
                ['memory', '@WebProfiler/Collector/memory.html.twig'],
                ['form', '@WebProfiler/Collector/form.html.twig'],
            ];

            if (class_exists('Symfony\Bridge\Twig\Extension\ProfilerExtension')) {
                $templates[] = ['twig', '@WebProfiler/Collector/twig.html.twig'];
            }

            if (isset($app['var_dumper.cli_dumper']) && $app['profiler.templates_path.debug']) {
                $templates[] = ['dump', '@Debug/Profiler/dump.html.twig'];
            }

            if (class_exists('Symfony\Component\HttpKernel\DataCollector\AjaxDataCollector')) {
                $templates[] = ['ajax', '@WebProfiler/Collector/ajax.html.twig'];
            }

            return $templates;
        };

        $app['data_collectors'] = function ($app) {
            return [
                'config'    => function ($app) { return new ConfigDataCollector('Formula Nine', NineApplication::VERSION); },
                'request'   => function ($app) { return new RequestDataCollector(); },
                'exception' => function ($app) { return new ExceptionDataCollector(); },
                'events'    => function ($app) { return new EventDataCollector($app['dispatcher']); },
                'logger'    => function ($app) { return new LoggerDataCollector($app['logger']); },
                'time'      => function ($app) { return new TimeDataCollector(NULL, $app['stopwatch']); },
                'router'    => function ($app) { return new RouterDataCollector(); },
                'memory'    => function ($app) { return new MemoryDataCollector(); },
            ];
        };

        if (isset($app['form.resolved_type_factory']) && class_exists('\Symfony\Component\Form\Extension\DataCollector\FormDataCollector')) {
            $app['data_collectors.form.extractor'] = function () { return new FormDataExtractor(); };

            $app->extend('data_collectors', function ($collectors, $app) {
                $collectors['form'] = function ($app) { return new FormDataCollector($app['data_collectors.form.extractor']); };

                return $collectors;
            });

            $app->extend('form.resolved_type_factory', function ($factory, $app) {
                return new ResolvedTypeFactoryDataCollectorProxy($factory, $app['data_collectors']['form']($app));
            });

            $app->extend('form.type.extensions', function ($extensions, $app) {
                $extensions[] = new DataCollectorTypeExtension($app['data_collectors']['form']($app));

                return $extensions;
            });
        }

        if (class_exists('Symfony\Bridge\Twig\Extension\ProfilerExtension')) {
            $app['data_collectors'] = $app->extend('data_collectors', function ($collectors, $app) {
                $collectors['twig'] = function ($app) {
                    return new TwigDataCollector($app['twig.profiler.profile']);
                };

                return $collectors;
            });

            $app['twig.profiler.profile'] = function () {
                return new \Twig_Profiler_Profile();
            };
        }

        if (isset($app['var_dumper.cli_dumper'])) {
            $app['var_dumper.dump_listener'] = function ($app) {
                return new DumpListener($app['var_dumper.cloner'], $app['var_dumper.data_collector']);
            };

            $app['data_collectors'] = $app->extend('data_collectors', function ($collectors, $app) {
                if ($app['profiler.templates_path.debug']) {
                    $collectors['dump'] = function ($app) {
                        $dumper = NULL === $app['var_dumper.dump_destination'] ? NULL : $app['var_dumper.cli_dumper'];

                        return $app['var_dumper.data_collector'] = new DumpDataCollector($app['stopwatch'], NULL, $app['charset'], $app['request_stack'], $dumper);
                    };
                }

                return $collectors;
            });
        }

        if (class_exists('Symfony\Component\HttpKernel\DataCollector\AjaxDataCollector')) {
            $app['data_collectors'] = $app->extend('data_collectors', function ($collectors, $app) {
                $collectors['ajax'] = function ($app) {
                    return new AjaxDataCollector();
                };

                return $collectors;
            });
        }

        if (isset($app['security.token_storage']) && class_exists('Symfony\Bundle\SecurityBundle\DataCollector\SecurityDataCollector')) {
            $app->extend('data_collectors', function ($collectors, $app) {
                $collectors['security'] = function ($app) {
                    $roleHierarchy = ! empty($app['security.role_hierarchy']) ? $app['security.role_hierarchy'] : NULL;
                    $logoutUrlGenerator = new LogoutUrlGenerator($app['request_stack'], $app['url_generator'], $app['security.token_storage']);

                    $sec_data_collector = 'Symfony\Bundle\SecurityBundle\DataCollector\SecurityDataCollector';

                    return new $sec_data_collector($app['security.token_storage'], $roleHierarchy, $logoutUrlGenerator);
                };

                return $collectors;
            });

            $app->extend('data_collector.templates', function ($templates) {
                $templates[] = ['security', '@Security/Collector/security.html.twig'];

                return $templates;
            });

            $app->extend('twig.loader.filesystem', function ($loader, $app) {
                if ($app['profiler.templates_path.security']) {
                    $loader->addPath($app['profiler.templates_path.security'], 'Security');
                }

                return $loader;
            });

            $app['profiler.templates_path.security'] = function () {
                $r = new \ReflectionClass('Symfony\Bundle\SecurityBundle\DataCollector\SecurityDataCollector');

                return dirname(dirname($r->getFileName())) . '/Resources/views';
            };

            $app['twig'] = $app->extend('twig', function ($twig, $app) {
                $twig->addFilter('yaml_encode', new \Twig_SimpleFilter('yaml_encode', function (array $var) {
                    return Yaml::dump($var);
                }));

                $twig->addFunction('yaml_encode', new \Twig_SimpleFunction('yaml_encode', function (array $var) {
                    return Yaml::dump($var);
                }));

                return $twig;
            });
        }

        $app['web_profiler.controller.profiler'] = function ($app) {
            return new ProfilerController($app['url_generator'], $app['profiler'], $app['twig'], $app['data_collector.templates'], $app['web_profiler.debug_toolbar.position']);
        };

        $app['web_profiler.controller.router'] = function ($app) {
            return new RouterController($app['profiler'], $app['twig'], $app['request_matcher'] ?? NULL, $app['routes']);
        };

        $app['web_profiler.controller.exception'] = function ($app) {
            return new ExceptionController($app['profiler'], $app['twig'], $app['debug']);
        };

        $app['web_profiler.toolbar.listener'] = function ($app) {
            $mode = $app['web_profiler.debug_toolbar.enable'] ? WebDebugToolbarListener::ENABLED : WebDebugToolbarListener::DISABLED;

            return new WebDebugToolbarListener($app['twig'], $app['web_profiler.debug_toolbar.intercept_redirects'], $mode, $app['web_profiler.debug_toolbar.position'], $app['url_generator']);
        };

        $app['profiler'] = function ($app) {
            $profiler = new Profiler($app['profiler.storage'], $app['logger']);

            foreach ($app['data_collectors'] as $collector) {
                /** @var callable $collector */
                $profiler->add($collector($app));
            }

            return $profiler;
        };

        $app['profiler.storage'] = function ($app) {
            return new FileProfilerStorage('file:' . $app['profiler.cache_dir']);
        };

        $app['profiler.request_matcher'] = NULL;
        $app['profiler.only_exceptions'] = FALSE;
        $app['profiler.only_master_requests'] = FALSE;
        $app['web_profiler.debug_toolbar.enable'] = TRUE;
        $app['web_profiler.debug_toolbar.position'] = 'bottom';
        $app['web_profiler.debug_toolbar.intercept_redirects'] = FALSE;

        $app['profiler.listener'] = function ($app) {
            if (Kernel::VERSION_ID >= 20800) {
                return new ProfilerListener($app['profiler'], $app['request_stack'], $app['profiler.request_matcher'], $app['profiler.only_exceptions'], $app['profiler.only_master_requests']);
            }
            else {
                /** @noinspection PhpParamsInspection */
                return new ProfilerListener($app['profiler'], $app['profiler.request_matcher'], $app['profiler.only_exceptions'], $app['profiler.only_master_requests'], $app['request_stack']);
            }
        };

        $app['stopwatch'] = function () {
            return new Stopwatch();
        };

        $app['code.file_link_format'] = NULL;

        $app->extend('twig', function ($twig, $app) {
            $twig->addExtension(new CodeExtension($app['code.file_link_format'], '', $app['charset']));

            if (class_exists('\Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension')) {
                $twig->addExtension(new WebProfilerExtension());
            }

            if (class_exists('Symfony\Bridge\Twig\Extension\ProfilerExtension')) {
                $twig->addExtension(new ProfilerExtension($app['twig.profiler.profile'], $app['stopwatch']));
            }

            return $twig;
        });

        $app->extend('twig.loader.filesystem', function ($loader, $app) {
            $loader->addPath($app['profiler.templates_path'], 'WebProfiler');
            if ($app['profiler.templates_path.debug']) {
                $loader->addPath($app['profiler.templates_path.debug'], 'Debug');
            }

            return $loader;
        });

        $app['profiler.templates_path'] = function () {
            $r = new \ReflectionClass('Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener');

            return dirname(dirname($r->getFileName())) . '/Resources/views';
        };

        $app['profiler.templates_path.debug'] = function () {
            foreach (spl_autoload_functions() as $autoloader) {
                if ( ! is_array($autoloader) || ! method_exists($autoloader[0], 'findFile')) {
                    continue;
                }

                if ($file = $autoloader[0]->{'findFile'}('Symfony\Bundle\DebugBundle\DebugBundle')) {
                    return dirname($file) . '/Resources/views';
                }
            }
        };
    }

    public function subscribe(Container $app, EventDispatcherInterface $dispatcher)
    {
        $dispatcher->addSubscriber($app['profiler.listener']);

        if ($app['web_profiler.debug_toolbar.enable']) {
            $dispatcher->addSubscriber($app['web_profiler.toolbar.listener']);
        }

        /** @noinspection PhpParamsInspection */
        $dispatcher->addSubscriber($app['profiler']->get('request'));

        if (isset($app['var_dumper.data_collector'])) {
            $dispatcher->addSubscriber($app['var_dumper.dump_listener']);
        }
    }
}