vendor/symfony/src/Symfony/Component/HttpKernel/Kernel.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     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 
       
    12 namespace Symfony\Component\HttpKernel;
       
    13 
       
    14 use Symfony\Component\DependencyInjection\ContainerInterface;
       
    15 use Symfony\Component\DependencyInjection\ContainerBuilder;
       
    16 use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
       
    17 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
       
    18 use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
       
    19 use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
       
    20 use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
       
    21 use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
       
    22 use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
       
    23 use Symfony\Component\HttpFoundation\Request;
       
    24 use Symfony\Component\HttpKernel\HttpKernelInterface;
       
    25 use Symfony\Component\HttpKernel\Bundle\BundleInterface;
       
    26 use Symfony\Component\HttpKernel\Config\FileLocator;
       
    27 use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
       
    28 use Symfony\Component\HttpKernel\DependencyInjection\AddClassesToCachePass;
       
    29 use Symfony\Component\HttpKernel\DependencyInjection\Extension as DIExtension;
       
    30 use Symfony\Component\HttpKernel\Debug\ErrorHandler;
       
    31 use Symfony\Component\HttpKernel\Debug\ExceptionHandler;
       
    32 use Symfony\Component\Config\Loader\LoaderResolver;
       
    33 use Symfony\Component\Config\Loader\DelegatingLoader;
       
    34 use Symfony\Component\Config\ConfigCache;
       
    35 use Symfony\Component\ClassLoader\ClassCollectionLoader;
       
    36 use Symfony\Component\ClassLoader\DebugUniversalClassLoader;
       
    37 
       
    38 /**
       
    39  * The Kernel is the heart of the Symfony system.
       
    40  *
       
    41  * It manages an environment made of bundles.
       
    42  *
       
    43  * @author Fabien Potencier <fabien@symfony.com>
       
    44  *
       
    45  * @api
       
    46  */
       
    47 abstract class Kernel implements KernelInterface
       
    48 {
       
    49     protected $bundles;
       
    50     protected $bundleMap;
       
    51     protected $container;
       
    52     protected $rootDir;
       
    53     protected $environment;
       
    54     protected $debug;
       
    55     protected $booted;
       
    56     protected $name;
       
    57     protected $startTime;
       
    58     protected $classes;
       
    59 
       
    60     const VERSION = '2.0.1';
       
    61 
       
    62     /**
       
    63      * Constructor.
       
    64      *
       
    65      * @param string  $environment The environment
       
    66      * @param Boolean $debug       Whether to enable debugging or not
       
    67      *
       
    68      * @api
       
    69      */
       
    70     public function __construct($environment, $debug)
       
    71     {
       
    72         $this->environment = $environment;
       
    73         $this->debug = (Boolean) $debug;
       
    74         $this->booted = false;
       
    75         $this->rootDir = $this->getRootDir();
       
    76         $this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir));
       
    77         $this->classes = array();
       
    78 
       
    79         if ($this->debug) {
       
    80             $this->startTime = microtime(true);
       
    81         }
       
    82 
       
    83         $this->init();
       
    84     }
       
    85 
       
    86     public function init()
       
    87     {
       
    88         if ($this->debug) {
       
    89             ini_set('display_errors', 1);
       
    90             error_reporting(-1);
       
    91 
       
    92             DebugUniversalClassLoader::enable();
       
    93             ErrorHandler::register();
       
    94             if ('cli' !== php_sapi_name()) {
       
    95                 ExceptionHandler::register();
       
    96             }
       
    97         } else {
       
    98             ini_set('display_errors', 0);
       
    99         }
       
   100     }
       
   101 
       
   102     public function __clone()
       
   103     {
       
   104         if ($this->debug) {
       
   105             $this->startTime = microtime(true);
       
   106         }
       
   107 
       
   108         $this->booted = false;
       
   109         $this->container = null;
       
   110     }
       
   111 
       
   112     /**
       
   113      * Boots the current kernel.
       
   114      *
       
   115      * @api
       
   116      */
       
   117     public function boot()
       
   118     {
       
   119         if (true === $this->booted) {
       
   120             return;
       
   121         }
       
   122 
       
   123         // init bundles
       
   124         $this->initializeBundles();
       
   125 
       
   126         // init container
       
   127         $this->initializeContainer();
       
   128 
       
   129         foreach ($this->getBundles() as $bundle) {
       
   130             $bundle->setContainer($this->container);
       
   131             $bundle->boot();
       
   132         }
       
   133 
       
   134         $this->booted = true;
       
   135     }
       
   136 
       
   137     /**
       
   138      * Shutdowns the kernel.
       
   139      *
       
   140      * This method is mainly useful when doing functional testing.
       
   141      *
       
   142      * @api
       
   143      */
       
   144     public function shutdown()
       
   145     {
       
   146         if (false === $this->booted) {
       
   147             return;
       
   148         }
       
   149 
       
   150         $this->booted = false;
       
   151 
       
   152         foreach ($this->getBundles() as $bundle) {
       
   153             $bundle->shutdown();
       
   154             $bundle->setContainer(null);
       
   155         }
       
   156 
       
   157         $this->container = null;
       
   158     }
       
   159 
       
   160     /**
       
   161      * {@inheritdoc}
       
   162      *
       
   163      * @api
       
   164      */
       
   165     public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
       
   166     {
       
   167         if (false === $this->booted) {
       
   168             $this->boot();
       
   169         }
       
   170 
       
   171         return $this->getHttpKernel()->handle($request, $type, $catch);
       
   172     }
       
   173 
       
   174     /**
       
   175      * Gets a http kernel from the container
       
   176      *
       
   177      * @return HttpKernel
       
   178      */
       
   179     protected function getHttpKernel()
       
   180     {
       
   181         return $this->container->get('http_kernel');
       
   182     }
       
   183 
       
   184     /**
       
   185      * Gets the registered bundle instances.
       
   186      *
       
   187      * @return array An array of registered bundle instances
       
   188      *
       
   189      * @api
       
   190      */
       
   191     public function getBundles()
       
   192     {
       
   193         return $this->bundles;
       
   194     }
       
   195 
       
   196     /**
       
   197      * Checks if a given class name belongs to an active bundle.
       
   198      *
       
   199      * @param string $class A class name
       
   200      *
       
   201      * @return Boolean true if the class belongs to an active bundle, false otherwise
       
   202      *
       
   203      * @api
       
   204      */
       
   205     public function isClassInActiveBundle($class)
       
   206     {
       
   207         foreach ($this->getBundles() as $bundle) {
       
   208             if (0 === strpos($class, $bundle->getNamespace())) {
       
   209                 return true;
       
   210             }
       
   211         }
       
   212 
       
   213         return false;
       
   214     }
       
   215 
       
   216     /**
       
   217      * Returns a bundle and optionally its descendants by its name.
       
   218      *
       
   219      * @param string  $name  Bundle name
       
   220      * @param Boolean $first Whether to return the first bundle only or together with its descendants
       
   221      *
       
   222      * @return BundleInterface|Array A BundleInterface instance or an array of BundleInterface instances if $first is false
       
   223      *
       
   224      * @throws \InvalidArgumentException when the bundle is not enabled
       
   225      *
       
   226      * @api
       
   227      */
       
   228     public function getBundle($name, $first = true)
       
   229     {
       
   230         if (!isset($this->bundleMap[$name])) {
       
   231             throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled. Maybe you forgot to add it in the registerBundles() function of your %s.php file?', $name, get_class($this)));
       
   232         }
       
   233 
       
   234         if (true === $first) {
       
   235             return $this->bundleMap[$name][0];
       
   236         }
       
   237 
       
   238         return $this->bundleMap[$name];
       
   239     }
       
   240 
       
   241     /**
       
   242      * Returns the file path for a given resource.
       
   243      *
       
   244      * A Resource can be a file or a directory.
       
   245      *
       
   246      * The resource name must follow the following pattern:
       
   247      *
       
   248      *     @<BundleName>/path/to/a/file.something
       
   249      *
       
   250      * where BundleName is the name of the bundle
       
   251      * and the remaining part is the relative path in the bundle.
       
   252      *
       
   253      * If $dir is passed, and the first segment of the path is "Resources",
       
   254      * this method will look for a file named:
       
   255      *
       
   256      *     $dir/<BundleName>/path/without/Resources
       
   257      *
       
   258      * before looking in the bundle resource folder.
       
   259      *
       
   260      * @param string  $name  A resource name to locate
       
   261      * @param string  $dir   A directory where to look for the resource first
       
   262      * @param Boolean $first Whether to return the first path or paths for all matching bundles
       
   263      *
       
   264      * @return string|array The absolute path of the resource or an array if $first is false
       
   265      *
       
   266      * @throws \InvalidArgumentException if the file cannot be found or the name is not valid
       
   267      * @throws \RuntimeException         if the name contains invalid/unsafe
       
   268      * @throws \RuntimeException         if a custom resource is hidden by a resource in a derived bundle
       
   269      *
       
   270      * @api
       
   271      */
       
   272     public function locateResource($name, $dir = null, $first = true)
       
   273     {
       
   274         if ('@' !== $name[0]) {
       
   275             throw new \InvalidArgumentException(sprintf('A resource name must start with @ ("%s" given).', $name));
       
   276         }
       
   277 
       
   278         if (false !== strpos($name, '..')) {
       
   279             throw new \RuntimeException(sprintf('File name "%s" contains invalid characters (..).', $name));
       
   280         }
       
   281 
       
   282         $bundleName = substr($name, 1);
       
   283         $path = '';
       
   284         if (false !== strpos($bundleName, '/')) {
       
   285             list($bundleName, $path) = explode('/', $bundleName, 2);
       
   286         }
       
   287 
       
   288         $isResource = 0 === strpos($path, 'Resources') && null !== $dir;
       
   289         $overridePath = substr($path, 9);
       
   290         $resourceBundle = null;
       
   291         $bundles = $this->getBundle($bundleName, false);
       
   292         $files = array();
       
   293 
       
   294         foreach ($bundles as $bundle) {
       
   295             if ($isResource && file_exists($file = $dir.'/'.$bundle->getName().$overridePath)) {
       
   296                 if (null !== $resourceBundle) {
       
   297                     throw new \RuntimeException(sprintf('"%s" resource is hidden by a resource from the "%s" derived bundle. Create a "%s" file to override the bundle resource.',
       
   298                         $file,
       
   299                         $resourceBundle,
       
   300                         $dir.'/'.$bundles[0]->getName().$overridePath
       
   301                     ));
       
   302                 }
       
   303 
       
   304                 if ($first) {
       
   305                     return $file;
       
   306                 }
       
   307                 $files[] = $file;
       
   308             }
       
   309 
       
   310             if (file_exists($file = $bundle->getPath().'/'.$path)) {
       
   311                 if ($first && !$isResource) {
       
   312                     return $file;
       
   313                 }
       
   314                 $files[] = $file;
       
   315                 $resourceBundle = $bundle->getName();
       
   316             }
       
   317         }
       
   318 
       
   319         if (count($files) > 0) {
       
   320             return $first && $isResource ? $files[0] : $files;
       
   321         }
       
   322 
       
   323         throw new \InvalidArgumentException(sprintf('Unable to find file "%s".', $name));
       
   324     }
       
   325 
       
   326     /**
       
   327      * Gets the name of the kernel
       
   328      *
       
   329      * @return string The kernel name
       
   330      *
       
   331      * @api
       
   332      */
       
   333     public function getName()
       
   334     {
       
   335         return $this->name;
       
   336     }
       
   337 
       
   338     /**
       
   339      * Gets the environment.
       
   340      *
       
   341      * @return string The current environment
       
   342      *
       
   343      * @api
       
   344      */
       
   345     public function getEnvironment()
       
   346     {
       
   347         return $this->environment;
       
   348     }
       
   349 
       
   350     /**
       
   351      * Checks if debug mode is enabled.
       
   352      *
       
   353      * @return Boolean true if debug mode is enabled, false otherwise
       
   354      *
       
   355      * @api
       
   356      */
       
   357     public function isDebug()
       
   358     {
       
   359         return $this->debug;
       
   360     }
       
   361 
       
   362     /**
       
   363      * Gets the application root dir.
       
   364      *
       
   365      * @return string The application root dir
       
   366      *
       
   367      * @api
       
   368      */
       
   369     public function getRootDir()
       
   370     {
       
   371         if (null === $this->rootDir) {
       
   372             $r = new \ReflectionObject($this);
       
   373             $this->rootDir = dirname($r->getFileName());
       
   374         }
       
   375 
       
   376         return $this->rootDir;
       
   377     }
       
   378 
       
   379     /**
       
   380      * Gets the current container.
       
   381      *
       
   382      * @return ContainerInterface A ContainerInterface instance
       
   383      *
       
   384      * @api
       
   385      */
       
   386     public function getContainer()
       
   387     {
       
   388         return $this->container;
       
   389     }
       
   390 
       
   391     /**
       
   392      * Loads the PHP class cache.
       
   393      *
       
   394      * @param string  $name      The cache name prefix
       
   395      * @param string  $extension File extension of the resulting file
       
   396      */
       
   397     public function loadClassCache($name = 'classes', $extension = '.php')
       
   398     {
       
   399         if (!$this->booted && file_exists($this->getCacheDir().'/classes.map')) {
       
   400             ClassCollectionLoader::load(include($this->getCacheDir().'/classes.map'), $this->getCacheDir(), $name, $this->debug, false, $extension);
       
   401         }
       
   402     }
       
   403 
       
   404     /**
       
   405      * Used internally.
       
   406      */
       
   407     public function setClassCache(array $classes)
       
   408     {
       
   409         file_put_contents($this->getCacheDir().'/classes.map', sprintf('<?php return %s;', var_export($classes, true)));
       
   410     }
       
   411 
       
   412     /**
       
   413      * Gets the request start time (not available if debug is disabled).
       
   414      *
       
   415      * @return integer The request start timestamp
       
   416      *
       
   417      * @api
       
   418      */
       
   419     public function getStartTime()
       
   420     {
       
   421         return $this->debug ? $this->startTime : -INF;
       
   422     }
       
   423 
       
   424     /**
       
   425      * Gets the cache directory.
       
   426      *
       
   427      * @return string The cache directory
       
   428      *
       
   429      * @api
       
   430      */
       
   431     public function getCacheDir()
       
   432     {
       
   433         return $this->rootDir.'/cache/'.$this->environment;
       
   434     }
       
   435 
       
   436     /**
       
   437      * Gets the log directory.
       
   438      *
       
   439      * @return string The log directory
       
   440      *
       
   441      * @api
       
   442      */
       
   443     public function getLogDir()
       
   444     {
       
   445         return $this->rootDir.'/logs';
       
   446     }
       
   447 
       
   448     /**
       
   449      * Initializes the data structures related to the bundle management.
       
   450      *
       
   451      *  - the bundles property maps a bundle name to the bundle instance,
       
   452      *  - the bundleMap property maps a bundle name to the bundle inheritance hierarchy (most derived bundle first).
       
   453      *
       
   454      * @throws \LogicException if two bundles share a common name
       
   455      * @throws \LogicException if a bundle tries to extend a non-registered bundle
       
   456      * @throws \LogicException if a bundle tries to extend itself
       
   457      * @throws \LogicException if two bundles extend the same ancestor
       
   458      */
       
   459     protected function initializeBundles()
       
   460     {
       
   461         // init bundles
       
   462         $this->bundles = array();
       
   463         $topMostBundles = array();
       
   464         $directChildren = array();
       
   465 
       
   466         foreach ($this->registerBundles() as $bundle) {
       
   467             $name = $bundle->getName();
       
   468             if (isset($this->bundles[$name])) {
       
   469                 throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s"', $name));
       
   470             }
       
   471             $this->bundles[$name] = $bundle;
       
   472 
       
   473             if ($parentName = $bundle->getParent()) {
       
   474                 if (isset($directChildren[$parentName])) {
       
   475                     throw new \LogicException(sprintf('Bundle "%s" is directly extended by two bundles "%s" and "%s".', $parentName, $name, $directChildren[$parentName]));
       
   476                 }
       
   477                 if ($parentName == $name) {
       
   478                     throw new \LogicException(sprintf('Bundle "%s" can not extend itself.', $name));
       
   479                 }
       
   480                 $directChildren[$parentName] = $name;
       
   481             } else {
       
   482                 $topMostBundles[$name] = $bundle;
       
   483             }
       
   484         }
       
   485 
       
   486         // look for orphans
       
   487         if (count($diff = array_values(array_diff(array_keys($directChildren), array_keys($this->bundles))))) {
       
   488             throw new \LogicException(sprintf('Bundle "%s" extends bundle "%s", which is not registered.', $directChildren[$diff[0]], $diff[0]));
       
   489         }
       
   490 
       
   491         // inheritance
       
   492         $this->bundleMap = array();
       
   493         foreach ($topMostBundles as $name => $bundle) {
       
   494             $bundleMap = array($bundle);
       
   495             $hierarchy = array($name);
       
   496 
       
   497             while (isset($directChildren[$name])) {
       
   498                 $name = $directChildren[$name];
       
   499                 array_unshift($bundleMap, $this->bundles[$name]);
       
   500                 $hierarchy[] = $name;
       
   501             }
       
   502 
       
   503             foreach ($hierarchy as $bundle) {
       
   504                 $this->bundleMap[$bundle] = $bundleMap;
       
   505                 array_pop($bundleMap);
       
   506             }
       
   507         }
       
   508 
       
   509     }
       
   510 
       
   511     /**
       
   512      * Gets the container class.
       
   513      *
       
   514      * @return string The container class
       
   515      */
       
   516     protected function getContainerClass()
       
   517     {
       
   518         return $this->name.ucfirst($this->environment).($this->debug ? 'Debug' : '').'ProjectContainer';
       
   519     }
       
   520 
       
   521     /**
       
   522      * Gets the container's base class.
       
   523      *
       
   524      * All names except Container must be fully qualified.
       
   525      *
       
   526      * @return string
       
   527      */
       
   528     protected function getContainerBaseClass()
       
   529     {
       
   530         return 'Container';
       
   531     }
       
   532 
       
   533     /**
       
   534      * Initializes the service container.
       
   535      *
       
   536      * The cached version of the service container is used when fresh, otherwise the
       
   537      * container is built.
       
   538      */
       
   539     protected function initializeContainer()
       
   540     {
       
   541         $class = $this->getContainerClass();
       
   542         $cache = new ConfigCache($this->getCacheDir().'/'.$class.'.php', $this->debug);
       
   543         $fresh = true;
       
   544         if (!$cache->isFresh()) {
       
   545             $container = $this->buildContainer();
       
   546             $this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
       
   547 
       
   548             $fresh = false;
       
   549         }
       
   550 
       
   551         require_once $cache;
       
   552 
       
   553         $this->container = new $class();
       
   554         $this->container->set('kernel', $this);
       
   555 
       
   556         if (!$fresh) {
       
   557             $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'));
       
   558         }
       
   559     }
       
   560 
       
   561     /**
       
   562      * Returns the kernel parameters.
       
   563      *
       
   564      * @return array An array of kernel parameters
       
   565      */
       
   566     protected function getKernelParameters()
       
   567     {
       
   568         $bundles = array();
       
   569         foreach ($this->bundles as $name => $bundle) {
       
   570             $bundles[$name] = get_class($bundle);
       
   571         }
       
   572 
       
   573         return array_merge(
       
   574             array(
       
   575                 'kernel.root_dir'        => $this->rootDir,
       
   576                 'kernel.environment'     => $this->environment,
       
   577                 'kernel.debug'           => $this->debug,
       
   578                 'kernel.name'            => $this->name,
       
   579                 'kernel.cache_dir'       => $this->getCacheDir(),
       
   580                 'kernel.logs_dir'        => $this->getLogDir(),
       
   581                 'kernel.bundles'         => $bundles,
       
   582                 'kernel.charset'         => 'UTF-8',
       
   583                 'kernel.container_class' => $this->getContainerClass(),
       
   584             ),
       
   585             $this->getEnvParameters()
       
   586         );
       
   587     }
       
   588 
       
   589     /**
       
   590      * Gets the environment parameters.
       
   591      *
       
   592      * Only the parameters starting with "SYMFONY__" are considered.
       
   593      *
       
   594      * @return array An array of parameters
       
   595      */
       
   596     protected function getEnvParameters()
       
   597     {
       
   598         $parameters = array();
       
   599         foreach ($_SERVER as $key => $value) {
       
   600             if ('SYMFONY__' === substr($key, 0, 9)) {
       
   601                 $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
       
   602             }
       
   603         }
       
   604 
       
   605         return $parameters;
       
   606     }
       
   607 
       
   608     /**
       
   609      * Builds the service container.
       
   610      *
       
   611      * @return ContainerBuilder The compiled service container
       
   612      */
       
   613     protected function buildContainer()
       
   614     {
       
   615         foreach (array('cache' => $this->getCacheDir(), 'logs' => $this->getLogDir()) as $name => $dir) {
       
   616             if (!is_dir($dir)) {
       
   617                 if (false === @mkdir($dir, 0777, true)) {
       
   618                     throw new \RuntimeException(sprintf("Unable to create the %s directory (%s)\n", $name, dirname($dir)));
       
   619                 }
       
   620             } elseif (!is_writable($dir)) {
       
   621                 throw new \RuntimeException(sprintf("Unable to write in the %s directory (%s)\n", $name, $dir));
       
   622             }
       
   623         }
       
   624 
       
   625         $container = new ContainerBuilder(new ParameterBag($this->getKernelParameters()));
       
   626         $extensions = array();
       
   627         foreach ($this->bundles as $bundle) {
       
   628             $bundle->build($container);
       
   629 
       
   630             if ($extension = $bundle->getContainerExtension()) {
       
   631                 $container->registerExtension($extension);
       
   632                 $extensions[] = $extension->getAlias();
       
   633             }
       
   634 
       
   635             if ($this->debug) {
       
   636                 $container->addObjectResource($bundle);
       
   637             }
       
   638         }
       
   639         $container->addObjectResource($this);
       
   640 
       
   641         // ensure these extensions are implicitly loaded
       
   642         $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));
       
   643 
       
   644         if (null !== $cont = $this->registerContainerConfiguration($this->getContainerLoader($container))) {
       
   645             $container->merge($cont);
       
   646         }
       
   647 
       
   648         $container->addCompilerPass(new AddClassesToCachePass($this));
       
   649         $container->compile();
       
   650 
       
   651         return $container;
       
   652     }
       
   653 
       
   654     /**
       
   655      * Dumps the service container to PHP code in the cache.
       
   656      *
       
   657      * @param ConfigCache      $cache     The config cache
       
   658      * @param ContainerBuilder $container The service container
       
   659      * @param string           $class     The name of the class to generate
       
   660      * @param string           $baseClass The name of the container's base class
       
   661      */
       
   662     protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container, $class, $baseClass)
       
   663     {
       
   664         // cache the container
       
   665         $dumper = new PhpDumper($container);
       
   666         $content = $dumper->dump(array('class' => $class, 'base_class' => $baseClass));
       
   667         if (!$this->debug) {
       
   668             $content = self::stripComments($content);
       
   669         }
       
   670 
       
   671         $cache->write($content, $container->getResources());
       
   672     }
       
   673 
       
   674     /**
       
   675      * Returns a loader for the container.
       
   676      *
       
   677      * @param ContainerInterface $container The service container
       
   678      *
       
   679      * @return DelegatingLoader The loader
       
   680      */
       
   681     protected function getContainerLoader(ContainerInterface $container)
       
   682     {
       
   683         $locator = new FileLocator($this);
       
   684         $resolver = new LoaderResolver(array(
       
   685             new XmlFileLoader($container, $locator),
       
   686             new YamlFileLoader($container, $locator),
       
   687             new IniFileLoader($container, $locator),
       
   688             new PhpFileLoader($container, $locator),
       
   689             new ClosureLoader($container),
       
   690         ));
       
   691 
       
   692         return new DelegatingLoader($resolver);
       
   693     }
       
   694 
       
   695     /**
       
   696      * Removes comments from a PHP source string.
       
   697      *
       
   698      * We don't use the PHP php_strip_whitespace() function
       
   699      * as we want the content to be readable and well-formatted.
       
   700      *
       
   701      * @param string $source A PHP string
       
   702      *
       
   703      * @return string The PHP string with the comments removed
       
   704      */
       
   705     static public function stripComments($source)
       
   706     {
       
   707         if (!function_exists('token_get_all')) {
       
   708             return $source;
       
   709         }
       
   710 
       
   711         $output = '';
       
   712         foreach (token_get_all($source) as $token) {
       
   713             if (is_string($token)) {
       
   714                 $output .= $token;
       
   715             } elseif (!in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
       
   716                 $output .= $token[1];
       
   717             }
       
   718         }
       
   719 
       
   720         // replace multiple new lines with a single newline
       
   721         $output = preg_replace(array('/\s+$/Sm', '/\n+/S'), "\n", $output);
       
   722 
       
   723         return $output;
       
   724     }
       
   725 
       
   726     public function serialize()
       
   727     {
       
   728         return serialize(array($this->environment, $this->debug));
       
   729     }
       
   730 
       
   731     public function unserialize($data)
       
   732     {
       
   733         list($environment, $debug) = unserialize($data);
       
   734 
       
   735         $this->__construct($environment, $debug);
       
   736     }
       
   737 }