1<?php 2 3/* 4 * This file is part of the Silex framework. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Silex\Provider; 13 14use Symfony\Bundle\WebProfilerBundle\Controller\ExceptionController; 15use Symfony\Bundle\WebProfilerBundle\Controller\RouterController; 16use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController; 17use Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener; 18use Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension; 19use Symfony\Component\Form\Extension\DataCollector\FormDataCollector; 20use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor; 21use Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeFactoryDataCollectorProxy; 22use Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension; 23use Symfony\Component\HttpKernel\Profiler\Profiler; 24use Symfony\Component\HttpKernel\EventListener\ProfilerListener; 25use Symfony\Component\HttpKernel\Profiler\FileProfilerStorage; 26use Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector; 27use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector; 28use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector; 29use Symfony\Component\HttpKernel\DataCollector\RouterDataCollector; 30use Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector; 31use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector; 32use Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector; 33use Symfony\Component\HttpKernel\DataCollector\EventDataCollector; 34use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher; 35use Symfony\Component\Stopwatch\Stopwatch; 36use Symfony\Bridge\Twig\Extension\CodeExtension; 37use Silex\Application; 38use Silex\ServiceProviderInterface; 39use Silex\ControllerProviderInterface; 40use Silex\ServiceControllerResolver; 41 42/** 43 * Symfony Web Profiler provider. 44 * 45 * @author Fabien Potencier <fabien@symfony.com> 46 */ 47class WebProfilerServiceProvider implements ServiceProviderInterface, ControllerProviderInterface 48{ 49 public function register(Application $app) 50 { 51 $app['profiler.mount_prefix'] = '/_profiler'; 52 $app['dispatcher'] = $app->share($app->extend('dispatcher', function ($dispatcher, $app) { 53 return new TraceableEventDispatcher($dispatcher, $app['stopwatch'], $app['logger']); 54 })); 55 56 $app['data_collector.templates'] = array( 57 array('config', '@WebProfiler/Collector/config.html.twig'), 58 array('request', '@WebProfiler/Collector/request.html.twig'), 59 array('exception', '@WebProfiler/Collector/exception.html.twig'), 60 array('events', '@WebProfiler/Collector/events.html.twig'), 61 array('logger', '@WebProfiler/Collector/logger.html.twig'), 62 array('time', '@WebProfiler/Collector/time.html.twig'), 63 array('router', '@WebProfiler/Collector/router.html.twig'), 64 array('memory', '@WebProfiler/Collector/memory.html.twig'), 65 array('form', '@WebProfiler/Collector/form.html.twig'), 66 ); 67 68 $app['data_collectors'] = $app->share(function ($app) { 69 return array( 70 'config' => $app->share(function ($app) { return new ConfigDataCollector(); }), 71 'request' => $app->share(function ($app) { return new RequestDataCollector(); }), 72 'exception' => $app->share(function ($app) { return new ExceptionDataCollector(); }), 73 'events' => $app->share(function ($app) { return new EventDataCollector($app['dispatcher']); }), 74 'logger' => $app->share(function ($app) { return new LoggerDataCollector($app['logger']); }), 75 'time' => $app->share(function ($app) { return new TimeDataCollector(null, $app['stopwatch']); }), 76 'router' => $app->share(function ($app) { return new RouterDataCollector(); }), 77 'memory' => $app->share(function ($app) { return new MemoryDataCollector(); }), 78 ); 79 }); 80 81 if (isset($app['form.resolved_type_factory']) && class_exists('\Symfony\Component\Form\Extension\DataCollector\FormDataCollector')) { 82 $app['data_collectors.form.extractor'] = $app->share(function () { return new FormDataExtractor(); }); 83 84 $app['data_collectors'] = $app->share($app->extend('data_collectors', function ($collectors, $app) { 85 $collectors['form'] = $app->share(function ($app) { return new FormDataCollector($app['data_collectors.form.extractor']); }); 86 87 return $collectors; 88 })); 89 90 $app['form.resolved_type_factory'] = $app->share($app->extend('form.resolved_type_factory', function ($factory, $app) { 91 return new ResolvedTypeFactoryDataCollectorProxy($factory, $app['data_collectors']['form']($app)); 92 })); 93 94 $app['form.type.extensions'] = $app->share($app->extend('form.type.extensions', function ($extensions, $app) { 95 $extensions[] = new DataCollectorTypeExtension($app['data_collectors']['form']($app)); 96 97 return $extensions; 98 })); 99 } 100 101 $app['web_profiler.controller.profiler'] = $app->share(function ($app) { 102 return new ProfilerController($app['url_generator'], $app['profiler'], $app['twig'], $app['data_collector.templates'], $app['web_profiler.debug_toolbar.position']); 103 }); 104 105 $app['web_profiler.controller.router'] = $app->share(function ($app) { 106 return new RouterController($app['profiler'], $app['twig'], isset($app['url_matcher']) ? $app['url_matcher'] : null, $app['routes']); 107 }); 108 109 $app['web_profiler.controller.exception'] = $app->share(function ($app) { 110 return new ExceptionController($app['profiler'], $app['twig'], $app['debug']); 111 }); 112 113 $app['web_profiler.toolbar.listener'] = $app->share(function ($app) { 114 return new WebDebugToolbarListener($app['twig'], $app['web_profiler.debug_toolbar.intercept_redirects'], $app['web_profiler.debug_toolbar.position'], $app['url_generator']); 115 }); 116 117 $app['profiler'] = $app->share(function ($app) { 118 $profiler = new Profiler($app['profiler.storage'], $app['logger']); 119 120 foreach ($app['data_collectors'] as $collector) { 121 $profiler->add($collector($app)); 122 } 123 124 return $profiler; 125 }); 126 127 $app['profiler.storage'] = $app->share(function ($app) { 128 return new FileProfilerStorage('file:'.$app['profiler.cache_dir']); 129 }); 130 131 $app['profiler.request_matcher'] = null; 132 $app['profiler.only_exceptions'] = false; 133 $app['profiler.only_master_requests'] = false; 134 $app['web_profiler.debug_toolbar.enable'] = true; 135 $app['web_profiler.debug_toolbar.position'] = 'bottom'; 136 $app['web_profiler.debug_toolbar.intercept_redirects'] = false; 137 138 $app['profiler.listener'] = $app->share(function ($app) { 139 return new ProfilerListener( 140 $app['profiler'], 141 $app['profiler.request_matcher'], 142 $app['profiler.only_exceptions'], 143 $app['profiler.only_master_requests'] 144 ); 145 }); 146 147 $app['stopwatch'] = $app->share(function () { 148 return new Stopwatch(); 149 }); 150 151 $app['code.file_link_format'] = null; 152 153 $app['twig'] = $app->share($app->extend('twig', function ($twig, $app) { 154 $twig->addExtension(new CodeExtension($app['code.file_link_format'], '', $app['charset'])); 155 156 if (class_exists('\Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension')) { 157 $twig->addExtension(new WebProfilerExtension()); 158 } 159 160 return $twig; 161 })); 162 163 $app['twig.loader.filesystem'] = $app->share($app->extend('twig.loader.filesystem', function ($loader, $app) { 164 $loader->addPath($app['profiler.templates_path'], 'WebProfiler'); 165 166 return $loader; 167 })); 168 169 $app['profiler.templates_path'] = function () { 170 $r = new \ReflectionClass('Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener'); 171 172 return dirname(dirname($r->getFileName())).'/Resources/views'; 173 }; 174 } 175 176 public function connect(Application $app) 177 { 178 if (!$app['resolver'] instanceof ServiceControllerResolver) { 179 // using RuntimeException crashes PHP?! 180 throw new \LogicException('You must enable the ServiceController service provider to be able to use the WebProfiler.'); 181 } 182 183 $controllers = $app['controllers_factory']; 184 185 $controllers->get('/router/{token}', 'web_profiler.controller.router:panelAction')->bind('_profiler_router'); 186 $controllers->get('/exception/{token}.css', 'web_profiler.controller.exception:cssAction')->bind('_profiler_exception_css'); 187 $controllers->get('/exception/{token}', 'web_profiler.controller.exception:showAction')->bind('_profiler_exception'); 188 $controllers->get('/search', 'web_profiler.controller.profiler:searchAction')->bind('_profiler_search'); 189 $controllers->get('/search_bar', 'web_profiler.controller.profiler:searchBarAction')->bind('_profiler_search_bar'); 190 $controllers->get('/purge', 'web_profiler.controller.profiler:purgeAction')->bind('_profiler_purge'); 191 $controllers->get('/info/{about}', 'web_profiler.controller.profiler:infoAction')->bind('_profiler_info'); 192 $controllers->get('/phpinfo', 'web_profiler.controller.profiler:phpinfoAction')->bind('_profiler_phpinfo'); 193 $controllers->get('/{token}/search/results', 'web_profiler.controller.profiler:searchResultsAction')->bind('_profiler_search_results'); 194 $controllers->get('/{token}', 'web_profiler.controller.profiler:panelAction')->bind('_profiler'); 195 $controllers->get('/wdt/{token}', 'web_profiler.controller.profiler:toolbarAction')->bind('_wdt'); 196 $controllers->get('/', 'web_profiler.controller.profiler:homeAction')->bind('_profiler_home'); 197 198 return $controllers; 199 } 200 201 public function boot(Application $app) 202 { 203 $dispatcher = $app['dispatcher']; 204 205 $dispatcher->addSubscriber($app['profiler.listener']); 206 207 if ($app['web_profiler.debug_toolbar.enable']) { 208 $dispatcher->addSubscriber($app['web_profiler.toolbar.listener']); 209 } 210 211 $dispatcher->addSubscriber($app['profiler']->get('request')); 212 $app->mount($app['profiler.mount_prefix'], $this->connect($app)); 213 } 214} 215