bootstrap.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. <?php
  2. namespace Symfony\Foundation\Bundle;
  3. use Symfony\Components\DependencyInjection\ContainerInterface;
  4. abstract class Bundle implements BundleInterface
  5. {
  6. public function buildContainer(ContainerInterface $container)
  7. {
  8. }
  9. public function boot(ContainerInterface $container)
  10. {
  11. }
  12. }
  13. namespace Symfony\Foundation\Bundle;
  14. use Symfony\Components\DependencyInjection\ContainerInterface;
  15. interface BundleInterface
  16. {
  17. public function buildContainer(ContainerInterface $container);
  18. public function boot(ContainerInterface $container);
  19. }
  20. namespace Symfony\Foundation\Bundle;
  21. use Symfony\Foundation\Bundle\Bundle;
  22. use Symfony\Foundation\ClassCollectionLoader;
  23. use Symfony\Components\DependencyInjection\ContainerInterface;
  24. use Symfony\Components\DependencyInjection\Loader\Loader;
  25. use Symfony\Components\DependencyInjection\Loader\XmlFileLoader;
  26. use Symfony\Components\DependencyInjection\BuilderConfiguration;
  27. class KernelBundle extends Bundle
  28. {
  29. public function buildContainer(ContainerInterface $container)
  30. {
  31. Loader::registerExtension(new KernelExtension());
  32. $configuration = new BuilderConfiguration();
  33. $loader = new XmlFileLoader(array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
  34. $configuration->merge($loader->load('services.xml'));
  35. if ($container->getParameter('kernel.debug'))
  36. {
  37. $configuration->merge($loader->load('debug.xml'));
  38. $configuration->setDefinition('event_dispatcher', $configuration->findDefinition('debug.event_dispatcher'));
  39. }
  40. return $configuration;
  41. }
  42. public function boot(ContainerInterface $container)
  43. {
  44. $container->getErrorHandlerService();
  45. ClassCollectionLoader::load($container->getParameter('kernel.compiled_classes'), $container->getParameter('kernel.cache_dir'), 'classes', $container->getParameter('kernel.debug'));
  46. }
  47. }
  48. namespace Symfony\Foundation\Bundle;
  49. use Symfony\Components\DependencyInjection\Loader\LoaderExtension;
  50. use Symfony\Components\DependencyInjection\Loader\XmlFileLoader;
  51. use Symfony\Components\DependencyInjection\BuilderConfiguration;
  52. class KernelExtension extends LoaderExtension
  53. {
  54. public function configLoad($config)
  55. {
  56. $configuration = new BuilderConfiguration();
  57. if (isset($config['charset']))
  58. {
  59. $configuration->setParameter('kernel.charset', $config['charset']);
  60. }
  61. if (!array_key_exists('compilation', $config))
  62. {
  63. $classes = array(
  64. 'Symfony\\Components\\Routing\\Router',
  65. 'Symfony\\Components\\Routing\\RouterInterface',
  66. 'Symfony\\Components\\EventDispatcher\\Event',
  67. 'Symfony\\Components\\Routing\\Matcher\\UrlMatcherInterface',
  68. 'Symfony\\Components\\Routing\\Matcher\\UrlMatcher',
  69. 'Symfony\\Components\\RequestHandler\\RequestInterface',
  70. 'Symfony\\Components\\RequestHandler\\Request',
  71. 'Symfony\\Components\\RequestHandler\\RequestHandler',
  72. 'Symfony\\Components\\RequestHandler\\ResponseInterface',
  73. 'Symfony\\Components\\RequestHandler\\Response',
  74. 'Symfony\\Components\\Templating\\Loader\\LoaderInterface',
  75. 'Symfony\\Components\\Templating\\Loader\\Loader',
  76. 'Symfony\\Components\\Templating\\Loader\\FilesystemLoader',
  77. 'Symfony\\Components\\Templating\\Engine',
  78. 'Symfony\\Components\\Templating\\Renderer\\RendererInterface',
  79. 'Symfony\\Components\\Templating\\Renderer\\Renderer',
  80. 'Symfony\\Components\\Templating\\Renderer\\PhpRenderer',
  81. 'Symfony\\Components\\Templating\\Storage\\Storage',
  82. 'Symfony\\Components\\Templating\\Storage\\FileStorage',
  83. 'Symfony\\Framework\\WebBundle\\Controller',
  84. 'Symfony\\Framework\\WebBundle\\Listener\\RequestParser',
  85. 'Symfony\\Framework\\WebBundle\\Listener\\ControllerLoader',
  86. 'Symfony\\Framework\\WebBundle\\Listener\\ResponseFilter',
  87. 'Symfony\\Framework\\WebBundle\\Templating\\Engine',
  88. );
  89. }
  90. else
  91. {
  92. $classes = array();
  93. foreach (explode("\n", $config['compilation']) as $class)
  94. {
  95. if ($class)
  96. {
  97. $classes[] = trim($class);
  98. }
  99. }
  100. }
  101. $configuration->setParameter('kernel.compiled_classes', $classes);
  102. if (array_key_exists('error_handler_level', $config))
  103. {
  104. $configuration->setParameter('error_handler.level', $config['error_handler_level']);
  105. }
  106. return $configuration;
  107. }
  108. public function getXsdValidationBasePath()
  109. {
  110. return false;
  111. }
  112. public function getNamespace()
  113. {
  114. return 'http://www.symfony-project.org/schema/dic/symfony/kernel';
  115. }
  116. public function getAlias()
  117. {
  118. return 'kernel';
  119. }
  120. }
  121. namespace Symfony\Foundation\Debug;
  122. class ErrorHandler
  123. {
  124. protected $levels = array(
  125. E_WARNING => 'Warning',
  126. E_NOTICE => 'Notice',
  127. E_USER_ERROR => 'User Error',
  128. E_USER_WARNING => 'User Warning',
  129. E_USER_NOTICE => 'User Notice',
  130. E_STRICT => 'Runtime Notice',
  131. E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
  132. );
  133. protected $level;
  134. public function __construct($level = null)
  135. {
  136. $this->level = null === $level ? error_reporting() : $level;
  137. }
  138. public function register()
  139. {
  140. set_error_handler(array($this, 'handle'));
  141. }
  142. public function handle($level, $message, $file, $line, $context)
  143. {
  144. if (0 === $this->level)
  145. {
  146. return false;
  147. }
  148. if (error_reporting() & $level && $this->level & $level)
  149. {
  150. throw new \ErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line));
  151. }
  152. return false;
  153. }
  154. }
  155. namespace Symfony\Foundation;
  156. class ClassCollectionLoader
  157. {
  158. static public function load($classes, $cacheDir, $name, $autoReload)
  159. {
  160. $cache = $cacheDir.'/'.$name.'.php';
  161. $reload = false;
  162. if ($autoReload)
  163. {
  164. $metadata = $cacheDir.'/'.$name.'.meta';
  165. if (!file_exists($metadata) || !file_exists($cache))
  166. {
  167. $reload = true;
  168. }
  169. else
  170. {
  171. $time = filemtime($cache);
  172. $meta = unserialize(file_get_contents($metadata));
  173. if ($meta[1] != $classes)
  174. {
  175. $reload = true;
  176. }
  177. else
  178. {
  179. foreach ($meta[0] as $resource)
  180. {
  181. if (!file_exists($resource) || filemtime($resource) > $time)
  182. {
  183. $reload = true;
  184. break;
  185. }
  186. }
  187. }
  188. }
  189. }
  190. if (!$reload && file_exists($cache))
  191. {
  192. require_once $cache;
  193. return;
  194. }
  195. $files = array();
  196. $content = '';
  197. foreach ($classes as $class)
  198. {
  199. if (!class_exists($class) && !interface_exists($class))
  200. {
  201. throw new \InvalidArgumentException(sprintf('Unable to load class "%s"', $class));
  202. }
  203. $r = new \ReflectionClass($class);
  204. $files[] = $r->getFileName();
  205. $content .= preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($r->getFileName()));
  206. }
  207. if (!is_dir(dirname($cache)))
  208. {
  209. mkdir(dirname($cache), 0777, true);
  210. }
  211. self::writeCacheFile($cache, Kernel::stripComments('<?php '.$content));
  212. if ($autoReload)
  213. {
  214. self::writeCacheFile($metadata, serialize(array($files, $classes)));
  215. }
  216. }
  217. static protected function writeCacheFile($file, $content)
  218. {
  219. $tmpFile = tempnam(dirname($file), basename($file));
  220. if (!$fp = @fopen($tmpFile, 'wb'))
  221. {
  222. die(sprintf('Failed to write cache file "%s".', $tmpFile));
  223. }
  224. @fwrite($fp, $content);
  225. @fclose($fp);
  226. if ($content != file_get_contents($tmpFile))
  227. {
  228. die(sprintf('Failed to write cache file "%s" (cache corrupted).', $tmpFile));
  229. }
  230. @rename($tmpFile, $file);
  231. chmod($file, 0644);
  232. }
  233. }
  234. namespace Symfony\Foundation;
  235. use Symfony\Components\DependencyInjection\ContainerInterface;
  236. use Symfony\Components\DependencyInjection\Builder;
  237. use Symfony\Components\DependencyInjection\BuilderConfiguration;
  238. use Symfony\Components\DependencyInjection\Dumper\PhpDumper;
  239. use Symfony\Components\DependencyInjection\FileResource;
  240. use Symfony\Components\RequestHandler\RequestInterface;
  241. abstract class Kernel implements \Serializable
  242. {
  243. protected $bundles;
  244. protected $bundleDirs;
  245. protected $container;
  246. protected $rootDir;
  247. protected $environment;
  248. protected $debug;
  249. protected $booted;
  250. protected $name;
  251. protected $startTime;
  252. const VERSION = '2.0.0-DEV';
  253. public function __construct($environment, $debug)
  254. {
  255. $this->debug = (Boolean) $debug;
  256. if ($this->debug)
  257. {
  258. ini_set('display_errors', 1);
  259. error_reporting(-1);
  260. }
  261. else
  262. {
  263. ini_set('display_errors', 0);
  264. }
  265. if ($this->debug)
  266. {
  267. $this->startTime = microtime(true);
  268. }
  269. $this->booted = false;
  270. $this->environment = $environment;
  271. $this->bundles = $this->registerBundles();
  272. $this->bundleDirs = $this->registerBundleDirs();
  273. $this->rootDir = realpath($this->registerRootDir());
  274. $this->name = basename($this->rootDir);
  275. }
  276. abstract public function registerRootDir();
  277. abstract public function registerBundles();
  278. abstract public function registerBundleDirs();
  279. abstract public function registerContainerConfiguration();
  280. abstract public function registerRoutes();
  281. public function isBooted()
  282. {
  283. return $this->booted;
  284. }
  285. public function boot()
  286. {
  287. if (true === $this->booted)
  288. {
  289. throw new \LogicException('The kernel is already booted.');
  290. }
  291. $this->container = $this->initializeContainer();
  292. $this->container->setService('kernel', $this);
  293. foreach ($this->bundles as $bundle)
  294. {
  295. $bundle->boot($this->container);
  296. }
  297. $this->booted = true;
  298. return $this;
  299. }
  300. public function run()
  301. {
  302. $this->handle()->send();
  303. }
  304. public function handle(RequestInterface $request = null)
  305. {
  306. if (false === $this->booted)
  307. {
  308. $this->boot();
  309. }
  310. if (null === $request)
  311. {
  312. $request = $this->container->getRequestService();
  313. }
  314. else
  315. {
  316. $this->container->setService('request', $request);
  317. }
  318. return $this->container->getRequestHandlerService()->handle($request);
  319. }
  320. public function getBundleDirs()
  321. {
  322. return $this->bundleDirs;
  323. }
  324. public function getBundles()
  325. {
  326. return $this->bundles;
  327. }
  328. public function getName()
  329. {
  330. return $this->name;
  331. }
  332. public function getEnvironment()
  333. {
  334. return $this->environment;
  335. }
  336. public function isDebug()
  337. {
  338. return $this->debug;
  339. }
  340. public function getRootDir()
  341. {
  342. return $this->rootDir;
  343. }
  344. public function getContainer()
  345. {
  346. return $this->container;
  347. }
  348. public function getStartTime()
  349. {
  350. return $this->debug ? $this->startTime : -INF;
  351. }
  352. public function getCacheDir()
  353. {
  354. return $this->rootDir.'/cache/'.$this->environment;
  355. }
  356. public function getLogDir()
  357. {
  358. return $this->rootDir.'/logs';
  359. }
  360. protected function initializeContainer()
  361. {
  362. $class = $this->name.'ProjectContainer';
  363. $location = $this->getCacheDir().'/'.$class;
  364. $reload = $this->debug ? $this->needsReload($class, $location) : false;
  365. if ($reload || !file_exists($location.'.php'))
  366. {
  367. $this->buildContainer($class, $location.'.php');
  368. }
  369. require_once $location.'.php';
  370. return new $class();
  371. }
  372. public function getKernelParameters()
  373. {
  374. $bundles = array();
  375. foreach ($this->bundles as $bundle)
  376. {
  377. $bundles[] = get_class($bundle);
  378. }
  379. return array_merge(
  380. array(
  381. 'kernel.root_dir' => $this->rootDir,
  382. 'kernel.environment' => $this->environment,
  383. 'kernel.debug' => $this->debug,
  384. 'kernel.name' => $this->name,
  385. 'kernel.cache_dir' => $this->getCacheDir(),
  386. 'kernel.logs_dir' => $this->getLogDir(),
  387. 'kernel.bundle_dirs' => $this->bundleDirs,
  388. 'kernel.bundles' => $bundles,
  389. 'kernel.charset' => 'UTF-8',
  390. ),
  391. $this->getEnvParameters()
  392. );
  393. }
  394. protected function getEnvParameters()
  395. {
  396. $parameters = array();
  397. foreach ($_SERVER as $key => $value)
  398. {
  399. if ('SYMFONY__' === substr($key, 0, 9))
  400. {
  401. $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
  402. }
  403. }
  404. return $parameters;
  405. }
  406. protected function needsReload($class, $location)
  407. {
  408. if (!file_exists($location.'.meta') || !file_exists($location.'.php'))
  409. {
  410. return true;
  411. }
  412. $meta = unserialize(file_get_contents($location.'.meta'));
  413. $time = filemtime($location.'.php');
  414. foreach ($meta as $resource)
  415. {
  416. if (!$resource->isUptodate($time))
  417. {
  418. return true;
  419. }
  420. }
  421. return false;
  422. }
  423. protected function buildContainer($class, $file)
  424. {
  425. $container = new Builder($this->getKernelParameters());
  426. $configuration = new BuilderConfiguration();
  427. foreach ($this->bundles as $bundle)
  428. {
  429. $configuration->merge($bundle->buildContainer($container));
  430. }
  431. $configuration->merge($this->registerContainerConfiguration());
  432. $container->merge($configuration);
  433. $this->optimizeContainer($container);
  434. foreach (array('cache', 'logs') as $name)
  435. {
  436. $dir = $container->getParameter(sprintf('kernel.%s_dir', $name));
  437. if (!is_dir($dir))
  438. {
  439. if (false === @mkdir($dir, 0777, true))
  440. {
  441. die(sprintf('Unable to create the %s directory (%s)', $name, dirname($dir)));
  442. }
  443. }
  444. elseif (!is_writable($dir))
  445. {
  446. die(sprintf('Unable to write in the %s directory (%s)', $name, $dir));
  447. }
  448. }
  449. $dumper = new PhpDumper($container);
  450. $content = $dumper->dump(array('class' => $class));
  451. if (!$this->debug)
  452. {
  453. $content = self::stripComments($content);
  454. }
  455. $this->writeCacheFile($file, $content);
  456. if ($this->debug)
  457. {
  458. $parent = new \ReflectionObject($this);
  459. $configuration->addResource(new FileResource($parent->getFileName()));
  460. while ($parent = $parent->getParentClass())
  461. {
  462. $configuration->addResource(new FileResource($parent->getFileName()));
  463. }
  464. $this->writeCacheFile($this->getCacheDir().'/'.$class.'.meta', serialize($configuration->getResources()));
  465. }
  466. }
  467. public function optimizeContainer(Builder $container)
  468. {
  469. foreach ($container->getDefinitions() as $definition)
  470. {
  471. if (false !== strpos($class = $definition->getClass(), '%'))
  472. {
  473. $definition->setClass(Builder::resolveValue($class, $container->getParameters()));
  474. unset($container[substr($class, 1, -1)]);
  475. }
  476. }
  477. }
  478. static public function stripComments($source)
  479. {
  480. if (!function_exists('token_get_all'))
  481. {
  482. return $source;
  483. }
  484. $ignore = array(T_COMMENT => true, T_DOC_COMMENT => true);
  485. $output = '';
  486. foreach (token_get_all($source) as $token)
  487. {
  488. if (isset($token[1]))
  489. {
  490. if (!isset($ignore[$token[0]]))
  491. {
  492. $output .= $token[1];
  493. }
  494. }
  495. else
  496. {
  497. $output .= $token;
  498. }
  499. }
  500. return $output;
  501. }
  502. protected function writeCacheFile($file, $content)
  503. {
  504. $tmpFile = tempnam(dirname($file), basename($file));
  505. if (!$fp = @fopen($tmpFile, 'wb'))
  506. {
  507. die(sprintf('Failed to write cache file "%s".', $tmpFile));
  508. }
  509. @fwrite($fp, $content);
  510. @fclose($fp);
  511. if ($content != file_get_contents($tmpFile))
  512. {
  513. die(sprintf('Failed to write cache file "%s" (cache corrupted).', $tmpFile));
  514. }
  515. @rename($tmpFile, $file);
  516. chmod($file, 0644);
  517. }
  518. public function serialize()
  519. {
  520. return serialize(array($this->environment, $this->debug));
  521. }
  522. public function unserialize($data)
  523. {
  524. list($environment, $debug) = unserialize($data);
  525. $this->__construct($environment, $debug);
  526. }
  527. }
  528. namespace Symfony\Foundation;
  529. use Symfony\Components\EventDispatcher\EventDispatcher as BaseEventDispatcher;
  530. use Symfony\Components\EventDispatcher\Event;
  531. use Symfony\Components\DependencyInjection\ContainerInterface;
  532. class EventDispatcher extends BaseEventDispatcher
  533. {
  534. protected $container;
  535. public function __construct(ContainerInterface $container)
  536. {
  537. $this->container = $container;
  538. foreach ($container->findAnnotatedServiceIds('kernel.listener') as $id => $attributes)
  539. {
  540. foreach ($attributes as $attribute)
  541. {
  542. if (isset($attribute['event']))
  543. {
  544. $this->connect($attribute['event'], array($id, isset($attribute['method']) ? $attribute['method'] : 'handle'));
  545. }
  546. }
  547. }
  548. }
  549. public function getListeners($name)
  550. {
  551. if (!isset($this->listeners[$name]))
  552. {
  553. return array();
  554. }
  555. foreach ($this->listeners[$name] as $i => $listener)
  556. {
  557. if (is_array($listener) && is_string($listener[0]))
  558. {
  559. $this->listeners[$name][$i] = array($this->container->getService($listener[0]), $listener[1]);
  560. }
  561. }
  562. return $this->listeners[$name];
  563. }
  564. }