PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/backend/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Kernel.php

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