var/cache/dev/classes.php line 5791

Open in your IDE?
  1. <?php 
  2. namespace Symfony\Component\EventDispatcher
  3. {
  4. interface EventSubscriberInterface
  5. {
  6. public static function getSubscribedEvents();
  7. }
  8. }
  9. namespace Symfony\Component\HttpKernel\EventListener
  10. {
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\HttpFoundation\Session\Session;
  13. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  14. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  15. use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
  16. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  17. use Symfony\Component\HttpKernel\KernelEvents;
  18. abstract class AbstractSessionListener implements EventSubscriberInterface
  19. {
  20. private $sessionUsageStack = [];
  21. public function onKernelRequest(GetResponseEvent $event)
  22. {
  23. if (!$event->isMasterRequest()) {
  24. return;
  25. }
  26. $request = $event->getRequest();
  27. $session = $this->getSession();
  28. $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : null;
  29. if (null === $session || $request->hasSession()) {
  30. return;
  31. }
  32. $request->setSession($session);
  33. }
  34. public function onKernelResponse(FilterResponseEvent $event)
  35. {
  36. if (!$event->isMasterRequest()) {
  37. return;
  38. }
  39. if (!$session = $event->getRequest()->getSession()) {
  40. return;
  41. }
  42. if ($session instanceof Session ? $session->getUsageIndex() !== end($this->sessionUsageStack) : $session->isStarted()) {
  43. $event->getResponse()
  44. ->setExpires(new \DateTime())
  45. ->setPrivate()
  46. ->setMaxAge(0)
  47. ->headers->addCacheControlDirective('must-revalidate');
  48. }
  49. }
  50. public function onFinishRequest(FinishRequestEvent $event)
  51. {
  52. if ($event->isMasterRequest()) {
  53. array_pop($this->sessionUsageStack);
  54. }
  55. }
  56. public static function getSubscribedEvents()
  57. {
  58. return [
  59. KernelEvents::REQUEST => ['onKernelRequest', 128],
  60. KernelEvents::RESPONSE => ['onKernelResponse', -1000],
  61. KernelEvents::FINISH_REQUEST => ['onFinishRequest'],
  62. ];
  63. }
  64. abstract protected function getSession();
  65. }
  66. }
  67. namespace Symfony\Component\HttpKernel\EventListener
  68. {
  69. use Psr\Container\ContainerInterface;
  70. class SessionListener extends AbstractSessionListener
  71. {
  72. private $container;
  73. public function __construct(ContainerInterface $container)
  74. {
  75. $this->container = $container;
  76. }
  77. protected function getSession()
  78. {
  79. if (!$this->container->has('session')) {
  80. return null;
  81. }
  82. return $this->container->get('session');
  83. }
  84. }
  85. }
  86. namespace Symfony\Component\HttpFoundation\Session\Storage
  87. {
  88. use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
  89. interface SessionStorageInterface
  90. {
  91. public function start();
  92. public function isStarted();
  93. public function getId();
  94. public function setId($id);
  95. public function getName();
  96. public function setName($name);
  97. public function regenerate($destroy = false, $lifetime = null);
  98. public function save();
  99. public function clear();
  100. public function getBag($name);
  101. public function registerBag(SessionBagInterface $bag);
  102. public function getMetadataBag();
  103. }
  104. }
  105. namespace Symfony\Component\HttpFoundation\Session\Storage
  106. {
  107. use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
  108. use Symfony\Component\HttpFoundation\Session\SessionUtils;
  109. use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler;
  110. use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
  111. use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
  112. class NativeSessionStorage implements SessionStorageInterface
  113. {
  114. protected $bags = [];
  115. protected $started = false;
  116. protected $closed = false;
  117. protected $saveHandler;
  118. protected $metadataBag;
  119. private $emulateSameSite;
  120. public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null)
  121. {
  122. if (!\extension_loaded('session')) {
  123. throw new \LogicException('PHP extension "session" is required.');
  124. }
  125. $options += ['cache_limiter'=>'','cache_expire'=> 0,'use_cookies'=> 1,'lazy_write'=> 1,
  126. ];
  127. session_register_shutdown();
  128. $this->setMetadataBag($metaBag);
  129. $this->setOptions($options);
  130. $this->setSaveHandler($handler);
  131. }
  132. public function getSaveHandler()
  133. {
  134. return $this->saveHandler;
  135. }
  136. public function start()
  137. {
  138. if ($this->started) {
  139. return true;
  140. }
  141. if (\PHP_SESSION_ACTIVE === session_status()) {
  142. throw new \RuntimeException('Failed to start the session: already started by PHP.');
  143. }
  144. if (filter_var(ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) {
  145. throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
  146. }
  147. if (!session_start()) {
  148. throw new \RuntimeException('Failed to start the session.');
  149. }
  150. if (null !== $this->emulateSameSite) {
  151. $originalCookie = SessionUtils::popSessionCookie(session_name(), session_id());
  152. if (null !== $originalCookie) {
  153. header(sprintf('%s; SameSite=%s', $originalCookie, $this->emulateSameSite), false);
  154. }
  155. }
  156. $this->loadSession();
  157. return true;
  158. }
  159. public function getId()
  160. {
  161. return $this->saveHandler->getId();
  162. }
  163. public function setId($id)
  164. {
  165. $this->saveHandler->setId($id);
  166. }
  167. public function getName()
  168. {
  169. return $this->saveHandler->getName();
  170. }
  171. public function setName($name)
  172. {
  173. $this->saveHandler->setName($name);
  174. }
  175. public function regenerate($destroy = false, $lifetime = null)
  176. {
  177. if (\PHP_SESSION_ACTIVE !== session_status()) {
  178. return false;
  179. }
  180. if (headers_sent()) {
  181. return false;
  182. }
  183. if (null !== $lifetime && $lifetime != ini_get('session.cookie_lifetime')) {
  184. $this->save();
  185. ini_set('session.cookie_lifetime', $lifetime);
  186. $this->start();
  187. }
  188. if ($destroy) {
  189. $this->metadataBag->stampNew();
  190. }
  191. $isRegenerated = session_regenerate_id($destroy);
  192. if (null !== $this->emulateSameSite) {
  193. $originalCookie = SessionUtils::popSessionCookie(session_name(), session_id());
  194. if (null !== $originalCookie) {
  195. header(sprintf('%s; SameSite=%s', $originalCookie, $this->emulateSameSite), false);
  196. }
  197. }
  198. return $isRegenerated;
  199. }
  200. public function save()
  201. {
  202. $session = $_SESSION;
  203. foreach ($this->bags as $bag) {
  204. if (empty($_SESSION[$key = $bag->getStorageKey()])) {
  205. unset($_SESSION[$key]);
  206. }
  207. }
  208. if ([$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) {
  209. unset($_SESSION[$key]);
  210. }
  211. $previousHandler = set_error_handler(function ($type, $msg, $file, $line) use (&$previousHandler) {
  212. if (\E_WARNING === $type && 0 === strpos($msg,'session_write_close():')) {
  213. $handler = $this->saveHandler instanceof SessionHandlerProxy ? $this->saveHandler->getHandler() : $this->saveHandler;
  214. $msg = sprintf('session_write_close(): Failed to write session data with "%s" handler', \get_class($handler));
  215. }
  216. return $previousHandler ? $previousHandler($type, $msg, $file, $line) : false;
  217. });
  218. try {
  219. session_write_close();
  220. } finally {
  221. restore_error_handler();
  222. if ($_SESSION) {
  223. $_SESSION = $session;
  224. }
  225. }
  226. $this->closed = true;
  227. $this->started = false;
  228. }
  229. public function clear()
  230. {
  231. foreach ($this->bags as $bag) {
  232. $bag->clear();
  233. }
  234. $_SESSION = [];
  235. $this->loadSession();
  236. }
  237. public function registerBag(SessionBagInterface $bag)
  238. {
  239. if ($this->started) {
  240. throw new \LogicException('Cannot register a bag when the session is already started.');
  241. }
  242. $this->bags[$bag->getName()] = $bag;
  243. }
  244. public function getBag($name)
  245. {
  246. if (!isset($this->bags[$name])) {
  247. throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name));
  248. }
  249. if (!$this->started && $this->saveHandler->isActive()) {
  250. $this->loadSession();
  251. } elseif (!$this->started) {
  252. $this->start();
  253. }
  254. return $this->bags[$name];
  255. }
  256. public function setMetadataBag(MetadataBag $metaBag = null)
  257. {
  258. if (null === $metaBag) {
  259. $metaBag = new MetadataBag();
  260. }
  261. $this->metadataBag = $metaBag;
  262. }
  263. public function getMetadataBag()
  264. {
  265. return $this->metadataBag;
  266. }
  267. public function isStarted()
  268. {
  269. return $this->started;
  270. }
  271. public function setOptions(array $options)
  272. {
  273. if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) {
  274. return;
  275. }
  276. $validOptions = array_flip(['cache_expire','cache_limiter','cookie_domain','cookie_httponly','cookie_lifetime','cookie_path','cookie_secure','cookie_samesite','entropy_file','entropy_length','gc_divisor','gc_maxlifetime','gc_probability','hash_bits_per_character','hash_function','lazy_write','name','referer_check','serialize_handler','use_strict_mode','use_cookies','use_only_cookies','use_trans_sid','upload_progress.enabled','upload_progress.cleanup','upload_progress.prefix','upload_progress.name','upload_progress.freq','upload_progress.min_freq','url_rewriter.tags','sid_length','sid_bits_per_character','trans_sid_hosts','trans_sid_tags',
  277. ]);
  278. foreach ($options as $key => $value) {
  279. if (isset($validOptions[$key])) {
  280. if ('cookie_samesite'=== $key && \PHP_VERSION_ID < 70300) {
  281. $this->emulateSameSite = $value;
  282. continue;
  283. }
  284. ini_set('url_rewriter.tags'!== $key ?'session.'.$key : $key, $value);
  285. }
  286. }
  287. }
  288. public function setSaveHandler($saveHandler = null)
  289. {
  290. if (!$saveHandler instanceof AbstractProxy &&
  291. !$saveHandler instanceof \SessionHandlerInterface &&
  292. null !== $saveHandler) {
  293. throw new \InvalidArgumentException('Must be instance of AbstractProxy; implement \SessionHandlerInterface; or be null.');
  294. }
  295. if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
  296. $saveHandler = new SessionHandlerProxy($saveHandler);
  297. } elseif (!$saveHandler instanceof AbstractProxy) {
  298. $saveHandler = new SessionHandlerProxy(new StrictSessionHandler(new \SessionHandler()));
  299. }
  300. $this->saveHandler = $saveHandler;
  301. if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) {
  302. return;
  303. }
  304. if ($this->saveHandler instanceof SessionHandlerProxy) {
  305. session_set_save_handler($this->saveHandler, false);
  306. }
  307. }
  308. protected function loadSession(array &$session = null)
  309. {
  310. if (null === $session) {
  311. $session = &$_SESSION;
  312. }
  313. $bags = array_merge($this->bags, [$this->metadataBag]);
  314. foreach ($bags as $bag) {
  315. $key = $bag->getStorageKey();
  316. $session[$key] = isset($session[$key]) && \is_array($session[$key]) ? $session[$key] : [];
  317. $bag->initialize($session[$key]);
  318. }
  319. $this->started = true;
  320. $this->closed = false;
  321. }
  322. }
  323. }
  324. namespace Symfony\Component\HttpFoundation\Session\Storage
  325. {
  326. class PhpBridgeSessionStorage extends NativeSessionStorage
  327. {
  328. public function __construct($handler = null, MetadataBag $metaBag = null)
  329. {
  330. if (!\extension_loaded('session')) {
  331. throw new \LogicException('PHP extension "session" is required.');
  332. }
  333. $this->setMetadataBag($metaBag);
  334. $this->setSaveHandler($handler);
  335. }
  336. public function start()
  337. {
  338. if ($this->started) {
  339. return true;
  340. }
  341. $this->loadSession();
  342. return true;
  343. }
  344. public function clear()
  345. {
  346. foreach ($this->bags as $bag) {
  347. $bag->clear();
  348. }
  349. $this->loadSession();
  350. }
  351. }
  352. }
  353. namespace Symfony\Component\HttpFoundation\Session\Storage\Handler
  354. {
  355. class NativeSessionHandler extends \SessionHandler
  356. {
  357. public function __construct()
  358. {
  359. @trigger_error('The '.__NAMESPACE__.'\NativeSessionHandler class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the \SessionHandler class instead.', \E_USER_DEPRECATED);
  360. }
  361. }
  362. }
  363. namespace Symfony\Component\HttpFoundation\Session\Storage\Handler
  364. {
  365. class NativeFileSessionHandler extends NativeSessionHandler
  366. {
  367. public function __construct($savePath = null)
  368. {
  369. if (null === $savePath) {
  370. $savePath = ini_get('session.save_path');
  371. }
  372. $baseDir = $savePath;
  373. if ($count = substr_count($savePath,';')) {
  374. if ($count > 2) {
  375. throw new \InvalidArgumentException(sprintf('Invalid argument $savePath \'%s\'.', $savePath));
  376. }
  377. $baseDir = ltrim(strrchr($savePath,';'),';');
  378. }
  379. if ($baseDir && !is_dir($baseDir) && !@mkdir($baseDir, 0777, true) && !is_dir($baseDir)) {
  380. throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $baseDir));
  381. }
  382. ini_set('session.save_path', $savePath);
  383. ini_set('session.save_handler','files');
  384. }
  385. }
  386. }
  387. namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy
  388. {
  389. abstract class AbstractProxy
  390. {
  391. protected $wrapper = false;
  392. protected $saveHandlerName;
  393. public function getSaveHandlerName()
  394. {
  395. return $this->saveHandlerName;
  396. }
  397. public function isSessionHandlerInterface()
  398. {
  399. return $this instanceof \SessionHandlerInterface;
  400. }
  401. public function isWrapper()
  402. {
  403. return $this->wrapper;
  404. }
  405. public function isActive()
  406. {
  407. return \PHP_SESSION_ACTIVE === session_status();
  408. }
  409. public function getId()
  410. {
  411. return session_id();
  412. }
  413. public function setId($id)
  414. {
  415. if ($this->isActive()) {
  416. throw new \LogicException('Cannot change the ID of an active session.');
  417. }
  418. session_id($id);
  419. }
  420. public function getName()
  421. {
  422. return session_name();
  423. }
  424. public function setName($name)
  425. {
  426. if ($this->isActive()) {
  427. throw new \LogicException('Cannot change the name of an active session.');
  428. }
  429. session_name($name);
  430. }
  431. }
  432. }
  433. namespace
  434. {
  435. interface SessionUpdateTimestampHandlerInterface
  436. {
  437. public function validateId($key);
  438. public function updateTimestamp($key, $val);
  439. }
  440. }
  441. namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy
  442. {
  443. class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
  444. {
  445. protected $handler;
  446. public function __construct(\SessionHandlerInterface $handler)
  447. {
  448. $this->handler = $handler;
  449. $this->wrapper = ($handler instanceof \SessionHandler);
  450. $this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') :'user';
  451. }
  452. public function getHandler()
  453. {
  454. return $this->handler;
  455. }
  456. public function open($savePath, $sessionName)
  457. {
  458. return (bool) $this->handler->open($savePath, $sessionName);
  459. }
  460. public function close()
  461. {
  462. return (bool) $this->handler->close();
  463. }
  464. public function read($sessionId)
  465. {
  466. return (string) $this->handler->read($sessionId);
  467. }
  468. public function write($sessionId, $data)
  469. {
  470. return (bool) $this->handler->write($sessionId, $data);
  471. }
  472. public function destroy($sessionId)
  473. {
  474. return (bool) $this->handler->destroy($sessionId);
  475. }
  476. public function gc($maxlifetime)
  477. {
  478. return (bool) $this->handler->gc($maxlifetime);
  479. }
  480. public function validateId($sessionId)
  481. {
  482. return !$this->handler instanceof \SessionUpdateTimestampHandlerInterface || $this->handler->validateId($sessionId);
  483. }
  484. public function updateTimestamp($sessionId, $data)
  485. {
  486. return $this->handler instanceof \SessionUpdateTimestampHandlerInterface ? $this->handler->updateTimestamp($sessionId, $data) : $this->write($sessionId, $data);
  487. }
  488. }
  489. }
  490. namespace Symfony\Component\HttpFoundation\Session
  491. {
  492. use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag;
  493. interface SessionInterface
  494. {
  495. public function start();
  496. public function getId();
  497. public function setId($id);
  498. public function getName();
  499. public function setName($name);
  500. public function invalidate($lifetime = null);
  501. public function migrate($destroy = false, $lifetime = null);
  502. public function save();
  503. public function has($name);
  504. public function get($name, $default = null);
  505. public function set($name, $value);
  506. public function all();
  507. public function replace(array $attributes);
  508. public function remove($name);
  509. public function clear();
  510. public function isStarted();
  511. public function registerBag(SessionBagInterface $bag);
  512. public function getBag($name);
  513. public function getMetadataBag();
  514. }
  515. }
  516. namespace Symfony\Component\HttpFoundation\Session
  517. {
  518. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
  519. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  520. use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
  521. use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
  522. use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
  523. use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
  524. class Session implements SessionInterface, \IteratorAggregate, \Countable
  525. {
  526. protected $storage;
  527. private $flashName;
  528. private $attributeName;
  529. private $data = [];
  530. private $usageIndex = 0;
  531. public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null)
  532. {
  533. $this->storage = $storage ?: new NativeSessionStorage();
  534. $attributes = $attributes ?: new AttributeBag();
  535. $this->attributeName = $attributes->getName();
  536. $this->registerBag($attributes);
  537. $flashes = $flashes ?: new FlashBag();
  538. $this->flashName = $flashes->getName();
  539. $this->registerBag($flashes);
  540. }
  541. public function start()
  542. {
  543. return $this->storage->start();
  544. }
  545. public function has($name)
  546. {
  547. return $this->getAttributeBag()->has($name);
  548. }
  549. public function get($name, $default = null)
  550. {
  551. return $this->getAttributeBag()->get($name, $default);
  552. }
  553. public function set($name, $value)
  554. {
  555. $this->getAttributeBag()->set($name, $value);
  556. }
  557. public function all()
  558. {
  559. return $this->getAttributeBag()->all();
  560. }
  561. public function replace(array $attributes)
  562. {
  563. $this->getAttributeBag()->replace($attributes);
  564. }
  565. public function remove($name)
  566. {
  567. return $this->getAttributeBag()->remove($name);
  568. }
  569. public function clear()
  570. {
  571. $this->getAttributeBag()->clear();
  572. }
  573. public function isStarted()
  574. {
  575. return $this->storage->isStarted();
  576. }
  577. public function getIterator()
  578. {
  579. return new \ArrayIterator($this->getAttributeBag()->all());
  580. }
  581. public function count()
  582. {
  583. return \count($this->getAttributeBag()->all());
  584. }
  585. public function getUsageIndex()
  586. {
  587. return $this->usageIndex;
  588. }
  589. public function isEmpty()
  590. {
  591. if ($this->isStarted()) {
  592. ++$this->usageIndex;
  593. }
  594. foreach ($this->data as &$data) {
  595. if (!empty($data)) {
  596. return false;
  597. }
  598. }
  599. return true;
  600. }
  601. public function invalidate($lifetime = null)
  602. {
  603. $this->storage->clear();
  604. return $this->migrate(true, $lifetime);
  605. }
  606. public function migrate($destroy = false, $lifetime = null)
  607. {
  608. return $this->storage->regenerate($destroy, $lifetime);
  609. }
  610. public function save()
  611. {
  612. $this->storage->save();
  613. }
  614. public function getId()
  615. {
  616. return $this->storage->getId();
  617. }
  618. public function setId($id)
  619. {
  620. if ($this->storage->getId() !== $id) {
  621. $this->storage->setId($id);
  622. }
  623. }
  624. public function getName()
  625. {
  626. return $this->storage->getName();
  627. }
  628. public function setName($name)
  629. {
  630. $this->storage->setName($name);
  631. }
  632. public function getMetadataBag()
  633. {
  634. ++$this->usageIndex;
  635. return $this->storage->getMetadataBag();
  636. }
  637. public function registerBag(SessionBagInterface $bag)
  638. {
  639. $this->storage->registerBag(new SessionBagProxy($bag, $this->data, $this->usageIndex));
  640. }
  641. public function getBag($name)
  642. {
  643. $bag = $this->storage->getBag($name);
  644. return method_exists($bag,'getBag') ? $bag->getBag() : $bag;
  645. }
  646. public function getFlashBag()
  647. {
  648. return $this->getBag($this->flashName);
  649. }
  650. private function getAttributeBag()
  651. {
  652. return $this->getBag($this->attributeName);
  653. }
  654. }
  655. }
  656. namespace Symfony\Bundle\FrameworkBundle\Templating
  657. {
  658. use Symfony\Component\DependencyInjection\ContainerInterface;
  659. use Symfony\Component\HttpFoundation\Request;
  660. use Symfony\Component\HttpFoundation\Session\Session;
  661. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  662. class GlobalVariables
  663. {
  664. protected $container;
  665. public function __construct(ContainerInterface $container)
  666. {
  667. $this->container = $container;
  668. }
  669. public function getToken()
  670. {
  671. if (!$this->container->has('security.token_storage')) {
  672. return null;
  673. }
  674. return $this->container->get('security.token_storage')->getToken();
  675. }
  676. public function getUser()
  677. {
  678. if (!$token = $this->getToken()) {
  679. return null;
  680. }
  681. $user = $token->getUser();
  682. return \is_object($user) ? $user : null;
  683. }
  684. public function getRequest()
  685. {
  686. return $this->container->has('request_stack') ? $this->container->get('request_stack')->getCurrentRequest() : null;
  687. }
  688. public function getSession()
  689. {
  690. return ($request = $this->getRequest()) ? $request->getSession() : null;
  691. }
  692. public function getEnvironment()
  693. {
  694. return $this->container->getParameter('kernel.environment');
  695. }
  696. public function getDebug()
  697. {
  698. return (bool) $this->container->getParameter('kernel.debug');
  699. }
  700. }
  701. }
  702. namespace Symfony\Component\Templating
  703. {
  704. interface TemplateReferenceInterface
  705. {
  706. public function all();
  707. public function set($name, $value);
  708. public function get($name);
  709. public function getPath();
  710. public function getLogicalName();
  711. public function __toString();
  712. }
  713. }
  714. namespace Symfony\Component\Templating
  715. {
  716. class TemplateReference implements TemplateReferenceInterface
  717. {
  718. protected $parameters;
  719. public function __construct($name = null, $engine = null)
  720. {
  721. $this->parameters = ['name'=> $name,'engine'=> $engine,
  722. ];
  723. }
  724. public function __toString()
  725. {
  726. return $this->getLogicalName();
  727. }
  728. public function set($name, $value)
  729. {
  730. if (\array_key_exists($name, $this->parameters)) {
  731. $this->parameters[$name] = $value;
  732. } else {
  733. throw new \InvalidArgumentException(sprintf('The template does not support the "%s" parameter.', $name));
  734. }
  735. return $this;
  736. }
  737. public function get($name)
  738. {
  739. if (\array_key_exists($name, $this->parameters)) {
  740. return $this->parameters[$name];
  741. }
  742. throw new \InvalidArgumentException(sprintf('The template does not support the "%s" parameter.', $name));
  743. }
  744. public function all()
  745. {
  746. return $this->parameters;
  747. }
  748. public function getPath()
  749. {
  750. return $this->parameters['name'];
  751. }
  752. public function getLogicalName()
  753. {
  754. return $this->parameters['name'];
  755. }
  756. }
  757. }
  758. namespace Symfony\Bundle\FrameworkBundle\Templating
  759. {
  760. use Symfony\Component\Templating\TemplateReference as BaseTemplateReference;
  761. class TemplateReference extends BaseTemplateReference
  762. {
  763. public function __construct($bundle = null, $controller = null, $name = null, $format = null, $engine = null)
  764. {
  765. $this->parameters = ['bundle'=> $bundle,'controller'=> $controller,'name'=> $name,'format'=> $format,'engine'=> $engine,
  766. ];
  767. }
  768. public function getPath()
  769. {
  770. $controller = str_replace('\\','/', $this->get('controller'));
  771. $path = (empty($controller) ?'': $controller.'/').$this->get('name').'.'.$this->get('format').'.'.$this->get('engine');
  772. return empty($this->parameters['bundle']) ?'views/'.$path :'@'.$this->get('bundle').'/Resources/views/'.$path;
  773. }
  774. public function getLogicalName()
  775. {
  776. return sprintf('%s:%s:%s.%s.%s', $this->parameters['bundle'], $this->parameters['controller'], $this->parameters['name'], $this->parameters['format'], $this->parameters['engine']);
  777. }
  778. }
  779. }
  780. namespace Symfony\Component\Templating
  781. {
  782. interface TemplateNameParserInterface
  783. {
  784. public function parse($name);
  785. }
  786. }
  787. namespace Symfony\Component\Templating
  788. {
  789. class TemplateNameParser implements TemplateNameParserInterface
  790. {
  791. public function parse($name)
  792. {
  793. if ($name instanceof TemplateReferenceInterface) {
  794. return $name;
  795. }
  796. $engine = null;
  797. if (false !== $pos = strrpos($name,'.')) {
  798. $engine = substr($name, $pos + 1);
  799. }
  800. return new TemplateReference($name, $engine);
  801. }
  802. }
  803. }
  804. namespace Symfony\Bundle\FrameworkBundle\Templating
  805. {
  806. use Symfony\Component\HttpKernel\KernelInterface;
  807. use Symfony\Component\Templating\TemplateNameParser as BaseTemplateNameParser;
  808. use Symfony\Component\Templating\TemplateReferenceInterface;
  809. class TemplateNameParser extends BaseTemplateNameParser
  810. {
  811. protected $kernel;
  812. protected $cache = [];
  813. public function __construct(KernelInterface $kernel)
  814. {
  815. $this->kernel = $kernel;
  816. }
  817. public function parse($name)
  818. {
  819. if ($name instanceof TemplateReferenceInterface) {
  820. return $name;
  821. } elseif (isset($this->cache[$name])) {
  822. return $this->cache[$name];
  823. }
  824. $name = preg_replace('#/{2,}#','/', str_replace('\\','/', $name));
  825. if (false !== strpos($name,'..')) {
  826. throw new \RuntimeException(sprintf('Template name "%s" contains invalid characters.', $name));
  827. }
  828. if ($this->isAbsolutePath($name) || !preg_match('/^(?:([^:]*):([^:]*):)?(.+)\.([^\.]+)\.([^\.]+)$/', $name, $matches) || 0 === strpos($name,'@')) {
  829. return parent::parse($name);
  830. }
  831. $template = new TemplateReference($matches[1], $matches[2], $matches[3], $matches[4], $matches[5]);
  832. if ($template->get('bundle')) {
  833. try {
  834. $this->kernel->getBundle($template->get('bundle'));
  835. } catch (\Exception $e) {
  836. throw new \InvalidArgumentException(sprintf('Template name "%s" is not valid.', $name), 0, $e);
  837. }
  838. }
  839. return $this->cache[$name] = $template;
  840. }
  841. private function isAbsolutePath($file)
  842. {
  843. $isAbsolute = (bool) preg_match('#^(?:/|[a-zA-Z]:)#', $file);
  844. if ($isAbsolute) {
  845. @trigger_error('Absolute template path support is deprecated since Symfony 3.1 and will be removed in 4.0.', \E_USER_DEPRECATED);
  846. }
  847. return $isAbsolute;
  848. }
  849. }
  850. }
  851. namespace Symfony\Component\Config
  852. {
  853. use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
  854. interface FileLocatorInterface
  855. {
  856. public function locate($name, $currentPath = null, $first = true);
  857. }
  858. }
  859. namespace Symfony\Bundle\FrameworkBundle\Templating\Loader
  860. {
  861. use Symfony\Component\Config\FileLocatorInterface;
  862. use Symfony\Component\Templating\TemplateReferenceInterface;
  863. class TemplateLocator implements FileLocatorInterface
  864. {
  865. protected $locator;
  866. protected $cache;
  867. private $cacheHits = [];
  868. public function __construct(FileLocatorInterface $locator, $cacheDir = null)
  869. {
  870. if (null !== $cacheDir && file_exists($cache = $cacheDir.'/templates.php')) {
  871. $this->cache = require $cache;
  872. }
  873. $this->locator = $locator;
  874. }
  875. protected function getCacheKey($template)
  876. {
  877. return $template->getLogicalName();
  878. }
  879. public function locate($template, $currentPath = null, $first = true)
  880. {
  881. if (!$template instanceof TemplateReferenceInterface) {
  882. throw new \InvalidArgumentException('The template must be an instance of TemplateReferenceInterface.');
  883. }
  884. $key = $this->getCacheKey($template);
  885. if (isset($this->cacheHits[$key])) {
  886. return $this->cacheHits[$key];
  887. }
  888. if (isset($this->cache[$key])) {
  889. return $this->cacheHits[$key] = realpath($this->cache[$key]) ?: $this->cache[$key];
  890. }
  891. try {
  892. return $this->cacheHits[$key] = $this->locator->locate($template->getPath(), $currentPath);
  893. } catch (\InvalidArgumentException $e) {
  894. throw new \InvalidArgumentException(sprintf('Unable to find template "%s": ', $template).$e->getMessage(), 0, $e);
  895. }
  896. }
  897. }
  898. }
  899. namespace Symfony\Component\Cache
  900. {
  901. interface ResettableInterface
  902. {
  903. public function reset();
  904. }
  905. }
  906. namespace Psr\Log
  907. {
  908. interface LoggerAwareInterface
  909. {
  910. public function setLogger(LoggerInterface $logger);
  911. }
  912. }
  913. namespace Psr\Cache
  914. {
  915. interface CacheItemPoolInterface
  916. {
  917. public function getItem($key);
  918. public function getItems(array $keys = array());
  919. public function hasItem($key);
  920. public function clear();
  921. public function deleteItem($key);
  922. public function deleteItems(array $keys);
  923. public function save(CacheItemInterface $item);
  924. public function saveDeferred(CacheItemInterface $item);
  925. public function commit();
  926. }
  927. }
  928. namespace Symfony\Component\Cache\Adapter
  929. {
  930. use Psr\Cache\CacheItemPoolInterface;
  931. use Symfony\Component\Cache\CacheItem;
  932. interface AdapterInterface extends CacheItemPoolInterface
  933. {
  934. public function getItem($key);
  935. public function getItems(array $keys = []);
  936. }
  937. }
  938. namespace Psr\Log
  939. {
  940. trait LoggerAwareTrait
  941. {
  942. protected $logger;
  943. public function setLogger(LoggerInterface $logger)
  944. {
  945. $this->logger = $logger;
  946. }
  947. }
  948. }
  949. namespace Symfony\Component\Cache\Traits
  950. {
  951. use Psr\Log\LoggerAwareTrait;
  952. use Symfony\Component\Cache\CacheItem;
  953. trait AbstractTrait
  954. {
  955. use LoggerAwareTrait;
  956. private $namespace;
  957. private $namespaceVersion ='';
  958. private $versioningIsEnabled = false;
  959. private $deferred = [];
  960. protected $maxIdLength;
  961. abstract protected function doFetch(array $ids);
  962. abstract protected function doHave($id);
  963. abstract protected function doClear($namespace);
  964. abstract protected function doDelete(array $ids);
  965. abstract protected function doSave(array $values, $lifetime);
  966. public function hasItem($key)
  967. {
  968. $id = $this->getId($key);
  969. if (isset($this->deferred[$key])) {
  970. $this->commit();
  971. }
  972. try {
  973. return $this->doHave($id);
  974. } catch (\Exception $e) {
  975. CacheItem::log($this->logger,'Failed to check if key "{key}" is cached', ['key'=> $key,'exception'=> $e]);
  976. return false;
  977. }
  978. }
  979. public function clear()
  980. {
  981. $this->deferred = [];
  982. if ($cleared = $this->versioningIsEnabled) {
  983. $namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5);
  984. try {
  985. $cleared = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0);
  986. } catch (\Exception $e) {
  987. $cleared = false;
  988. }
  989. if ($cleared = true === $cleared || [] === $cleared) {
  990. $this->namespaceVersion = $namespaceVersion;
  991. }
  992. }
  993. try {
  994. return $this->doClear($this->namespace) || $cleared;
  995. } catch (\Exception $e) {
  996. CacheItem::log($this->logger,'Failed to clear the cache', ['exception'=> $e]);
  997. return false;
  998. }
  999. }
  1000. public function deleteItem($key)
  1001. {
  1002. return $this->deleteItems([$key]);
  1003. }
  1004. public function deleteItems(array $keys)
  1005. {
  1006. $ids = [];
  1007. foreach ($keys as $key) {
  1008. $ids[$key] = $this->getId($key);
  1009. unset($this->deferred[$key]);
  1010. }
  1011. try {
  1012. if ($this->doDelete($ids)) {
  1013. return true;
  1014. }
  1015. } catch (\Exception $e) {
  1016. }
  1017. $ok = true;
  1018. foreach ($ids as $key => $id) {
  1019. try {
  1020. $e = null;
  1021. if ($this->doDelete([$id])) {
  1022. continue;
  1023. }
  1024. } catch (\Exception $e) {
  1025. }
  1026. CacheItem::log($this->logger,'Failed to delete key "{key}"', ['key'=> $key,'exception'=> $e]);
  1027. $ok = false;
  1028. }
  1029. return $ok;
  1030. }
  1031. public function enableVersioning($enable = true)
  1032. {
  1033. $wasEnabled = $this->versioningIsEnabled;
  1034. $this->versioningIsEnabled = (bool) $enable;
  1035. $this->namespaceVersion ='';
  1036. return $wasEnabled;
  1037. }
  1038. public function reset()
  1039. {
  1040. if ($this->deferred) {
  1041. $this->commit();
  1042. }
  1043. $this->namespaceVersion ='';
  1044. }
  1045. protected static function unserialize($value)
  1046. {
  1047. if ('b:0;'=== $value) {
  1048. return false;
  1049. }
  1050. $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
  1051. try {
  1052. if (false !== $value = unserialize($value)) {
  1053. return $value;
  1054. }
  1055. throw new \DomainException('Failed to unserialize cached value.');
  1056. } catch (\Error $e) {
  1057. throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
  1058. } finally {
  1059. ini_set('unserialize_callback_func', $unserializeCallbackHandler);
  1060. }
  1061. }
  1062. private function getId($key)
  1063. {
  1064. CacheItem::validateKey($key);
  1065. if ($this->versioningIsEnabled &&''=== $this->namespaceVersion) {
  1066. $this->namespaceVersion ='1'.static::NS_SEPARATOR;
  1067. try {
  1068. foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) {
  1069. $this->namespaceVersion = $v;
  1070. }
  1071. if ('1'.static::NS_SEPARATOR === $this->namespaceVersion) {
  1072. $this->namespaceVersion = substr_replace(base64_encode(pack('V', time())), static::NS_SEPARATOR, 5);
  1073. $this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0);
  1074. }
  1075. } catch (\Exception $e) {
  1076. }
  1077. }
  1078. if (null === $this->maxIdLength) {
  1079. return $this->namespace.$this->namespaceVersion.$key;
  1080. }
  1081. if (\strlen($id = $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) {
  1082. $id = $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256', $key, true)), static::NS_SEPARATOR, -(\strlen($this->namespaceVersion) + 22));
  1083. }
  1084. return $id;
  1085. }
  1086. public static function handleUnserializeCallback($class)
  1087. {
  1088. throw new \DomainException('Class not found: '.$class);
  1089. }
  1090. }
  1091. }
  1092. namespace Symfony\Component\Cache\Traits
  1093. {
  1094. use Symfony\Component\Cache\CacheItem;
  1095. use Symfony\Component\Cache\Exception\CacheException;
  1096. trait ApcuTrait
  1097. {
  1098. public static function isSupported()
  1099. {
  1100. return \function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN);
  1101. }
  1102. private function init($namespace, $defaultLifetime, $version)
  1103. {
  1104. if (!static::isSupported()) {
  1105. throw new CacheException('APCu is not enabled.');
  1106. }
  1107. if ('cli'=== \PHP_SAPI) {
  1108. ini_set('apc.use_request_time', 0);
  1109. }
  1110. parent::__construct($namespace, $defaultLifetime);
  1111. if (null !== $version) {
  1112. CacheItem::validateKey($version);
  1113. if (!apcu_exists($version.'@'.$namespace)) {
  1114. $this->doClear($namespace);
  1115. apcu_add($version.'@'.$namespace, null);
  1116. }
  1117. }
  1118. }
  1119. protected function doFetch(array $ids)
  1120. {
  1121. try {
  1122. foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) {
  1123. if (null !== $v || $ok) {
  1124. yield $k => $v;
  1125. }
  1126. }
  1127. } catch (\Error $e) {
  1128. throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
  1129. }
  1130. }
  1131. protected function doHave($id)
  1132. {
  1133. return apcu_exists($id);
  1134. }
  1135. protected function doClear($namespace)
  1136. {
  1137. return isset($namespace[0]) && class_exists('APCuIterator', false) && ('cli'!== \PHP_SAPI || filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))
  1138. ? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace,'/')), \APC_ITER_KEY))
  1139. : apcu_clear_cache();
  1140. }
  1141. protected function doDelete(array $ids)
  1142. {
  1143. foreach ($ids as $id) {
  1144. apcu_delete($id);
  1145. }
  1146. return true;
  1147. }
  1148. protected function doSave(array $values, $lifetime)
  1149. {
  1150. try {
  1151. if (false === $failures = apcu_store($values, null, $lifetime)) {
  1152. $failures = $values;
  1153. }
  1154. return array_keys($failures);
  1155. } catch (\Error $e) {
  1156. } catch (\Exception $e) {
  1157. }
  1158. if (1 === \count($values)) {
  1159. apcu_delete(key($values));
  1160. }
  1161. throw $e;
  1162. }
  1163. }
  1164. }
  1165. namespace Symfony\Component\Cache\Adapter
  1166. {
  1167. use Psr\Cache\CacheItemInterface;
  1168. use Psr\Log\LoggerAwareInterface;
  1169. use Psr\Log\LoggerInterface;
  1170. use Symfony\Component\Cache\CacheItem;
  1171. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  1172. use Symfony\Component\Cache\ResettableInterface;
  1173. use Symfony\Component\Cache\Traits\AbstractTrait;
  1174. abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
  1175. {
  1176. const NS_SEPARATOR =':';
  1177. use AbstractTrait;
  1178. private static $apcuSupported;
  1179. private static $phpFilesSupported;
  1180. private $createCacheItem;
  1181. private $mergeByLifetime;
  1182. protected function __construct($namespace ='', $defaultLifetime = 0)
  1183. {
  1184. $this->namespace =''=== $namespace ?'': CacheItem::validateKey($namespace).static::NS_SEPARATOR;
  1185. if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
  1186. throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace));
  1187. }
  1188. $this->createCacheItem = \Closure::bind(
  1189. static function ($key, $value, $isHit) {
  1190. $item = new CacheItem();
  1191. $item->key = $key;
  1192. $item->value = $value;
  1193. $item->isHit = $isHit;
  1194. return $item;
  1195. },
  1196. null,
  1197. CacheItem::class
  1198. );
  1199. $getId = function ($key) { return $this->getId((string) $key); };
  1200. $this->mergeByLifetime = \Closure::bind(
  1201. static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifetime) {
  1202. $byLifetime = [];
  1203. $now = time();
  1204. $expiredIds = [];
  1205. foreach ($deferred as $key => $item) {
  1206. if (null === $item->expiry) {
  1207. $byLifetime[0 < $defaultLifetime ? $defaultLifetime : 0][$getId($key)] = $item->value;
  1208. } elseif (0 === $item->expiry) {
  1209. $byLifetime[0][$getId($key)] = $item->value;
  1210. } elseif ($item->expiry > $now) {
  1211. $byLifetime[$item->expiry - $now][$getId($key)] = $item->value;
  1212. } else {
  1213. $expiredIds[] = $getId($key);
  1214. }
  1215. }
  1216. return $byLifetime;
  1217. },
  1218. null,
  1219. CacheItem::class
  1220. );
  1221. }
  1222. public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null)
  1223. {
  1224. if (null === self::$apcuSupported) {
  1225. self::$apcuSupported = ApcuAdapter::isSupported();
  1226. }
  1227. if (!self::$apcuSupported && null === self::$phpFilesSupported) {
  1228. self::$phpFilesSupported = PhpFilesAdapter::isSupported();
  1229. }
  1230. if (self::$phpFilesSupported) {
  1231. $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory);
  1232. if (null !== $logger) {
  1233. $opcache->setLogger($logger);
  1234. }
  1235. return $opcache;
  1236. }
  1237. $fs = new FilesystemAdapter($namespace, $defaultLifetime, $directory);
  1238. if (null !== $logger) {
  1239. $fs->setLogger($logger);
  1240. }
  1241. if (!self::$apcuSupported || (\in_array(\PHP_SAPI, ['cli','phpdbg'], true) && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) {
  1242. return $fs;
  1243. }
  1244. $apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version);
  1245. if (null !== $logger) {
  1246. $apcu->setLogger($logger);
  1247. }
  1248. return new ChainAdapter([$apcu, $fs]);
  1249. }
  1250. public static function createConnection($dsn, array $options = [])
  1251. {
  1252. if (!\is_string($dsn)) {
  1253. throw new InvalidArgumentException(sprintf('The "%s()" method expect argument #1 to be string, "%s" given.', __METHOD__, \gettype($dsn)));
  1254. }
  1255. if (0 === strpos($dsn,'redis://')) {
  1256. return RedisAdapter::createConnection($dsn, $options);
  1257. }
  1258. if (0 === strpos($dsn,'memcached://')) {
  1259. return MemcachedAdapter::createConnection($dsn, $options);
  1260. }
  1261. throw new InvalidArgumentException(sprintf('Unsupported DSN: "%s".', $dsn));
  1262. }
  1263. public function getItem($key)
  1264. {
  1265. if ($this->deferred) {
  1266. $this->commit();
  1267. }
  1268. $id = $this->getId($key);
  1269. $f = $this->createCacheItem;
  1270. $isHit = false;
  1271. $value = null;
  1272. try {
  1273. foreach ($this->doFetch([$id]) as $value) {
  1274. $isHit = true;
  1275. }
  1276. } catch (\Exception $e) {
  1277. CacheItem::log($this->logger,'Failed to fetch key "{key}"', ['key'=> $key,'exception'=> $e]);
  1278. }
  1279. return $f($key, $value, $isHit);
  1280. }
  1281. public function getItems(array $keys = [])
  1282. {
  1283. if ($this->deferred) {
  1284. $this->commit();
  1285. }
  1286. $ids = [];
  1287. foreach ($keys as $key) {
  1288. $ids[] = $this->getId($key);
  1289. }
  1290. try {
  1291. $items = $this->doFetch($ids);
  1292. } catch (\Exception $e) {
  1293. CacheItem::log($this->logger,'Failed to fetch requested items', ['keys'=> $keys,'exception'=> $e]);
  1294. $items = [];
  1295. }
  1296. $ids = array_combine($ids, $keys);
  1297. return $this->generateItems($items, $ids);
  1298. }
  1299. public function save(CacheItemInterface $item)
  1300. {
  1301. if (!$item instanceof CacheItem) {
  1302. return false;
  1303. }
  1304. $this->deferred[$item->getKey()] = $item;
  1305. return $this->commit();
  1306. }
  1307. public function saveDeferred(CacheItemInterface $item)
  1308. {
  1309. if (!$item instanceof CacheItem) {
  1310. return false;
  1311. }
  1312. $this->deferred[$item->getKey()] = $item;
  1313. return true;
  1314. }
  1315. public function commit()
  1316. {
  1317. $ok = true;
  1318. $byLifetime = $this->mergeByLifetime;
  1319. $byLifetime = $byLifetime($this->deferred, $this->namespace, $expiredIds);
  1320. $retry = $this->deferred = [];
  1321. if ($expiredIds) {
  1322. $this->doDelete($expiredIds);
  1323. }
  1324. foreach ($byLifetime as $lifetime => $values) {
  1325. try {
  1326. $e = $this->doSave($values, $lifetime);
  1327. } catch (\Exception $e) {
  1328. }
  1329. if (true === $e || [] === $e) {
  1330. continue;
  1331. }
  1332. if (\is_array($e) || 1 === \count($values)) {
  1333. foreach (\is_array($e) ? $e : array_keys($values) as $id) {
  1334. $ok = false;
  1335. $v = $values[$id];
  1336. $type = \is_object($v) ? \get_class($v) : \gettype($v);
  1337. CacheItem::log($this->logger,'Failed to save key "{key}" ({type})', ['key'=> substr($id, \strlen($this->namespace)),'type'=> $type,'exception'=> $e instanceof \Exception ? $e : null]);
  1338. }
  1339. } else {
  1340. foreach ($values as $id => $v) {
  1341. $retry[$lifetime][] = $id;
  1342. }
  1343. }
  1344. }
  1345. foreach ($retry as $lifetime => $ids) {
  1346. foreach ($ids as $id) {
  1347. try {
  1348. $v = $byLifetime[$lifetime][$id];
  1349. $e = $this->doSave([$id => $v], $lifetime);
  1350. } catch (\Exception $e) {
  1351. }
  1352. if (true === $e || [] === $e) {
  1353. continue;
  1354. }
  1355. $ok = false;
  1356. $type = \is_object($v) ? \get_class($v) : \gettype($v);
  1357. CacheItem::log($this->logger,'Failed to save key "{key}" ({type})', ['key'=> substr($id, \strlen($this->namespace)),'type'=> $type,'exception'=> $e instanceof \Exception ? $e : null]);
  1358. }
  1359. }
  1360. return $ok;
  1361. }
  1362. public function __sleep()
  1363. {
  1364. throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  1365. }
  1366. public function __wakeup()
  1367. {
  1368. throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  1369. }
  1370. public function __destruct()
  1371. {
  1372. if ($this->deferred) {
  1373. $this->commit();
  1374. }
  1375. }
  1376. private function generateItems($items, &$keys)
  1377. {
  1378. $f = $this->createCacheItem;
  1379. try {
  1380. foreach ($items as $id => $value) {
  1381. if (!isset($keys[$id])) {
  1382. $id = key($keys);
  1383. }
  1384. $key = $keys[$id];
  1385. unset($keys[$id]);
  1386. yield $key => $f($key, $value, true);
  1387. }
  1388. } catch (\Exception $e) {
  1389. CacheItem::log($this->logger,'Failed to fetch requested items', ['keys'=> array_values($keys),'exception'=> $e]);
  1390. }
  1391. foreach ($keys as $key) {
  1392. yield $key => $f($key, null, false);
  1393. }
  1394. }
  1395. }
  1396. }
  1397. namespace Symfony\Component\Cache\Adapter
  1398. {
  1399. use Symfony\Component\Cache\Traits\ApcuTrait;
  1400. class ApcuAdapter extends AbstractAdapter
  1401. {
  1402. use ApcuTrait;
  1403. public function __construct($namespace ='', $defaultLifetime = 0, $version = null)
  1404. {
  1405. $this->init($namespace, $defaultLifetime, $version);
  1406. }
  1407. }
  1408. }
  1409. namespace Symfony\Component\Cache
  1410. {
  1411. interface PruneableInterface
  1412. {
  1413. public function prune();
  1414. }
  1415. }
  1416. namespace Symfony\Component\Cache\Traits
  1417. {
  1418. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  1419. trait FilesystemCommonTrait
  1420. {
  1421. private $directory;
  1422. private $tmp;
  1423. private function init($namespace, $directory)
  1424. {
  1425. if (!isset($directory[0])) {
  1426. $directory = sys_get_temp_dir().'/symfony-cache';
  1427. } else {
  1428. $directory = realpath($directory) ?: $directory;
  1429. }
  1430. if (isset($namespace[0])) {
  1431. if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
  1432. throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
  1433. }
  1434. $directory .= \DIRECTORY_SEPARATOR.$namespace;
  1435. }
  1436. if (!file_exists($directory)) {
  1437. @mkdir($directory, 0777, true);
  1438. }
  1439. $directory .= \DIRECTORY_SEPARATOR;
  1440. if ('\\'=== \DIRECTORY_SEPARATOR && \strlen($directory) > 234) {
  1441. throw new InvalidArgumentException(sprintf('Cache directory too long (%s).', $directory));
  1442. }
  1443. $this->directory = $directory;
  1444. }
  1445. protected function doClear($namespace)
  1446. {
  1447. $ok = true;
  1448. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) {
  1449. $ok = ($file->isDir() || @unlink($file) || !file_exists($file)) && $ok;
  1450. }
  1451. return $ok;
  1452. }
  1453. protected function doDelete(array $ids)
  1454. {
  1455. $ok = true;
  1456. foreach ($ids as $id) {
  1457. $file = $this->getFile($id);
  1458. $ok = (!file_exists($file) || @unlink($file) || !file_exists($file)) && $ok;
  1459. }
  1460. return $ok;
  1461. }
  1462. private function write($file, $data, $expiresAt = null)
  1463. {
  1464. set_error_handler(__CLASS__.'::throwError');
  1465. try {
  1466. if (null === $this->tmp) {
  1467. $this->tmp = $this->directory.uniqid('', true);
  1468. }
  1469. file_put_contents($this->tmp, $data);
  1470. if (null !== $expiresAt) {
  1471. touch($this->tmp, $expiresAt);
  1472. }
  1473. return rename($this->tmp, $file);
  1474. } finally {
  1475. restore_error_handler();
  1476. }
  1477. }
  1478. private function getFile($id, $mkdir = false)
  1479. {
  1480. $hash = str_replace('/','-', base64_encode(hash('sha256', static::class.$id, true)));
  1481. $dir = $this->directory.strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR);
  1482. if ($mkdir && !file_exists($dir)) {
  1483. @mkdir($dir, 0777, true);
  1484. }
  1485. return $dir.substr($hash, 2, 20);
  1486. }
  1487. public static function throwError($type, $message, $file, $line)
  1488. {
  1489. throw new \ErrorException($message, 0, $type, $file, $line);
  1490. }
  1491. public function __sleep()
  1492. {
  1493. throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  1494. }
  1495. public function __wakeup()
  1496. {
  1497. throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  1498. }
  1499. public function __destruct()
  1500. {
  1501. if (method_exists(parent::class,'__destruct')) {
  1502. parent::__destruct();
  1503. }
  1504. if (null !== $this->tmp && file_exists($this->tmp)) {
  1505. unlink($this->tmp);
  1506. }
  1507. }
  1508. }
  1509. }
  1510. namespace Symfony\Component\Cache\Traits
  1511. {
  1512. use Symfony\Component\Cache\Exception\CacheException;
  1513. trait FilesystemTrait
  1514. {
  1515. use FilesystemCommonTrait;
  1516. public function prune()
  1517. {
  1518. $time = time();
  1519. $pruned = true;
  1520. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
  1521. if (!$h = @fopen($file,'rb')) {
  1522. continue;
  1523. }
  1524. if (($expiresAt = (int) fgets($h)) && $time >= $expiresAt) {
  1525. fclose($h);
  1526. $pruned = @unlink($file) && !file_exists($file) && $pruned;
  1527. } else {
  1528. fclose($h);
  1529. }
  1530. }
  1531. return $pruned;
  1532. }
  1533. protected function doFetch(array $ids)
  1534. {
  1535. $values = [];
  1536. $now = time();
  1537. foreach ($ids as $id) {
  1538. $file = $this->getFile($id);
  1539. if (!file_exists($file) || !$h = @fopen($file,'rb')) {
  1540. continue;
  1541. }
  1542. if (($expiresAt = (int) fgets($h)) && $now >= $expiresAt) {
  1543. fclose($h);
  1544. @unlink($file);
  1545. } else {
  1546. $i = rawurldecode(rtrim(fgets($h)));
  1547. $value = stream_get_contents($h);
  1548. fclose($h);
  1549. if ($i === $id) {
  1550. $values[$id] = parent::unserialize($value);
  1551. }
  1552. }
  1553. }
  1554. return $values;
  1555. }
  1556. protected function doHave($id)
  1557. {
  1558. $file = $this->getFile($id);
  1559. return file_exists($file) && (@filemtime($file) > time() || $this->doFetch([$id]));
  1560. }
  1561. protected function doSave(array $values, $lifetime)
  1562. {
  1563. $ok = true;
  1564. $expiresAt = $lifetime ? (time() + $lifetime) : 0;
  1565. foreach ($values as $id => $value) {
  1566. $ok = $this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".serialize($value), $expiresAt) && $ok;
  1567. }
  1568. if (!$ok && !is_writable($this->directory)) {
  1569. throw new CacheException(sprintf('Cache directory is not writable (%s).', $this->directory));
  1570. }
  1571. return $ok;
  1572. }
  1573. }
  1574. }
  1575. namespace Symfony\Component\Cache\Adapter
  1576. {
  1577. use Symfony\Component\Cache\PruneableInterface;
  1578. use Symfony\Component\Cache\Traits\FilesystemTrait;
  1579. class FilesystemAdapter extends AbstractAdapter implements PruneableInterface
  1580. {
  1581. use FilesystemTrait;
  1582. public function __construct($namespace ='', $defaultLifetime = 0, $directory = null)
  1583. {
  1584. parent::__construct('', $defaultLifetime);
  1585. $this->init($namespace, $directory);
  1586. }
  1587. }
  1588. }
  1589. namespace Psr\Cache
  1590. {
  1591. interface CacheItemInterface
  1592. {
  1593. public function getKey();
  1594. public function get();
  1595. public function isHit();
  1596. public function set($value);
  1597. public function expiresAt($expiration);
  1598. public function expiresAfter($time);
  1599. }
  1600. }
  1601. namespace Symfony\Component\Cache
  1602. {
  1603. use Psr\Cache\CacheItemInterface;
  1604. use Psr\Log\LoggerInterface;
  1605. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  1606. final class CacheItem implements CacheItemInterface
  1607. {
  1608. protected $key;
  1609. protected $value;
  1610. protected $isHit = false;
  1611. protected $expiry;
  1612. protected $tags = [];
  1613. protected $prevTags = [];
  1614. protected $innerItem;
  1615. protected $poolHash;
  1616. public function getKey()
  1617. {
  1618. return $this->key;
  1619. }
  1620. public function get()
  1621. {
  1622. return $this->value;
  1623. }
  1624. public function isHit()
  1625. {
  1626. return $this->isHit;
  1627. }
  1628. public function set($value)
  1629. {
  1630. $this->value = $value;
  1631. return $this;
  1632. }
  1633. public function expiresAt($expiration)
  1634. {
  1635. if (null === $expiration) {
  1636. $this->expiry = null;
  1637. } elseif ($expiration instanceof \DateTimeInterface) {
  1638. $this->expiry = (int) $expiration->format('U');
  1639. } else {
  1640. throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given.', \is_object($expiration) ? \get_class($expiration) : \gettype($expiration)));
  1641. }
  1642. return $this;
  1643. }
  1644. public function expiresAfter($time)
  1645. {
  1646. if (null === $time) {
  1647. $this->expiry = null;
  1648. } elseif ($time instanceof \DateInterval) {
  1649. $this->expiry = (int) \DateTime::createFromFormat('U', time())->add($time)->format('U');
  1650. } elseif (\is_int($time)) {
  1651. $this->expiry = $time + time();
  1652. } else {
  1653. throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($time) ? \get_class($time) : \gettype($time)));
  1654. }
  1655. return $this;
  1656. }
  1657. public function tag($tags)
  1658. {
  1659. if (!\is_array($tags)) {
  1660. $tags = [$tags];
  1661. }
  1662. foreach ($tags as $tag) {
  1663. if (!\is_string($tag)) {
  1664. throw new InvalidArgumentException(sprintf('Cache tag must be string, "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag)));
  1665. }
  1666. if (isset($this->tags[$tag])) {
  1667. continue;
  1668. }
  1669. if (''=== $tag) {
  1670. throw new InvalidArgumentException('Cache tag length must be greater than zero.');
  1671. }
  1672. if (false !== strpbrk($tag,'{}()/\@:')) {
  1673. throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:.', $tag));
  1674. }
  1675. $this->tags[$tag] = $tag;
  1676. }
  1677. return $this;
  1678. }
  1679. public function getPreviousTags()
  1680. {
  1681. return $this->prevTags;
  1682. }
  1683. public static function validateKey($key)
  1684. {
  1685. if (!\is_string($key)) {
  1686. throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  1687. }
  1688. if (''=== $key) {
  1689. throw new InvalidArgumentException('Cache key length must be greater than zero.');
  1690. }
  1691. if (false !== strpbrk($key,'{}()/\@:')) {
  1692. throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters {}()/\@:.', $key));
  1693. }
  1694. return $key;
  1695. }
  1696. public static function log(LoggerInterface $logger = null, $message, $context = [])
  1697. {
  1698. if ($logger) {
  1699. $logger->warning($message, $context);
  1700. } else {
  1701. $replace = [];
  1702. foreach ($context as $k => $v) {
  1703. if (is_scalar($v)) {
  1704. $replace['{'.$k.'}'] = $v;
  1705. }
  1706. }
  1707. @trigger_error(strtr($message, $replace), \E_USER_WARNING);
  1708. }
  1709. }
  1710. }
  1711. }
  1712. namespace Symfony\Component\Routing
  1713. {
  1714. interface RequestContextAwareInterface
  1715. {
  1716. public function setContext(RequestContext $context);
  1717. public function getContext();
  1718. }
  1719. }
  1720. namespace Symfony\Component\Routing\Generator
  1721. {
  1722. use Symfony\Component\Routing\Exception\InvalidParameterException;
  1723. use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
  1724. use Symfony\Component\Routing\Exception\RouteNotFoundException;
  1725. use Symfony\Component\Routing\RequestContextAwareInterface;
  1726. interface UrlGeneratorInterface extends RequestContextAwareInterface
  1727. {
  1728. const ABSOLUTE_URL = 0;
  1729. const ABSOLUTE_PATH = 1;
  1730. const RELATIVE_PATH = 2;
  1731. const NETWORK_PATH = 3;
  1732. public function generate($name, $parameters = [], $referenceType = self::ABSOLUTE_PATH);
  1733. }
  1734. }
  1735. namespace Symfony\Component\Routing\Generator
  1736. {
  1737. interface ConfigurableRequirementsInterface
  1738. {
  1739. public function setStrictRequirements($enabled);
  1740. public function isStrictRequirements();
  1741. }
  1742. }
  1743. namespace Symfony\Component\Routing\Generator
  1744. {
  1745. use Psr\Log\LoggerInterface;
  1746. use Symfony\Component\Routing\Exception\InvalidParameterException;
  1747. use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
  1748. use Symfony\Component\Routing\Exception\RouteNotFoundException;
  1749. use Symfony\Component\Routing\RequestContext;
  1750. use Symfony\Component\Routing\RouteCollection;
  1751. class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInterface
  1752. {
  1753. protected $routes;
  1754. protected $context;
  1755. protected $strictRequirements = true;
  1756. protected $logger;
  1757. protected $decodedChars = ['%2F'=>'/','%40'=>'@','%3A'=>':','%3B'=>';','%2C'=>',','%3D'=>'=','%2B'=>'+','%21'=>'!','%2A'=>'*','%7C'=>'|',
  1758. ];
  1759. public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null)
  1760. {
  1761. $this->routes = $routes;
  1762. $this->context = $context;
  1763. $this->logger = $logger;
  1764. }
  1765. public function setContext(RequestContext $context)
  1766. {
  1767. $this->context = $context;
  1768. }
  1769. public function getContext()
  1770. {
  1771. return $this->context;
  1772. }
  1773. public function setStrictRequirements($enabled)
  1774. {
  1775. $this->strictRequirements = null === $enabled ? null : (bool) $enabled;
  1776. }
  1777. public function isStrictRequirements()
  1778. {
  1779. return $this->strictRequirements;
  1780. }
  1781. public function generate($name, $parameters = [], $referenceType = self::ABSOLUTE_PATH)
  1782. {
  1783. if (null === $route = $this->routes->get($name)) {
  1784. throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
  1785. }
  1786. $compiledRoute = $route->compile();
  1787. return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostTokens(), $route->getSchemes());
  1788. }
  1789. protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, array $requiredSchemes = [])
  1790. {
  1791. $variables = array_flip($variables);
  1792. $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
  1793. if ($diff = array_diff_key($variables, $mergedParams)) {
  1794. throw new MissingMandatoryParametersException(sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', array_keys($diff)), $name));
  1795. }
  1796. $url ='';
  1797. $optional = true;
  1798. $message ='Parameter "{parameter}" for route "{route}" must match "{expected}" ("{given}" given) to generate a corresponding URL.';
  1799. foreach ($tokens as $token) {
  1800. if ('variable'=== $token[0]) {
  1801. if (!$optional || !\array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) {
  1802. if (null !== $this->strictRequirements && !preg_match('#^'.preg_replace('/\(\?(?:=|<=|!|<!)((?:[^()\\\\]+|\\\\.|\((?1)\))*)\)/','', $token[2]).'$#'.(empty($token[4]) ?'':'u'), $mergedParams[$token[3]])) {
  1803. if ($this->strictRequirements) {
  1804. throw new InvalidParameterException(strtr($message, ['{parameter}'=> $token[3],'{route}'=> $name,'{expected}'=> $token[2],'{given}'=> $mergedParams[$token[3]]]));
  1805. }
  1806. if ($this->logger) {
  1807. $this->logger->error($message, ['parameter'=> $token[3],'route'=> $name,'expected'=> $token[2],'given'=> $mergedParams[$token[3]]]);
  1808. }
  1809. return null;
  1810. }
  1811. $url = $token[1].$mergedParams[$token[3]].$url;
  1812. $optional = false;
  1813. }
  1814. } else {
  1815. $url = $token[1].$url;
  1816. $optional = false;
  1817. }
  1818. }
  1819. if (''=== $url) {
  1820. $url ='/';
  1821. }
  1822. $url = strtr(rawurlencode($url), $this->decodedChars);
  1823. $url = strtr($url, ['/../'=>'/%2E%2E/','/./'=>'/%2E/']);
  1824. if ('/..'=== substr($url, -3)) {
  1825. $url = substr($url, 0, -2).'%2E%2E';
  1826. } elseif ('/.'=== substr($url, -2)) {
  1827. $url = substr($url, 0, -1).'%2E';
  1828. }
  1829. $schemeAuthority ='';
  1830. $host = $this->context->getHost();
  1831. $scheme = $this->context->getScheme();
  1832. if ($requiredSchemes) {
  1833. if (!\in_array($scheme, $requiredSchemes, true)) {
  1834. $referenceType = self::ABSOLUTE_URL;
  1835. $scheme = current($requiredSchemes);
  1836. }
  1837. }
  1838. if ($hostTokens) {
  1839. $routeHost ='';
  1840. foreach ($hostTokens as $token) {
  1841. if ('variable'=== $token[0]) {
  1842. if (null !== $this->strictRequirements && !preg_match('#^'.preg_replace('/\(\?(?:=|<=|!|<!)((?:[^()\\\\]+|\\\\.|\((?1)\))*)\)/','', $token[2]).'$#i'.(empty($token[4]) ?'':'u'), $mergedParams[$token[3]])) {
  1843. if ($this->strictRequirements) {
  1844. throw new InvalidParameterException(strtr($message, ['{parameter}'=> $token[3],'{route}'=> $name,'{expected}'=> $token[2],'{given}'=> $mergedParams[$token[3]]]));
  1845. }
  1846. if ($this->logger) {
  1847. $this->logger->error($message, ['parameter'=> $token[3],'route'=> $name,'expected'=> $token[2],'given'=> $mergedParams[$token[3]]]);
  1848. }
  1849. return null;
  1850. }
  1851. $routeHost = $token[1].$mergedParams[$token[3]].$routeHost;
  1852. } else {
  1853. $routeHost = $token[1].$routeHost;
  1854. }
  1855. }
  1856. if ($routeHost !== $host) {
  1857. $host = $routeHost;
  1858. if (self::ABSOLUTE_URL !== $referenceType) {
  1859. $referenceType = self::NETWORK_PATH;
  1860. }
  1861. }
  1862. }
  1863. if (self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) {
  1864. if (''!== $host || (''!== $scheme &&'http'!== $scheme &&'https'!== $scheme)) {
  1865. $port ='';
  1866. if ('http'=== $scheme && 80 !== $this->context->getHttpPort()) {
  1867. $port =':'.$this->context->getHttpPort();
  1868. } elseif ('https'=== $scheme && 443 !== $this->context->getHttpsPort()) {
  1869. $port =':'.$this->context->getHttpsPort();
  1870. }
  1871. $schemeAuthority = self::NETWORK_PATH === $referenceType ||''=== $scheme ?'//': "$scheme://";
  1872. $schemeAuthority .= $host.$port;
  1873. }
  1874. }
  1875. if (self::RELATIVE_PATH === $referenceType) {
  1876. $url = self::getRelativePath($this->context->getPathInfo(), $url);
  1877. } else {
  1878. $url = $schemeAuthority.$this->context->getBaseUrl().$url;
  1879. }
  1880. $extra = array_udiff_assoc(array_diff_key($parameters, $variables), $defaults, function ($a, $b) {
  1881. return $a == $b ? 0 : 1;
  1882. });
  1883. $fragment ='';
  1884. if (isset($defaults['_fragment'])) {
  1885. $fragment = $defaults['_fragment'];
  1886. }
  1887. if (isset($extra['_fragment'])) {
  1888. $fragment = $extra['_fragment'];
  1889. unset($extra['_fragment']);
  1890. }
  1891. if ($extra && $query = http_build_query($extra,'','&', \PHP_QUERY_RFC3986)) {
  1892. $url .='?'.strtr($query, ['%2F'=>'/']);
  1893. }
  1894. if (''!== $fragment) {
  1895. $url .='#'.strtr(rawurlencode($fragment), ['%2F'=>'/','%3F'=>'?']);
  1896. }
  1897. return $url;
  1898. }
  1899. public static function getRelativePath($basePath, $targetPath)
  1900. {
  1901. if ($basePath === $targetPath) {
  1902. return'';
  1903. }
  1904. $sourceDirs = explode('/', isset($basePath[0]) &&'/'=== $basePath[0] ? substr($basePath, 1) : $basePath);
  1905. $targetDirs = explode('/', isset($targetPath[0]) &&'/'=== $targetPath[0] ? substr($targetPath, 1) : $targetPath);
  1906. array_pop($sourceDirs);
  1907. $targetFile = array_pop($targetDirs);
  1908. foreach ($sourceDirs as $i => $dir) {
  1909. if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
  1910. unset($sourceDirs[$i], $targetDirs[$i]);
  1911. } else {
  1912. break;
  1913. }
  1914. }
  1915. $targetDirs[] = $targetFile;
  1916. $path = str_repeat('../', \count($sourceDirs)).implode('/', $targetDirs);
  1917. return''=== $path ||'/'=== $path[0]
  1918. || false !== ($colonPos = strpos($path,':')) && ($colonPos < ($slashPos = strpos($path,'/')) || false === $slashPos)
  1919. ? "./$path" : $path;
  1920. }
  1921. }
  1922. }
  1923. namespace Symfony\Component\Routing
  1924. {
  1925. use Symfony\Component\HttpFoundation\Request;
  1926. class RequestContext
  1927. {
  1928. private $baseUrl;
  1929. private $pathInfo;
  1930. private $method;
  1931. private $host;
  1932. private $scheme;
  1933. private $httpPort;
  1934. private $httpsPort;
  1935. private $queryString;
  1936. private $parameters = [];
  1937. public function __construct($baseUrl ='', $method ='GET', $host ='localhost', $scheme ='http', $httpPort = 80, $httpsPort = 443, $path ='/', $queryString ='')
  1938. {
  1939. $this->setBaseUrl($baseUrl);
  1940. $this->setMethod($method);
  1941. $this->setHost($host);
  1942. $this->setScheme($scheme);
  1943. $this->setHttpPort($httpPort);
  1944. $this->setHttpsPort($httpsPort);
  1945. $this->setPathInfo($path);
  1946. $this->setQueryString($queryString);
  1947. }
  1948. public function fromRequest(Request $request)
  1949. {
  1950. $this->setBaseUrl($request->getBaseUrl());
  1951. $this->setPathInfo($request->getPathInfo());
  1952. $this->setMethod($request->getMethod());
  1953. $this->setHost($request->getHost());
  1954. $this->setScheme($request->getScheme());
  1955. $this->setHttpPort($request->isSecure() || null === $request->getPort() ? $this->httpPort : $request->getPort());
  1956. $this->setHttpsPort($request->isSecure() && null !== $request->getPort() ? $request->getPort() : $this->httpsPort);
  1957. $this->setQueryString($request->server->get('QUERY_STRING',''));
  1958. return $this;
  1959. }
  1960. public function getBaseUrl()
  1961. {
  1962. return $this->baseUrl;
  1963. }
  1964. public function setBaseUrl($baseUrl)
  1965. {
  1966. $this->baseUrl = $baseUrl;
  1967. return $this;
  1968. }
  1969. public function getPathInfo()
  1970. {
  1971. return $this->pathInfo;
  1972. }
  1973. public function setPathInfo($pathInfo)
  1974. {
  1975. $this->pathInfo = $pathInfo;
  1976. return $this;
  1977. }
  1978. public function getMethod()
  1979. {
  1980. return $this->method;
  1981. }
  1982. public function setMethod($method)
  1983. {
  1984. $this->method = strtoupper($method);
  1985. return $this;
  1986. }
  1987. public function getHost()
  1988. {
  1989. return $this->host;
  1990. }
  1991. public function setHost($host)
  1992. {
  1993. $this->host = strtolower($host);
  1994. return $this;
  1995. }
  1996. public function getScheme()
  1997. {
  1998. return $this->scheme;
  1999. }
  2000. public function setScheme($scheme)
  2001. {
  2002. $this->scheme = strtolower($scheme);
  2003. return $this;
  2004. }
  2005. public function getHttpPort()
  2006. {
  2007. return $this->httpPort;
  2008. }
  2009. public function setHttpPort($httpPort)
  2010. {
  2011. $this->httpPort = (int) $httpPort;
  2012. return $this;
  2013. }
  2014. public function getHttpsPort()
  2015. {
  2016. return $this->httpsPort;
  2017. }
  2018. public function setHttpsPort($httpsPort)
  2019. {
  2020. $this->httpsPort = (int) $httpsPort;
  2021. return $this;
  2022. }
  2023. public function getQueryString()
  2024. {
  2025. return $this->queryString;
  2026. }
  2027. public function setQueryString($queryString)
  2028. {
  2029. $this->queryString = (string) $queryString;
  2030. return $this;
  2031. }
  2032. public function getParameters()
  2033. {
  2034. return $this->parameters;
  2035. }
  2036. public function setParameters(array $parameters)
  2037. {
  2038. $this->parameters = $parameters;
  2039. return $this;
  2040. }
  2041. public function getParameter($name)
  2042. {
  2043. return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
  2044. }
  2045. public function hasParameter($name)
  2046. {
  2047. return \array_key_exists($name, $this->parameters);
  2048. }
  2049. public function setParameter($name, $parameter)
  2050. {
  2051. $this->parameters[$name] = $parameter;
  2052. return $this;
  2053. }
  2054. }
  2055. }
  2056. namespace Symfony\Component\Routing\Matcher
  2057. {
  2058. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  2059. use Symfony\Component\Routing\Exception\NoConfigurationException;
  2060. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  2061. use Symfony\Component\Routing\RequestContextAwareInterface;
  2062. interface UrlMatcherInterface extends RequestContextAwareInterface
  2063. {
  2064. public function match($pathinfo);
  2065. }
  2066. }
  2067. namespace Symfony\Component\Routing
  2068. {
  2069. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  2070. use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
  2071. interface RouterInterface extends UrlMatcherInterface, UrlGeneratorInterface
  2072. {
  2073. public function getRouteCollection();
  2074. }
  2075. }
  2076. namespace Symfony\Component\Routing\Matcher
  2077. {
  2078. use Symfony\Component\HttpFoundation\Request;
  2079. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  2080. use Symfony\Component\Routing\Exception\NoConfigurationException;
  2081. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  2082. interface RequestMatcherInterface
  2083. {
  2084. public function matchRequest(Request $request);
  2085. }
  2086. }
  2087. namespace Symfony\Component\Routing
  2088. {
  2089. use Psr\Log\LoggerInterface;
  2090. use Symfony\Component\Config\ConfigCacheFactory;
  2091. use Symfony\Component\Config\ConfigCacheFactoryInterface;
  2092. use Symfony\Component\Config\ConfigCacheInterface;
  2093. use Symfony\Component\Config\Loader\LoaderInterface;
  2094. use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
  2095. use Symfony\Component\HttpFoundation\Request;
  2096. use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface;
  2097. use Symfony\Component\Routing\Generator\Dumper\GeneratorDumperInterface;
  2098. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  2099. use Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface;
  2100. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  2101. use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
  2102. class Router implements RouterInterface, RequestMatcherInterface
  2103. {
  2104. protected $matcher;
  2105. protected $generator;
  2106. protected $context;
  2107. protected $loader;
  2108. protected $collection;
  2109. protected $resource;
  2110. protected $options = [];
  2111. protected $logger;
  2112. private $configCacheFactory;
  2113. private $expressionLanguageProviders = [];
  2114. public function __construct(LoaderInterface $loader, $resource, array $options = [], RequestContext $context = null, LoggerInterface $logger = null)
  2115. {
  2116. $this->loader = $loader;
  2117. $this->resource = $resource;
  2118. $this->logger = $logger;
  2119. $this->context = $context ?: new RequestContext();
  2120. $this->setOptions($options);
  2121. }
  2122. public function setOptions(array $options)
  2123. {
  2124. $this->options = ['cache_dir'=> null,'debug'=> false,'generator_class'=>'Symfony\\Component\\Routing\\Generator\\UrlGenerator','generator_base_class'=>'Symfony\\Component\\Routing\\Generator\\UrlGenerator','generator_dumper_class'=>'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper','generator_cache_class'=>'ProjectUrlGenerator','matcher_class'=>'Symfony\\Component\\Routing\\Matcher\\UrlMatcher','matcher_base_class'=>'Symfony\\Component\\Routing\\Matcher\\UrlMatcher','matcher_dumper_class'=>'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper','matcher_cache_class'=>'ProjectUrlMatcher','resource_type'=> null,'strict_requirements'=> true,
  2125. ];
  2126. $invalid = [];
  2127. foreach ($options as $key => $value) {
  2128. if (\array_key_exists($key, $this->options)) {
  2129. $this->options[$key] = $value;
  2130. } else {
  2131. $invalid[] = $key;
  2132. }
  2133. }
  2134. if ($invalid) {
  2135. throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid)));
  2136. }
  2137. }
  2138. public function setOption($key, $value)
  2139. {
  2140. if (!\array_key_exists($key, $this->options)) {
  2141. throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
  2142. }
  2143. $this->options[$key] = $value;
  2144. }
  2145. public function getOption($key)
  2146. {
  2147. if (!\array_key_exists($key, $this->options)) {
  2148. throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
  2149. }
  2150. return $this->options[$key];
  2151. }
  2152. public function getRouteCollection()
  2153. {
  2154. if (null === $this->collection) {
  2155. $this->collection = $this->loader->load($this->resource, $this->options['resource_type']);
  2156. }
  2157. return $this->collection;
  2158. }
  2159. public function setContext(RequestContext $context)
  2160. {
  2161. $this->context = $context;
  2162. if (null !== $this->matcher) {
  2163. $this->getMatcher()->setContext($context);
  2164. }
  2165. if (null !== $this->generator) {
  2166. $this->getGenerator()->setContext($context);
  2167. }
  2168. }
  2169. public function getContext()
  2170. {
  2171. return $this->context;
  2172. }
  2173. public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)
  2174. {
  2175. $this->configCacheFactory = $configCacheFactory;
  2176. }
  2177. public function generate($name, $parameters = [], $referenceType = self::ABSOLUTE_PATH)
  2178. {
  2179. return $this->getGenerator()->generate($name, $parameters, $referenceType);
  2180. }
  2181. public function match($pathinfo)
  2182. {
  2183. return $this->getMatcher()->match($pathinfo);
  2184. }
  2185. public function matchRequest(Request $request)
  2186. {
  2187. $matcher = $this->getMatcher();
  2188. if (!$matcher instanceof RequestMatcherInterface) {
  2189. return $matcher->match($request->getPathInfo());
  2190. }
  2191. return $matcher->matchRequest($request);
  2192. }
  2193. public function getMatcher()
  2194. {
  2195. if (null !== $this->matcher) {
  2196. return $this->matcher;
  2197. }
  2198. if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) {
  2199. $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context);
  2200. if (method_exists($this->matcher,'addExpressionLanguageProvider')) {
  2201. foreach ($this->expressionLanguageProviders as $provider) {
  2202. $this->matcher->addExpressionLanguageProvider($provider);
  2203. }
  2204. }
  2205. return $this->matcher;
  2206. }
  2207. $cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$this->options['matcher_cache_class'].'.php',
  2208. function (ConfigCacheInterface $cache) {
  2209. $dumper = $this->getMatcherDumperInstance();
  2210. if (method_exists($dumper,'addExpressionLanguageProvider')) {
  2211. foreach ($this->expressionLanguageProviders as $provider) {
  2212. $dumper->addExpressionLanguageProvider($provider);
  2213. }
  2214. }
  2215. $options = ['class'=> $this->options['matcher_cache_class'],'base_class'=> $this->options['matcher_base_class'],
  2216. ];
  2217. $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
  2218. }
  2219. );
  2220. if (!class_exists($this->options['matcher_cache_class'], false)) {
  2221. require_once $cache->getPath();
  2222. }
  2223. return $this->matcher = new $this->options['matcher_cache_class']($this->context);
  2224. }
  2225. public function getGenerator()
  2226. {
  2227. if (null !== $this->generator) {
  2228. return $this->generator;
  2229. }
  2230. if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
  2231. $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger);
  2232. } else {
  2233. $cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$this->options['generator_cache_class'].'.php',
  2234. function (ConfigCacheInterface $cache) {
  2235. $dumper = $this->getGeneratorDumperInstance();
  2236. $options = ['class'=> $this->options['generator_cache_class'],'base_class'=> $this->options['generator_base_class'],
  2237. ];
  2238. $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
  2239. }
  2240. );
  2241. if (!class_exists($this->options['generator_cache_class'], false)) {
  2242. require_once $cache->getPath();
  2243. }
  2244. $this->generator = new $this->options['generator_cache_class']($this->context, $this->logger);
  2245. }
  2246. if ($this->generator instanceof ConfigurableRequirementsInterface) {
  2247. $this->generator->setStrictRequirements($this->options['strict_requirements']);
  2248. }
  2249. return $this->generator;
  2250. }
  2251. public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
  2252. {
  2253. $this->expressionLanguageProviders[] = $provider;
  2254. }
  2255. protected function getGeneratorDumperInstance()
  2256. {
  2257. return new $this->options['generator_dumper_class']($this->getRouteCollection());
  2258. }
  2259. protected function getMatcherDumperInstance()
  2260. {
  2261. return new $this->options['matcher_dumper_class']($this->getRouteCollection());
  2262. }
  2263. private function getConfigCacheFactory()
  2264. {
  2265. if (null === $this->configCacheFactory) {
  2266. $this->configCacheFactory = new ConfigCacheFactory($this->options['debug']);
  2267. }
  2268. return $this->configCacheFactory;
  2269. }
  2270. }
  2271. }
  2272. namespace Symfony\Component\Routing\Matcher
  2273. {
  2274. interface RedirectableUrlMatcherInterface
  2275. {
  2276. public function redirect($path, $route, $scheme = null);
  2277. }
  2278. }
  2279. namespace Symfony\Component\Routing\Matcher
  2280. {
  2281. use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
  2282. use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
  2283. use Symfony\Component\HttpFoundation\Request;
  2284. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  2285. use Symfony\Component\Routing\Exception\NoConfigurationException;
  2286. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  2287. use Symfony\Component\Routing\RequestContext;
  2288. use Symfony\Component\Routing\Route;
  2289. use Symfony\Component\Routing\RouteCollection;
  2290. class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
  2291. {
  2292. const REQUIREMENT_MATCH = 0;
  2293. const REQUIREMENT_MISMATCH = 1;
  2294. const ROUTE_MATCH = 2;
  2295. protected $context;
  2296. protected $allow = [];
  2297. protected $routes;
  2298. protected $request;
  2299. protected $expressionLanguage;
  2300. protected $expressionLanguageProviders = [];
  2301. public function __construct(RouteCollection $routes, RequestContext $context)
  2302. {
  2303. $this->routes = $routes;
  2304. $this->context = $context;
  2305. }
  2306. public function setContext(RequestContext $context)
  2307. {
  2308. $this->context = $context;
  2309. }
  2310. public function getContext()
  2311. {
  2312. return $this->context;
  2313. }
  2314. public function match($pathinfo)
  2315. {
  2316. $this->allow = [];
  2317. if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) {
  2318. return $ret;
  2319. }
  2320. if ('/'=== $pathinfo && !$this->allow) {
  2321. throw new NoConfigurationException();
  2322. }
  2323. throw 0 < \count($this->allow) ? new MethodNotAllowedException(array_unique($this->allow)) : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
  2324. }
  2325. public function matchRequest(Request $request)
  2326. {
  2327. $this->request = $request;
  2328. $ret = $this->match($request->getPathInfo());
  2329. $this->request = null;
  2330. return $ret;
  2331. }
  2332. public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
  2333. {
  2334. $this->expressionLanguageProviders[] = $provider;
  2335. }
  2336. protected function matchCollection($pathinfo, RouteCollection $routes)
  2337. {
  2338. if ('HEAD'=== $method = $this->context->getMethod()) {
  2339. $method ='GET';
  2340. }
  2341. $supportsTrailingSlash ='/'!== $pathinfo &&''!== $pathinfo && $this instanceof RedirectableUrlMatcherInterface;
  2342. foreach ($routes as $name => $route) {
  2343. $compiledRoute = $route->compile();
  2344. $staticPrefix = $compiledRoute->getStaticPrefix();
  2345. $requiredMethods = $route->getMethods();
  2346. if (''=== $staticPrefix || 0 === strpos($pathinfo, $staticPrefix)) {
  2347. } elseif (!$supportsTrailingSlash || ($requiredMethods && !\in_array('GET', $requiredMethods)) ||'GET'!== $method) {
  2348. continue;
  2349. } elseif ('/'=== substr($staticPrefix, -1) && substr($staticPrefix, 0, -1) === $pathinfo) {
  2350. return $this->allow = [];
  2351. } else {
  2352. continue;
  2353. }
  2354. $regex = $compiledRoute->getRegex();
  2355. if ($supportsTrailingSlash && $pos = strpos($regex,'/$')) {
  2356. $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
  2357. $hasTrailingSlash = true;
  2358. } else {
  2359. $hasTrailingSlash = false;
  2360. }
  2361. if (!preg_match($regex, $pathinfo, $matches)) {
  2362. continue;
  2363. }
  2364. if ($hasTrailingSlash &&'/'!== substr($pathinfo, -1)) {
  2365. if ((!$requiredMethods || \in_array('GET', $requiredMethods)) &&'GET'=== $method) {
  2366. return $this->allow = [];
  2367. }
  2368. continue;
  2369. }
  2370. $hostMatches = [];
  2371. if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
  2372. continue;
  2373. }
  2374. $status = $this->handleRouteRequirements($pathinfo, $name, $route);
  2375. if (self::REQUIREMENT_MISMATCH === $status[0]) {
  2376. continue;
  2377. }
  2378. if ($requiredMethods) {
  2379. if (!\in_array($method, $requiredMethods)) {
  2380. if (self::REQUIREMENT_MATCH === $status[0]) {
  2381. $this->allow = array_merge($this->allow, $requiredMethods);
  2382. }
  2383. continue;
  2384. }
  2385. }
  2386. return $this->getAttributes($route, $name, array_replace($matches, $hostMatches, isset($status[1]) ? $status[1] : []));
  2387. }
  2388. return [];
  2389. }
  2390. protected function getAttributes(Route $route, $name, array $attributes)
  2391. {
  2392. $attributes['_route'] = $name;
  2393. return $this->mergeDefaults($attributes, $route->getDefaults());
  2394. }
  2395. protected function handleRouteRequirements($pathinfo, $name, Route $route)
  2396. {
  2397. if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), ['context'=> $this->context,'request'=> $this->request ?: $this->createRequest($pathinfo)])) {
  2398. return [self::REQUIREMENT_MISMATCH, null];
  2399. }
  2400. $scheme = $this->context->getScheme();
  2401. $status = $route->getSchemes() && !$route->hasScheme($scheme) ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH;
  2402. return [$status, null];
  2403. }
  2404. protected function mergeDefaults($params, $defaults)
  2405. {
  2406. foreach ($params as $key => $value) {
  2407. if (!\is_int($key)) {
  2408. $defaults[$key] = $value;
  2409. }
  2410. }
  2411. return $defaults;
  2412. }
  2413. protected function getExpressionLanguage()
  2414. {
  2415. if (null === $this->expressionLanguage) {
  2416. if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
  2417. throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
  2418. }
  2419. $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
  2420. }
  2421. return $this->expressionLanguage;
  2422. }
  2423. protected function createRequest($pathinfo)
  2424. {
  2425. if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
  2426. return null;
  2427. }
  2428. return Request::create($this->context->getScheme().'://'.$this->context->getHost().$this->context->getBaseUrl().$pathinfo, $this->context->getMethod(), $this->context->getParameters(), [], [], ['SCRIPT_FILENAME'=> $this->context->getBaseUrl(),'SCRIPT_NAME'=> $this->context->getBaseUrl(),
  2429. ]);
  2430. }
  2431. }
  2432. }
  2433. namespace Symfony\Component\Routing\Matcher
  2434. {
  2435. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  2436. use Symfony\Component\Routing\Route;
  2437. abstract class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
  2438. {
  2439. public function match($pathinfo)
  2440. {
  2441. try {
  2442. $parameters = parent::match($pathinfo);
  2443. } catch (ResourceNotFoundException $e) {
  2444. if ('/'=== substr($pathinfo, -1) || !\in_array($this->context->getMethod(), ['HEAD','GET'])) {
  2445. throw $e;
  2446. }
  2447. try {
  2448. $parameters = parent::match($pathinfo.'/');
  2449. return array_replace($parameters, $this->redirect($pathinfo.'/', isset($parameters['_route']) ? $parameters['_route'] : null));
  2450. } catch (ResourceNotFoundException $e2) {
  2451. throw $e;
  2452. }
  2453. }
  2454. return $parameters;
  2455. }
  2456. protected function handleRouteRequirements($pathinfo, $name, Route $route)
  2457. {
  2458. if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), ['context'=> $this->context,'request'=> $this->request ?: $this->createRequest($pathinfo)])) {
  2459. return [self::REQUIREMENT_MISMATCH, null];
  2460. }
  2461. $scheme = $this->context->getScheme();
  2462. $schemes = $route->getSchemes();
  2463. if ($schemes && !$route->hasScheme($scheme)) {
  2464. return [self::ROUTE_MATCH, $this->redirect($pathinfo, $name, current($schemes))];
  2465. }
  2466. return [self::REQUIREMENT_MATCH, null];
  2467. }
  2468. }
  2469. }
  2470. namespace Symfony\Bundle\FrameworkBundle\Routing
  2471. {
  2472. use Symfony\Component\Routing\Matcher\RedirectableUrlMatcher as BaseMatcher;
  2473. class RedirectableUrlMatcher extends BaseMatcher
  2474. {
  2475. public function redirect($path, $route, $scheme = null)
  2476. {
  2477. return ['_controller'=>'Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController::urlRedirectAction','path'=> $path,'permanent'=> true,'scheme'=> $scheme,'httpPort'=> $this->context->getHttpPort(),'httpsPort'=> $this->context->getHttpsPort(),'_route'=> $route,
  2478. ];
  2479. }
  2480. }
  2481. }
  2482. namespace Symfony\Component\HttpKernel\CacheWarmer
  2483. {
  2484. interface WarmableInterface
  2485. {
  2486. public function warmUp($cacheDir);
  2487. }
  2488. }
  2489. namespace Symfony\Component\DependencyInjection
  2490. {
  2491. interface ServiceSubscriberInterface
  2492. {
  2493. public static function getSubscribedServices();
  2494. }
  2495. }
  2496. namespace Symfony\Bundle\FrameworkBundle\Routing
  2497. {
  2498. use Symfony\Component\Config\Loader\LoaderInterface;
  2499. use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
  2500. use Symfony\Component\DependencyInjection\ContainerInterface;
  2501. use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
  2502. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  2503. use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
  2504. use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
  2505. use Symfony\Component\Routing\RequestContext;
  2506. use Symfony\Component\Routing\RouteCollection;
  2507. use Symfony\Component\Routing\Router as BaseRouter;
  2508. class Router extends BaseRouter implements WarmableInterface, ServiceSubscriberInterface
  2509. {
  2510. private $container;
  2511. private $collectedParameters = [];
  2512. public function __construct(ContainerInterface $container, $resource, array $options = [], RequestContext $context = null)
  2513. {
  2514. $this->container = $container;
  2515. $this->resource = $resource;
  2516. $this->context = $context ?: new RequestContext();
  2517. $this->setOptions($options);
  2518. }
  2519. public function getRouteCollection()
  2520. {
  2521. if (null === $this->collection) {
  2522. $this->collection = $this->container->get('routing.loader')->load($this->resource, $this->options['resource_type']);
  2523. $this->resolveParameters($this->collection);
  2524. $this->collection->addResource(new ContainerParametersResource($this->collectedParameters));
  2525. }
  2526. return $this->collection;
  2527. }
  2528. public function warmUp($cacheDir)
  2529. {
  2530. $currentDir = $this->getOption('cache_dir');
  2531. $this->setOption('cache_dir', $cacheDir);
  2532. $this->getMatcher();
  2533. $this->getGenerator();
  2534. $this->setOption('cache_dir', $currentDir);
  2535. }
  2536. private function resolveParameters(RouteCollection $collection)
  2537. {
  2538. foreach ($collection as $route) {
  2539. foreach ($route->getDefaults() as $name => $value) {
  2540. $route->setDefault($name, $this->resolve($value));
  2541. }
  2542. foreach ($route->getRequirements() as $name => $value) {
  2543. $route->setRequirement($name, $this->resolve($value));
  2544. }
  2545. $route->setPath($this->resolve($route->getPath()));
  2546. $route->setHost($this->resolve($route->getHost()));
  2547. $schemes = [];
  2548. foreach ($route->getSchemes() as $scheme) {
  2549. $schemes = array_merge($schemes, explode('|', $this->resolve($scheme)));
  2550. }
  2551. $route->setSchemes($schemes);
  2552. $methods = [];
  2553. foreach ($route->getMethods() as $method) {
  2554. $methods = array_merge($methods, explode('|', $this->resolve($method)));
  2555. }
  2556. $route->setMethods($methods);
  2557. $route->setCondition($this->resolve($route->getCondition()));
  2558. }
  2559. }
  2560. private function resolve($value)
  2561. {
  2562. if (\is_array($value)) {
  2563. foreach ($value as $key => $val) {
  2564. $value[$key] = $this->resolve($val);
  2565. }
  2566. return $value;
  2567. }
  2568. if (!\is_string($value)) {
  2569. return $value;
  2570. }
  2571. $container = $this->container;
  2572. $escapedValue = preg_replace_callback('/%%|%([^%\s]++)%/', function ($match) use ($container, $value) {
  2573. if (!isset($match[1])) {
  2574. return'%%';
  2575. }
  2576. if (preg_match('/^env\((?:\w++:)*+\w++\)$/', $match[1])) {
  2577. throw new RuntimeException(sprintf('Using "%%%s%%" is not allowed in routing configuration.', $match[1]));
  2578. }
  2579. $resolved = $container->getParameter($match[1]);
  2580. if (\is_string($resolved) || is_numeric($resolved)) {
  2581. $this->collectedParameters[$match[1]] = $resolved;
  2582. return (string) $this->resolve($resolved);
  2583. }
  2584. throw new RuntimeException(sprintf('The container parameter "%s", used in the route configuration value "%s", must be a string or numeric, but it is of type "%s".', $match[1], $value, \gettype($resolved)));
  2585. }, $value);
  2586. return str_replace('%%','%', $escapedValue);
  2587. }
  2588. public static function getSubscribedServices()
  2589. {
  2590. return ['routing.loader'=> LoaderInterface::class,
  2591. ];
  2592. }
  2593. }
  2594. }
  2595. namespace Symfony\Component\Cache\Traits
  2596. {
  2597. use Symfony\Component\Cache\PruneableInterface;
  2598. use Symfony\Component\Cache\ResettableInterface;
  2599. trait ProxyTrait
  2600. {
  2601. private $pool;
  2602. public function prune()
  2603. {
  2604. return $this->pool instanceof PruneableInterface && $this->pool->prune();
  2605. }
  2606. public function reset()
  2607. {
  2608. if ($this->pool instanceof ResettableInterface) {
  2609. $this->pool->reset();
  2610. }
  2611. }
  2612. }
  2613. }
  2614. namespace Symfony\Component\Cache\Traits
  2615. {
  2616. use Symfony\Component\Cache\CacheItem;
  2617. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  2618. trait PhpArrayTrait
  2619. {
  2620. use ProxyTrait;
  2621. private $file;
  2622. private $values;
  2623. private $zendDetectUnicode;
  2624. private static $valuesCache = [];
  2625. public function warmUp(array $values)
  2626. {
  2627. if (file_exists($this->file)) {
  2628. if (!is_file($this->file)) {
  2629. throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: "%s".', $this->file));
  2630. }
  2631. if (!is_writable($this->file)) {
  2632. throw new InvalidArgumentException(sprintf('Cache file is not writable: "%s".', $this->file));
  2633. }
  2634. } else {
  2635. $directory = \dirname($this->file);
  2636. if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
  2637. throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: "%s".', $directory));
  2638. }
  2639. if (!is_writable($directory)) {
  2640. throw new InvalidArgumentException(sprintf('Cache directory is not writable: "%s".', $directory));
  2641. }
  2642. }
  2643. $dump =<<<'EOF'
  2644. <?php
  2645. // This file has been auto-generated by the Symfony Cache Component.
  2646. return [
  2647. EOF
  2648. ;
  2649. foreach ($values as $key => $value) {
  2650. CacheItem::validateKey(\is_int($key) ? (string) $key : $key);
  2651. if (null === $value || \is_object($value)) {
  2652. try {
  2653. $value = serialize($value);
  2654. } catch (\Exception $e) {
  2655. throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \get_class($value)), 0, $e);
  2656. }
  2657. } elseif (\is_array($value)) {
  2658. try {
  2659. $serialized = serialize($value);
  2660. $unserialized = unserialize($serialized);
  2661. } catch (\Exception $e) {
  2662. throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
  2663. }
  2664. if ($unserialized !== $value || (false !== strpos($serialized,';R:') && preg_match('/;R:[1-9]/', $serialized))) {
  2665. $value = $serialized;
  2666. }
  2667. } elseif (\is_string($value)) {
  2668. if ('N;'=== $value || (isset($value[2]) &&':'=== $value[1])) {
  2669. $value = serialize($value);
  2670. }
  2671. } elseif (!is_scalar($value)) {
  2672. throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \gettype($value)));
  2673. }
  2674. $dump .= var_export($key, true).' => '.var_export($value, true).",\n";
  2675. }
  2676. $dump .="\n];\n";
  2677. $dump = str_replace("' . \"\\0\" . '","\0", $dump);
  2678. $tmpFile = uniqid($this->file, true);
  2679. file_put_contents($tmpFile, $dump);
  2680. @chmod($tmpFile, 0666 & ~umask());
  2681. unset($serialized, $unserialized, $value, $dump);
  2682. @rename($tmpFile, $this->file);
  2683. unset(self::$valuesCache[$this->file]);
  2684. $this->initialize();
  2685. }
  2686. public function clear()
  2687. {
  2688. $this->values = [];
  2689. $cleared = @unlink($this->file) || !file_exists($this->file);
  2690. unset(self::$valuesCache[$this->file]);
  2691. return $this->pool->clear() && $cleared;
  2692. }
  2693. private function initialize()
  2694. {
  2695. if (isset(self::$valuesCache[$this->file])) {
  2696. $this->values = self::$valuesCache[$this->file];
  2697. return;
  2698. }
  2699. if ($this->zendDetectUnicode) {
  2700. $zmb = ini_set('zend.detect_unicode', 0);
  2701. }
  2702. try {
  2703. $this->values = self::$valuesCache[$this->file] = file_exists($this->file) ? (include $this->file ?: []) : [];
  2704. } finally {
  2705. if ($this->zendDetectUnicode) {
  2706. ini_set('zend.detect_unicode', $zmb);
  2707. }
  2708. }
  2709. }
  2710. }
  2711. }
  2712. namespace Symfony\Component\Cache\Adapter
  2713. {
  2714. use Psr\Cache\CacheItemInterface;
  2715. use Psr\Cache\CacheItemPoolInterface;
  2716. use Symfony\Component\Cache\CacheItem;
  2717. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  2718. use Symfony\Component\Cache\PruneableInterface;
  2719. use Symfony\Component\Cache\ResettableInterface;
  2720. use Symfony\Component\Cache\Traits\PhpArrayTrait;
  2721. class PhpArrayAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
  2722. {
  2723. use PhpArrayTrait;
  2724. private $createCacheItem;
  2725. public function __construct($file, AdapterInterface $fallbackPool)
  2726. {
  2727. $this->file = $file;
  2728. $this->pool = $fallbackPool;
  2729. $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN);
  2730. $this->createCacheItem = \Closure::bind(
  2731. static function ($key, $value, $isHit) {
  2732. $item = new CacheItem();
  2733. $item->key = $key;
  2734. $item->value = $value;
  2735. $item->isHit = $isHit;
  2736. return $item;
  2737. },
  2738. null,
  2739. CacheItem::class
  2740. );
  2741. }
  2742. public static function create($file, CacheItemPoolInterface $fallbackPool)
  2743. {
  2744. if (\PHP_VERSION_ID >= 70000) {
  2745. if (!$fallbackPool instanceof AdapterInterface) {
  2746. $fallbackPool = new ProxyAdapter($fallbackPool);
  2747. }
  2748. return new static($file, $fallbackPool);
  2749. }
  2750. return $fallbackPool;
  2751. }
  2752. public function getItem($key)
  2753. {
  2754. if (!\is_string($key)) {
  2755. throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  2756. }
  2757. if (null === $this->values) {
  2758. $this->initialize();
  2759. }
  2760. if (!isset($this->values[$key])) {
  2761. return $this->pool->getItem($key);
  2762. }
  2763. $value = $this->values[$key];
  2764. $isHit = true;
  2765. if ('N;'=== $value) {
  2766. $value = null;
  2767. } elseif (\is_string($value) && isset($value[2]) &&':'=== $value[1]) {
  2768. try {
  2769. $e = null;
  2770. $value = unserialize($value);
  2771. } catch (\Error $e) {
  2772. } catch (\Exception $e) {
  2773. }
  2774. if (null !== $e) {
  2775. $value = null;
  2776. $isHit = false;
  2777. }
  2778. }
  2779. $f = $this->createCacheItem;
  2780. return $f($key, $value, $isHit);
  2781. }
  2782. public function getItems(array $keys = [])
  2783. {
  2784. foreach ($keys as $key) {
  2785. if (!\is_string($key)) {
  2786. throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  2787. }
  2788. }
  2789. if (null === $this->values) {
  2790. $this->initialize();
  2791. }
  2792. return $this->generateItems($keys);
  2793. }
  2794. public function hasItem($key)
  2795. {
  2796. if (!\is_string($key)) {
  2797. throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  2798. }
  2799. if (null === $this->values) {
  2800. $this->initialize();
  2801. }
  2802. return isset($this->values[$key]) || $this->pool->hasItem($key);
  2803. }
  2804. public function deleteItem($key)
  2805. {
  2806. if (!\is_string($key)) {
  2807. throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  2808. }
  2809. if (null === $this->values) {
  2810. $this->initialize();
  2811. }
  2812. return !isset($this->values[$key]) && $this->pool->deleteItem($key);
  2813. }
  2814. public function deleteItems(array $keys)
  2815. {
  2816. $deleted = true;
  2817. $fallbackKeys = [];
  2818. foreach ($keys as $key) {
  2819. if (!\is_string($key)) {
  2820. throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  2821. }
  2822. if (isset($this->values[$key])) {
  2823. $deleted = false;
  2824. } else {
  2825. $fallbackKeys[] = $key;
  2826. }
  2827. }
  2828. if (null === $this->values) {
  2829. $this->initialize();
  2830. }
  2831. if ($fallbackKeys) {
  2832. $deleted = $this->pool->deleteItems($fallbackKeys) && $deleted;
  2833. }
  2834. return $deleted;
  2835. }
  2836. public function save(CacheItemInterface $item)
  2837. {
  2838. if (null === $this->values) {
  2839. $this->initialize();
  2840. }
  2841. return !isset($this->values[$item->getKey()]) && $this->pool->save($item);
  2842. }
  2843. public function saveDeferred(CacheItemInterface $item)
  2844. {
  2845. if (null === $this->values) {
  2846. $this->initialize();
  2847. }
  2848. return !isset($this->values[$item->getKey()]) && $this->pool->saveDeferred($item);
  2849. }
  2850. public function commit()
  2851. {
  2852. return $this->pool->commit();
  2853. }
  2854. private function generateItems(array $keys)
  2855. {
  2856. $f = $this->createCacheItem;
  2857. $fallbackKeys = [];
  2858. foreach ($keys as $key) {
  2859. if (isset($this->values[$key])) {
  2860. $value = $this->values[$key];
  2861. if ('N;'=== $value) {
  2862. yield $key => $f($key, null, true);
  2863. } elseif (\is_string($value) && isset($value[2]) &&':'=== $value[1]) {
  2864. try {
  2865. yield $key => $f($key, unserialize($value), true);
  2866. } catch (\Error $e) {
  2867. yield $key => $f($key, null, false);
  2868. } catch (\Exception $e) {
  2869. yield $key => $f($key, null, false);
  2870. }
  2871. } else {
  2872. yield $key => $f($key, $value, true);
  2873. }
  2874. } else {
  2875. $fallbackKeys[] = $key;
  2876. }
  2877. }
  2878. if ($fallbackKeys) {
  2879. foreach ($this->pool->getItems($fallbackKeys) as $key => $item) {
  2880. yield $key => $item;
  2881. }
  2882. }
  2883. }
  2884. public static function throwOnRequiredClass($class)
  2885. {
  2886. $e = new \ReflectionException("Class $class does not exist");
  2887. $trace = debug_backtrace();
  2888. $autoloadFrame = ['function'=>'spl_autoload_call','args'=> [$class],
  2889. ];
  2890. if (\PHP_VERSION_ID >= 80000 && isset($trace[1])) {
  2891. $callerFrame = $trace[1];
  2892. } elseif (false !== $i = array_search($autoloadFrame, $trace, true)) {
  2893. $callerFrame = $trace[++$i];
  2894. } else {
  2895. throw $e;
  2896. }
  2897. if (isset($callerFrame['function']) && !isset($callerFrame['class'])) {
  2898. switch ($callerFrame['function']) {
  2899. case'get_class_methods':
  2900. case'get_class_vars':
  2901. case'get_parent_class':
  2902. case'is_a':
  2903. case'is_subclass_of':
  2904. case'class_exists':
  2905. case'class_implements':
  2906. case'class_parents':
  2907. case'trait_exists':
  2908. case'defined':
  2909. case'interface_exists':
  2910. case'method_exists':
  2911. case'property_exists':
  2912. case'is_callable':
  2913. return;
  2914. }
  2915. }
  2916. throw $e;
  2917. }
  2918. }
  2919. }
  2920. namespace Doctrine\Common\Cache
  2921. {
  2922. interface MultiPutCache
  2923. {
  2924. function saveMultiple(array $keysAndValues, $lifetime = 0);
  2925. }
  2926. }
  2927. namespace Doctrine\Common\Cache
  2928. {
  2929. interface MultiGetCache
  2930. {
  2931. function fetchMultiple(array $keys);
  2932. }
  2933. }
  2934. namespace Doctrine\Common\Cache
  2935. {
  2936. interface ClearableCache
  2937. {
  2938. public function deleteAll();
  2939. }
  2940. }
  2941. namespace Doctrine\Common\Cache
  2942. {
  2943. interface FlushableCache
  2944. {
  2945. public function flushAll();
  2946. }
  2947. }
  2948. namespace Doctrine\Common\Cache
  2949. {
  2950. interface Cache
  2951. {
  2952. const STATS_HITS ='hits';
  2953. const STATS_MISSES ='misses';
  2954. const STATS_UPTIME ='uptime';
  2955. const STATS_MEMORY_USAGE ='memory_usage';
  2956. const STATS_MEMORY_AVAILABLE ='memory_available';
  2957. const STATS_MEMORY_AVAILIABLE ='memory_available';
  2958. public function fetch($id);
  2959. public function contains($id);
  2960. public function save($id, $data, $lifeTime = 0);
  2961. public function delete($id);
  2962. public function getStats();
  2963. }
  2964. }
  2965. namespace Doctrine\Common\Cache
  2966. {
  2967. abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, MultiGetCache, MultiPutCache
  2968. {
  2969. const DOCTRINE_NAMESPACE_CACHEKEY ='DoctrineNamespaceCacheKey[%s]';
  2970. private $namespace ='';
  2971. private $namespaceVersion;
  2972. public function setNamespace($namespace)
  2973. {
  2974. $this->namespace = (string) $namespace;
  2975. $this->namespaceVersion = null;
  2976. }
  2977. public function getNamespace()
  2978. {
  2979. return $this->namespace;
  2980. }
  2981. public function fetch($id)
  2982. {
  2983. return $this->doFetch($this->getNamespacedId($id));
  2984. }
  2985. public function fetchMultiple(array $keys)
  2986. {
  2987. if (empty($keys)) {
  2988. return array();
  2989. }
  2990. $namespacedKeys = array_combine($keys, array_map(array($this,'getNamespacedId'), $keys));
  2991. $items = $this->doFetchMultiple($namespacedKeys);
  2992. $foundItems = array();
  2993. foreach ($namespacedKeys as $requestedKey => $namespacedKey) {
  2994. if (isset($items[$namespacedKey]) || array_key_exists($namespacedKey, $items)) {
  2995. $foundItems[$requestedKey] = $items[$namespacedKey];
  2996. }
  2997. }
  2998. return $foundItems;
  2999. }
  3000. public function saveMultiple(array $keysAndValues, $lifetime = 0)
  3001. {
  3002. $namespacedKeysAndValues = array();
  3003. foreach ($keysAndValues as $key => $value) {
  3004. $namespacedKeysAndValues[$this->getNamespacedId($key)] = $value;
  3005. }
  3006. return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime);
  3007. }
  3008. public function contains($id)
  3009. {
  3010. return $this->doContains($this->getNamespacedId($id));
  3011. }
  3012. public function save($id, $data, $lifeTime = 0)
  3013. {
  3014. return $this->doSave($this->getNamespacedId($id), $data, $lifeTime);
  3015. }
  3016. public function delete($id)
  3017. {
  3018. return $this->doDelete($this->getNamespacedId($id));
  3019. }
  3020. public function getStats()
  3021. {
  3022. return $this->doGetStats();
  3023. }
  3024. public function flushAll()
  3025. {
  3026. return $this->doFlush();
  3027. }
  3028. public function deleteAll()
  3029. {
  3030. $namespaceCacheKey = $this->getNamespaceCacheKey();
  3031. $namespaceVersion = $this->getNamespaceVersion() + 1;
  3032. if ($this->doSave($namespaceCacheKey, $namespaceVersion)) {
  3033. $this->namespaceVersion = $namespaceVersion;
  3034. return true;
  3035. }
  3036. return false;
  3037. }
  3038. private function getNamespacedId($id)
  3039. {
  3040. $namespaceVersion = $this->getNamespaceVersion();
  3041. return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion);
  3042. }
  3043. private function getNamespaceCacheKey()
  3044. {
  3045. return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
  3046. }
  3047. private function getNamespaceVersion()
  3048. {
  3049. if (null !== $this->namespaceVersion) {
  3050. return $this->namespaceVersion;
  3051. }
  3052. $namespaceCacheKey = $this->getNamespaceCacheKey();
  3053. $this->namespaceVersion = $this->doFetch($namespaceCacheKey) ?: 1;
  3054. return $this->namespaceVersion;
  3055. }
  3056. protected function doFetchMultiple(array $keys)
  3057. {
  3058. $returnValues = array();
  3059. foreach ($keys as $key) {
  3060. if (false !== ($item = $this->doFetch($key)) || $this->doContains($key)) {
  3061. $returnValues[$key] = $item;
  3062. }
  3063. }
  3064. return $returnValues;
  3065. }
  3066. abstract protected function doFetch($id);
  3067. abstract protected function doContains($id);
  3068. protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
  3069. {
  3070. $success = true;
  3071. foreach ($keysAndValues as $key => $value) {
  3072. if (!$this->doSave($key, $value, $lifetime)) {
  3073. $success = false;
  3074. }
  3075. }
  3076. return $success;
  3077. }
  3078. abstract protected function doSave($id, $data, $lifeTime = 0);
  3079. abstract protected function doDelete($id);
  3080. abstract protected function doFlush();
  3081. abstract protected function doGetStats();
  3082. }
  3083. }
  3084. namespace Symfony\Component\Cache
  3085. {
  3086. use Doctrine\Common\Cache\CacheProvider;
  3087. use Psr\Cache\CacheItemPoolInterface;
  3088. class DoctrineProvider extends CacheProvider implements PruneableInterface, ResettableInterface
  3089. {
  3090. private $pool;
  3091. public function __construct(CacheItemPoolInterface $pool)
  3092. {
  3093. $this->pool = $pool;
  3094. }
  3095. public function prune()
  3096. {
  3097. return $this->pool instanceof PruneableInterface && $this->pool->prune();
  3098. }
  3099. public function reset()
  3100. {
  3101. if ($this->pool instanceof ResettableInterface) {
  3102. $this->pool->reset();
  3103. }
  3104. $this->setNamespace($this->getNamespace());
  3105. }
  3106. protected function doFetch($id)
  3107. {
  3108. $item = $this->pool->getItem(rawurlencode($id));
  3109. return $item->isHit() ? $item->get() : false;
  3110. }
  3111. protected function doContains($id)
  3112. {
  3113. return $this->pool->hasItem(rawurlencode($id));
  3114. }
  3115. protected function doSave($id, $data, $lifeTime = 0)
  3116. {
  3117. $item = $this->pool->getItem(rawurlencode($id));
  3118. if (0 < $lifeTime) {
  3119. $item->expiresAfter($lifeTime);
  3120. }
  3121. return $this->pool->save($item->set($data));
  3122. }
  3123. protected function doDelete($id)
  3124. {
  3125. return $this->pool->deleteItem(rawurlencode($id));
  3126. }
  3127. protected function doFlush()
  3128. {
  3129. return $this->pool->clear();
  3130. }
  3131. protected function doGetStats()
  3132. {
  3133. return null;
  3134. }
  3135. }
  3136. }
  3137. namespace Symfony\Component\Config
  3138. {
  3139. use Symfony\Component\Config\Resource\ResourceInterface;
  3140. interface ConfigCacheInterface
  3141. {
  3142. public function getPath();
  3143. public function isFresh();
  3144. public function write($content, array $metadata = null);
  3145. }
  3146. }
  3147. namespace {require __DIR__.'/../../../../versions/b2c15_7b7c4073/vendor/symfony/symfony/src/Symfony/Component/Config/ResourceCheckerConfigCache.php';}
  3148. namespace Symfony\Component\Config
  3149. {
  3150. use Symfony\Component\Config\Resource\SelfCheckingResourceChecker;
  3151. class ConfigCache extends ResourceCheckerConfigCache
  3152. {
  3153. private $debug;
  3154. public function __construct($file, $debug)
  3155. {
  3156. $this->debug = (bool) $debug;
  3157. $checkers = [];
  3158. if (true === $this->debug) {
  3159. $checkers = [new SelfCheckingResourceChecker()];
  3160. }
  3161. parent::__construct($file, $checkers);
  3162. }
  3163. public function isFresh()
  3164. {
  3165. if (!$this->debug && is_file($this->getPath())) {
  3166. return true;
  3167. }
  3168. return parent::isFresh();
  3169. }
  3170. }
  3171. }
  3172. namespace Symfony\Component\Config
  3173. {
  3174. use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
  3175. class FileLocator implements FileLocatorInterface
  3176. {
  3177. protected $paths;
  3178. public function __construct($paths = [])
  3179. {
  3180. $this->paths = (array) $paths;
  3181. }
  3182. public function locate($name, $currentPath = null, $first = true)
  3183. {
  3184. if (''== $name) {
  3185. throw new \InvalidArgumentException('An empty file name is not valid to be located.');
  3186. }
  3187. if ($this->isAbsolutePath($name)) {
  3188. if (!file_exists($name)) {
  3189. throw new FileLocatorFileNotFoundException(sprintf('The file "%s" does not exist.', $name), 0, null, [$name]);
  3190. }
  3191. return $name;
  3192. }
  3193. $paths = $this->paths;
  3194. if (null !== $currentPath) {
  3195. array_unshift($paths, $currentPath);
  3196. }
  3197. $paths = array_unique($paths);
  3198. $filepaths = $notfound = [];
  3199. foreach ($paths as $path) {
  3200. if (@file_exists($file = $path.\DIRECTORY_SEPARATOR.$name)) {
  3201. if (true === $first) {
  3202. return $file;
  3203. }
  3204. $filepaths[] = $file;
  3205. } else {
  3206. $notfound[] = $file;
  3207. }
  3208. }
  3209. if (!$filepaths) {
  3210. throw new FileLocatorFileNotFoundException(sprintf('The file "%s" does not exist (in: "%s").', $name, implode('", "', $paths)), 0, null, $notfound);
  3211. }
  3212. return $filepaths;
  3213. }
  3214. private function isAbsolutePath($file)
  3215. {
  3216. if ('/'=== $file[0] ||'\\'=== $file[0]
  3217. || (\strlen($file) > 3 && ctype_alpha($file[0])
  3218. &&':'=== $file[1]
  3219. && ('\\'=== $file[2] ||'/'=== $file[2])
  3220. )
  3221. || null !== parse_url($file, \PHP_URL_SCHEME)
  3222. ) {
  3223. return true;
  3224. }
  3225. return false;
  3226. }
  3227. }
  3228. }
  3229. namespace Symfony\Component\DependencyInjection
  3230. {
  3231. interface ContainerAwareInterface
  3232. {
  3233. public function setContainer(ContainerInterface $container = null);
  3234. }
  3235. }
  3236. namespace Psr\Container
  3237. {
  3238. interface ContainerInterface
  3239. {
  3240. public function get($id);
  3241. public function has($id);
  3242. }
  3243. }
  3244. namespace Symfony\Component\DependencyInjection
  3245. {
  3246. use Psr\Container\ContainerInterface as PsrContainerInterface;
  3247. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  3248. use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  3249. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  3250. interface ContainerInterface extends PsrContainerInterface
  3251. {
  3252. const EXCEPTION_ON_INVALID_REFERENCE = 1;
  3253. const NULL_ON_INVALID_REFERENCE = 2;
  3254. const IGNORE_ON_INVALID_REFERENCE = 3;
  3255. const IGNORE_ON_UNINITIALIZED_REFERENCE = 4;
  3256. public function set($id, $service);
  3257. public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE);
  3258. public function has($id);
  3259. public function initialized($id);
  3260. public function getParameter($name);
  3261. public function hasParameter($name);
  3262. public function setParameter($name, $value);
  3263. }
  3264. }
  3265. namespace Symfony\Component\DependencyInjection
  3266. {
  3267. interface ResettableContainerInterface extends ContainerInterface
  3268. {
  3269. public function reset();
  3270. }
  3271. }
  3272. namespace Symfony\Component\DependencyInjection
  3273. {
  3274. use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
  3275. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  3276. use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
  3277. use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  3278. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  3279. use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
  3280. use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
  3281. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  3282. class Container implements ResettableContainerInterface
  3283. {
  3284. protected $parameterBag;
  3285. protected $services = [];
  3286. protected $fileMap = [];
  3287. protected $methodMap = [];
  3288. protected $aliases = [];
  3289. protected $loading = [];
  3290. protected $resolving = [];
  3291. protected $syntheticIds = [];
  3292. protected $privates = [];
  3293. protected $normalizedIds = [];
  3294. private $underscoreMap = ['_'=>'','.'=>'_','\\'=>'_'];
  3295. private $envCache = [];
  3296. private $compiled = false;
  3297. private $getEnv;
  3298. public function __construct(ParameterBagInterface $parameterBag = null)
  3299. {
  3300. $this->parameterBag = $parameterBag ?: new EnvPlaceholderParameterBag();
  3301. }
  3302. public function compile()
  3303. {
  3304. $this->parameterBag->resolve();
  3305. $this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
  3306. $this->compiled = true;
  3307. }
  3308. public function isCompiled()
  3309. {
  3310. return $this->compiled;
  3311. }
  3312. public function isFrozen()
  3313. {
  3314. @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), \E_USER_DEPRECATED);
  3315. return $this->parameterBag instanceof FrozenParameterBag;
  3316. }
  3317. public function getParameterBag()
  3318. {
  3319. return $this->parameterBag;
  3320. }
  3321. public function getParameter($name)
  3322. {
  3323. return $this->parameterBag->get($name);
  3324. }
  3325. public function hasParameter($name)
  3326. {
  3327. return $this->parameterBag->has($name);
  3328. }
  3329. public function setParameter($name, $value)
  3330. {
  3331. $this->parameterBag->set($name, $value);
  3332. }
  3333. public function set($id, $service)
  3334. {
  3335. if (isset($this->privates['service_container']) && $this->privates['service_container'] instanceof \Closure) {
  3336. $initialize = $this->privates['service_container'];
  3337. unset($this->privates['service_container']);
  3338. $initialize();
  3339. }
  3340. $id = $this->normalizeId($id);
  3341. if ('service_container'=== $id) {
  3342. throw new InvalidArgumentException('You cannot set service "service_container".');
  3343. }
  3344. if (isset($this->privates[$id]) || !(isset($this->fileMap[$id]) || isset($this->methodMap[$id]))) {
  3345. if (!isset($this->privates[$id]) && !isset($this->getRemovedIds()[$id])) {
  3346. } elseif (null === $service) {
  3347. @trigger_error(sprintf('The "%s" service is private, unsetting it is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
  3348. unset($this->privates[$id]);
  3349. } else {
  3350. @trigger_error(sprintf('The "%s" service is private, replacing it is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
  3351. }
  3352. } elseif (isset($this->services[$id])) {
  3353. if (null === $service) {
  3354. @trigger_error(sprintf('The "%s" service is already initialized, unsetting it is deprecated since Symfony 3.3 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
  3355. } else {
  3356. @trigger_error(sprintf('The "%s" service is already initialized, replacing it is deprecated since Symfony 3.3 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
  3357. }
  3358. }
  3359. if (isset($this->aliases[$id])) {
  3360. unset($this->aliases[$id]);
  3361. }
  3362. if (null === $service) {
  3363. unset($this->services[$id]);
  3364. return;
  3365. }
  3366. $this->services[$id] = $service;
  3367. }
  3368. public function has($id)
  3369. {
  3370. for ($i = 2;;) {
  3371. if (isset($this->privates[$id])) {
  3372. @trigger_error(sprintf('The "%s" service is private, checking for its existence is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
  3373. }
  3374. if (isset($this->aliases[$id])) {
  3375. $id = $this->aliases[$id];
  3376. }
  3377. if (isset($this->services[$id])) {
  3378. return true;
  3379. }
  3380. if ('service_container'=== $id) {
  3381. return true;
  3382. }
  3383. if (isset($this->fileMap[$id]) || isset($this->methodMap[$id])) {
  3384. return true;
  3385. }
  3386. if (--$i && $id !== $normalizedId = $this->normalizeId($id)) {
  3387. $id = $normalizedId;
  3388. continue;
  3389. }
  3390. if (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class && method_exists($this,'get'.strtr($id, $this->underscoreMap).'Service')) {
  3391. @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED);
  3392. return true;
  3393. }
  3394. return false;
  3395. }
  3396. }
  3397. public function get($id, $invalidBehavior = 1)
  3398. {
  3399. for ($i = 2;;) {
  3400. if (isset($this->privates[$id])) {
  3401. @trigger_error(sprintf('The "%s" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead.', $id), \E_USER_DEPRECATED);
  3402. }
  3403. if (isset($this->aliases[$id])) {
  3404. $id = $this->aliases[$id];
  3405. }
  3406. if (isset($this->services[$id])) {
  3407. return $this->services[$id];
  3408. }
  3409. if ('service_container'=== $id) {
  3410. return $this;
  3411. }
  3412. if (isset($this->loading[$id])) {
  3413. throw new ServiceCircularReferenceException($id, array_merge(array_keys($this->loading), [$id]));
  3414. }
  3415. $this->loading[$id] = true;
  3416. try {
  3417. if (isset($this->fileMap[$id])) {
  3418. return 4 === $invalidBehavior ? null : $this->load($this->fileMap[$id]);
  3419. } elseif (isset($this->methodMap[$id])) {
  3420. return 4 === $invalidBehavior ? null : $this->{$this->methodMap[$id]}();
  3421. } elseif (--$i && $id !== $normalizedId = $this->normalizeId($id)) {
  3422. unset($this->loading[$id]);
  3423. $id = $normalizedId;
  3424. continue;
  3425. } elseif (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class && method_exists($this, $method ='get'.strtr($id, $this->underscoreMap).'Service')) {
  3426. @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED);
  3427. return 4 === $invalidBehavior ? null : $this->{$method}();
  3428. }
  3429. break;
  3430. } catch (\Exception $e) {
  3431. unset($this->services[$id]);
  3432. throw $e;
  3433. } finally {
  3434. unset($this->loading[$id]);
  3435. }
  3436. }
  3437. if ( 1 === $invalidBehavior) {
  3438. if (!$id) {
  3439. throw new ServiceNotFoundException($id);
  3440. }
  3441. if (isset($this->syntheticIds[$id])) {
  3442. throw new ServiceNotFoundException($id, null, null, [], sprintf('The "%s" service is synthetic, it needs to be set at boot time before it can be used.', $id));
  3443. }
  3444. if (isset($this->getRemovedIds()[$id])) {
  3445. throw new ServiceNotFoundException($id, null, null, [], sprintf('The "%s" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.', $id));
  3446. }
  3447. $alternatives = [];
  3448. foreach ($this->getServiceIds() as $knownId) {
  3449. $lev = levenshtein($id, $knownId);
  3450. if ($lev <= \strlen($id) / 3 || false !== strpos($knownId, $id)) {
  3451. $alternatives[] = $knownId;
  3452. }
  3453. }
  3454. throw new ServiceNotFoundException($id, null, null, $alternatives);
  3455. }
  3456. }
  3457. public function initialized($id)
  3458. {
  3459. $id = $this->normalizeId($id);
  3460. if (isset($this->privates[$id])) {
  3461. @trigger_error(sprintf('Checking for the initialization of the "%s" private service is deprecated since Symfony 3.4 and won\'t be supported anymore in Symfony 4.0.', $id), \E_USER_DEPRECATED);
  3462. }
  3463. if (isset($this->aliases[$id])) {
  3464. $id = $this->aliases[$id];
  3465. }
  3466. if ('service_container'=== $id) {
  3467. return false;
  3468. }
  3469. return isset($this->services[$id]);
  3470. }
  3471. public function reset()
  3472. {
  3473. $this->services = [];
  3474. }
  3475. public function getServiceIds()
  3476. {
  3477. $ids = [];
  3478. if (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class) {
  3479. @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED);
  3480. foreach (get_class_methods($this) as $method) {
  3481. if (preg_match('/^get(.+)Service$/', $method, $match)) {
  3482. $ids[] = self::underscore($match[1]);
  3483. }
  3484. }
  3485. }
  3486. $ids[] ='service_container';
  3487. return array_map('strval', array_unique(array_merge($ids, array_keys($this->methodMap), array_keys($this->fileMap), array_keys($this->aliases), array_keys($this->services))));
  3488. }
  3489. public function getRemovedIds()
  3490. {
  3491. return [];
  3492. }
  3493. public static function camelize($id)
  3494. {
  3495. return strtr(ucwords(strtr($id, ['_'=>' ','.'=>'_ ','\\'=>'_ '])), [' '=>'']);
  3496. }
  3497. public static function underscore($id)
  3498. {
  3499. return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/','/([a-z\d])([A-Z])/'], ['\\1_\\2','\\1_\\2'], str_replace('_','.', $id)));
  3500. }
  3501. protected function load($file)
  3502. {
  3503. return require $file;
  3504. }
  3505. protected function getEnv($name)
  3506. {
  3507. if (isset($this->resolving[$envName = "env($name)"])) {
  3508. throw new ParameterCircularReferenceException(array_keys($this->resolving));
  3509. }
  3510. if (isset($this->envCache[$name]) || \array_key_exists($name, $this->envCache)) {
  3511. return $this->envCache[$name];
  3512. }
  3513. if (!$this->has($id ='container.env_var_processors_locator')) {
  3514. $this->set($id, new ServiceLocator([]));
  3515. }
  3516. if (!$this->getEnv) {
  3517. $this->getEnv = new \ReflectionMethod($this, __FUNCTION__);
  3518. $this->getEnv->setAccessible(true);
  3519. $this->getEnv = $this->getEnv->getClosure($this);
  3520. }
  3521. $processors = $this->get($id);
  3522. if (false !== $i = strpos($name,':')) {
  3523. $prefix = substr($name, 0, $i);
  3524. $localName = substr($name, 1 + $i);
  3525. } else {
  3526. $prefix ='string';
  3527. $localName = $name;
  3528. }
  3529. $processor = $processors->has($prefix) ? $processors->get($prefix) : new EnvVarProcessor($this);
  3530. $this->resolving[$envName] = true;
  3531. try {
  3532. return $this->envCache[$name] = $processor->getEnv($prefix, $localName, $this->getEnv);
  3533. } finally {
  3534. unset($this->resolving[$envName]);
  3535. }
  3536. }
  3537. public function normalizeId($id)
  3538. {
  3539. if (!\is_string($id)) {
  3540. $id = (string) $id;
  3541. }
  3542. if (isset($this->normalizedIds[$normalizedId = strtolower($id)])) {
  3543. $normalizedId = $this->normalizedIds[$normalizedId];
  3544. if ($id !== $normalizedId) {
  3545. @trigger_error(sprintf('Service identifiers will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.3.', $id, $normalizedId), \E_USER_DEPRECATED);
  3546. }
  3547. } else {
  3548. $normalizedId = $this->normalizedIds[$normalizedId] = $id;
  3549. }
  3550. return $normalizedId;
  3551. }
  3552. private function __clone()
  3553. {
  3554. }
  3555. }
  3556. }
  3557. namespace Symfony\Component\EventDispatcher
  3558. {
  3559. class Event
  3560. {
  3561. private $propagationStopped = false;
  3562. public function isPropagationStopped()
  3563. {
  3564. return $this->propagationStopped;
  3565. }
  3566. public function stopPropagation()
  3567. {
  3568. $this->propagationStopped = true;
  3569. }
  3570. }
  3571. }
  3572. namespace Symfony\Component\EventDispatcher
  3573. {
  3574. interface EventDispatcherInterface
  3575. {
  3576. public function dispatch($eventName, Event $event = null);
  3577. public function addListener($eventName, $listener, $priority = 0);
  3578. public function addSubscriber(EventSubscriberInterface $subscriber);
  3579. public function removeListener($eventName, $listener);
  3580. public function removeSubscriber(EventSubscriberInterface $subscriber);
  3581. public function getListeners($eventName = null);
  3582. public function getListenerPriority($eventName, $listener);
  3583. public function hasListeners($eventName = null);
  3584. }
  3585. }
  3586. namespace Symfony\Component\EventDispatcher
  3587. {
  3588. class EventDispatcher implements EventDispatcherInterface
  3589. {
  3590. private $listeners = [];
  3591. private $sorted = [];
  3592. public function dispatch($eventName, Event $event = null)
  3593. {
  3594. if (null === $event) {
  3595. $event = new Event();
  3596. }
  3597. if ($listeners = $this->getListeners($eventName)) {
  3598. $this->doDispatch($listeners, $eventName, $event);
  3599. }
  3600. return $event;
  3601. }
  3602. public function getListeners($eventName = null)
  3603. {
  3604. if (null !== $eventName) {
  3605. if (empty($this->listeners[$eventName])) {
  3606. return [];
  3607. }
  3608. if (!isset($this->sorted[$eventName])) {
  3609. $this->sortListeners($eventName);
  3610. }
  3611. return $this->sorted[$eventName];
  3612. }
  3613. foreach ($this->listeners as $eventName => $eventListeners) {
  3614. if (!isset($this->sorted[$eventName])) {
  3615. $this->sortListeners($eventName);
  3616. }
  3617. }
  3618. return array_filter($this->sorted);
  3619. }
  3620. public function getListenerPriority($eventName, $listener)
  3621. {
  3622. if (empty($this->listeners[$eventName])) {
  3623. return null;
  3624. }
  3625. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
  3626. $listener[0] = $listener[0]();
  3627. }
  3628. foreach ($this->listeners[$eventName] as $priority => $listeners) {
  3629. foreach ($listeners as $k => $v) {
  3630. if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
  3631. $v[0] = $v[0]();
  3632. $this->listeners[$eventName][$priority][$k] = $v;
  3633. }
  3634. if ($v === $listener) {
  3635. return $priority;
  3636. }
  3637. }
  3638. }
  3639. return null;
  3640. }
  3641. public function hasListeners($eventName = null)
  3642. {
  3643. if (null !== $eventName) {
  3644. return !empty($this->listeners[$eventName]);
  3645. }
  3646. foreach ($this->listeners as $eventListeners) {
  3647. if ($eventListeners) {
  3648. return true;
  3649. }
  3650. }
  3651. return false;
  3652. }
  3653. public function addListener($eventName, $listener, $priority = 0)
  3654. {
  3655. $this->listeners[$eventName][$priority][] = $listener;
  3656. unset($this->sorted[$eventName]);
  3657. }
  3658. public function removeListener($eventName, $listener)
  3659. {
  3660. if (empty($this->listeners[$eventName])) {
  3661. return;
  3662. }
  3663. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
  3664. $listener[0] = $listener[0]();
  3665. }
  3666. foreach ($this->listeners[$eventName] as $priority => $listeners) {
  3667. foreach ($listeners as $k => $v) {
  3668. if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
  3669. $v[0] = $v[0]();
  3670. }
  3671. if ($v === $listener) {
  3672. unset($listeners[$k], $this->sorted[$eventName]);
  3673. } else {
  3674. $listeners[$k] = $v;
  3675. }
  3676. }
  3677. if ($listeners) {
  3678. $this->listeners[$eventName][$priority] = $listeners;
  3679. } else {
  3680. unset($this->listeners[$eventName][$priority]);
  3681. }
  3682. }
  3683. }
  3684. public function addSubscriber(EventSubscriberInterface $subscriber)
  3685. {
  3686. foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
  3687. if (\is_string($params)) {
  3688. $this->addListener($eventName, [$subscriber, $params]);
  3689. } elseif (\is_string($params[0])) {
  3690. $this->addListener($eventName, [$subscriber, $params[0]], isset($params[1]) ? $params[1] : 0);
  3691. } else {
  3692. foreach ($params as $listener) {
  3693. $this->addListener($eventName, [$subscriber, $listener[0]], isset($listener[1]) ? $listener[1] : 0);
  3694. }
  3695. }
  3696. }
  3697. }
  3698. public function removeSubscriber(EventSubscriberInterface $subscriber)
  3699. {
  3700. foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
  3701. if (\is_array($params) && \is_array($params[0])) {
  3702. foreach ($params as $listener) {
  3703. $this->removeListener($eventName, [$subscriber, $listener[0]]);
  3704. }
  3705. } else {
  3706. $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]);
  3707. }
  3708. }
  3709. }
  3710. protected function doDispatch($listeners, $eventName, Event $event)
  3711. {
  3712. foreach ($listeners as $listener) {
  3713. if ($event->isPropagationStopped()) {
  3714. break;
  3715. }
  3716. \call_user_func($listener, $event, $eventName, $this);
  3717. }
  3718. }
  3719. private function sortListeners($eventName)
  3720. {
  3721. krsort($this->listeners[$eventName]);
  3722. $this->sorted[$eventName] = [];
  3723. foreach ($this->listeners[$eventName] as $priority => $listeners) {
  3724. foreach ($listeners as $k => $listener) {
  3725. if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
  3726. $listener[0] = $listener[0]();
  3727. $this->listeners[$eventName][$priority][$k] = $listener;
  3728. }
  3729. $this->sorted[$eventName][] = $listener;
  3730. }
  3731. }
  3732. }
  3733. }
  3734. }
  3735. namespace Symfony\Component\EventDispatcher
  3736. {
  3737. use PHPUnit\Framework\MockObject\MockObject;
  3738. use Symfony\Component\DependencyInjection\ContainerInterface;
  3739. class ContainerAwareEventDispatcher extends EventDispatcher
  3740. {
  3741. private $container;
  3742. private $listenerIds = [];
  3743. private $listeners = [];
  3744. public function __construct(ContainerInterface $container)
  3745. {
  3746. $this->container = $container;
  3747. $class = static::class;
  3748. if ($this instanceof \PHPUnit_Framework_MockObject_MockObject || $this instanceof MockObject || $this instanceof \Prophecy\Doubler\DoubleInterface) {
  3749. $class = get_parent_class($class);
  3750. }
  3751. if (__CLASS__ !== $class) {
  3752. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), \E_USER_DEPRECATED);
  3753. }
  3754. }
  3755. public function addListenerService($eventName, $callback, $priority = 0)
  3756. {
  3757. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), \E_USER_DEPRECATED);
  3758. if (!\is_array($callback) || 2 !== \count($callback)) {
  3759. throw new \InvalidArgumentException('Expected an ["service", "method"] argument.');
  3760. }
  3761. $this->listenerIds[$eventName][] = [$callback[0], $callback[1], $priority];
  3762. }
  3763. public function removeListener($eventName, $listener)
  3764. {
  3765. $this->lazyLoad($eventName);
  3766. if (isset($this->listenerIds[$eventName])) {
  3767. foreach ($this->listenerIds[$eventName] as $i => list($serviceId, $method)) {
  3768. $key = $serviceId.'.'.$method;
  3769. if (isset($this->listeners[$eventName][$key]) && $listener === [$this->listeners[$eventName][$key], $method]) {
  3770. unset($this->listeners[$eventName][$key]);
  3771. if (empty($this->listeners[$eventName])) {
  3772. unset($this->listeners[$eventName]);
  3773. }
  3774. unset($this->listenerIds[$eventName][$i]);
  3775. if (empty($this->listenerIds[$eventName])) {
  3776. unset($this->listenerIds[$eventName]);
  3777. }
  3778. }
  3779. }
  3780. }
  3781. parent::removeListener($eventName, $listener);
  3782. }
  3783. public function hasListeners($eventName = null)
  3784. {
  3785. if (null === $eventName) {
  3786. return $this->listenerIds || $this->listeners || parent::hasListeners();
  3787. }
  3788. if (isset($this->listenerIds[$eventName])) {
  3789. return true;
  3790. }
  3791. return parent::hasListeners($eventName);
  3792. }
  3793. public function getListeners($eventName = null)
  3794. {
  3795. if (null === $eventName) {
  3796. foreach ($this->listenerIds as $serviceEventName => $args) {
  3797. $this->lazyLoad($serviceEventName);
  3798. }
  3799. } else {
  3800. $this->lazyLoad($eventName);
  3801. }
  3802. return parent::getListeners($eventName);
  3803. }
  3804. public function getListenerPriority($eventName, $listener)
  3805. {
  3806. $this->lazyLoad($eventName);
  3807. return parent::getListenerPriority($eventName, $listener);
  3808. }
  3809. public function addSubscriberService($serviceId, $class)
  3810. {
  3811. @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), \E_USER_DEPRECATED);
  3812. foreach ($class::getSubscribedEvents() as $eventName => $params) {
  3813. if (\is_string($params)) {
  3814. $this->listenerIds[$eventName][] = [$serviceId, $params, 0];
  3815. } elseif (\is_string($params[0])) {
  3816. $this->listenerIds[$eventName][] = [$serviceId, $params[0], isset($params[1]) ? $params[1] : 0];
  3817. } else {
  3818. foreach ($params as $listener) {
  3819. $this->listenerIds[$eventName][] = [$serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0];
  3820. }
  3821. }
  3822. }
  3823. }
  3824. public function getContainer()
  3825. {
  3826. @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 as its class will be removed in 4.0. Inject the container or the services you need in your listeners/subscribers instead.', \E_USER_DEPRECATED);
  3827. return $this->container;
  3828. }
  3829. protected function lazyLoad($eventName)
  3830. {
  3831. if (isset($this->listenerIds[$eventName])) {
  3832. foreach ($this->listenerIds[$eventName] as list($serviceId, $method, $priority)) {
  3833. $listener = $this->container->get($serviceId);
  3834. $key = $serviceId.'.'.$method;
  3835. if (!isset($this->listeners[$eventName][$key])) {
  3836. $this->addListener($eventName, [$listener, $method], $priority);
  3837. } elseif ($this->listeners[$eventName][$key] !== $listener) {
  3838. parent::removeListener($eventName, [$this->listeners[$eventName][$key], $method]);
  3839. $this->addListener($eventName, [$listener, $method], $priority);
  3840. }
  3841. $this->listeners[$eventName][$key] = $listener;
  3842. }
  3843. }
  3844. }
  3845. }
  3846. }
  3847. namespace Symfony\Component\HttpKernel\EventListener
  3848. {
  3849. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  3850. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  3851. use Symfony\Component\HttpKernel\KernelEvents;
  3852. class ResponseListener implements EventSubscriberInterface
  3853. {
  3854. private $charset;
  3855. public function __construct($charset)
  3856. {
  3857. $this->charset = $charset;
  3858. }
  3859. public function onKernelResponse(FilterResponseEvent $event)
  3860. {
  3861. if (!$event->isMasterRequest()) {
  3862. return;
  3863. }
  3864. $response = $event->getResponse();
  3865. if (null === $response->getCharset()) {
  3866. $response->setCharset($this->charset);
  3867. }
  3868. $response->prepare($event->getRequest());
  3869. }
  3870. public static function getSubscribedEvents()
  3871. {
  3872. return [
  3873. KernelEvents::RESPONSE =>'onKernelResponse',
  3874. ];
  3875. }
  3876. }
  3877. }
  3878. namespace {require __DIR__.'/../../../../versions/b2c15_7b7c4073/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php';}
  3879. namespace Symfony\Component\HttpKernel\Bundle
  3880. {
  3881. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  3882. use Symfony\Component\DependencyInjection\ContainerBuilder;
  3883. use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
  3884. interface BundleInterface extends ContainerAwareInterface
  3885. {
  3886. public function boot();
  3887. public function shutdown();
  3888. public function build(ContainerBuilder $container);
  3889. public function getContainerExtension();
  3890. public function getParent();
  3891. public function getName();
  3892. public function getNamespace();
  3893. public function getPath();
  3894. }
  3895. }
  3896. namespace Symfony\Component\DependencyInjection
  3897. {
  3898. trait ContainerAwareTrait
  3899. {
  3900. protected $container;
  3901. public function setContainer(ContainerInterface $container = null)
  3902. {
  3903. $this->container = $container;
  3904. }
  3905. }
  3906. }
  3907. namespace Symfony\Component\HttpKernel\Bundle
  3908. {
  3909. use Symfony\Component\Console\Application;
  3910. use Symfony\Component\DependencyInjection\Container;
  3911. use Symfony\Component\DependencyInjection\ContainerAwareTrait;
  3912. use Symfony\Component\DependencyInjection\ContainerBuilder;
  3913. use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
  3914. use Symfony\Component\Finder\Finder;
  3915. abstract class Bundle implements BundleInterface
  3916. {
  3917. use ContainerAwareTrait;
  3918. protected $name;
  3919. protected $extension;
  3920. protected $path;
  3921. private $namespace;
  3922. public function boot()
  3923. {
  3924. }
  3925. public function shutdown()
  3926. {
  3927. }
  3928. public function build(ContainerBuilder $container)
  3929. {
  3930. }
  3931. public function getContainerExtension()
  3932. {
  3933. if (null === $this->extension) {
  3934. $extension = $this->createContainerExtension();
  3935. if (null !== $extension) {
  3936. if (!$extension instanceof ExtensionInterface) {
  3937. throw new \LogicException(sprintf('Extension "%s" must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.', \get_class($extension)));
  3938. }
  3939. $basename = preg_replace('/Bundle$/','', $this->getName());
  3940. $expectedAlias = Container::underscore($basename);
  3941. if ($expectedAlias != $extension->getAlias()) {
  3942. throw new \LogicException(sprintf('Users will expect the alias of the default extension of a bundle to be the underscored version of the bundle name ("%s"). You can override "Bundle::getContainerExtension()" if you want to use "%s" or another alias.', $expectedAlias, $extension->getAlias()));
  3943. }
  3944. $this->extension = $extension;
  3945. } else {
  3946. $this->extension = false;
  3947. }
  3948. }
  3949. return $this->extension ?: null;
  3950. }
  3951. public function getNamespace()
  3952. {
  3953. if (null === $this->namespace) {
  3954. $this->parseClassName();
  3955. }
  3956. return $this->namespace;
  3957. }
  3958. public function getPath()
  3959. {
  3960. if (null === $this->path) {
  3961. $reflected = new \ReflectionObject($this);
  3962. $this->path = \dirname($reflected->getFileName());
  3963. }
  3964. return $this->path;
  3965. }
  3966. public function getParent()
  3967. {
  3968. }
  3969. final public function getName()
  3970. {
  3971. if (null === $this->name) {
  3972. $this->parseClassName();
  3973. }
  3974. return $this->name;
  3975. }
  3976. public function registerCommands(Application $application)
  3977. {
  3978. if (!is_dir($dir = $this->getPath().'/Command')) {
  3979. return;
  3980. }
  3981. if (!class_exists('Symfony\Component\Finder\Finder')) {
  3982. throw new \RuntimeException('You need the symfony/finder component to register bundle commands.');
  3983. }
  3984. $finder = new Finder();
  3985. $finder->files()->name('*Command.php')->in($dir);
  3986. $prefix = $this->getNamespace().'\\Command';
  3987. foreach ($finder as $file) {
  3988. $ns = $prefix;
  3989. if ($relativePath = $file->getRelativePath()) {
  3990. $ns .='\\'.str_replace('/','\\', $relativePath);
  3991. }
  3992. $class = $ns.'\\'.$file->getBasename('.php');
  3993. if ($this->container) {
  3994. $commandIds = $this->container->hasParameter('console.command.ids') ? $this->container->getParameter('console.command.ids') : [];
  3995. $alias ='console.command.'.strtolower(str_replace('\\','_', $class));
  3996. if (isset($commandIds[$alias]) || $this->container->has($alias)) {
  3997. continue;
  3998. }
  3999. }
  4000. $r = new \ReflectionClass($class);
  4001. if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract() && !$r->getConstructor()->getNumberOfRequiredParameters()) {
  4002. @trigger_error(sprintf('Auto-registration of the command "%s" is deprecated since Symfony 3.4 and won\'t be supported in 4.0. Use PSR-4 based service discovery instead.', $class), \E_USER_DEPRECATED);
  4003. $application->add($r->newInstance());
  4004. }
  4005. }
  4006. }
  4007. protected function getContainerExtensionClass()
  4008. {
  4009. $basename = preg_replace('/Bundle$/','', $this->getName());
  4010. return $this->getNamespace().'\\DependencyInjection\\'.$basename.'Extension';
  4011. }
  4012. protected function createContainerExtension()
  4013. {
  4014. return class_exists($class = $this->getContainerExtensionClass()) ? new $class() : null;
  4015. }
  4016. private function parseClassName()
  4017. {
  4018. $pos = strrpos(static::class,'\\');
  4019. $this->namespace = false === $pos ?'': substr(static::class, 0, $pos);
  4020. if (null === $this->name) {
  4021. $this->name = false === $pos ? static::class : substr(static::class, $pos + 1);
  4022. }
  4023. }
  4024. }
  4025. }
  4026. namespace Symfony\Component\HttpKernel\Controller
  4027. {
  4028. use Symfony\Component\HttpFoundation\Request;
  4029. interface ArgumentResolverInterface
  4030. {
  4031. public function getArguments(Request $request, $controller);
  4032. }
  4033. }
  4034. namespace Symfony\Component\HttpKernel\Controller
  4035. {
  4036. use Symfony\Component\HttpFoundation\Request;
  4037. interface ControllerResolverInterface
  4038. {
  4039. public function getController(Request $request);
  4040. public function getArguments(Request $request, $controller);
  4041. }
  4042. }
  4043. namespace Symfony\Component\HttpKernel\Controller
  4044. {
  4045. use Psr\Log\LoggerInterface;
  4046. use Symfony\Component\HttpFoundation\Request;
  4047. class ControllerResolver implements ArgumentResolverInterface, ControllerResolverInterface
  4048. {
  4049. private $logger;
  4050. private $supportsVariadic;
  4051. private $supportsScalarTypes;
  4052. public function __construct(LoggerInterface $logger = null)
  4053. {
  4054. $this->logger = $logger;
  4055. $this->supportsVariadic = method_exists('ReflectionParameter','isVariadic');
  4056. $this->supportsScalarTypes = method_exists('ReflectionParameter','getType');
  4057. }
  4058. public function getController(Request $request)
  4059. {
  4060. if (!$controller = $request->attributes->get('_controller')) {
  4061. if (null !== $this->logger) {
  4062. $this->logger->warning('Unable to look for the controller as the "_controller" parameter is missing.');
  4063. }
  4064. return false;
  4065. }
  4066. if (\is_array($controller)) {
  4067. return $controller;
  4068. }
  4069. if (\is_object($controller)) {
  4070. if (method_exists($controller,'__invoke')) {
  4071. return $controller;
  4072. }
  4073. throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', \get_class($controller), $request->getPathInfo()));
  4074. }
  4075. if (\is_string($controller) && false === strpos($controller,':')) {
  4076. if (method_exists($controller,'__invoke')) {
  4077. return $this->instantiateController($controller);
  4078. } elseif (\function_exists($controller)) {
  4079. return $controller;
  4080. }
  4081. }
  4082. try {
  4083. $callable = $this->createController($controller);
  4084. } catch (\InvalidArgumentException $e) {
  4085. throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$e->getMessage(), 0, $e);
  4086. }
  4087. return $callable;
  4088. }
  4089. public function getArguments(Request $request, $controller)
  4090. {
  4091. @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Implement the %s and inject it in the HttpKernel instead.', __METHOD__, ArgumentResolverInterface::class), \E_USER_DEPRECATED);
  4092. if (\is_array($controller)) {
  4093. $r = new \ReflectionMethod($controller[0], $controller[1]);
  4094. } elseif (\is_object($controller) && !$controller instanceof \Closure) {
  4095. $r = new \ReflectionObject($controller);
  4096. $r = $r->getMethod('__invoke');
  4097. } else {
  4098. $r = new \ReflectionFunction($controller);
  4099. }
  4100. return $this->doGetArguments($request, $controller, $r->getParameters());
  4101. }
  4102. protected function doGetArguments(Request $request, $controller, array $parameters)
  4103. {
  4104. @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Implement the %s and inject it in the HttpKernel instead.', __METHOD__, ArgumentResolverInterface::class), \E_USER_DEPRECATED);
  4105. $attributes = $request->attributes->all();
  4106. $arguments = [];
  4107. foreach ($parameters as $param) {
  4108. if (\array_key_exists($param->name, $attributes)) {
  4109. if ($this->supportsVariadic && $param->isVariadic() && \is_array($attributes[$param->name])) {
  4110. $arguments = array_merge($arguments, array_values($attributes[$param->name]));
  4111. } else {
  4112. $arguments[] = $attributes[$param->name];
  4113. }
  4114. } elseif ($this->typeMatchesRequestClass($param, $request)) {
  4115. $arguments[] = $request;
  4116. } elseif ($param->isDefaultValueAvailable()) {
  4117. $arguments[] = $param->getDefaultValue();
  4118. } elseif ($this->supportsScalarTypes && $param->hasType() && $param->allowsNull()) {
  4119. $arguments[] = null;
  4120. } else {
  4121. if (\is_array($controller)) {
  4122. $repr = sprintf('%s::%s()', \get_class($controller[0]), $controller[1]);
  4123. } elseif (\is_object($controller)) {
  4124. $repr = \get_class($controller);
  4125. } else {
  4126. $repr = $controller;
  4127. }
  4128. throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $repr, $param->name));
  4129. }
  4130. }
  4131. return $arguments;
  4132. }
  4133. protected function createController($controller)
  4134. {
  4135. if (false === strpos($controller,'::')) {
  4136. throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller));
  4137. }
  4138. list($class, $method) = explode('::', $controller, 2);
  4139. if (!class_exists($class)) {
  4140. throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
  4141. }
  4142. $controller = [$this->instantiateController($class), $method];
  4143. if (!\is_callable($controller)) {
  4144. throw new \InvalidArgumentException($this->getControllerError($controller));
  4145. }
  4146. return $controller;
  4147. }
  4148. protected function instantiateController($class)
  4149. {
  4150. return new $class();
  4151. }
  4152. private function getControllerError($callable)
  4153. {
  4154. if (\is_string($callable)) {
  4155. if (false !== strpos($callable,'::')) {
  4156. $callable = explode('::', $callable);
  4157. }
  4158. if (class_exists($callable) && !method_exists($callable,'__invoke')) {
  4159. return sprintf('Class "%s" does not have a method "__invoke".', $callable);
  4160. }
  4161. if (!\function_exists($callable)) {
  4162. return sprintf('Function "%s" does not exist.', $callable);
  4163. }
  4164. }
  4165. if (!\is_array($callable)) {
  4166. return sprintf('Invalid type for controller given, expected string or array, got "%s".', \gettype($callable));
  4167. }
  4168. if (2 !== \count($callable)) {
  4169. return'Invalid format for controller, expected [controller, method] or controller::method.';
  4170. }
  4171. list($controller, $method) = $callable;
  4172. if (\is_string($controller) && !class_exists($controller)) {
  4173. return sprintf('Class "%s" does not exist.', $controller);
  4174. }
  4175. $className = \is_object($controller) ? \get_class($controller) : $controller;
  4176. if (method_exists($controller, $method)) {
  4177. return sprintf('Method "%s" on class "%s" should be public and non-abstract.', $method, $className);
  4178. }
  4179. $collection = get_class_methods($controller);
  4180. $alternatives = [];
  4181. foreach ($collection as $item) {
  4182. $lev = levenshtein($method, $item);
  4183. if ($lev <= \strlen($method) / 3 || false !== strpos($item, $method)) {
  4184. $alternatives[] = $item;
  4185. }
  4186. }
  4187. asort($alternatives);
  4188. $message = sprintf('Expected method "%s" on class "%s"', $method, $className);
  4189. if (\count($alternatives) > 0) {
  4190. $message .= sprintf(', did you mean "%s"?', implode('", "', $alternatives));
  4191. } else {
  4192. $message .= sprintf('. Available methods: "%s".', implode('", "', $collection));
  4193. }
  4194. return $message;
  4195. }
  4196. private function typeMatchesRequestClass(\ReflectionParameter $param, Request $request)
  4197. {
  4198. if (!method_exists($param,'getType')) {
  4199. return $param->getClass() && $param->getClass()->isInstance($request);
  4200. }
  4201. if (!($type = $param->getType()) || $type->isBuiltin()) {
  4202. return false;
  4203. }
  4204. $class = new \ReflectionClass($type instanceof \ReflectionNamedType ? $type->getName() : (string) $type);
  4205. return $class && $class->isInstance($request);
  4206. }
  4207. }
  4208. }
  4209. namespace Symfony\Component\HttpKernel\Controller
  4210. {
  4211. use Symfony\Component\HttpFoundation\Request;
  4212. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver;
  4213. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver;
  4214. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver;
  4215. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver;
  4216. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver;
  4217. use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
  4218. use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface;
  4219. final class ArgumentResolver implements ArgumentResolverInterface
  4220. {
  4221. private $argumentMetadataFactory;
  4222. private $argumentValueResolvers;
  4223. public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, $argumentValueResolvers = [])
  4224. {
  4225. $this->argumentMetadataFactory = $argumentMetadataFactory ?: new ArgumentMetadataFactory();
  4226. $this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers();
  4227. }
  4228. public function getArguments(Request $request, $controller)
  4229. {
  4230. $arguments = [];
  4231. foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller) as $metadata) {
  4232. foreach ($this->argumentValueResolvers as $resolver) {
  4233. if (!$resolver->supports($request, $metadata)) {
  4234. continue;
  4235. }
  4236. $resolved = $resolver->resolve($request, $metadata);
  4237. if (!$resolved instanceof \Generator) {
  4238. throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', \get_class($resolver)));
  4239. }
  4240. foreach ($resolved as $append) {
  4241. $arguments[] = $append;
  4242. }
  4243. continue 2;
  4244. }
  4245. $representative = $controller;
  4246. if (\is_array($representative)) {
  4247. $representative = sprintf('%s::%s()', \get_class($representative[0]), $representative[1]);
  4248. } elseif (\is_object($representative)) {
  4249. $representative = \get_class($representative);
  4250. }
  4251. throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.', $representative, $metadata->getName()));
  4252. }
  4253. return $arguments;
  4254. }
  4255. public static function getDefaultArgumentValueResolvers()
  4256. {
  4257. return [
  4258. new RequestAttributeValueResolver(),
  4259. new RequestValueResolver(),
  4260. new SessionValueResolver(),
  4261. new DefaultValueResolver(),
  4262. new VariadicValueResolver(),
  4263. ];
  4264. }
  4265. }
  4266. }
  4267. namespace Symfony\Component\HttpKernel\ControllerMetadata
  4268. {
  4269. class ArgumentMetadata
  4270. {
  4271. private $name;
  4272. private $type;
  4273. private $isVariadic;
  4274. private $hasDefaultValue;
  4275. private $defaultValue;
  4276. private $isNullable;
  4277. public function __construct($name, $type, $isVariadic, $hasDefaultValue, $defaultValue, $isNullable = false)
  4278. {
  4279. $this->name = $name;
  4280. $this->type = $type;
  4281. $this->isVariadic = $isVariadic;
  4282. $this->hasDefaultValue = $hasDefaultValue;
  4283. $this->defaultValue = $defaultValue;
  4284. $this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue);
  4285. }
  4286. public function getName()
  4287. {
  4288. return $this->name;
  4289. }
  4290. public function getType()
  4291. {
  4292. return $this->type;
  4293. }
  4294. public function isVariadic()
  4295. {
  4296. return $this->isVariadic;
  4297. }
  4298. public function hasDefaultValue()
  4299. {
  4300. return $this->hasDefaultValue;
  4301. }
  4302. public function isNullable()
  4303. {
  4304. return $this->isNullable;
  4305. }
  4306. public function getDefaultValue()
  4307. {
  4308. if (!$this->hasDefaultValue) {
  4309. throw new \LogicException(sprintf('Argument $%s does not have a default value. Use "%s::hasDefaultValue()" to avoid this exception.', $this->name, __CLASS__));
  4310. }
  4311. return $this->defaultValue;
  4312. }
  4313. }
  4314. }
  4315. namespace Symfony\Component\HttpKernel\ControllerMetadata
  4316. {
  4317. interface ArgumentMetadataFactoryInterface
  4318. {
  4319. public function createArgumentMetadata($controller);
  4320. }
  4321. }
  4322. namespace Symfony\Component\HttpKernel\ControllerMetadata
  4323. {
  4324. final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface
  4325. {
  4326. private $supportsVariadic;
  4327. private $supportsParameterType;
  4328. public function __construct()
  4329. {
  4330. $this->supportsVariadic = method_exists('ReflectionParameter','isVariadic');
  4331. $this->supportsParameterType = method_exists('ReflectionParameter','getType');
  4332. }
  4333. public function createArgumentMetadata($controller)
  4334. {
  4335. $arguments = [];
  4336. if (\is_array($controller)) {
  4337. $reflection = new \ReflectionMethod($controller[0], $controller[1]);
  4338. } elseif (\is_object($controller) && !$controller instanceof \Closure) {
  4339. $reflection = (new \ReflectionObject($controller))->getMethod('__invoke');
  4340. } else {
  4341. $reflection = new \ReflectionFunction($controller);
  4342. }
  4343. foreach ($reflection->getParameters() as $param) {
  4344. $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $this->isVariadic($param), $this->hasDefaultValue($param), $this->getDefaultValue($param), $param->allowsNull());
  4345. }
  4346. return $arguments;
  4347. }
  4348. private function isVariadic(\ReflectionParameter $parameter)
  4349. {
  4350. return $this->supportsVariadic && $parameter->isVariadic();
  4351. }
  4352. private function hasDefaultValue(\ReflectionParameter $parameter)
  4353. {
  4354. return $parameter->isDefaultValueAvailable();
  4355. }
  4356. private function getDefaultValue(\ReflectionParameter $parameter)
  4357. {
  4358. return $this->hasDefaultValue($parameter) ? $parameter->getDefaultValue() : null;
  4359. }
  4360. private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function)
  4361. {
  4362. if ($this->supportsParameterType) {
  4363. if (!$type = $parameter->getType()) {
  4364. return null;
  4365. }
  4366. $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
  4367. if ('array'=== $name && !$type->isBuiltin()) {
  4368. return null;
  4369. }
  4370. } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $parameter, $name)) {
  4371. $name = $name[1];
  4372. } else {
  4373. return null;
  4374. }
  4375. $lcName = strtolower($name);
  4376. if ('self'!== $lcName &&'parent'!== $lcName) {
  4377. return $name;
  4378. }
  4379. if (!$function instanceof \ReflectionMethod) {
  4380. return null;
  4381. }
  4382. if ('self'=== $lcName) {
  4383. return $function->getDeclaringClass()->name;
  4384. }
  4385. if ($parent = $function->getDeclaringClass()->getParentClass()) {
  4386. return $parent->name;
  4387. }
  4388. return null;
  4389. }
  4390. }
  4391. }
  4392. namespace Symfony\Component\HttpKernel\Event
  4393. {
  4394. use Symfony\Component\EventDispatcher\Event;
  4395. use Symfony\Component\HttpFoundation\Request;
  4396. use Symfony\Component\HttpKernel\HttpKernelInterface;
  4397. class KernelEvent extends Event
  4398. {
  4399. private $kernel;
  4400. private $request;
  4401. private $requestType;
  4402. public function __construct(HttpKernelInterface $kernel, Request $request, $requestType)
  4403. {
  4404. $this->kernel = $kernel;
  4405. $this->request = $request;
  4406. $this->requestType = $requestType;
  4407. }
  4408. public function getKernel()
  4409. {
  4410. return $this->kernel;
  4411. }
  4412. public function getRequest()
  4413. {
  4414. return $this->request;
  4415. }
  4416. public function getRequestType()
  4417. {
  4418. return $this->requestType;
  4419. }
  4420. public function isMasterRequest()
  4421. {
  4422. return HttpKernelInterface::MASTER_REQUEST === $this->requestType;
  4423. }
  4424. }
  4425. }
  4426. namespace Symfony\Component\HttpKernel\Event
  4427. {
  4428. use Symfony\Component\HttpFoundation\Request;
  4429. use Symfony\Component\HttpKernel\HttpKernelInterface;
  4430. class FilterControllerEvent extends KernelEvent
  4431. {
  4432. private $controller;
  4433. public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, $requestType)
  4434. {
  4435. parent::__construct($kernel, $request, $requestType);
  4436. $this->setController($controller);
  4437. }
  4438. public function getController()
  4439. {
  4440. return $this->controller;
  4441. }
  4442. public function setController(callable $controller)
  4443. {
  4444. $this->controller = $controller;
  4445. }
  4446. }
  4447. }
  4448. namespace Symfony\Component\HttpKernel\Event
  4449. {
  4450. use Symfony\Component\HttpFoundation\Request;
  4451. use Symfony\Component\HttpFoundation\Response;
  4452. use Symfony\Component\HttpKernel\HttpKernelInterface;
  4453. class FilterResponseEvent extends KernelEvent
  4454. {
  4455. private $response;
  4456. public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, Response $response)
  4457. {
  4458. parent::__construct($kernel, $request, $requestType);
  4459. $this->setResponse($response);
  4460. }
  4461. public function getResponse()
  4462. {
  4463. return $this->response;
  4464. }
  4465. public function setResponse(Response $response)
  4466. {
  4467. $this->response = $response;
  4468. }
  4469. }
  4470. }
  4471. namespace Symfony\Component\HttpKernel\Event
  4472. {
  4473. use Symfony\Component\HttpFoundation\Response;
  4474. class GetResponseEvent extends KernelEvent
  4475. {
  4476. private $response;
  4477. public function getResponse()
  4478. {
  4479. return $this->response;
  4480. }
  4481. public function setResponse(Response $response)
  4482. {
  4483. $this->response = $response;
  4484. $this->stopPropagation();
  4485. }
  4486. public function hasResponse()
  4487. {
  4488. return null !== $this->response;
  4489. }
  4490. }
  4491. }
  4492. namespace Symfony\Component\HttpKernel\Event
  4493. {
  4494. use Symfony\Component\HttpFoundation\Request;
  4495. use Symfony\Component\HttpKernel\HttpKernelInterface;
  4496. class GetResponseForControllerResultEvent extends GetResponseEvent
  4497. {
  4498. private $controllerResult;
  4499. public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, $controllerResult)
  4500. {
  4501. parent::__construct($kernel, $request, $requestType);
  4502. $this->controllerResult = $controllerResult;
  4503. }
  4504. public function getControllerResult()
  4505. {
  4506. return $this->controllerResult;
  4507. }
  4508. public function setControllerResult($controllerResult)
  4509. {
  4510. $this->controllerResult = $controllerResult;
  4511. }
  4512. }
  4513. }
  4514. namespace Symfony\Component\HttpKernel\Event
  4515. {
  4516. use Symfony\Component\HttpFoundation\Request;
  4517. use Symfony\Component\HttpKernel\HttpKernelInterface;
  4518. class GetResponseForExceptionEvent extends GetResponseEvent
  4519. {
  4520. private $exception;
  4521. private $allowCustomResponseCode = false;
  4522. public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, \Exception $e)
  4523. {
  4524. parent::__construct($kernel, $request, $requestType);
  4525. $this->setException($e);
  4526. }
  4527. public function getException()
  4528. {
  4529. return $this->exception;
  4530. }
  4531. public function setException(\Exception $exception)
  4532. {
  4533. $this->exception = $exception;
  4534. }
  4535. public function allowCustomResponseCode()
  4536. {
  4537. $this->allowCustomResponseCode = true;
  4538. }
  4539. public function isAllowingCustomResponseCode()
  4540. {
  4541. return $this->allowCustomResponseCode;
  4542. }
  4543. }
  4544. }
  4545. namespace Symfony\Component\HttpKernel
  4546. {
  4547. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  4548. use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface;
  4549. use Symfony\Component\HttpFoundation\Request;
  4550. use Symfony\Component\HttpFoundation\RequestStack;
  4551. use Symfony\Component\HttpFoundation\Response;
  4552. use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
  4553. use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
  4554. use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
  4555. use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent;
  4556. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  4557. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  4558. use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
  4559. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  4560. use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
  4561. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
  4562. use Symfony\Component\HttpKernel\Event\PostResponseEvent;
  4563. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  4564. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  4565. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  4566. class HttpKernel implements HttpKernelInterface, TerminableInterface
  4567. {
  4568. protected $dispatcher;
  4569. protected $resolver;
  4570. protected $requestStack;
  4571. private $argumentResolver;
  4572. public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $resolver, RequestStack $requestStack = null, ArgumentResolverInterface $argumentResolver = null)
  4573. {
  4574. $this->dispatcher = $dispatcher;
  4575. $this->resolver = $resolver;
  4576. $this->requestStack = $requestStack ?: new RequestStack();
  4577. $this->argumentResolver = $argumentResolver;
  4578. if (null === $this->argumentResolver) {
  4579. @trigger_error(sprintf('As of 3.1 an %s is used to resolve arguments. In 4.0 the $argumentResolver becomes the %s if no other is provided instead of using the $resolver argument.', ArgumentResolverInterface::class, ArgumentResolver::class), \E_USER_DEPRECATED);
  4580. $this->argumentResolver = $resolver;
  4581. }
  4582. }
  4583. public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
  4584. {
  4585. $request->headers->set('X-Php-Ob-Level', (string) ob_get_level());
  4586. try {
  4587. return $this->handleRaw($request, $type);
  4588. } catch (\Exception $e) {
  4589. if ($e instanceof RequestExceptionInterface) {
  4590. $e = new BadRequestHttpException($e->getMessage(), $e);
  4591. }
  4592. if (false === $catch) {
  4593. $this->finishRequest($request, $type);
  4594. throw $e;
  4595. }
  4596. return $this->handleException($e, $request, $type);
  4597. }
  4598. }
  4599. public function terminate(Request $request, Response $response)
  4600. {
  4601. $this->dispatcher->dispatch(KernelEvents::TERMINATE, new PostResponseEvent($this, $request, $response));
  4602. }
  4603. public function terminateWithException(\Exception $exception, Request $request = null)
  4604. {
  4605. if (!$request = $request ?: $this->requestStack->getMasterRequest()) {
  4606. throw $exception;
  4607. }
  4608. $response = $this->handleException($exception, $request, self::MASTER_REQUEST);
  4609. $response->sendHeaders();
  4610. $response->sendContent();
  4611. $this->terminate($request, $response);
  4612. }
  4613. private function handleRaw(Request $request, $type = self::MASTER_REQUEST)
  4614. {
  4615. $this->requestStack->push($request);
  4616. $event = new GetResponseEvent($this, $request, $type);
  4617. $this->dispatcher->dispatch(KernelEvents::REQUEST, $event);
  4618. if ($event->hasResponse()) {
  4619. return $this->filterResponse($event->getResponse(), $request, $type);
  4620. }
  4621. if (false === $controller = $this->resolver->getController($request)) {
  4622. throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". The route is wrongly configured.', $request->getPathInfo()));
  4623. }
  4624. $event = new FilterControllerEvent($this, $controller, $request, $type);
  4625. $this->dispatcher->dispatch(KernelEvents::CONTROLLER, $event);
  4626. $controller = $event->getController();
  4627. $arguments = $this->argumentResolver->getArguments($request, $controller);
  4628. $event = new FilterControllerArgumentsEvent($this, $controller, $arguments, $request, $type);
  4629. $this->dispatcher->dispatch(KernelEvents::CONTROLLER_ARGUMENTS, $event);
  4630. $controller = $event->getController();
  4631. $arguments = $event->getArguments();
  4632. $response = \call_user_func_array($controller, $arguments);
  4633. if (!$response instanceof Response) {
  4634. $event = new GetResponseForControllerResultEvent($this, $request, $type, $response);
  4635. $this->dispatcher->dispatch(KernelEvents::VIEW, $event);
  4636. if ($event->hasResponse()) {
  4637. $response = $event->getResponse();
  4638. }
  4639. if (!$response instanceof Response) {
  4640. $msg = sprintf('The controller must return a response (%s given).', $this->varToString($response));
  4641. if (null === $response) {
  4642. $msg .=' Did you forget to add a return statement somewhere in your controller?';
  4643. }
  4644. throw new \LogicException($msg);
  4645. }
  4646. }
  4647. return $this->filterResponse($response, $request, $type);
  4648. }
  4649. private function filterResponse(Response $response, Request $request, $type)
  4650. {
  4651. $event = new FilterResponseEvent($this, $request, $type, $response);
  4652. $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event);
  4653. $this->finishRequest($request, $type);
  4654. return $event->getResponse();
  4655. }
  4656. private function finishRequest(Request $request, $type)
  4657. {
  4658. $this->dispatcher->dispatch(KernelEvents::FINISH_REQUEST, new FinishRequestEvent($this, $request, $type));
  4659. $this->requestStack->pop();
  4660. }
  4661. private function handleException(\Exception $e, $request, $type)
  4662. {
  4663. $event = new GetResponseForExceptionEvent($this, $request, $type, $e);
  4664. $this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event);
  4665. $e = $event->getException();
  4666. if (!$event->hasResponse()) {
  4667. $this->finishRequest($request, $type);
  4668. throw $e;
  4669. }
  4670. $response = $event->getResponse();
  4671. if ($response->headers->has('X-Status-Code')) {
  4672. @trigger_error(sprintf('Using the X-Status-Code header is deprecated since Symfony 3.3 and will be removed in 4.0. Use %s::allowCustomResponseCode() instead.', GetResponseForExceptionEvent::class), \E_USER_DEPRECATED);
  4673. $response->setStatusCode($response->headers->get('X-Status-Code'));
  4674. $response->headers->remove('X-Status-Code');
  4675. } elseif (!$event->isAllowingCustomResponseCode() && !$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) {
  4676. if ($e instanceof HttpExceptionInterface) {
  4677. $response->setStatusCode($e->getStatusCode());
  4678. $response->headers->add($e->getHeaders());
  4679. } else {
  4680. $response->setStatusCode(500);
  4681. }
  4682. }
  4683. try {
  4684. return $this->filterResponse($response, $request, $type);
  4685. } catch (\Exception $e) {
  4686. return $response;
  4687. }
  4688. }
  4689. private function varToString($var)
  4690. {
  4691. if (\is_object($var)) {
  4692. return sprintf('Object(%s)', \get_class($var));
  4693. }
  4694. if (\is_array($var)) {
  4695. $a = [];
  4696. foreach ($var as $k => $v) {
  4697. $a[] = sprintf('%s => %s', $k, $this->varToString($v));
  4698. }
  4699. return sprintf('Array(%s)', implode(', ', $a));
  4700. }
  4701. if (\is_resource($var)) {
  4702. return sprintf('Resource(%s)', get_resource_type($var));
  4703. }
  4704. if (null === $var) {
  4705. return'null';
  4706. }
  4707. if (false === $var) {
  4708. return'false';
  4709. }
  4710. if (true === $var) {
  4711. return'true';
  4712. }
  4713. return (string) $var;
  4714. }
  4715. }
  4716. }
  4717. namespace Symfony\Component\HttpKernel
  4718. {
  4719. final class KernelEvents
  4720. {
  4721. const REQUEST ='kernel.request';
  4722. const EXCEPTION ='kernel.exception';
  4723. const VIEW ='kernel.view';
  4724. const CONTROLLER ='kernel.controller';
  4725. const CONTROLLER_ARGUMENTS ='kernel.controller_arguments';
  4726. const RESPONSE ='kernel.response';
  4727. const TERMINATE ='kernel.terminate';
  4728. const FINISH_REQUEST ='kernel.finish_request';
  4729. }
  4730. }
  4731. namespace Symfony\Component\HttpKernel\Config
  4732. {
  4733. use Symfony\Component\Config\FileLocator as BaseFileLocator;
  4734. use Symfony\Component\HttpKernel\KernelInterface;
  4735. class FileLocator extends BaseFileLocator
  4736. {
  4737. private $kernel;
  4738. private $path;
  4739. public function __construct(KernelInterface $kernel, $path = null, array $paths = [])
  4740. {
  4741. $this->kernel = $kernel;
  4742. if (null !== $path) {
  4743. $this->path = $path;
  4744. $paths[] = $path;
  4745. }
  4746. parent::__construct($paths);
  4747. }
  4748. public function locate($file, $currentPath = null, $first = true)
  4749. {
  4750. if (isset($file[0]) &&'@'=== $file[0]) {
  4751. return $this->kernel->locateResource($file, $this->path, $first);
  4752. }
  4753. return parent::locate($file, $currentPath, $first);
  4754. }
  4755. }
  4756. }
  4757. namespace Symfony\Bundle\FrameworkBundle\Controller
  4758. {
  4759. use Symfony\Component\HttpKernel\KernelInterface;
  4760. class ControllerNameParser
  4761. {
  4762. protected $kernel;
  4763. public function __construct(KernelInterface $kernel)
  4764. {
  4765. $this->kernel = $kernel;
  4766. }
  4767. public function parse($controller)
  4768. {
  4769. $parts = explode(':', $controller);
  4770. if (3 !== \count($parts) || \in_array('', $parts, true)) {
  4771. throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "a:b:c" controller string.', $controller));
  4772. }
  4773. $originalController = $controller;
  4774. list($bundle, $controller, $action) = $parts;
  4775. $controller = str_replace('/','\\', $controller);
  4776. $bundles = [];
  4777. try {
  4778. $allBundles = $this->kernel->getBundle($bundle, false, true);
  4779. } catch (\InvalidArgumentException $e) {
  4780. $message = sprintf('The "%s" (from the _controller value "%s") does not exist or is not enabled in your kernel!',
  4781. $bundle,
  4782. $originalController
  4783. );
  4784. if ($alternative = $this->findAlternative($bundle)) {
  4785. $message .= sprintf(' Did you mean "%s:%s:%s"?', $alternative, $controller, $action);
  4786. }
  4787. throw new \InvalidArgumentException($message, 0, $e);
  4788. }
  4789. if (!\is_array($allBundles)) {
  4790. $allBundles = [$allBundles];
  4791. }
  4792. foreach ($allBundles as $b) {
  4793. $try = $b->getNamespace().'\\Controller\\'.$controller.'Controller';
  4794. if (class_exists($try)) {
  4795. return $try.'::'.$action.'Action';
  4796. }
  4797. $bundles[] = $b->getName();
  4798. $msg = sprintf('The _controller value "%s:%s:%s" maps to a "%s" class, but this class was not found. Create this class or check the spelling of the class and its namespace.', $bundle, $controller, $action, $try);
  4799. }
  4800. if (\count($bundles) > 1) {
  4801. $msg = sprintf('Unable to find controller "%s:%s" in bundles %s.', $bundle, $controller, implode(', ', $bundles));
  4802. }
  4803. throw new \InvalidArgumentException($msg);
  4804. }
  4805. public function build($controller)
  4806. {
  4807. if (0 === preg_match('#^(.*?\\\\Controller\\\\(.+)Controller)::(.+)Action$#', $controller, $match)) {
  4808. throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "class::method" string.', $controller));
  4809. }
  4810. $className = $match[1];
  4811. $controllerName = $match[2];
  4812. $actionName = $match[3];
  4813. foreach ($this->kernel->getBundles() as $name => $bundle) {
  4814. if (0 !== strpos($className, $bundle->getNamespace())) {
  4815. continue;
  4816. }
  4817. return sprintf('%s:%s:%s', $name, $controllerName, $actionName);
  4818. }
  4819. throw new \InvalidArgumentException(sprintf('Unable to find a bundle that defines controller "%s".', $controller));
  4820. }
  4821. private function findAlternative($nonExistentBundleName)
  4822. {
  4823. $bundleNames = array_map(function ($b) {
  4824. return $b->getName();
  4825. }, $this->kernel->getBundles());
  4826. $alternative = null;
  4827. $shortest = null;
  4828. foreach ($bundleNames as $bundleName) {
  4829. if (false !== strpos($bundleName, $nonExistentBundleName)) {
  4830. return $bundleName;
  4831. }
  4832. $lev = levenshtein($nonExistentBundleName, $bundleName);
  4833. if ($lev <= \strlen($nonExistentBundleName) / 3 && (null === $alternative || $lev < $shortest)) {
  4834. $alternative = $bundleName;
  4835. $shortest = $lev;
  4836. }
  4837. }
  4838. return $alternative;
  4839. }
  4840. }
  4841. }
  4842. namespace Symfony\Component\HttpKernel\Controller
  4843. {
  4844. use Psr\Container\ContainerInterface;
  4845. use Psr\Log\LoggerInterface;
  4846. use Symfony\Component\DependencyInjection\Container;
  4847. use Symfony\Component\HttpFoundation\Request;
  4848. class ContainerControllerResolver extends ControllerResolver
  4849. {
  4850. protected $container;
  4851. public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
  4852. {
  4853. $this->container = $container;
  4854. parent::__construct($logger);
  4855. }
  4856. public function getController(Request $request)
  4857. {
  4858. $controller = parent::getController($request);
  4859. if (\is_array($controller) && isset($controller[0]) && \is_string($controller[0]) && $this->container->has($controller[0])) {
  4860. $controller[0] = $this->instantiateController($controller[0]);
  4861. }
  4862. return $controller;
  4863. }
  4864. protected function createController($controller)
  4865. {
  4866. if (false !== strpos($controller,'::')) {
  4867. return parent::createController($controller);
  4868. }
  4869. $method = null;
  4870. if (1 == substr_count($controller,':')) {
  4871. list($controller, $method) = explode(':', $controller, 2);
  4872. }
  4873. if (!$this->container->has($controller)) {
  4874. $this->throwExceptionIfControllerWasRemoved($controller);
  4875. throw new \LogicException(sprintf('Controller not found: service "%s" does not exist.', $controller));
  4876. }
  4877. $service = $this->container->get($controller);
  4878. if (null !== $method) {
  4879. return [$service, $method];
  4880. }
  4881. if (!method_exists($service,'__invoke')) {
  4882. throw new \LogicException(sprintf('Controller "%s" cannot be called without a method name. Did you forget an "__invoke" method?', $controller));
  4883. }
  4884. return $service;
  4885. }
  4886. protected function instantiateController($class)
  4887. {
  4888. if ($this->container->has($class)) {
  4889. return $this->container->get($class);
  4890. }
  4891. try {
  4892. return parent::instantiateController($class);
  4893. } catch (\ArgumentCountError $e) {
  4894. } catch (\ErrorException $e) {
  4895. } catch (\TypeError $e) {
  4896. }
  4897. $this->throwExceptionIfControllerWasRemoved($class, $e);
  4898. throw $e;
  4899. }
  4900. private function throwExceptionIfControllerWasRemoved($controller, $previous = null)
  4901. {
  4902. if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) {
  4903. throw new \LogicException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous);
  4904. }
  4905. }
  4906. }
  4907. }
  4908. namespace Symfony\Bundle\FrameworkBundle\Controller
  4909. {
  4910. use Psr\Log\LoggerInterface;
  4911. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  4912. use Symfony\Component\DependencyInjection\ContainerInterface;
  4913. use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver;
  4914. class ControllerResolver extends ContainerControllerResolver
  4915. {
  4916. protected $parser;
  4917. public function __construct(ContainerInterface $container, ControllerNameParser $parser, LoggerInterface $logger = null)
  4918. {
  4919. $this->parser = $parser;
  4920. parent::__construct($container, $logger);
  4921. }
  4922. protected function createController($controller)
  4923. {
  4924. if (false === strpos($controller,'::') && 2 === substr_count($controller,':')) {
  4925. $controller = $this->parser->parse($controller);
  4926. }
  4927. $resolvedController = parent::createController($controller);
  4928. if (1 === substr_count($controller,':') && \is_array($resolvedController)) {
  4929. $resolvedController[0] = $this->configureController($resolvedController[0]);
  4930. }
  4931. return $resolvedController;
  4932. }
  4933. protected function instantiateController($class)
  4934. {
  4935. return $this->configureController(parent::instantiateController($class));
  4936. }
  4937. private function configureController($controller)
  4938. {
  4939. if ($controller instanceof ContainerAwareInterface) {
  4940. switch (\get_class($controller)) {
  4941. case RedirectController::class:
  4942. case TemplateController::class:
  4943. return $controller;
  4944. }
  4945. $controller->setContainer($this->container);
  4946. }
  4947. if ($controller instanceof AbstractController && null !== $previousContainer = $controller->setContainer($this->container)) {
  4948. $controller->setContainer($previousContainer);
  4949. }
  4950. return $controller;
  4951. }
  4952. }
  4953. }
  4954. namespace Symfony\Component\Security\Http
  4955. {
  4956. use Symfony\Component\HttpFoundation\Request;
  4957. interface AccessMapInterface
  4958. {
  4959. public function getPatterns(Request $request);
  4960. }
  4961. }
  4962. namespace Symfony\Component\Security\Http
  4963. {
  4964. use Symfony\Component\HttpFoundation\Request;
  4965. use Symfony\Component\HttpFoundation\RequestMatcherInterface;
  4966. class AccessMap implements AccessMapInterface
  4967. {
  4968. private $map = [];
  4969. public function add(RequestMatcherInterface $requestMatcher, array $attributes = [], $channel = null)
  4970. {
  4971. $this->map[] = [$requestMatcher, $attributes, $channel];
  4972. }
  4973. public function getPatterns(Request $request)
  4974. {
  4975. foreach ($this->map as $elements) {
  4976. if (null === $elements[0] || $elements[0]->matches($request)) {
  4977. return [$elements[1], $elements[2]];
  4978. }
  4979. }
  4980. return [null, null];
  4981. }
  4982. }
  4983. }
  4984. namespace Symfony\Component\Security\Http
  4985. {
  4986. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  4987. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  4988. use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
  4989. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  4990. use Symfony\Component\HttpKernel\KernelEvents;
  4991. use Symfony\Component\Security\Http\Firewall\AccessListener;
  4992. class Firewall implements EventSubscriberInterface
  4993. {
  4994. private $map;
  4995. private $dispatcher;
  4996. private $exceptionListeners;
  4997. public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher)
  4998. {
  4999. $this->map = $map;
  5000. $this->dispatcher = $dispatcher;
  5001. $this->exceptionListeners = new \SplObjectStorage();
  5002. }
  5003. public function onKernelRequest(GetResponseEvent $event)
  5004. {
  5005. if (!$event->isMasterRequest()) {
  5006. return;
  5007. }
  5008. $listeners = $this->map->getListeners($event->getRequest());
  5009. $authenticationListeners = $listeners[0];
  5010. $exceptionListener = $listeners[1];
  5011. $logoutListener = isset($listeners[2]) ? $listeners[2] : null;
  5012. if (null !== $exceptionListener) {
  5013. $this->exceptionListeners[$event->getRequest()] = $exceptionListener;
  5014. $exceptionListener->register($this->dispatcher);
  5015. }
  5016. $authenticationListeners = function () use ($authenticationListeners, $logoutListener) {
  5017. $accessListener = null;
  5018. foreach ($authenticationListeners as $listener) {
  5019. if ($listener instanceof AccessListener) {
  5020. $accessListener = $listener;
  5021. continue;
  5022. }
  5023. yield $listener;
  5024. }
  5025. if (null !== $logoutListener) {
  5026. yield $logoutListener;
  5027. }
  5028. if (null !== $accessListener) {
  5029. yield $accessListener;
  5030. }
  5031. };
  5032. $this->handleRequest($event, $authenticationListeners());
  5033. }
  5034. public function onKernelFinishRequest(FinishRequestEvent $event)
  5035. {
  5036. $request = $event->getRequest();
  5037. if (isset($this->exceptionListeners[$request])) {
  5038. $this->exceptionListeners[$request]->unregister($this->dispatcher);
  5039. unset($this->exceptionListeners[$request]);
  5040. }
  5041. }
  5042. public static function getSubscribedEvents()
  5043. {
  5044. return [
  5045. KernelEvents::REQUEST => ['onKernelRequest', 8],
  5046. KernelEvents::FINISH_REQUEST =>'onKernelFinishRequest',
  5047. ];
  5048. }
  5049. protected function handleRequest(GetResponseEvent $event, $listeners)
  5050. {
  5051. foreach ($listeners as $listener) {
  5052. $listener->handle($event);
  5053. if ($event->hasResponse()) {
  5054. break;
  5055. }
  5056. }
  5057. }
  5058. }
  5059. }
  5060. namespace Symfony\Component\Security\Core\User
  5061. {
  5062. use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
  5063. use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
  5064. interface UserProviderInterface
  5065. {
  5066. public function loadUserByUsername($username);
  5067. public function refreshUser(UserInterface $user);
  5068. public function supportsClass($class);
  5069. }
  5070. }
  5071. namespace Symfony\Component\Security\Core\Authentication
  5072. {
  5073. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  5074. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  5075. interface AuthenticationManagerInterface
  5076. {
  5077. public function authenticate(TokenInterface $token);
  5078. }
  5079. }
  5080. namespace Symfony\Component\Security\Core\Authentication
  5081. {
  5082. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  5083. use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
  5084. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  5085. use Symfony\Component\Security\Core\AuthenticationEvents;
  5086. use Symfony\Component\Security\Core\Event\AuthenticationEvent;
  5087. use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
  5088. use Symfony\Component\Security\Core\Exception\AccountStatusException;
  5089. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  5090. use Symfony\Component\Security\Core\Exception\ProviderNotFoundException;
  5091. class AuthenticationProviderManager implements AuthenticationManagerInterface
  5092. {
  5093. private $providers;
  5094. private $eraseCredentials;
  5095. private $eventDispatcher;
  5096. public function __construct($providers, $eraseCredentials = true)
  5097. {
  5098. if (!$providers) {
  5099. throw new \InvalidArgumentException('You must at least add one authentication provider.');
  5100. }
  5101. $this->providers = $providers;
  5102. $this->eraseCredentials = (bool) $eraseCredentials;
  5103. }
  5104. public function setEventDispatcher(EventDispatcherInterface $dispatcher)
  5105. {
  5106. $this->eventDispatcher = $dispatcher;
  5107. }
  5108. public function authenticate(TokenInterface $token)
  5109. {
  5110. $lastException = null;
  5111. $result = null;
  5112. foreach ($this->providers as $provider) {
  5113. if (!$provider instanceof AuthenticationProviderInterface) {
  5114. throw new \InvalidArgumentException(sprintf('Provider "%s" must implement the AuthenticationProviderInterface.', \get_class($provider)));
  5115. }
  5116. if (!$provider->supports($token)) {
  5117. continue;
  5118. }
  5119. try {
  5120. $result = $provider->authenticate($token);
  5121. if (null !== $result) {
  5122. break;
  5123. }
  5124. } catch (AccountStatusException $e) {
  5125. $lastException = $e;
  5126. break;
  5127. } catch (AuthenticationException $e) {
  5128. $lastException = $e;
  5129. }
  5130. }
  5131. if (null !== $result) {
  5132. if (true === $this->eraseCredentials) {
  5133. $result->eraseCredentials();
  5134. }
  5135. if (null !== $this->eventDispatcher) {
  5136. $this->eventDispatcher->dispatch(AuthenticationEvents::AUTHENTICATION_SUCCESS, new AuthenticationEvent($result));
  5137. }
  5138. return $result;
  5139. }
  5140. if (null === $lastException) {
  5141. $lastException = new ProviderNotFoundException(sprintf('No Authentication Provider found for token of class "%s".', \get_class($token)));
  5142. }
  5143. if (null !== $this->eventDispatcher) {
  5144. $this->eventDispatcher->dispatch(AuthenticationEvents::AUTHENTICATION_FAILURE, new AuthenticationFailureEvent($token, $lastException));
  5145. }
  5146. $lastException->setToken($token);
  5147. throw $lastException;
  5148. }
  5149. }
  5150. }
  5151. namespace Symfony\Component\Security\Core\Authentication\Token\Storage
  5152. {
  5153. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  5154. interface TokenStorageInterface
  5155. {
  5156. public function getToken();
  5157. public function setToken(TokenInterface $token = null);
  5158. }
  5159. }
  5160. namespace Symfony\Component\Security\Core\Authentication\Token\Storage
  5161. {
  5162. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  5163. class TokenStorage implements TokenStorageInterface
  5164. {
  5165. private $token;
  5166. public function getToken()
  5167. {
  5168. return $this->token;
  5169. }
  5170. public function setToken(TokenInterface $token = null)
  5171. {
  5172. $this->token = $token;
  5173. }
  5174. }
  5175. }
  5176. namespace Symfony\Component\Security\Core\Authorization
  5177. {
  5178. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  5179. interface AccessDecisionManagerInterface
  5180. {
  5181. public function decide(TokenInterface $token, array $attributes, $object = null);
  5182. }
  5183. }
  5184. namespace Symfony\Component\Security\Core\Authorization
  5185. {
  5186. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  5187. use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
  5188. use Symfony\Component\Security\Core\Exception\LogicException;
  5189. class AccessDecisionManager implements AccessDecisionManagerInterface
  5190. {
  5191. const STRATEGY_AFFIRMATIVE ='affirmative';
  5192. const STRATEGY_CONSENSUS ='consensus';
  5193. const STRATEGY_UNANIMOUS ='unanimous';
  5194. private $voters;
  5195. private $strategy;
  5196. private $allowIfAllAbstainDecisions;
  5197. private $allowIfEqualGrantedDeniedDecisions;
  5198. public function __construct($voters = [], $strategy = self::STRATEGY_AFFIRMATIVE, $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true)
  5199. {
  5200. $strategyMethod ='decide'.ucfirst($strategy);
  5201. if (''=== $strategy || !\is_callable([$this, $strategyMethod])) {
  5202. throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.', $strategy));
  5203. }
  5204. $this->voters = $voters;
  5205. $this->strategy = $strategyMethod;
  5206. $this->allowIfAllAbstainDecisions = (bool) $allowIfAllAbstainDecisions;
  5207. $this->allowIfEqualGrantedDeniedDecisions = (bool) $allowIfEqualGrantedDeniedDecisions;
  5208. }
  5209. public function setVoters(array $voters)
  5210. {
  5211. @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Pass the voters to the constructor instead.', __METHOD__), \E_USER_DEPRECATED);
  5212. $this->voters = $voters;
  5213. }
  5214. public function decide(TokenInterface $token, array $attributes, $object = null)
  5215. {
  5216. return $this->{$this->strategy}($token, $attributes, $object);
  5217. }
  5218. private function decideAffirmative(TokenInterface $token, array $attributes, $object = null)
  5219. {
  5220. $deny = 0;
  5221. foreach ($this->voters as $voter) {
  5222. $result = $this->vote($voter, $token, $object, $attributes);
  5223. if (VoterInterface::ACCESS_GRANTED === $result) {
  5224. return true;
  5225. }
  5226. if (VoterInterface::ACCESS_DENIED === $result) {
  5227. ++$deny;
  5228. }
  5229. }
  5230. if ($deny > 0) {
  5231. return false;
  5232. }
  5233. return $this->allowIfAllAbstainDecisions;
  5234. }
  5235. private function decideConsensus(TokenInterface $token, array $attributes, $object = null)
  5236. {
  5237. $grant = 0;
  5238. $deny = 0;
  5239. foreach ($this->voters as $voter) {
  5240. $result = $this->vote($voter, $token, $object, $attributes);
  5241. if (VoterInterface::ACCESS_GRANTED === $result) {
  5242. ++$grant;
  5243. } elseif (VoterInterface::ACCESS_DENIED === $result) {
  5244. ++$deny;
  5245. }
  5246. }
  5247. if ($grant > $deny) {
  5248. return true;
  5249. }
  5250. if ($deny > $grant) {
  5251. return false;
  5252. }
  5253. if ($grant > 0) {
  5254. return $this->allowIfEqualGrantedDeniedDecisions;
  5255. }
  5256. return $this->allowIfAllAbstainDecisions;
  5257. }
  5258. private function decideUnanimous(TokenInterface $token, array $attributes, $object = null)
  5259. {
  5260. $grant = 0;
  5261. foreach ($this->voters as $voter) {
  5262. foreach ($attributes as $attribute) {
  5263. $result = $this->vote($voter, $token, $object, [$attribute]);
  5264. if (VoterInterface::ACCESS_DENIED === $result) {
  5265. return false;
  5266. }
  5267. if (VoterInterface::ACCESS_GRANTED === $result) {
  5268. ++$grant;
  5269. }
  5270. }
  5271. }
  5272. if ($grant > 0) {
  5273. return true;
  5274. }
  5275. return $this->allowIfAllAbstainDecisions;
  5276. }
  5277. private function vote($voter, TokenInterface $token, $subject, $attributes)
  5278. {
  5279. if ($voter instanceof VoterInterface) {
  5280. return $voter->vote($token, $subject, $attributes);
  5281. }
  5282. if (method_exists($voter,'vote')) {
  5283. @trigger_error(sprintf('Calling vote() on an voter without %1$s is deprecated as of 3.4 and will be removed in 4.0. Implement the %1$s on your voter.', VoterInterface::class), \E_USER_DEPRECATED);
  5284. return $voter->vote($token, $subject, $attributes);
  5285. }
  5286. throw new LogicException(sprintf('"%s" should implement the "%s" interface when used as voter.', \get_class($voter), VoterInterface::class));
  5287. }
  5288. }
  5289. }
  5290. namespace Symfony\Component\Security\Core\Authorization
  5291. {
  5292. interface AuthorizationCheckerInterface
  5293. {
  5294. public function isGranted($attributes, $subject = null);
  5295. }
  5296. }
  5297. namespace Symfony\Component\Security\Core\Authorization
  5298. {
  5299. use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
  5300. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  5301. use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
  5302. class AuthorizationChecker implements AuthorizationCheckerInterface
  5303. {
  5304. private $tokenStorage;
  5305. private $accessDecisionManager;
  5306. private $authenticationManager;
  5307. private $alwaysAuthenticate;
  5308. public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager, $alwaysAuthenticate = false)
  5309. {
  5310. $this->tokenStorage = $tokenStorage;
  5311. $this->authenticationManager = $authenticationManager;
  5312. $this->accessDecisionManager = $accessDecisionManager;
  5313. $this->alwaysAuthenticate = $alwaysAuthenticate;
  5314. }
  5315. final public function isGranted($attributes, $subject = null)
  5316. {
  5317. if (null === ($token = $this->tokenStorage->getToken())) {
  5318. throw new AuthenticationCredentialsNotFoundException('The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.');
  5319. }
  5320. if ($this->alwaysAuthenticate || !$token->isAuthenticated()) {
  5321. $this->tokenStorage->setToken($token = $this->authenticationManager->authenticate($token));
  5322. }
  5323. if (!\is_array($attributes)) {
  5324. $attributes = [$attributes];
  5325. }
  5326. return $this->accessDecisionManager->decide($token, $attributes, $subject);
  5327. }
  5328. }
  5329. }
  5330. namespace Symfony\Component\Security\Core\Authorization\Voter
  5331. {
  5332. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  5333. interface VoterInterface
  5334. {
  5335. const ACCESS_GRANTED = 1;
  5336. const ACCESS_ABSTAIN = 0;
  5337. const ACCESS_DENIED = -1;
  5338. public function vote(TokenInterface $token, $subject, array $attributes);
  5339. }
  5340. }
  5341. namespace Symfony\Bundle\SecurityBundle\Security
  5342. {
  5343. final class FirewallConfig
  5344. {
  5345. private $name;
  5346. private $userChecker;
  5347. private $requestMatcher;
  5348. private $securityEnabled;
  5349. private $stateless;
  5350. private $provider;
  5351. private $context;
  5352. private $entryPoint;
  5353. private $accessDeniedHandler;
  5354. private $accessDeniedUrl;
  5355. private $listeners;
  5356. private $switchUser;
  5357. public function __construct($name, $userChecker, $requestMatcher = null, $securityEnabled = true, $stateless = false, $provider = null, $context = null, $entryPoint = null, $accessDeniedHandler = null, $accessDeniedUrl = null, $listeners = [], $switchUser = null)
  5358. {
  5359. $this->name = $name;
  5360. $this->userChecker = $userChecker;
  5361. $this->requestMatcher = $requestMatcher;
  5362. $this->securityEnabled = $securityEnabled;
  5363. $this->stateless = $stateless;
  5364. $this->provider = $provider;
  5365. $this->context = $context;
  5366. $this->entryPoint = $entryPoint;
  5367. $this->accessDeniedHandler = $accessDeniedHandler;
  5368. $this->accessDeniedUrl = $accessDeniedUrl;
  5369. $this->listeners = $listeners;
  5370. $this->switchUser = $switchUser;
  5371. }
  5372. public function getName()
  5373. {
  5374. return $this->name;
  5375. }
  5376. public function getRequestMatcher()
  5377. {
  5378. return $this->requestMatcher;
  5379. }
  5380. public function isSecurityEnabled()
  5381. {
  5382. return $this->securityEnabled;
  5383. }
  5384. public function allowsAnonymous()
  5385. {
  5386. return \in_array('anonymous', $this->listeners, true);
  5387. }
  5388. public function isStateless()
  5389. {
  5390. return $this->stateless;
  5391. }
  5392. public function getProvider()
  5393. {
  5394. return $this->provider;
  5395. }
  5396. public function getContext()
  5397. {
  5398. return $this->context;
  5399. }
  5400. public function getEntryPoint()
  5401. {
  5402. return $this->entryPoint;
  5403. }
  5404. public function getUserChecker()
  5405. {
  5406. return $this->userChecker;
  5407. }
  5408. public function getAccessDeniedHandler()
  5409. {
  5410. return $this->accessDeniedHandler;
  5411. }
  5412. public function getAccessDeniedUrl()
  5413. {
  5414. return $this->accessDeniedUrl;
  5415. }
  5416. public function getListeners()
  5417. {
  5418. return $this->listeners;
  5419. }
  5420. public function getSwitchUser()
  5421. {
  5422. return $this->switchUser;
  5423. }
  5424. }
  5425. }
  5426. namespace Symfony\Bundle\SecurityBundle\Security
  5427. {
  5428. use Symfony\Component\Security\Http\Firewall\ExceptionListener;
  5429. use Symfony\Component\Security\Http\Firewall\LogoutListener;
  5430. class FirewallContext
  5431. {
  5432. private $listeners;
  5433. private $exceptionListener;
  5434. private $logoutListener;
  5435. private $config;
  5436. public function __construct($listeners, ExceptionListener $exceptionListener = null, $logoutListener = null, FirewallConfig $config = null)
  5437. {
  5438. $this->listeners = $listeners;
  5439. $this->exceptionListener = $exceptionListener;
  5440. if ($logoutListener instanceof FirewallConfig) {
  5441. $this->config = $logoutListener;
  5442. } elseif (null === $logoutListener || $logoutListener instanceof LogoutListener) {
  5443. $this->logoutListener = $logoutListener;
  5444. $this->config = $config;
  5445. } else {
  5446. throw new \InvalidArgumentException(sprintf('Argument 3 passed to "%s()" must be instance of "%s" or null, "%s" given.', __METHOD__, LogoutListener::class, \is_object($logoutListener) ? \get_class($logoutListener) : \gettype($logoutListener)));
  5447. }
  5448. }
  5449. public function getConfig()
  5450. {
  5451. return $this->config;
  5452. }
  5453. public function getContext()
  5454. {
  5455. @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use %s::getListeners/getExceptionListener() instead.', __METHOD__, __CLASS__), \E_USER_DEPRECATED);
  5456. return [$this->getListeners(), $this->getExceptionListener(), $this->getLogoutListener()];
  5457. }
  5458. public function getListeners()
  5459. {
  5460. return $this->listeners;
  5461. }
  5462. public function getExceptionListener()
  5463. {
  5464. return $this->exceptionListener;
  5465. }
  5466. public function getLogoutListener()
  5467. {
  5468. return $this->logoutListener;
  5469. }
  5470. }
  5471. }
  5472. namespace Symfony\Component\HttpFoundation
  5473. {
  5474. interface RequestMatcherInterface
  5475. {
  5476. public function matches(Request $request);
  5477. }
  5478. }
  5479. namespace Symfony\Component\HttpFoundation
  5480. {
  5481. class RequestMatcher implements RequestMatcherInterface
  5482. {
  5483. private $path;
  5484. private $host;
  5485. private $methods = [];
  5486. private $ips = [];
  5487. private $attributes = [];
  5488. private $schemes = [];
  5489. public function __construct($path = null, $host = null, $methods = null, $ips = null, array $attributes = [], $schemes = null)
  5490. {
  5491. $this->matchPath($path);
  5492. $this->matchHost($host);
  5493. $this->matchMethod($methods);
  5494. $this->matchIps($ips);
  5495. $this->matchScheme($schemes);
  5496. foreach ($attributes as $k => $v) {
  5497. $this->matchAttribute($k, $v);
  5498. }
  5499. }
  5500. public function matchScheme($scheme)
  5501. {
  5502. $this->schemes = null !== $scheme ? array_map('strtolower', (array) $scheme) : [];
  5503. }
  5504. public function matchHost($regexp)
  5505. {
  5506. $this->host = $regexp;
  5507. }
  5508. public function matchPath($regexp)
  5509. {
  5510. $this->path = $regexp;
  5511. }
  5512. public function matchIp($ip)
  5513. {
  5514. $this->matchIps($ip);
  5515. }
  5516. public function matchIps($ips)
  5517. {
  5518. $this->ips = null !== $ips ? (array) $ips : [];
  5519. }
  5520. public function matchMethod($method)
  5521. {
  5522. $this->methods = null !== $method ? array_map('strtoupper', (array) $method) : [];
  5523. }
  5524. public function matchAttribute($key, $regexp)
  5525. {
  5526. $this->attributes[$key] = $regexp;
  5527. }
  5528. public function matches(Request $request)
  5529. {
  5530. if ($this->schemes && !\in_array($request->getScheme(), $this->schemes, true)) {
  5531. return false;
  5532. }
  5533. if ($this->methods && !\in_array($request->getMethod(), $this->methods, true)) {
  5534. return false;
  5535. }
  5536. foreach ($this->attributes as $key => $pattern) {
  5537. if (!preg_match('{'.$pattern.'}', $request->attributes->get($key))) {
  5538. return false;
  5539. }
  5540. }
  5541. if (null !== $this->path && !preg_match('{'.$this->path.'}', rawurldecode($request->getPathInfo()))) {
  5542. return false;
  5543. }
  5544. if (null !== $this->host && !preg_match('{'.$this->host.'}i', $request->getHost())) {
  5545. return false;
  5546. }
  5547. if (IpUtils::checkIp($request->getClientIp(), $this->ips)) {
  5548. return true;
  5549. }
  5550. return 0 === \count($this->ips);
  5551. }
  5552. }
  5553. }
  5554. namespace Twig
  5555. {
  5556. use Twig\Cache\CacheInterface;
  5557. use Twig\Cache\FilesystemCache;
  5558. use Twig\Cache\NullCache;
  5559. use Twig\Error\Error;
  5560. use Twig\Error\LoaderError;
  5561. use Twig\Error\RuntimeError;
  5562. use Twig\Error\SyntaxError;
  5563. use Twig\Extension\CoreExtension;
  5564. use Twig\Extension\EscaperExtension;
  5565. use Twig\Extension\ExtensionInterface;
  5566. use Twig\Extension\GlobalsInterface;
  5567. use Twig\Extension\InitRuntimeInterface;
  5568. use Twig\Extension\OptimizerExtension;
  5569. use Twig\Extension\StagingExtension;
  5570. use Twig\Loader\ArrayLoader;
  5571. use Twig\Loader\ChainLoader;
  5572. use Twig\Loader\LoaderInterface;
  5573. use Twig\Loader\SourceContextLoaderInterface;
  5574. use Twig\Node\ModuleNode;
  5575. use Twig\NodeVisitor\NodeVisitorInterface;
  5576. use Twig\RuntimeLoader\RuntimeLoaderInterface;
  5577. use Twig\TokenParser\TokenParserInterface;
  5578. class Environment
  5579. {
  5580. const VERSION ='1.42.5';
  5581. const VERSION_ID = 14205;
  5582. const MAJOR_VERSION = 1;
  5583. const MINOR_VERSION = 42;
  5584. const RELEASE_VERSION = 5;
  5585. const EXTRA_VERSION ='';
  5586. protected $charset;
  5587. protected $loader;
  5588. protected $debug;
  5589. protected $autoReload;
  5590. protected $cache;
  5591. protected $lexer;
  5592. protected $parser;
  5593. protected $compiler;
  5594. protected $baseTemplateClass;
  5595. protected $extensions;
  5596. protected $parsers;
  5597. protected $visitors;
  5598. protected $filters;
  5599. protected $tests;
  5600. protected $functions;
  5601. protected $globals;
  5602. protected $runtimeInitialized = false;
  5603. protected $extensionInitialized = false;
  5604. protected $loadedTemplates;
  5605. protected $strictVariables;
  5606. protected $unaryOperators;
  5607. protected $binaryOperators;
  5608. protected $templateClassPrefix ='__TwigTemplate_';
  5609. protected $functionCallbacks = [];
  5610. protected $filterCallbacks = [];
  5611. protected $staging;
  5612. private $originalCache;
  5613. private $bcWriteCacheFile = false;
  5614. private $bcGetCacheFilename = false;
  5615. private $lastModifiedExtension = 0;
  5616. private $extensionsByClass = [];
  5617. private $runtimeLoaders = [];
  5618. private $runtimes = [];
  5619. private $optionsHash;
  5620. public function __construct(LoaderInterface $loader = null, $options = [])
  5621. {
  5622. if (null !== $loader) {
  5623. $this->setLoader($loader);
  5624. } else {
  5625. @trigger_error('Not passing a "Twig\Lodaer\LoaderInterface" as the first constructor argument of "Twig\Environment" is deprecated since version 1.21.', E_USER_DEPRECATED);
  5626. }
  5627. $options = array_merge(['debug'=> false,'charset'=>'UTF-8','base_template_class'=>'\Twig\Template','strict_variables'=> false,'autoescape'=>'html','cache'=> false,'auto_reload'=> null,'optimizations'=> -1,
  5628. ], $options);
  5629. $this->debug = (bool) $options['debug'];
  5630. $this->charset = strtoupper($options['charset']);
  5631. $this->baseTemplateClass = $options['base_template_class'];
  5632. $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
  5633. $this->strictVariables = (bool) $options['strict_variables'];
  5634. $this->setCache($options['cache']);
  5635. $this->addExtension(new CoreExtension());
  5636. $this->addExtension(new EscaperExtension($options['autoescape']));
  5637. $this->addExtension(new OptimizerExtension($options['optimizations']));
  5638. $this->staging = new StagingExtension();
  5639. if (\is_string($this->originalCache)) {
  5640. $r = new \ReflectionMethod($this,'writeCacheFile');
  5641. if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
  5642. @trigger_error('The Twig\Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED);
  5643. $this->bcWriteCacheFile = true;
  5644. }
  5645. $r = new \ReflectionMethod($this,'getCacheFilename');
  5646. if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
  5647. @trigger_error('The Twig\Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED);
  5648. $this->bcGetCacheFilename = true;
  5649. }
  5650. }
  5651. }
  5652. public function getBaseTemplateClass()
  5653. {
  5654. return $this->baseTemplateClass;
  5655. }
  5656. public function setBaseTemplateClass($class)
  5657. {
  5658. $this->baseTemplateClass = $class;
  5659. $this->updateOptionsHash();
  5660. }
  5661. public function enableDebug()
  5662. {
  5663. $this->debug = true;
  5664. $this->updateOptionsHash();
  5665. }
  5666. public function disableDebug()
  5667. {
  5668. $this->debug = false;
  5669. $this->updateOptionsHash();
  5670. }
  5671. public function isDebug()
  5672. {
  5673. return $this->debug;
  5674. }
  5675. public function enableAutoReload()
  5676. {
  5677. $this->autoReload = true;
  5678. }
  5679. public function disableAutoReload()
  5680. {
  5681. $this->autoReload = false;
  5682. }
  5683. public function isAutoReload()
  5684. {
  5685. return $this->autoReload;
  5686. }
  5687. public function enableStrictVariables()
  5688. {
  5689. $this->strictVariables = true;
  5690. $this->updateOptionsHash();
  5691. }
  5692. public function disableStrictVariables()
  5693. {
  5694. $this->strictVariables = false;
  5695. $this->updateOptionsHash();
  5696. }
  5697. public function isStrictVariables()
  5698. {
  5699. return $this->strictVariables;
  5700. }
  5701. public function getCache($original = true)
  5702. {
  5703. return $original ? $this->originalCache : $this->cache;
  5704. }
  5705. public function setCache($cache)
  5706. {
  5707. if (\is_string($cache)) {
  5708. $this->originalCache = $cache;
  5709. $this->cache = new FilesystemCache($cache);
  5710. } elseif (false === $cache) {
  5711. $this->originalCache = $cache;
  5712. $this->cache = new NullCache();
  5713. } elseif (null === $cache) {
  5714. @trigger_error('Using "null" as the cache strategy is deprecated since version 1.23 and will be removed in Twig 2.0.', E_USER_DEPRECATED);
  5715. $this->originalCache = false;
  5716. $this->cache = new NullCache();
  5717. } elseif ($cache instanceof CacheInterface) {
  5718. $this->originalCache = $this->cache = $cache;
  5719. } else {
  5720. throw new \LogicException(sprintf('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.'));
  5721. }
  5722. }
  5723. public function getCacheFilename($name)
  5724. {
  5725. @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
  5726. $key = $this->cache->generateKey($name, $this->getTemplateClass($name));
  5727. return !$key ? false : $key;
  5728. }
  5729. public function getTemplateClass($name, $index = null)
  5730. {
  5731. $key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
  5732. return $this->templateClassPrefix.hash('sha256', $key).(null === $index ?'':'___'.$index);
  5733. }
  5734. public function getTemplateClassPrefix()
  5735. {
  5736. @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
  5737. return $this->templateClassPrefix;
  5738. }
  5739. public function render($name, array $context = [])
  5740. {
  5741. return $this->load($name)->render($context);
  5742. }
  5743. public function display($name, array $context = [])
  5744. {
  5745. $this->load($name)->display($context);
  5746. }
  5747. public function load($name)
  5748. {
  5749. if ($name instanceof TemplateWrapper) {
  5750. return $name;
  5751. }
  5752. if ($name instanceof Template) {
  5753. return new TemplateWrapper($this, $name);
  5754. }
  5755. return new TemplateWrapper($this, $this->loadTemplate($name));
  5756. }
  5757. public function loadTemplate($name, $index = null)
  5758. {
  5759. return $this->loadClass($this->getTemplateClass($name), $name, $index);
  5760. }
  5761. public function loadClass($cls, $name, $index = null)
  5762. {
  5763. $mainCls = $cls;
  5764. if (null !== $index) {
  5765. $cls .='___'.$index;
  5766. }
  5767. if (isset($this->loadedTemplates[$cls])) {
  5768. return $this->loadedTemplates[$cls];
  5769. }
  5770. if (!class_exists($cls, false)) {
  5771. if ($this->bcGetCacheFilename) {
  5772. $key = $this->getCacheFilename($name);
  5773. } else {
  5774. $key = $this->cache->generateKey($name, $mainCls);
  5775. }
  5776. if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
  5777. $this->cache->load($key);
  5778. }
  5779. $source = null;
  5780. if (!class_exists($cls, false)) {
  5781. $loader = $this->getLoader();
  5782. if (!$loader instanceof SourceContextLoaderInterface) {
  5783. $source = new Source($loader->getSource($name), $name);
  5784. } else {
  5785. $source = $loader->getSourceContext($name);
  5786. }
  5787. $content = $this->compileSource($source);
  5788. if ($this->bcWriteCacheFile) {
  5789. $this->writeCacheFile($key, $content);
  5790. } else {
  5791. $this->cache->write($key, $content);
  5792. $this->cache->load($key);
  5793. }
  5794. if (!class_exists($mainCls, false)) {
  5795. eval('?>'.$content);
  5796. }
  5797. }
  5798. if (!class_exists($cls, false)) {
  5799. throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
  5800. }
  5801. }
  5802. if (!$this->runtimeInitialized) {
  5803. $this->initRuntime();
  5804. }
  5805. return $this->loadedTemplates[$cls] = new $cls($this);
  5806. }
  5807. public function createTemplate($template, $name = null)
  5808. {
  5809. $hash = hash('sha256', $template, false);
  5810. if (null !== $name) {
  5811. $name = sprintf('%s (string template %s)', $name, $hash);
  5812. } else {
  5813. $name = sprintf('__string_template__%s', $hash);
  5814. }
  5815. $loader = new ChainLoader([
  5816. new ArrayLoader([$name => $template]),
  5817. $current = $this->getLoader(),
  5818. ]);
  5819. $this->setLoader($loader);
  5820. try {
  5821. $template = new TemplateWrapper($this, $this->loadTemplate($name));
  5822. } catch (\Exception $e) {
  5823. $this->setLoader($current);
  5824. throw $e;
  5825. } catch (\Throwable $e) {
  5826. $this->setLoader($current);
  5827. throw $e;
  5828. }
  5829. $this->setLoader($current);
  5830. return $template;
  5831. }
  5832. public function isTemplateFresh($name, $time)
  5833. {
  5834. if (0 === $this->lastModifiedExtension) {
  5835. foreach ($this->extensions as $extension) {
  5836. $r = new \ReflectionObject($extension);
  5837. if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) {
  5838. $this->lastModifiedExtension = $extensionTime;
  5839. }
  5840. }
  5841. }
  5842. return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time);
  5843. }
  5844. public function resolveTemplate($names)
  5845. {
  5846. if (!\is_array($names)) {
  5847. $names = [$names];
  5848. }
  5849. foreach ($names as $name) {
  5850. if ($name instanceof Template) {
  5851. return $name;
  5852. }
  5853. if ($name instanceof TemplateWrapper) {
  5854. return $name;
  5855. }
  5856. try {
  5857. return $this->loadTemplate($name);
  5858. } catch (LoaderError $e) {
  5859. if (1 === \count($names)) {
  5860. throw $e;
  5861. }
  5862. }
  5863. }
  5864. throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
  5865. }
  5866. public function clearTemplateCache()
  5867. {
  5868. @trigger_error(sprintf('The %s method is deprecated since version 1.18.3 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
  5869. $this->loadedTemplates = [];
  5870. }
  5871. public function clearCacheFiles()
  5872. {
  5873. @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
  5874. if (\is_string($this->originalCache)) {
  5875. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->originalCache), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
  5876. if ($file->isFile()) {
  5877. @unlink($file->getPathname());
  5878. }
  5879. }
  5880. }
  5881. }
  5882. public function getLexer()
  5883. {
  5884. @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
  5885. if (null === $this->lexer) {
  5886. $this->lexer = new Lexer($this);
  5887. }
  5888. return $this->lexer;
  5889. }
  5890. public function setLexer(\Twig_LexerInterface $lexer)
  5891. {
  5892. $this->lexer = $lexer;
  5893. }
  5894. public function tokenize($source, $name = null)
  5895. {
  5896. if (!$source instanceof Source) {
  5897. @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED);
  5898. $source = new Source($source, $name);
  5899. }
  5900. if (null === $this->lexer) {
  5901. $this->lexer = new Lexer($this);
  5902. }
  5903. return $this->lexer->tokenize($source);
  5904. }
  5905. public function getParser()
  5906. {
  5907. @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
  5908. if (null === $this->parser) {
  5909. $this->parser = new Parser($this);
  5910. }
  5911. return $this->parser;
  5912. }
  5913. public function setParser(\Twig_ParserInterface $parser)
  5914. {
  5915. $this->parser = $parser;
  5916. }
  5917. public function parse(TokenStream $stream)
  5918. {
  5919. if (null === $this->parser) {
  5920. $this->parser = new Parser($this);
  5921. }
  5922. return $this->parser->parse($stream);
  5923. }
  5924. public function getCompiler()
  5925. {
  5926. @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
  5927. if (null === $this->compiler) {
  5928. $this->compiler = new Compiler($this);
  5929. }
  5930. return $this->compiler;
  5931. }
  5932. public function setCompiler(\Twig_CompilerInterface $compiler)
  5933. {
  5934. $this->compiler = $compiler;
  5935. }
  5936. public function compile(\Twig_NodeInterface $node)
  5937. {
  5938. if (null === $this->compiler) {
  5939. $this->compiler = new Compiler($this);
  5940. }
  5941. return $this->compiler->compile($node)->getSource();
  5942. }
  5943. public function compileSource($source, $name = null)
  5944. {
  5945. if (!$source instanceof Source) {
  5946. @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED);
  5947. $source = new Source($source, $name);
  5948. }
  5949. try {
  5950. return $this->compile($this->parse($this->tokenize($source)));
  5951. } catch (Error $e) {
  5952. $e->setSourceContext($source);
  5953. throw $e;
  5954. } catch (\Exception $e) {
  5955. throw new SyntaxError(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
  5956. }
  5957. }
  5958. public function setLoader(LoaderInterface $loader)
  5959. {
  5960. if (!$loader instanceof SourceContextLoaderInterface && 0 !== strpos(\get_class($loader),'Mock_')) {
  5961. @trigger_error(sprintf('Twig loader "%s" should implement Twig\Loader\SourceContextLoaderInterface since version 1.27.', \get_class($loader)), E_USER_DEPRECATED);
  5962. }
  5963. $this->loader = $loader;
  5964. }
  5965. public function getLoader()
  5966. {
  5967. if (null === $this->loader) {
  5968. throw new \LogicException('You must set a loader first.');
  5969. }
  5970. return $this->loader;
  5971. }
  5972. public function setCharset($charset)
  5973. {
  5974. $this->charset = strtoupper($charset);
  5975. }
  5976. public function getCharset()
  5977. {
  5978. return $this->charset;
  5979. }
  5980. public function initRuntime()
  5981. {
  5982. $this->runtimeInitialized = true;
  5983. foreach ($this->getExtensions() as $name => $extension) {
  5984. if (!$extension instanceof InitRuntimeInterface) {
  5985. $m = new \ReflectionMethod($extension,'initRuntime');
  5986. $parentClass = $m->getDeclaringClass()->getName();
  5987. if ('Twig_Extension'!== $parentClass &&'Twig\Extension\AbstractExtension'!== $parentClass) {
  5988. @trigger_error(sprintf('Defining the initRuntime() method in the "%s" extension is deprecated since version 1.23. Use the `needs_environment` option to get the \Twig_Environment instance in filters, functions, or tests; or explicitly implement Twig\Extension\InitRuntimeInterface if needed (not recommended).', $name), E_USER_DEPRECATED);
  5989. }
  5990. }
  5991. $extension->initRuntime($this);
  5992. }
  5993. }
  5994. public function hasExtension($class)
  5995. {
  5996. $class = ltrim($class,'\\');
  5997. if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) {
  5998. $class = new \ReflectionClass($class);
  5999. $class = $class->name;
  6000. }
  6001. if (isset($this->extensions[$class])) {
  6002. if ($class !== \get_class($this->extensions[$class])) {
  6003. @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED);
  6004. }
  6005. return true;
  6006. }
  6007. return isset($this->extensionsByClass[$class]);
  6008. }
  6009. public function addRuntimeLoader(RuntimeLoaderInterface $loader)
  6010. {
  6011. $this->runtimeLoaders[] = $loader;
  6012. }
  6013. public function getExtension($class)
  6014. {
  6015. $class = ltrim($class,'\\');
  6016. if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) {
  6017. $class = new \ReflectionClass($class);
  6018. $class = $class->name;
  6019. }
  6020. if (isset($this->extensions[$class])) {
  6021. if ($class !== \get_class($this->extensions[$class])) {
  6022. @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED);
  6023. }
  6024. return $this->extensions[$class];
  6025. }
  6026. if (!isset($this->extensionsByClass[$class])) {
  6027. throw new RuntimeError(sprintf('The "%s" extension is not enabled.', $class));
  6028. }
  6029. return $this->extensionsByClass[$class];
  6030. }
  6031. public function getRuntime($class)
  6032. {
  6033. if (isset($this->runtimes[$class])) {
  6034. return $this->runtimes[$class];
  6035. }
  6036. foreach ($this->runtimeLoaders as $loader) {
  6037. if (null !== $runtime = $loader->load($class)) {
  6038. return $this->runtimes[$class] = $runtime;
  6039. }
  6040. }
  6041. throw new RuntimeError(sprintf('Unable to load the "%s" runtime.', $class));
  6042. }
  6043. public function addExtension(ExtensionInterface $extension)
  6044. {
  6045. if ($this->extensionInitialized) {
  6046. throw new \LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
  6047. }
  6048. $class = \get_class($extension);
  6049. if ($class !== $extension->getName()) {
  6050. if (isset($this->extensions[$extension->getName()])) {
  6051. unset($this->extensions[$extension->getName()], $this->extensionsByClass[$class]);
  6052. @trigger_error(sprintf('The possibility to register the same extension twice ("%s") is deprecated since version 1.23 and will be removed in Twig 2.0. Use proper PHP inheritance instead.', $extension->getName()), E_USER_DEPRECATED);
  6053. }
  6054. }
  6055. $this->lastModifiedExtension = 0;
  6056. $this->extensionsByClass[$class] = $extension;
  6057. $this->extensions[$extension->getName()] = $extension;
  6058. $this->updateOptionsHash();
  6059. }
  6060. public function removeExtension($name)
  6061. {
  6062. @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
  6063. if ($this->extensionInitialized) {
  6064. throw new \LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
  6065. }
  6066. $class = ltrim($name,'\\');
  6067. if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) {
  6068. $class = new \ReflectionClass($class);
  6069. $class = $class->name;
  6070. }
  6071. if (isset($this->extensions[$class])) {
  6072. if ($class !== \get_class($this->extensions[$class])) {
  6073. @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED);
  6074. }
  6075. unset($this->extensions[$class]);
  6076. }
  6077. unset($this->extensions[$class]);
  6078. $this->updateOptionsHash();
  6079. }
  6080. public function setExtensions(array $extensions)
  6081. {
  6082. foreach ($extensions as $extension) {
  6083. $this->addExtension($extension);
  6084. }
  6085. }
  6086. public function getExtensions()
  6087. {
  6088. return $this->extensions;
  6089. }
  6090. public function addTokenParser(TokenParserInterface $parser)
  6091. {
  6092. if ($this->extensionInitialized) {
  6093. throw new \LogicException('Unable to add a token parser as extensions have already been initialized.');
  6094. }
  6095. $this->staging->addTokenParser($parser);
  6096. }
  6097. public function getTokenParsers()
  6098. {
  6099. if (!$this->extensionInitialized) {
  6100. $this->initExtensions();
  6101. }
  6102. return $this->parsers;
  6103. }
  6104. public function getTags()
  6105. {
  6106. $tags = [];
  6107. foreach ($this->getTokenParsers()->getParsers() as $parser) {
  6108. if ($parser instanceof TokenParserInterface) {
  6109. $tags[$parser->getTag()] = $parser;
  6110. }
  6111. }
  6112. return $tags;
  6113. }
  6114. public function addNodeVisitor(NodeVisitorInterface $visitor)
  6115. {
  6116. if ($this->extensionInitialized) {
  6117. throw new \LogicException('Unable to add a node visitor as extensions have already been initialized.');
  6118. }
  6119. $this->staging->addNodeVisitor($visitor);
  6120. }
  6121. public function getNodeVisitors()
  6122. {
  6123. if (!$this->extensionInitialized) {
  6124. $this->initExtensions();
  6125. }
  6126. return $this->visitors;
  6127. }
  6128. public function addFilter($name, $filter = null)
  6129. {
  6130. if (!$name instanceof TwigFilter && !($filter instanceof TwigFilter || $filter instanceof \Twig_FilterInterface)) {
  6131. throw new \LogicException('A filter must be an instance of \Twig_FilterInterface or \Twig_SimpleFilter.');
  6132. }
  6133. if ($name instanceof TwigFilter) {
  6134. $filter = $name;
  6135. $name = $filter->getName();
  6136. } else {
  6137. @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFilter" instead when defining filter "%s".', __METHOD__, $name), E_USER_DEPRECATED);
  6138. }
  6139. if ($this->extensionInitialized) {
  6140. throw new \LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
  6141. }
  6142. $this->staging->addFilter($name, $filter);
  6143. }
  6144. public function getFilter($name)
  6145. {
  6146. if (!$this->extensionInitialized) {
  6147. $this->initExtensions();
  6148. }
  6149. if (isset($this->filters[$name])) {
  6150. return $this->filters[$name];
  6151. }
  6152. foreach ($this->filters as $pattern => $filter) {
  6153. $pattern = str_replace('\\*','(.*?)', preg_quote($pattern,'#'), $count);
  6154. if ($count) {
  6155. if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
  6156. array_shift($matches);
  6157. $filter->setArguments($matches);
  6158. return $filter;
  6159. }
  6160. }
  6161. }
  6162. foreach ($this->filterCallbacks as $callback) {
  6163. if (false !== $filter = \call_user_func($callback, $name)) {
  6164. return $filter;
  6165. }
  6166. }
  6167. return false;
  6168. }
  6169. public function registerUndefinedFilterCallback($callable)
  6170. {
  6171. $this->filterCallbacks[] = $callable;
  6172. }
  6173. public function getFilters()
  6174. {
  6175. if (!$this->extensionInitialized) {
  6176. $this->initExtensions();
  6177. }
  6178. return $this->filters;
  6179. }
  6180. public function addTest($name, $test = null)
  6181. {
  6182. if (!$name instanceof TwigTest && !($test instanceof TwigTest || $test instanceof \Twig_TestInterface)) {
  6183. throw new \LogicException('A test must be an instance of \Twig_TestInterface or \Twig_SimpleTest.');
  6184. }
  6185. if ($name instanceof TwigTest) {
  6186. $test = $name;
  6187. $name = $test->getName();
  6188. } else {
  6189. @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleTest" instead when defining test "%s".', __METHOD__, $name), E_USER_DEPRECATED);
  6190. }
  6191. if ($this->extensionInitialized) {
  6192. throw new \LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
  6193. }
  6194. $this->staging->addTest($name, $test);
  6195. }
  6196. public function getTests()
  6197. {
  6198. if (!$this->extensionInitialized) {
  6199. $this->initExtensions();
  6200. }
  6201. return $this->tests;
  6202. }
  6203. public function getTest($name)
  6204. {
  6205. if (!$this->extensionInitialized) {
  6206. $this->initExtensions();
  6207. }
  6208. if (isset($this->tests[$name])) {
  6209. return $this->tests[$name];
  6210. }
  6211. foreach ($this->tests as $pattern => $test) {
  6212. $pattern = str_replace('\\*','(.*?)', preg_quote($pattern,'#'), $count);
  6213. if ($count) {
  6214. if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
  6215. array_shift($matches);
  6216. $test->setArguments($matches);
  6217. return $test;
  6218. }
  6219. }
  6220. }
  6221. return false;
  6222. }
  6223. public function addFunction($name, $function = null)
  6224. {
  6225. if (!$name instanceof TwigFunction && !($function instanceof TwigFunction || $function instanceof \Twig_FunctionInterface)) {
  6226. throw new \LogicException('A function must be an instance of \Twig_FunctionInterface or \Twig_SimpleFunction.');
  6227. }
  6228. if ($name instanceof TwigFunction) {
  6229. $function = $name;
  6230. $name = $function->getName();
  6231. } else {
  6232. @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFunction" instead when defining function "%s".', __METHOD__, $name), E_USER_DEPRECATED);
  6233. }
  6234. if ($this->extensionInitialized) {
  6235. throw new \LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
  6236. }
  6237. $this->staging->addFunction($name, $function);
  6238. }
  6239. public function getFunction($name)
  6240. {
  6241. if (!$this->extensionInitialized) {
  6242. $this->initExtensions();
  6243. }
  6244. if (isset($this->functions[$name])) {
  6245. return $this->functions[$name];
  6246. }
  6247. foreach ($this->functions as $pattern => $function) {
  6248. $pattern = str_replace('\\*','(.*?)', preg_quote($pattern,'#'), $count);
  6249. if ($count) {
  6250. if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
  6251. array_shift($matches);
  6252. $function->setArguments($matches);
  6253. return $function;
  6254. }
  6255. }
  6256. }
  6257. foreach ($this->functionCallbacks as $callback) {
  6258. if (false !== $function = \call_user_func($callback, $name)) {
  6259. return $function;
  6260. }
  6261. }
  6262. return false;
  6263. }
  6264. public function registerUndefinedFunctionCallback($callable)
  6265. {
  6266. $this->functionCallbacks[] = $callable;
  6267. }
  6268. public function getFunctions()
  6269. {
  6270. if (!$this->extensionInitialized) {
  6271. $this->initExtensions();
  6272. }
  6273. return $this->functions;
  6274. }
  6275. public function addGlobal($name, $value)
  6276. {
  6277. if ($this->extensionInitialized || $this->runtimeInitialized) {
  6278. if (null === $this->globals) {
  6279. $this->globals = $this->initGlobals();
  6280. }
  6281. if (!\array_key_exists($name, $this->globals)) {
  6282. @trigger_error(sprintf('Registering global variable "%s" at runtime or when the extensions have already been initialized is deprecated since version 1.21.', $name), E_USER_DEPRECATED);
  6283. }
  6284. }
  6285. if ($this->extensionInitialized || $this->runtimeInitialized) {
  6286. $this->globals[$name] = $value;
  6287. } else {
  6288. $this->staging->addGlobal($name, $value);
  6289. }
  6290. }
  6291. public function getGlobals()
  6292. {
  6293. if (!$this->runtimeInitialized && !$this->extensionInitialized) {
  6294. return $this->initGlobals();
  6295. }
  6296. if (null === $this->globals) {
  6297. $this->globals = $this->initGlobals();
  6298. }
  6299. return $this->globals;
  6300. }
  6301. public function mergeGlobals(array $context)
  6302. {
  6303. foreach ($this->getGlobals() as $key => $value) {
  6304. if (!\array_key_exists($key, $context)) {
  6305. $context[$key] = $value;
  6306. }
  6307. }
  6308. return $context;
  6309. }
  6310. public function getUnaryOperators()
  6311. {
  6312. if (!$this->extensionInitialized) {
  6313. $this->initExtensions();
  6314. }
  6315. return $this->unaryOperators;
  6316. }
  6317. public function getBinaryOperators()
  6318. {
  6319. if (!$this->extensionInitialized) {
  6320. $this->initExtensions();
  6321. }
  6322. return $this->binaryOperators;
  6323. }
  6324. public function computeAlternatives($name, $items)
  6325. {
  6326. @trigger_error(sprintf('The %s method is deprecated since version 1.23 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
  6327. return SyntaxError::computeAlternatives($name, $items);
  6328. }
  6329. protected function initGlobals()
  6330. {
  6331. $globals = [];
  6332. foreach ($this->extensions as $name => $extension) {
  6333. if (!$extension instanceof GlobalsInterface) {
  6334. $m = new \ReflectionMethod($extension,'getGlobals');
  6335. $parentClass = $m->getDeclaringClass()->getName();
  6336. if ('Twig_Extension'!== $parentClass &&'Twig\Extension\AbstractExtension'!== $parentClass) {
  6337. @trigger_error(sprintf('Defining the getGlobals() method in the "%s" extension without explicitly implementing Twig\Extension\GlobalsInterface is deprecated since version 1.23.', $name), E_USER_DEPRECATED);
  6338. }
  6339. }
  6340. $extGlob = $extension->getGlobals();
  6341. if (!\is_array($extGlob)) {
  6342. throw new \UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension)));
  6343. }
  6344. $globals[] = $extGlob;
  6345. }
  6346. $globals[] = $this->staging->getGlobals();
  6347. return \call_user_func_array('array_merge', $globals);
  6348. }
  6349. protected function initExtensions()
  6350. {
  6351. if ($this->extensionInitialized) {
  6352. return;
  6353. }
  6354. $this->parsers = new \Twig_TokenParserBroker([], [], false);
  6355. $this->filters = [];
  6356. $this->functions = [];
  6357. $this->tests = [];
  6358. $this->visitors = [];
  6359. $this->unaryOperators = [];
  6360. $this->binaryOperators = [];
  6361. foreach ($this->extensions as $extension) {
  6362. $this->initExtension($extension);
  6363. }
  6364. $this->initExtension($this->staging);
  6365. $this->extensionInitialized = true;
  6366. }
  6367. protected function initExtension(ExtensionInterface $extension)
  6368. {
  6369. foreach ($extension->getFilters() as $name => $filter) {
  6370. if ($filter instanceof TwigFilter) {
  6371. $name = $filter->getName();
  6372. } else {
  6373. @trigger_error(sprintf('Using an instance of "%s" for filter "%s" is deprecated since version 1.21. Use \Twig_SimpleFilter instead.', \get_class($filter), $name), E_USER_DEPRECATED);
  6374. }
  6375. $this->filters[$name] = $filter;
  6376. }
  6377. foreach ($extension->getFunctions() as $name => $function) {
  6378. if ($function instanceof TwigFunction) {
  6379. $name = $function->getName();
  6380. } else {
  6381. @trigger_error(sprintf('Using an instance of "%s" for function "%s" is deprecated since version 1.21. Use \Twig_SimpleFunction instead.', \get_class($function), $name), E_USER_DEPRECATED);
  6382. }
  6383. $this->functions[$name] = $function;
  6384. }
  6385. foreach ($extension->getTests() as $name => $test) {
  6386. if ($test instanceof TwigTest) {
  6387. $name = $test->getName();
  6388. } else {
  6389. @trigger_error(sprintf('Using an instance of "%s" for test "%s" is deprecated since version 1.21. Use \Twig_SimpleTest instead.', \get_class($test), $name), E_USER_DEPRECATED);
  6390. }
  6391. $this->tests[$name] = $test;
  6392. }
  6393. foreach ($extension->getTokenParsers() as $parser) {
  6394. if ($parser instanceof TokenParserInterface) {
  6395. $this->parsers->addTokenParser($parser);
  6396. } elseif ($parser instanceof \Twig_TokenParserBrokerInterface) {
  6397. @trigger_error('Registering a \Twig_TokenParserBrokerInterface instance is deprecated since version 1.21.', E_USER_DEPRECATED);
  6398. $this->parsers->addTokenParserBroker($parser);
  6399. } else {
  6400. throw new \LogicException('getTokenParsers() must return an array of \Twig_TokenParserInterface or \Twig_TokenParserBrokerInterface instances.');
  6401. }
  6402. }
  6403. foreach ($extension->getNodeVisitors() as $visitor) {
  6404. $this->visitors[] = $visitor;
  6405. }
  6406. if ($operators = $extension->getOperators()) {
  6407. if (!\is_array($operators)) {
  6408. throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ?'':'#'.$operators)));
  6409. }
  6410. if (2 !== \count($operators)) {
  6411. throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators)));
  6412. }
  6413. $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
  6414. $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
  6415. }
  6416. }
  6417. protected function writeCacheFile($file, $content)
  6418. {
  6419. $this->cache->write($file, $content);
  6420. }
  6421. private function updateOptionsHash()
  6422. {
  6423. $hashParts = array_merge(
  6424. array_keys($this->extensions),
  6425. [
  6426. (int) \function_exists('twig_template_get_attributes'),
  6427. PHP_MAJOR_VERSION,
  6428. PHP_MINOR_VERSION,
  6429. self::VERSION,
  6430. (int) $this->debug,
  6431. $this->baseTemplateClass,
  6432. (int) $this->strictVariables,
  6433. ]
  6434. );
  6435. $this->optionsHash = implode(':', $hashParts);
  6436. }
  6437. }
  6438. class_alias('Twig\Environment','Twig_Environment');
  6439. }
  6440. namespace Twig\Extension
  6441. {
  6442. use Twig\Environment;
  6443. use Twig\NodeVisitor\NodeVisitorInterface;
  6444. use Twig\TokenParser\TokenParserInterface;
  6445. use Twig\TwigFilter;
  6446. use Twig\TwigFunction;
  6447. use Twig\TwigTest;
  6448. interface ExtensionInterface
  6449. {
  6450. public function initRuntime(Environment $environment);
  6451. public function getTokenParsers();
  6452. public function getNodeVisitors();
  6453. public function getFilters();
  6454. public function getTests();
  6455. public function getFunctions();
  6456. public function getOperators();
  6457. public function getGlobals();
  6458. public function getName();
  6459. }
  6460. class_alias('Twig\Extension\ExtensionInterface','Twig_ExtensionInterface');
  6461. class_exists('Twig\Environment');
  6462. }
  6463. namespace Twig\Extension
  6464. {
  6465. use Twig\Environment;
  6466. abstract class AbstractExtension implements ExtensionInterface
  6467. {
  6468. public function initRuntime(Environment $environment)
  6469. {
  6470. }
  6471. public function getTokenParsers()
  6472. {
  6473. return [];
  6474. }
  6475. public function getNodeVisitors()
  6476. {
  6477. return [];
  6478. }
  6479. public function getFilters()
  6480. {
  6481. return [];
  6482. }
  6483. public function getTests()
  6484. {
  6485. return [];
  6486. }
  6487. public function getFunctions()
  6488. {
  6489. return [];
  6490. }
  6491. public function getOperators()
  6492. {
  6493. return [];
  6494. }
  6495. public function getGlobals()
  6496. {
  6497. return [];
  6498. }
  6499. public function getName()
  6500. {
  6501. return \get_class($this);
  6502. }
  6503. }
  6504. class_alias('Twig\Extension\AbstractExtension','Twig_Extension');
  6505. }
  6506. namespace Twig\Extension {
  6507. use Twig\ExpressionParser;
  6508. use Twig\TokenParser\ApplyTokenParser;
  6509. use Twig\TokenParser\BlockTokenParser;
  6510. use Twig\TokenParser\DeprecatedTokenParser;
  6511. use Twig\TokenParser\DoTokenParser;
  6512. use Twig\TokenParser\EmbedTokenParser;
  6513. use Twig\TokenParser\ExtendsTokenParser;
  6514. use Twig\TokenParser\FilterTokenParser;
  6515. use Twig\TokenParser\FlushTokenParser;
  6516. use Twig\TokenParser\ForTokenParser;
  6517. use Twig\TokenParser\FromTokenParser;
  6518. use Twig\TokenParser\IfTokenParser;
  6519. use Twig\TokenParser\ImportTokenParser;
  6520. use Twig\TokenParser\IncludeTokenParser;
  6521. use Twig\TokenParser\MacroTokenParser;
  6522. use Twig\TokenParser\SetTokenParser;
  6523. use Twig\TokenParser\SpacelessTokenParser;
  6524. use Twig\TokenParser\UseTokenParser;
  6525. use Twig\TokenParser\WithTokenParser;
  6526. use Twig\TwigFilter;
  6527. use Twig\TwigFunction;
  6528. use Twig\TwigTest;
  6529. class CoreExtension extends AbstractExtension
  6530. {
  6531. protected $dateFormats = ['F j, Y H:i','%d days'];
  6532. protected $numberFormat = [0,'.',','];
  6533. protected $timezone = null;
  6534. protected $escapers = [];
  6535. public function setEscaper($strategy, $callable)
  6536. {
  6537. $this->escapers[$strategy] = $callable;
  6538. }
  6539. public function getEscapers()
  6540. {
  6541. return $this->escapers;
  6542. }
  6543. public function setDateFormat($format = null, $dateIntervalFormat = null)
  6544. {
  6545. if (null !== $format) {
  6546. $this->dateFormats[0] = $format;
  6547. }
  6548. if (null !== $dateIntervalFormat) {
  6549. $this->dateFormats[1] = $dateIntervalFormat;
  6550. }
  6551. }
  6552. public function getDateFormat()
  6553. {
  6554. return $this->dateFormats;
  6555. }
  6556. public function setTimezone($timezone)
  6557. {
  6558. $this->timezone = $timezone instanceof \DateTimeZone ? $timezone : new \DateTimeZone($timezone);
  6559. }
  6560. public function getTimezone()
  6561. {
  6562. if (null === $this->timezone) {
  6563. $this->timezone = new \DateTimeZone(date_default_timezone_get());
  6564. }
  6565. return $this->timezone;
  6566. }
  6567. public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
  6568. {
  6569. $this->numberFormat = [$decimal, $decimalPoint, $thousandSep];
  6570. }
  6571. public function getNumberFormat()
  6572. {
  6573. return $this->numberFormat;
  6574. }
  6575. public function getTokenParsers()
  6576. {
  6577. return [
  6578. new ApplyTokenParser(),
  6579. new ForTokenParser(),
  6580. new IfTokenParser(),
  6581. new ExtendsTokenParser(),
  6582. new IncludeTokenParser(),
  6583. new BlockTokenParser(),
  6584. new UseTokenParser(),
  6585. new FilterTokenParser(),
  6586. new MacroTokenParser(),
  6587. new ImportTokenParser(),
  6588. new FromTokenParser(),
  6589. new SetTokenParser(),
  6590. new SpacelessTokenParser(),
  6591. new FlushTokenParser(),
  6592. new DoTokenParser(),
  6593. new EmbedTokenParser(),
  6594. new WithTokenParser(),
  6595. new DeprecatedTokenParser(),
  6596. ];
  6597. }
  6598. public function getFilters()
  6599. {
  6600. $filters = [
  6601. new TwigFilter('date','twig_date_format_filter', ['needs_environment'=> true]),
  6602. new TwigFilter('date_modify','twig_date_modify_filter', ['needs_environment'=> true]),
  6603. new TwigFilter('format','sprintf'),
  6604. new TwigFilter('replace','twig_replace_filter'),
  6605. new TwigFilter('number_format','twig_number_format_filter', ['needs_environment'=> true]),
  6606. new TwigFilter('abs','abs'),
  6607. new TwigFilter('round','twig_round'),
  6608. new TwigFilter('url_encode','twig_urlencode_filter'),
  6609. new TwigFilter('json_encode','twig_jsonencode_filter'),
  6610. new TwigFilter('convert_encoding','twig_convert_encoding'),
  6611. new TwigFilter('title','twig_title_string_filter', ['needs_environment'=> true]),
  6612. new TwigFilter('capitalize','twig_capitalize_string_filter', ['needs_environment'=> true]),
  6613. new TwigFilter('upper','strtoupper'),
  6614. new TwigFilter('lower','strtolower'),
  6615. new TwigFilter('striptags','strip_tags'),
  6616. new TwigFilter('trim','twig_trim_filter'),
  6617. new TwigFilter('nl2br','nl2br', ['pre_escape'=>'html','is_safe'=> ['html']]),
  6618. new TwigFilter('spaceless','twig_spaceless', ['is_safe'=> ['html']]),
  6619. new TwigFilter('join','twig_join_filter'),
  6620. new TwigFilter('split','twig_split_filter', ['needs_environment'=> true]),
  6621. new TwigFilter('sort','twig_sort_filter'),
  6622. new TwigFilter('merge','twig_array_merge'),
  6623. new TwigFilter('batch','twig_array_batch'),
  6624. new TwigFilter('filter','twig_array_filter'),
  6625. new TwigFilter('map','twig_array_map'),
  6626. new TwigFilter('reduce','twig_array_reduce'),
  6627. new TwigFilter('reverse','twig_reverse_filter', ['needs_environment'=> true]),
  6628. new TwigFilter('length','twig_length_filter', ['needs_environment'=> true]),
  6629. new TwigFilter('slice','twig_slice', ['needs_environment'=> true]),
  6630. new TwigFilter('first','twig_first', ['needs_environment'=> true]),
  6631. new TwigFilter('last','twig_last', ['needs_environment'=> true]),
  6632. new TwigFilter('default','_twig_default_filter', ['node_class'=>'\Twig\Node\Expression\Filter\DefaultFilter']),
  6633. new TwigFilter('keys','twig_get_array_keys_filter'),
  6634. new TwigFilter('escape','twig_escape_filter', ['needs_environment'=> true,'is_safe_callback'=>'twig_escape_filter_is_safe']),
  6635. new TwigFilter('e','twig_escape_filter', ['needs_environment'=> true,'is_safe_callback'=>'twig_escape_filter_is_safe']),
  6636. ];
  6637. if (\function_exists('mb_get_info')) {
  6638. $filters[] = new TwigFilter('upper','twig_upper_filter', ['needs_environment'=> true]);
  6639. $filters[] = new TwigFilter('lower','twig_lower_filter', ['needs_environment'=> true]);
  6640. }
  6641. return $filters;
  6642. }
  6643. public function getFunctions()
  6644. {
  6645. return [
  6646. new TwigFunction('max','max'),
  6647. new TwigFunction('min','min'),
  6648. new TwigFunction('range','range'),
  6649. new TwigFunction('constant','twig_constant'),
  6650. new TwigFunction('cycle','twig_cycle'),
  6651. new TwigFunction('random','twig_random', ['needs_environment'=> true]),
  6652. new TwigFunction('date','twig_date_converter', ['needs_environment'=> true]),
  6653. new TwigFunction('include','twig_include', ['needs_environment'=> true,'needs_context'=> true,'is_safe'=> ['all']]),
  6654. new TwigFunction('source','twig_source', ['needs_environment'=> true,'is_safe'=> ['all']]),
  6655. ];
  6656. }
  6657. public function getTests()
  6658. {
  6659. return [
  6660. new TwigTest('even', null, ['node_class'=>'\Twig\Node\Expression\Test\EvenTest']),
  6661. new TwigTest('odd', null, ['node_class'=>'\Twig\Node\Expression\Test\OddTest']),
  6662. new TwigTest('defined', null, ['node_class'=>'\Twig\Node\Expression\Test\DefinedTest']),
  6663. new TwigTest('sameas', null, ['node_class'=>'\Twig\Node\Expression\Test\SameasTest','deprecated'=>'1.21','alternative'=>'same as']),
  6664. new TwigTest('same as', null, ['node_class'=>'\Twig\Node\Expression\Test\SameasTest']),
  6665. new TwigTest('none', null, ['node_class'=>'\Twig\Node\Expression\Test\NullTest']),
  6666. new TwigTest('null', null, ['node_class'=>'\Twig\Node\Expression\Test\NullTest']),
  6667. new TwigTest('divisibleby', null, ['node_class'=>'\Twig\Node\Expression\Test\DivisiblebyTest','deprecated'=>'1.21','alternative'=>'divisible by']),
  6668. new TwigTest('divisible by', null, ['node_class'=>'\Twig\Node\Expression\Test\DivisiblebyTest']),
  6669. new TwigTest('constant', null, ['node_class'=>'\Twig\Node\Expression\Test\ConstantTest']),
  6670. new TwigTest('empty','twig_test_empty'),
  6671. new TwigTest('iterable','twig_test_iterable'),
  6672. ];
  6673. }
  6674. public function getOperators()
  6675. {
  6676. return [
  6677. ['not'=> ['precedence'=> 50,'class'=>'\Twig\Node\Expression\Unary\NotUnary'],'-'=> ['precedence'=> 500,'class'=>'\Twig\Node\Expression\Unary\NegUnary'],'+'=> ['precedence'=> 500,'class'=>'\Twig\Node\Expression\Unary\PosUnary'],
  6678. ],
  6679. ['or'=> ['precedence'=> 10,'class'=>'\Twig\Node\Expression\Binary\OrBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'and'=> ['precedence'=> 15,'class'=>'\Twig\Node\Expression\Binary\AndBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'b-or'=> ['precedence'=> 16,'class'=>'\Twig\Node\Expression\Binary\BitwiseOrBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'b-xor'=> ['precedence'=> 17,'class'=>'\Twig\Node\Expression\Binary\BitwiseXorBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'b-and'=> ['precedence'=> 18,'class'=>'\Twig\Node\Expression\Binary\BitwiseAndBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'=='=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\EqualBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'!='=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\NotEqualBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'<'=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\LessBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'>'=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\GreaterBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'>='=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\GreaterEqualBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'<='=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\LessEqualBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'not in'=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\NotInBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'in'=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\InBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'matches'=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\MatchesBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'starts with'=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\StartsWithBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'ends with'=> ['precedence'=> 20,'class'=>'\Twig\Node\Expression\Binary\EndsWithBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'..'=> ['precedence'=> 25,'class'=>'\Twig\Node\Expression\Binary\RangeBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'+'=> ['precedence'=> 30,'class'=>'\Twig\Node\Expression\Binary\AddBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'-'=> ['precedence'=> 30,'class'=>'\Twig\Node\Expression\Binary\SubBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'~'=> ['precedence'=> 40,'class'=>'\Twig\Node\Expression\Binary\ConcatBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'*'=> ['precedence'=> 60,'class'=>'\Twig\Node\Expression\Binary\MulBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'/'=> ['precedence'=> 60,'class'=>'\Twig\Node\Expression\Binary\DivBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'//'=> ['precedence'=> 60,'class'=>'\Twig\Node\Expression\Binary\FloorDivBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'%'=> ['precedence'=> 60,'class'=>'\Twig\Node\Expression\Binary\ModBinary','associativity'=> ExpressionParser::OPERATOR_LEFT],'is'=> ['precedence'=> 100,'associativity'=> ExpressionParser::OPERATOR_LEFT],'is not'=> ['precedence'=> 100,'associativity'=> ExpressionParser::OPERATOR_LEFT],'**'=> ['precedence'=> 200,'class'=>'\Twig\Node\Expression\Binary\PowerBinary','associativity'=> ExpressionParser::OPERATOR_RIGHT],'??'=> ['precedence'=> 300,'class'=>'\Twig\Node\Expression\NullCoalesceExpression','associativity'=> ExpressionParser::OPERATOR_RIGHT],
  6680. ],
  6681. ];
  6682. }
  6683. public function getName()
  6684. {
  6685. return'core';
  6686. }
  6687. }
  6688. class_alias('Twig\Extension\CoreExtension','Twig_Extension_Core');
  6689. }
  6690. namespace {
  6691. use Twig\Environment;
  6692. use Twig\Error\LoaderError;
  6693. use Twig\Error\RuntimeError;
  6694. use Twig\Loader\SourceContextLoaderInterface;
  6695. use Twig\Markup;
  6696. use Twig\Node\Expression\ConstantExpression;
  6697. use Twig\Node\Node;
  6698. function twig_cycle($values, $position)
  6699. {
  6700. if (!\is_array($values) && !$values instanceof \ArrayAccess) {
  6701. return $values;
  6702. }
  6703. return $values[$position % \count($values)];
  6704. }
  6705. function twig_random(Environment $env, $values = null, $max = null)
  6706. {
  6707. if (null === $values) {
  6708. return null === $max ? mt_rand() : mt_rand(0, $max);
  6709. }
  6710. if (\is_int($values) || \is_float($values)) {
  6711. if (null === $max) {
  6712. if ($values < 0) {
  6713. $max = 0;
  6714. $min = $values;
  6715. } else {
  6716. $max = $values;
  6717. $min = 0;
  6718. }
  6719. } else {
  6720. $min = $values;
  6721. $max = $max;
  6722. }
  6723. return mt_rand($min, $max);
  6724. }
  6725. if (\is_string($values)) {
  6726. if (''=== $values) {
  6727. return'';
  6728. }
  6729. if (null !== $charset = $env->getCharset()) {
  6730. if ('UTF-8'!== $charset) {
  6731. $values = twig_convert_encoding($values,'UTF-8', $charset);
  6732. }
  6733. $values = preg_split('/(?<!^)(?!$)/u', $values);
  6734. if ('UTF-8'!== $charset) {
  6735. foreach ($values as $i => $value) {
  6736. $values[$i] = twig_convert_encoding($value, $charset,'UTF-8');
  6737. }
  6738. }
  6739. } else {
  6740. return $values[mt_rand(0, \strlen($values) - 1)];
  6741. }
  6742. }
  6743. if (!twig_test_iterable($values)) {
  6744. return $values;
  6745. }
  6746. $values = twig_to_array($values);
  6747. if (0 === \count($values)) {
  6748. throw new RuntimeError('The random function cannot pick from an empty array.');
  6749. }
  6750. return $values[array_rand($values, 1)];
  6751. }
  6752. function twig_date_format_filter(Environment $env, $date, $format = null, $timezone = null)
  6753. {
  6754. if (null === $format) {
  6755. $formats = $env->getExtension('\Twig\Extension\CoreExtension')->getDateFormat();
  6756. $format = $date instanceof \DateInterval ? $formats[1] : $formats[0];
  6757. }
  6758. if ($date instanceof \DateInterval) {
  6759. return $date->format($format);
  6760. }
  6761. return twig_date_converter($env, $date, $timezone)->format($format);
  6762. }
  6763. function twig_date_modify_filter(Environment $env, $date, $modifier)
  6764. {
  6765. $date = twig_date_converter($env, $date, false);
  6766. $resultDate = $date->modify($modifier);
  6767. return null === $resultDate ? $date : $resultDate;
  6768. }
  6769. function twig_date_converter(Environment $env, $date = null, $timezone = null)
  6770. {
  6771. if (false !== $timezone) {
  6772. if (null === $timezone) {
  6773. $timezone = $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone();
  6774. } elseif (!$timezone instanceof \DateTimeZone) {
  6775. $timezone = new \DateTimeZone($timezone);
  6776. }
  6777. }
  6778. if ($date instanceof \DateTimeImmutable) {
  6779. return false !== $timezone ? $date->setTimezone($timezone) : $date;
  6780. }
  6781. if ($date instanceof \DateTime || $date instanceof \DateTimeInterface) {
  6782. $date = clone $date;
  6783. if (false !== $timezone) {
  6784. $date->setTimezone($timezone);
  6785. }
  6786. return $date;
  6787. }
  6788. if (null === $date ||'now'=== $date) {
  6789. return new \DateTime($date, false !== $timezone ? $timezone : $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone());
  6790. }
  6791. $asString = (string) $date;
  6792. if (ctype_digit($asString) || (!empty($asString) &&'-'=== $asString[0] && ctype_digit(substr($asString, 1)))) {
  6793. $date = new \DateTime('@'.$date);
  6794. } else {
  6795. $date = new \DateTime($date, $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone());
  6796. }
  6797. if (false !== $timezone) {
  6798. $date->setTimezone($timezone);
  6799. }
  6800. return $date;
  6801. }
  6802. function twig_replace_filter($str, $from, $to = null)
  6803. {
  6804. if (\is_string($from) && \is_string($to)) {
  6805. @trigger_error('Using "replace" with character by character replacement is deprecated since version 1.22 and will be removed in Twig 2.0', E_USER_DEPRECATED);
  6806. return strtr($str, $from, $to);
  6807. }
  6808. if (!twig_test_iterable($from)) {
  6809. throw new RuntimeError(sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from)));
  6810. }
  6811. return strtr($str, twig_to_array($from));
  6812. }
  6813. function twig_round($value, $precision = 0, $method ='common')
  6814. {
  6815. if ('common'== $method) {
  6816. return round($value, $precision);
  6817. }
  6818. if ('ceil'!= $method &&'floor'!= $method) {
  6819. throw new RuntimeError('The round filter only supports the "common", "ceil", and "floor" methods.');
  6820. }
  6821. return $method($value * pow(10, $precision)) / pow(10, $precision);
  6822. }
  6823. function twig_number_format_filter(Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
  6824. {
  6825. $defaults = $env->getExtension('\Twig\Extension\CoreExtension')->getNumberFormat();
  6826. if (null === $decimal) {
  6827. $decimal = $defaults[0];
  6828. }
  6829. if (null === $decimalPoint) {
  6830. $decimalPoint = $defaults[1];
  6831. }
  6832. if (null === $thousandSep) {
  6833. $thousandSep = $defaults[2];
  6834. }
  6835. return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
  6836. }
  6837. function twig_urlencode_filter($url)
  6838. {
  6839. if (\is_array($url)) {
  6840. if (\defined('PHP_QUERY_RFC3986')) {
  6841. return http_build_query($url,'','&', PHP_QUERY_RFC3986);
  6842. }
  6843. return http_build_query($url,'','&');
  6844. }
  6845. return rawurlencode($url);
  6846. }
  6847. function twig_jsonencode_filter($value, $options = 0)
  6848. {
  6849. if ($value instanceof Markup) {
  6850. $value = (string) $value;
  6851. } elseif (\is_array($value)) {
  6852. array_walk_recursive($value,'_twig_markup2string');
  6853. }
  6854. return json_encode($value, $options);
  6855. }
  6856. function _twig_markup2string(&$value)
  6857. {
  6858. if ($value instanceof Markup) {
  6859. $value = (string) $value;
  6860. }
  6861. }
  6862. function twig_array_merge($arr1, $arr2)
  6863. {
  6864. if (!twig_test_iterable($arr1)) {
  6865. throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($arr1)));
  6866. }
  6867. if (!twig_test_iterable($arr2)) {
  6868. throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as second argument.', \gettype($arr2)));
  6869. }
  6870. return array_merge(twig_to_array($arr1), twig_to_array($arr2));
  6871. }
  6872. function twig_slice(Environment $env, $item, $start, $length = null, $preserveKeys = false)
  6873. {
  6874. if ($item instanceof \Traversable) {
  6875. while ($item instanceof \IteratorAggregate) {
  6876. $item = $item->getIterator();
  6877. }
  6878. if ($start >= 0 && $length >= 0 && $item instanceof \Iterator) {
  6879. try {
  6880. return iterator_to_array(new \LimitIterator($item, $start, null === $length ? -1 : $length), $preserveKeys);
  6881. } catch (\OutOfBoundsException $e) {
  6882. return [];
  6883. }
  6884. }
  6885. $item = iterator_to_array($item, $preserveKeys);
  6886. }
  6887. if (\is_array($item)) {
  6888. return \array_slice($item, $start, $length, $preserveKeys);
  6889. }
  6890. $item = (string) $item;
  6891. if (\function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
  6892. return (string) mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
  6893. }
  6894. return (string) (null === $length ? substr($item, $start) : substr($item, $start, $length));
  6895. }
  6896. function twig_first(Environment $env, $item)
  6897. {
  6898. $elements = twig_slice($env, $item, 0, 1, false);
  6899. return \is_string($elements) ? $elements : current($elements);
  6900. }
  6901. function twig_last(Environment $env, $item)
  6902. {
  6903. $elements = twig_slice($env, $item, -1, 1, false);
  6904. return \is_string($elements) ? $elements : current($elements);
  6905. }
  6906. function twig_join_filter($value, $glue ='', $and = null)
  6907. {
  6908. if (!twig_test_iterable($value)) {
  6909. $value = (array) $value;
  6910. }
  6911. $value = twig_to_array($value, false);
  6912. if (0 === \count($value)) {
  6913. return'';
  6914. }
  6915. if (null === $and || $and === $glue) {
  6916. return implode($glue, $value);
  6917. }
  6918. if (1 === \count($value)) {
  6919. return $value[0];
  6920. }
  6921. return implode($glue, \array_slice($value, 0, -1)).$and.$value[\count($value) - 1];
  6922. }
  6923. function twig_split_filter(Environment $env, $value, $delimiter, $limit = null)
  6924. {
  6925. if (\strlen($delimiter) > 0) {
  6926. return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
  6927. }
  6928. if (!\function_exists('mb_get_info') || null === $charset = $env->getCharset()) {
  6929. return str_split($value, null === $limit ? 1 : $limit);
  6930. }
  6931. if ($limit <= 1) {
  6932. return preg_split('/(?<!^)(?!$)/u', $value);
  6933. }
  6934. $length = mb_strlen($value, $charset);
  6935. if ($length < $limit) {
  6936. return [$value];
  6937. }
  6938. $r = [];
  6939. for ($i = 0; $i < $length; $i += $limit) {
  6940. $r[] = mb_substr($value, $i, $limit, $charset);
  6941. }
  6942. return $r;
  6943. }
  6944. function _twig_default_filter($value, $default ='')
  6945. {
  6946. if (twig_test_empty($value)) {
  6947. return $default;
  6948. }
  6949. return $value;
  6950. }
  6951. function twig_get_array_keys_filter($array)
  6952. {
  6953. if ($array instanceof \Traversable) {
  6954. while ($array instanceof \IteratorAggregate) {
  6955. $array = $array->getIterator();
  6956. }
  6957. if ($array instanceof \Iterator) {
  6958. $keys = [];
  6959. $array->rewind();
  6960. while ($array->valid()) {
  6961. $keys[] = $array->key();
  6962. $array->next();
  6963. }
  6964. return $keys;
  6965. }
  6966. $keys = [];
  6967. foreach ($array as $key => $item) {
  6968. $keys[] = $key;
  6969. }
  6970. return $keys;
  6971. }
  6972. if (!\is_array($array)) {
  6973. return [];
  6974. }
  6975. return array_keys($array);
  6976. }
  6977. function twig_reverse_filter(Environment $env, $item, $preserveKeys = false)
  6978. {
  6979. if ($item instanceof \Traversable) {
  6980. return array_reverse(iterator_to_array($item), $preserveKeys);
  6981. }
  6982. if (\is_array($item)) {
  6983. return array_reverse($item, $preserveKeys);
  6984. }
  6985. if (null !== $charset = $env->getCharset()) {
  6986. $string = (string) $item;
  6987. if ('UTF-8'!== $charset) {
  6988. $item = twig_convert_encoding($string,'UTF-8', $charset);
  6989. }
  6990. preg_match_all('/./us', $item, $matches);
  6991. $string = implode('', array_reverse($matches[0]));
  6992. if ('UTF-8'!== $charset) {
  6993. $string = twig_convert_encoding($string, $charset,'UTF-8');
  6994. }
  6995. return $string;
  6996. }
  6997. return strrev((string) $item);
  6998. }
  6999. function twig_sort_filter($array)
  7000. {
  7001. if ($array instanceof \Traversable) {
  7002. $array = iterator_to_array($array);
  7003. } elseif (!\is_array($array)) {
  7004. throw new RuntimeError(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', \gettype($array)));
  7005. }
  7006. asort($array);
  7007. return $array;
  7008. }
  7009. function twig_in_filter($value, $compare)
  7010. {
  7011. if ($value instanceof Markup) {
  7012. $value = (string) $value;
  7013. }
  7014. if ($compare instanceof Markup) {
  7015. $compare = (string) $compare;
  7016. }
  7017. if (\is_array($compare)) {
  7018. return \in_array($value, $compare, \is_object($value) || \is_resource($value));
  7019. } elseif (\is_string($compare) && (\is_string($value) || \is_int($value) || \is_float($value))) {
  7020. return''=== $value || false !== strpos($compare, (string) $value);
  7021. } elseif ($compare instanceof \Traversable) {
  7022. if (\is_object($value) || \is_resource($value)) {
  7023. foreach ($compare as $item) {
  7024. if ($item === $value) {
  7025. return true;
  7026. }
  7027. }
  7028. } else {
  7029. foreach ($compare as $item) {
  7030. if ($item == $value) {
  7031. return true;
  7032. }
  7033. }
  7034. }
  7035. return false;
  7036. }
  7037. return false;
  7038. }
  7039. function twig_trim_filter($string, $characterMask = null, $side ='both')
  7040. {
  7041. if (null === $characterMask) {
  7042. $characterMask =" \t\n\r\0\x0B";
  7043. }
  7044. switch ($side) {
  7045. case'both':
  7046. return trim($string, $characterMask);
  7047. case'left':
  7048. return ltrim($string, $characterMask);
  7049. case'right':
  7050. return rtrim($string, $characterMask);
  7051. default:
  7052. throw new RuntimeError('Trimming side must be "left", "right" or "both".');
  7053. }
  7054. }
  7055. function twig_spaceless($content)
  7056. {
  7057. return trim(preg_replace('/>\s+</','><', $content));
  7058. }
  7059. function twig_escape_filter(Environment $env, $string, $strategy ='html', $charset = null, $autoescape = false)
  7060. {
  7061. if ($autoescape && $string instanceof Markup) {
  7062. return $string;
  7063. }
  7064. if (!\is_string($string)) {
  7065. if (\is_object($string) && method_exists($string,'__toString')) {
  7066. $string = (string) $string;
  7067. } elseif (\in_array($strategy, ['html','js','css','html_attr','url'])) {
  7068. return $string;
  7069. }
  7070. }
  7071. if (''=== $string) {
  7072. return'';
  7073. }
  7074. if (null === $charset) {
  7075. $charset = $env->getCharset();
  7076. }
  7077. switch ($strategy) {
  7078. case'html':
  7079. static $htmlspecialcharsCharsets = ['ISO-8859-1'=> true,'ISO8859-1'=> true,'ISO-8859-15'=> true,'ISO8859-15'=> true,'utf-8'=> true,'UTF-8'=> true,'CP866'=> true,'IBM866'=> true,'866'=> true,'CP1251'=> true,'WINDOWS-1251'=> true,'WIN-1251'=> true,'1251'=> true,'CP1252'=> true,'WINDOWS-1252'=> true,'1252'=> true,'KOI8-R'=> true,'KOI8-RU'=> true,'KOI8R'=> true,'BIG5'=> true,'950'=> true,'GB2312'=> true,'936'=> true,'BIG5-HKSCS'=> true,'SHIFT_JIS'=> true,'SJIS'=> true,'932'=> true,'EUC-JP'=> true,'EUCJP'=> true,'ISO8859-5'=> true,'ISO-8859-5'=> true,'MACROMAN'=> true,
  7080. ];
  7081. if (isset($htmlspecialcharsCharsets[$charset])) {
  7082. return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
  7083. }
  7084. if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
  7085. $htmlspecialcharsCharsets[$charset] = true;
  7086. return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
  7087. }
  7088. $string = twig_convert_encoding($string,'UTF-8', $charset);
  7089. $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE,'UTF-8');
  7090. return twig_convert_encoding($string, $charset,'UTF-8');
  7091. case'js':
  7092. if ('UTF-8'!== $charset) {
  7093. $string = twig_convert_encoding($string,'UTF-8', $charset);
  7094. }
  7095. if (!preg_match('//u', $string)) {
  7096. throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
  7097. }
  7098. $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su','_twig_escape_js_callback', $string);
  7099. if ('UTF-8'!== $charset) {
  7100. $string = twig_convert_encoding($string, $charset,'UTF-8');
  7101. }
  7102. return $string;
  7103. case'css':
  7104. if ('UTF-8'!== $charset) {
  7105. $string = twig_convert_encoding($string,'UTF-8', $charset);
  7106. }
  7107. if (!preg_match('//u', $string)) {
  7108. throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
  7109. }
  7110. $string = preg_replace_callback('#[^a-zA-Z0-9]#Su','_twig_escape_css_callback', $string);
  7111. if ('UTF-8'!== $charset) {
  7112. $string = twig_convert_encoding($string, $charset,'UTF-8');
  7113. }
  7114. return $string;
  7115. case'html_attr':
  7116. if ('UTF-8'!== $charset) {
  7117. $string = twig_convert_encoding($string,'UTF-8', $charset);
  7118. }
  7119. if (!preg_match('//u', $string)) {
  7120. throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
  7121. }
  7122. $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su','_twig_escape_html_attr_callback', $string);
  7123. if ('UTF-8'!== $charset) {
  7124. $string = twig_convert_encoding($string, $charset,'UTF-8');
  7125. }
  7126. return $string;
  7127. case'url':
  7128. return rawurlencode($string);
  7129. default:
  7130. static $escapers;
  7131. if (null === $escapers) {
  7132. $escapers = $env->getExtension('\Twig\Extension\CoreExtension')->getEscapers();
  7133. }
  7134. if (isset($escapers[$strategy])) {
  7135. return \call_user_func($escapers[$strategy], $env, $string, $charset);
  7136. }
  7137. $validStrategies = implode(', ', array_merge(['html','js','url','css','html_attr'], array_keys($escapers)));
  7138. throw new RuntimeError(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
  7139. }
  7140. }
  7141. function twig_escape_filter_is_safe(Node $filterArgs)
  7142. {
  7143. foreach ($filterArgs as $arg) {
  7144. if ($arg instanceof ConstantExpression) {
  7145. return [$arg->getAttribute('value')];
  7146. }
  7147. return [];
  7148. }
  7149. return ['html'];
  7150. }
  7151. if (\function_exists('mb_convert_encoding')) {
  7152. function twig_convert_encoding($string, $to, $from)
  7153. {
  7154. return mb_convert_encoding($string, $to, $from);
  7155. }
  7156. } elseif (\function_exists('iconv')) {
  7157. function twig_convert_encoding($string, $to, $from)
  7158. {
  7159. return iconv($from, $to, $string);
  7160. }
  7161. } else {
  7162. function twig_convert_encoding($string, $to, $from)
  7163. {
  7164. throw new RuntimeError('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
  7165. }
  7166. }
  7167. if (\function_exists('mb_ord')) {
  7168. function twig_ord($string)
  7169. {
  7170. return mb_ord($string,'UTF-8');
  7171. }
  7172. } else {
  7173. function twig_ord($string)
  7174. {
  7175. $code = ($string = unpack('C*', substr($string, 0, 4))) ? $string[1] : 0;
  7176. if (0xF0 <= $code) {
  7177. return (($code - 0xF0) << 18) + (($string[2] - 0x80) << 12) + (($string[3] - 0x80) << 6) + $string[4] - 0x80;
  7178. }
  7179. if (0xE0 <= $code) {
  7180. return (($code - 0xE0) << 12) + (($string[2] - 0x80) << 6) + $string[3] - 0x80;
  7181. }
  7182. if (0xC0 <= $code) {
  7183. return (($code - 0xC0) << 6) + $string[2] - 0x80;
  7184. }
  7185. return $code;
  7186. }
  7187. }
  7188. function _twig_escape_js_callback($matches)
  7189. {
  7190. $char = $matches[0];
  7191. static $shortMap = ['\\'=>'\\\\','/'=>'\\/',"\x08"=>'\b',"\x0C"=>'\f',"\x0A"=>'\n',"\x0D"=>'\r',"\x09"=>'\t',
  7192. ];
  7193. if (isset($shortMap[$char])) {
  7194. return $shortMap[$char];
  7195. }
  7196. $char = twig_convert_encoding($char,'UTF-16BE','UTF-8');
  7197. $char = strtoupper(bin2hex($char));
  7198. if (4 >= \strlen($char)) {
  7199. return sprintf('\u%04s', $char);
  7200. }
  7201. return sprintf('\u%04s\u%04s', substr($char, 0, -4), substr($char, -4));
  7202. }
  7203. function _twig_escape_css_callback($matches)
  7204. {
  7205. $char = $matches[0];
  7206. return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : twig_ord($char));
  7207. }
  7208. function _twig_escape_html_attr_callback($matches)
  7209. {
  7210. $chr = $matches[0];
  7211. $ord = \ord($chr);
  7212. if (($ord <= 0x1f &&"\t"!= $chr &&"\n"!= $chr &&"\r"!= $chr) || ($ord >= 0x7f && $ord <= 0x9f)) {
  7213. return'&#xFFFD;';
  7214. }
  7215. if (1 == \strlen($chr)) {
  7216. static $entityMap = [
  7217. 34 =>'&quot;',
  7218. 38 =>'&amp;',
  7219. 60 =>'&lt;',
  7220. 62 =>'&gt;',
  7221. ];
  7222. if (isset($entityMap[$ord])) {
  7223. return $entityMap[$ord];
  7224. }
  7225. return sprintf('&#x%02X;', $ord);
  7226. }
  7227. return sprintf('&#x%04X;', twig_ord($chr));
  7228. }
  7229. if (\function_exists('mb_get_info')) {
  7230. function twig_length_filter(Environment $env, $thing)
  7231. {
  7232. if (null === $thing) {
  7233. return 0;
  7234. }
  7235. if (is_scalar($thing)) {
  7236. return mb_strlen($thing, $env->getCharset());
  7237. }
  7238. if ($thing instanceof \Countable || \is_array($thing) || $thing instanceof \SimpleXMLElement) {
  7239. return \count($thing);
  7240. }
  7241. if ($thing instanceof \Traversable) {
  7242. return iterator_count($thing);
  7243. }
  7244. if (\is_object($thing) && method_exists($thing,'__toString')) {
  7245. return mb_strlen((string) $thing, $env->getCharset());
  7246. }
  7247. return 1;
  7248. }
  7249. function twig_upper_filter(Environment $env, $string)
  7250. {
  7251. if (null !== $charset = $env->getCharset()) {
  7252. return mb_strtoupper($string, $charset);
  7253. }
  7254. return strtoupper($string);
  7255. }
  7256. function twig_lower_filter(Environment $env, $string)
  7257. {
  7258. if (null !== $charset = $env->getCharset()) {
  7259. return mb_strtolower($string, $charset);
  7260. }
  7261. return strtolower($string);
  7262. }
  7263. function twig_title_string_filter(Environment $env, $string)
  7264. {
  7265. if (null !== $charset = $env->getCharset()) {
  7266. return mb_convert_case($string, MB_CASE_TITLE, $charset);
  7267. }
  7268. return ucwords(strtolower($string));
  7269. }
  7270. function twig_capitalize_string_filter(Environment $env, $string)
  7271. {
  7272. if (null !== $charset = $env->getCharset()) {
  7273. return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
  7274. }
  7275. return ucfirst(strtolower($string));
  7276. }
  7277. }
  7278. else {
  7279. function twig_length_filter(Environment $env, $thing)
  7280. {
  7281. if (null === $thing) {
  7282. return 0;
  7283. }
  7284. if (is_scalar($thing)) {
  7285. return \strlen($thing);
  7286. }
  7287. if ($thing instanceof \SimpleXMLElement) {
  7288. return \count($thing);
  7289. }
  7290. if (\is_object($thing) && method_exists($thing,'__toString') && !$thing instanceof \Countable) {
  7291. return \strlen((string) $thing);
  7292. }
  7293. if ($thing instanceof \Countable || \is_array($thing)) {
  7294. return \count($thing);
  7295. }
  7296. if ($thing instanceof \IteratorAggregate) {
  7297. return iterator_count($thing);
  7298. }
  7299. return 1;
  7300. }
  7301. function twig_title_string_filter(Environment $env, $string)
  7302. {
  7303. return ucwords(strtolower($string));
  7304. }
  7305. function twig_capitalize_string_filter(Environment $env, $string)
  7306. {
  7307. return ucfirst(strtolower($string));
  7308. }
  7309. }
  7310. function twig_ensure_traversable($seq)
  7311. {
  7312. if ($seq instanceof \Traversable || \is_array($seq)) {
  7313. return $seq;
  7314. }
  7315. return [];
  7316. }
  7317. function twig_to_array($seq, $preserveKeys = true)
  7318. {
  7319. if ($seq instanceof \Traversable) {
  7320. return iterator_to_array($seq, $preserveKeys);
  7321. }
  7322. if (!\is_array($seq)) {
  7323. return $seq;
  7324. }
  7325. return $preserveKeys ? $seq : array_values($seq);
  7326. }
  7327. function twig_test_empty($value)
  7328. {
  7329. if ($value instanceof \Countable) {
  7330. return 0 == \count($value);
  7331. }
  7332. if ($value instanceof \Traversable) {
  7333. return !iterator_count($value);
  7334. }
  7335. if (\is_object($value) && method_exists($value,'__toString')) {
  7336. return''=== (string) $value;
  7337. }
  7338. return''=== $value || false === $value || null === $value || [] === $value;
  7339. }
  7340. function twig_test_iterable($value)
  7341. {
  7342. return $value instanceof \Traversable || \is_array($value);
  7343. }
  7344. function twig_include(Environment $env, $context, $template, $variables = [], $withContext = true, $ignoreMissing = false, $sandboxed = false)
  7345. {
  7346. $alreadySandboxed = false;
  7347. $sandbox = null;
  7348. if ($withContext) {
  7349. $variables = array_merge($context, $variables);
  7350. }
  7351. if ($isSandboxed = $sandboxed && $env->hasExtension('\Twig\Extension\SandboxExtension')) {
  7352. $sandbox = $env->getExtension('\Twig\Extension\SandboxExtension');
  7353. if (!$alreadySandboxed = $sandbox->isSandboxed()) {
  7354. $sandbox->enableSandbox();
  7355. }
  7356. }
  7357. $loaded = null;
  7358. try {
  7359. $loaded = $env->resolveTemplate($template);
  7360. } catch (LoaderError $e) {
  7361. if (!$ignoreMissing) {
  7362. if ($isSandboxed && !$alreadySandboxed) {
  7363. $sandbox->disableSandbox();
  7364. }
  7365. throw $e;
  7366. }
  7367. } catch (\Throwable $e) {
  7368. if ($isSandboxed && !$alreadySandboxed) {
  7369. $sandbox->disableSandbox();
  7370. }
  7371. throw $e;
  7372. } catch (\Exception $e) {
  7373. if ($isSandboxed && !$alreadySandboxed) {
  7374. $sandbox->disableSandbox();
  7375. }
  7376. throw $e;
  7377. }
  7378. try {
  7379. $ret = $loaded ? $loaded->render($variables) :'';
  7380. } catch (\Exception $e) {
  7381. if ($isSandboxed && !$alreadySandboxed) {
  7382. $sandbox->disableSandbox();
  7383. }
  7384. throw $e;
  7385. }
  7386. if ($isSandboxed && !$alreadySandboxed) {
  7387. $sandbox->disableSandbox();
  7388. }
  7389. return $ret;
  7390. }
  7391. function twig_source(Environment $env, $name, $ignoreMissing = false)
  7392. {
  7393. $loader = $env->getLoader();
  7394. try {
  7395. if (!$loader instanceof SourceContextLoaderInterface) {
  7396. return $loader->getSource($name);
  7397. } else {
  7398. return $loader->getSourceContext($name)->getCode();
  7399. }
  7400. } catch (LoaderError $e) {
  7401. if (!$ignoreMissing) {
  7402. throw $e;
  7403. }
  7404. }
  7405. }
  7406. function twig_constant($constant, $object = null)
  7407. {
  7408. if (null !== $object) {
  7409. $constant = \get_class($object).'::'.$constant;
  7410. }
  7411. return \constant($constant);
  7412. }
  7413. function twig_constant_is_defined($constant, $object = null)
  7414. {
  7415. if (null !== $object) {
  7416. $constant = \get_class($object).'::'.$constant;
  7417. }
  7418. return \defined($constant);
  7419. }
  7420. function twig_array_batch($items, $size, $fill = null, $preserveKeys = true)
  7421. {
  7422. if (!twig_test_iterable($items)) {
  7423. throw new RuntimeError(sprintf('The "batch" filter expects an array or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items)));
  7424. }
  7425. $size = ceil($size);
  7426. $result = array_chunk(twig_to_array($items, $preserveKeys), $size, $preserveKeys);
  7427. if (null !== $fill && $result) {
  7428. $last = \count($result) - 1;
  7429. if ($fillCount = $size - \count($result[$last])) {
  7430. for ($i = 0; $i < $fillCount; ++$i) {
  7431. $result[$last][] = $fill;
  7432. }
  7433. }
  7434. }
  7435. return $result;
  7436. }
  7437. function twig_array_filter($array, $arrow)
  7438. {
  7439. if (\is_array($array)) {
  7440. if (\PHP_VERSION_ID >= 50600) {
  7441. return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
  7442. }
  7443. return array_filter($array, $arrow);
  7444. }
  7445. return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow);
  7446. }
  7447. function twig_array_map($array, $arrow)
  7448. {
  7449. $r = [];
  7450. foreach ($array as $k => $v) {
  7451. $r[$k] = $arrow($v, $k);
  7452. }
  7453. return $r;
  7454. }
  7455. function twig_array_reduce($array, $arrow, $initial = null)
  7456. {
  7457. if (!\is_array($array)) {
  7458. $array = iterator_to_array($array);
  7459. }
  7460. return array_reduce($array, $arrow, $initial);
  7461. }
  7462. }
  7463. namespace Twig\Extension {
  7464. use Twig\NodeVisitor\EscaperNodeVisitor;
  7465. use Twig\TokenParser\AutoEscapeTokenParser;
  7466. use Twig\TwigFilter;
  7467. class EscaperExtension extends AbstractExtension
  7468. {
  7469. protected $defaultStrategy;
  7470. public function __construct($defaultStrategy ='html')
  7471. {
  7472. $this->setDefaultStrategy($defaultStrategy);
  7473. }
  7474. public function getTokenParsers()
  7475. {
  7476. return [new AutoEscapeTokenParser()];
  7477. }
  7478. public function getNodeVisitors()
  7479. {
  7480. return [new EscaperNodeVisitor()];
  7481. }
  7482. public function getFilters()
  7483. {
  7484. return [
  7485. new TwigFilter('raw','twig_raw_filter', ['is_safe'=> ['all']]),
  7486. ];
  7487. }
  7488. public function setDefaultStrategy($defaultStrategy)
  7489. {
  7490. if (true === $defaultStrategy) {
  7491. @trigger_error('Using "true" as the default strategy is deprecated since version 1.21. Use "html" instead.', E_USER_DEPRECATED);
  7492. $defaultStrategy ='html';
  7493. }
  7494. if ('filename'=== $defaultStrategy) {
  7495. @trigger_error('Using "filename" as the default strategy is deprecated since version 1.27. Use "name" instead.', E_USER_DEPRECATED);
  7496. $defaultStrategy ='name';
  7497. }
  7498. if ('name'=== $defaultStrategy) {
  7499. $defaultStrategy = ['\Twig\FileExtensionEscapingStrategy','guess'];
  7500. }
  7501. $this->defaultStrategy = $defaultStrategy;
  7502. }
  7503. public function getDefaultStrategy($name)
  7504. {
  7505. if (!\is_string($this->defaultStrategy) && false !== $this->defaultStrategy) {
  7506. return \call_user_func($this->defaultStrategy, $name);
  7507. }
  7508. return $this->defaultStrategy;
  7509. }
  7510. public function getName()
  7511. {
  7512. return'escaper';
  7513. }
  7514. }
  7515. class_alias('Twig\Extension\EscaperExtension','Twig_Extension_Escaper');
  7516. }
  7517. namespace {
  7518. function twig_raw_filter($string)
  7519. {
  7520. return $string;
  7521. }
  7522. }
  7523. namespace Twig\Extension
  7524. {
  7525. use Twig\NodeVisitor\OptimizerNodeVisitor;
  7526. class OptimizerExtension extends AbstractExtension
  7527. {
  7528. protected $optimizers;
  7529. public function __construct($optimizers = -1)
  7530. {
  7531. $this->optimizers = $optimizers;
  7532. }
  7533. public function getNodeVisitors()
  7534. {
  7535. return [new OptimizerNodeVisitor($this->optimizers)];
  7536. }
  7537. public function getName()
  7538. {
  7539. return'optimizer';
  7540. }
  7541. }
  7542. class_alias('Twig\Extension\OptimizerExtension','Twig_Extension_Optimizer');
  7543. }
  7544. namespace Twig\Loader
  7545. {
  7546. use Twig\Error\LoaderError;
  7547. interface LoaderInterface
  7548. {
  7549. public function getSource($name);
  7550. public function getCacheKey($name);
  7551. public function isFresh($name, $time);
  7552. }
  7553. class_alias('Twig\Loader\LoaderInterface','Twig_LoaderInterface');
  7554. }
  7555. namespace Twig
  7556. {
  7557. class Markup implements \Countable
  7558. {
  7559. protected $content;
  7560. protected $charset;
  7561. public function __construct($content, $charset)
  7562. {
  7563. $this->content = (string) $content;
  7564. $this->charset = $charset;
  7565. }
  7566. public function __toString()
  7567. {
  7568. return $this->content;
  7569. }
  7570. public function count()
  7571. {
  7572. return \function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : \strlen($this->content);
  7573. }
  7574. }
  7575. class_alias('Twig\Markup','Twig_Markup');
  7576. }
  7577. namespace
  7578. {
  7579. use Twig\Environment;
  7580. interface Twig_TemplateInterface
  7581. {
  7582. const ANY_CALL ='any';
  7583. const ARRAY_CALL ='array';
  7584. const METHOD_CALL ='method';
  7585. public function render(array $context);
  7586. public function display(array $context, array $blocks = []);
  7587. public function getEnvironment();
  7588. }
  7589. }
  7590. namespace Twig
  7591. {
  7592. use Twig\Error\Error;
  7593. use Twig\Error\LoaderError;
  7594. use Twig\Error\RuntimeError;
  7595. abstract class Template implements \Twig_TemplateInterface
  7596. {
  7597. protected static $cache = [];
  7598. protected $parent;
  7599. protected $parents = [];
  7600. protected $env;
  7601. protected $blocks = [];
  7602. protected $traits = [];
  7603. protected $sandbox;
  7604. public function __construct(Environment $env)
  7605. {
  7606. $this->env = $env;
  7607. }
  7608. public function __toString()
  7609. {
  7610. return $this->getTemplateName();
  7611. }
  7612. abstract public function getTemplateName();
  7613. public function getDebugInfo()
  7614. {
  7615. return [];
  7616. }
  7617. public function getSource()
  7618. {
  7619. @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);
  7620. return'';
  7621. }
  7622. public function getSourceContext()
  7623. {
  7624. return new Source('', $this->getTemplateName());
  7625. }
  7626. public function getEnvironment()
  7627. {
  7628. @trigger_error('The '.__METHOD__.' method is deprecated since version 1.20 and will be removed in 2.0.', E_USER_DEPRECATED);
  7629. return $this->env;
  7630. }
  7631. public function getParent(array $context)
  7632. {
  7633. if (null !== $this->parent) {
  7634. return $this->parent;
  7635. }
  7636. try {
  7637. $parent = $this->doGetParent($context);
  7638. if (false === $parent) {
  7639. return false;
  7640. }
  7641. if ($parent instanceof self || $parent instanceof TemplateWrapper) {
  7642. return $this->parents[$parent->getSourceContext()->getName()] = $parent;
  7643. }
  7644. if (!isset($this->parents[$parent])) {
  7645. $this->parents[$parent] = $this->loadTemplate($parent);
  7646. }
  7647. } catch (LoaderError $e) {
  7648. $e->setSourceContext(null);
  7649. $e->guess();
  7650. throw $e;
  7651. }
  7652. return $this->parents[$parent];
  7653. }
  7654. protected function doGetParent(array $context)
  7655. {
  7656. return false;
  7657. }
  7658. public function isTraitable()
  7659. {
  7660. return true;
  7661. }
  7662. public function displayParentBlock($name, array $context, array $blocks = [])
  7663. {
  7664. $name = (string) $name;
  7665. if (isset($this->traits[$name])) {
  7666. $this->traits[$name][0]->displayBlock($name, $context, $blocks, false);
  7667. } elseif (false !== $parent = $this->getParent($context)) {
  7668. $parent->displayBlock($name, $context, $blocks, false);
  7669. } else {
  7670. throw new RuntimeError(sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getSourceContext());
  7671. }
  7672. }
  7673. public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true)
  7674. {
  7675. $name = (string) $name;
  7676. if ($useBlocks && isset($blocks[$name])) {
  7677. $template = $blocks[$name][0];
  7678. $block = $blocks[$name][1];
  7679. } elseif (isset($this->blocks[$name])) {
  7680. $template = $this->blocks[$name][0];
  7681. $block = $this->blocks[$name][1];
  7682. } else {
  7683. $template = null;
  7684. $block = null;
  7685. }
  7686. if (null !== $template && !$template instanceof self) {
  7687. throw new \LogicException('A block must be a method on a \Twig\Template instance.');
  7688. }
  7689. if (null !== $template) {
  7690. try {
  7691. $template->$block($context, $blocks);
  7692. } catch (Error $e) {
  7693. if (!$e->getSourceContext()) {
  7694. $e->setSourceContext($template->getSourceContext());
  7695. }
  7696. if (-1 === $e->getTemplateLine()) {
  7697. $e->guess();
  7698. }
  7699. throw $e;
  7700. } catch (\Exception $e) {
  7701. $e = new RuntimeError(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getSourceContext(), $e);
  7702. $e->guess();
  7703. throw $e;
  7704. }
  7705. } elseif (false !== $parent = $this->getParent($context)) {
  7706. $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false);
  7707. } else {
  7708. @trigger_error(sprintf('Silent display of undefined block "%s" in template "%s" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block(\'%s\') is defined" expression to test for block existence.', $name, $this->getTemplateName(), $name), E_USER_DEPRECATED);
  7709. }
  7710. }
  7711. public function renderParentBlock($name, array $context, array $blocks = [])
  7712. {
  7713. if ($this->env->isDebug()) {
  7714. ob_start();
  7715. } else {
  7716. ob_start(function () { return''; });
  7717. }
  7718. $this->displayParentBlock($name, $context, $blocks);
  7719. return ob_get_clean();
  7720. }
  7721. public function renderBlock($name, array $context, array $blocks = [], $useBlocks = true)
  7722. {
  7723. if ($this->env->isDebug()) {
  7724. ob_start();
  7725. } else {
  7726. ob_start(function () { return''; });
  7727. }
  7728. $this->displayBlock($name, $context, $blocks, $useBlocks);
  7729. return ob_get_clean();
  7730. }
  7731. public function hasBlock($name, array $context = null, array $blocks = [])
  7732. {
  7733. if (null === $context) {
  7734. @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED);
  7735. return isset($this->blocks[(string) $name]);
  7736. }
  7737. if (isset($blocks[$name])) {
  7738. return $blocks[$name][0] instanceof self;
  7739. }
  7740. if (isset($this->blocks[$name])) {
  7741. return true;
  7742. }
  7743. if (false !== $parent = $this->getParent($context)) {
  7744. return $parent->hasBlock($name, $context);
  7745. }
  7746. return false;
  7747. }
  7748. public function getBlockNames(array $context = null, array $blocks = [])
  7749. {
  7750. if (null === $context) {
  7751. @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED);
  7752. return array_keys($this->blocks);
  7753. }
  7754. $names = array_merge(array_keys($blocks), array_keys($this->blocks));
  7755. if (false !== $parent = $this->getParent($context)) {
  7756. $names = array_merge($names, $parent->getBlockNames($context));
  7757. }
  7758. return array_unique($names);
  7759. }
  7760. protected function loadTemplate($template, $templateName = null, $line = null, $index = null)
  7761. {
  7762. try {
  7763. if (\is_array($template)) {
  7764. return $this->env->resolveTemplate($template);
  7765. }
  7766. if ($template instanceof self || $template instanceof TemplateWrapper) {
  7767. return $template;
  7768. }
  7769. if ($template === $this->getTemplateName()) {
  7770. $class = \get_class($this);
  7771. if (false !== $pos = strrpos($class,'___', -1)) {
  7772. $class = substr($class, 0, $pos);
  7773. }
  7774. return $this->env->loadClass($class, $template, $index);
  7775. }
  7776. return $this->env->loadTemplate($template, $index);
  7777. } catch (Error $e) {
  7778. if (!$e->getSourceContext()) {
  7779. $e->setSourceContext($templateName ? new Source('', $templateName) : $this->getSourceContext());
  7780. }
  7781. if ($e->getTemplateLine() > 0) {
  7782. throw $e;
  7783. }
  7784. if (!$line) {
  7785. $e->guess();
  7786. } else {
  7787. $e->setTemplateLine($line);
  7788. }
  7789. throw $e;
  7790. }
  7791. }
  7792. protected function unwrap()
  7793. {
  7794. return $this;
  7795. }
  7796. public function getBlocks()
  7797. {
  7798. return $this->blocks;
  7799. }
  7800. public function display(array $context, array $blocks = [])
  7801. {
  7802. $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
  7803. }
  7804. public function render(array $context)
  7805. {
  7806. $level = ob_get_level();
  7807. if ($this->env->isDebug()) {
  7808. ob_start();
  7809. } else {
  7810. ob_start(function () { return''; });
  7811. }
  7812. try {
  7813. $this->display($context);
  7814. } catch (\Exception $e) {
  7815. while (ob_get_level() > $level) {
  7816. ob_end_clean();
  7817. }
  7818. throw $e;
  7819. } catch (\Throwable $e) {
  7820. while (ob_get_level() > $level) {
  7821. ob_end_clean();
  7822. }
  7823. throw $e;
  7824. }
  7825. return ob_get_clean();
  7826. }
  7827. protected function displayWithErrorHandling(array $context, array $blocks = [])
  7828. {
  7829. try {
  7830. $this->doDisplay($context, $blocks);
  7831. } catch (Error $e) {
  7832. if (!$e->getSourceContext()) {
  7833. $e->setSourceContext($this->getSourceContext());
  7834. }
  7835. if (-1 === $e->getTemplateLine()) {
  7836. $e->guess();
  7837. }
  7838. throw $e;
  7839. } catch (\Exception $e) {
  7840. $e = new RuntimeError(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getSourceContext(), $e);
  7841. $e->guess();
  7842. throw $e;
  7843. }
  7844. }
  7845. abstract protected function doDisplay(array $context, array $blocks = []);
  7846. final protected function getContext($context, $item, $ignoreStrictCheck = false)
  7847. {
  7848. if (!\array_key_exists($item, $context)) {
  7849. if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
  7850. return;
  7851. }
  7852. throw new RuntimeError(sprintf('Variable "%s" does not exist.', $item), -1, $this->getSourceContext());
  7853. }
  7854. return $context[$item];
  7855. }
  7856. protected function getAttribute($object, $item, array $arguments = [], $type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
  7857. {
  7858. if (self::METHOD_CALL !== $type) {
  7859. $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item;
  7860. if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, (array) $object)))
  7861. || ($object instanceof \ArrayAccess && isset($object[$arrayItem]))
  7862. ) {
  7863. if ($isDefinedTest) {
  7864. return true;
  7865. }
  7866. return $object[$arrayItem];
  7867. }
  7868. if (self::ARRAY_CALL === $type || !\is_object($object)) {
  7869. if ($isDefinedTest) {
  7870. return false;
  7871. }
  7872. if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
  7873. return;
  7874. }
  7875. if ($object instanceof \ArrayAccess) {
  7876. $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object));
  7877. } elseif (\is_object($object)) {
  7878. $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object));
  7879. } elseif (\is_array($object)) {
  7880. if (empty($object)) {
  7881. $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem);
  7882. } else {
  7883. $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object)));
  7884. }
  7885. } elseif (self::ARRAY_CALL === $type) {
  7886. if (null === $object) {
  7887. $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item);
  7888. } else {
  7889. $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
  7890. }
  7891. } elseif (null === $object) {
  7892. $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item);
  7893. } else {
  7894. $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
  7895. }
  7896. throw new RuntimeError($message, -1, $this->getSourceContext());
  7897. }
  7898. }
  7899. if (!\is_object($object)) {
  7900. if ($isDefinedTest) {
  7901. return false;
  7902. }
  7903. if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
  7904. return;
  7905. }
  7906. if (null === $object) {
  7907. $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item);
  7908. } elseif (\is_array($object)) {
  7909. $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item);
  7910. } else {
  7911. $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
  7912. }
  7913. throw new RuntimeError($message, -1, $this->getSourceContext());
  7914. }
  7915. if (self::METHOD_CALL !== $type && !$object instanceof self) { if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) {
  7916. if ($isDefinedTest) {
  7917. return true;
  7918. }
  7919. if ($this->env->hasExtension('\Twig\Extension\SandboxExtension')) {
  7920. $this->env->getExtension('\Twig\Extension\SandboxExtension')->checkPropertyAllowed($object, $item);
  7921. }
  7922. return $object->$item;
  7923. }
  7924. }
  7925. $class = \get_class($object);
  7926. if (!isset(self::$cache[$class])) {
  7927. if ($object instanceof self) {
  7928. $ref = new \ReflectionClass($class);
  7929. $methods = [];
  7930. foreach ($ref->getMethods(\ReflectionMethod::IS_PUBLIC) as $refMethod) {
  7931. if ('getenvironment'!== strtr($refMethod->name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')) {
  7932. $methods[] = $refMethod->name;
  7933. }
  7934. }
  7935. } else {
  7936. $methods = get_class_methods($object);
  7937. }
  7938. sort($methods);
  7939. $cache = [];
  7940. foreach ($methods as $method) {
  7941. $cache[$method] = $method;
  7942. $cache[$lcName = strtr($method,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')] = $method;
  7943. if ('g'=== $lcName[0] && 0 === strpos($lcName,'get')) {
  7944. $name = substr($method, 3);
  7945. $lcName = substr($lcName, 3);
  7946. } elseif ('i'=== $lcName[0] && 0 === strpos($lcName,'is')) {
  7947. $name = substr($method, 2);
  7948. $lcName = substr($lcName, 2);
  7949. } else {
  7950. continue;
  7951. }
  7952. if ($name) {
  7953. if (!isset($cache[$name])) {
  7954. $cache[$name] = $method;
  7955. }
  7956. if (!isset($cache[$lcName])) {
  7957. $cache[$lcName] = $method;
  7958. }
  7959. }
  7960. }
  7961. self::$cache[$class] = $cache;
  7962. }
  7963. $call = false;
  7964. if (isset(self::$cache[$class][$item])) {
  7965. $method = self::$cache[$class][$item];
  7966. } elseif (isset(self::$cache[$class][$lcItem = strtr($item,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')])) {
  7967. $method = self::$cache[$class][$lcItem];
  7968. } elseif (isset(self::$cache[$class]['__call'])) {
  7969. $method = $item;
  7970. $call = true;
  7971. } else {
  7972. if ($isDefinedTest) {
  7973. return false;
  7974. }
  7975. if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
  7976. return;
  7977. }
  7978. throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), -1, $this->getSourceContext());
  7979. }
  7980. if ($isDefinedTest) {
  7981. return true;
  7982. }
  7983. if ($this->env->hasExtension('\Twig\Extension\SandboxExtension')) {
  7984. $this->env->getExtension('\Twig\Extension\SandboxExtension')->checkMethodAllowed($object, $method);
  7985. }
  7986. try {
  7987. if (!$arguments) {
  7988. $ret = $object->$method();
  7989. } else {
  7990. $ret = \call_user_func_array([$object, $method], $arguments);
  7991. }
  7992. } catch (\BadMethodCallException $e) {
  7993. if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
  7994. return;
  7995. }
  7996. throw $e;
  7997. }
  7998. if ($object instanceof \Twig_TemplateInterface) {
  7999. $self = $object->getTemplateName() === $this->getTemplateName();
  8000. $message = sprintf('Calling "%s" on template "%s" from template "%s" is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', $item, $object->getTemplateName(), $this->getTemplateName());
  8001. if ('renderBlock'=== $method ||'displayBlock'=== $method) {
  8002. $message .= sprintf(' Use block("%s"%s) instead).', $arguments[0], $self ?'':', template');
  8003. } elseif ('hasBlock'=== $method) {
  8004. $message .= sprintf(' Use "block("%s"%s) is defined" instead).', $arguments[0], $self ?'':', template');
  8005. } elseif ('render'=== $method ||'display'=== $method) {
  8006. $message .= sprintf(' Use include("%s") instead).', $object->getTemplateName());
  8007. }
  8008. @trigger_error($message, E_USER_DEPRECATED);
  8009. return''=== $ret ?'': new Markup($ret, $this->env->getCharset());
  8010. }
  8011. return $ret;
  8012. }
  8013. }
  8014. class_alias('Twig\Template','Twig_Template');
  8015. }
  8016. namespace Monolog\Formatter
  8017. {
  8018. interface FormatterInterface
  8019. {
  8020. public function format(array $record);
  8021. public function formatBatch(array $records);
  8022. }
  8023. }
  8024. namespace Monolog\Formatter
  8025. {
  8026. use Exception;
  8027. use Monolog\Utils;
  8028. class NormalizerFormatter implements FormatterInterface
  8029. {
  8030. const SIMPLE_DATE ="Y-m-d H:i:s";
  8031. protected $dateFormat;
  8032. protected $maxDepth;
  8033. public function __construct($dateFormat = null, $maxDepth = 9)
  8034. {
  8035. $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE;
  8036. $this->maxDepth = $maxDepth;
  8037. if (!function_exists('json_encode')) {
  8038. throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter');
  8039. }
  8040. }
  8041. public function format(array $record)
  8042. {
  8043. return $this->normalize($record);
  8044. }
  8045. public function formatBatch(array $records)
  8046. {
  8047. foreach ($records as $key => $record) {
  8048. $records[$key] = $this->format($record);
  8049. }
  8050. return $records;
  8051. }
  8052. public function getMaxDepth()
  8053. {
  8054. return $this->maxDepth;
  8055. }
  8056. public function setMaxDepth($maxDepth)
  8057. {
  8058. $this->maxDepth = $maxDepth;
  8059. }
  8060. protected function normalize($data, $depth = 0)
  8061. {
  8062. if ($depth > $this->maxDepth) {
  8063. return'Over '.$this->maxDepth.' levels deep, aborting normalization';
  8064. }
  8065. if (null === $data || is_scalar($data)) {
  8066. if (is_float($data)) {
  8067. if (is_infinite($data)) {
  8068. return ($data > 0 ?'':'-') .'INF';
  8069. }
  8070. if (is_nan($data)) {
  8071. return'NaN';
  8072. }
  8073. }
  8074. return $data;
  8075. }
  8076. if (is_array($data)) {
  8077. $normalized = array();
  8078. $count = 1;
  8079. foreach ($data as $key => $value) {
  8080. if ($count++ > 1000) {
  8081. $normalized['...'] ='Over 1000 items ('.count($data).' total), aborting normalization';
  8082. break;
  8083. }
  8084. $normalized[$key] = $this->normalize($value, $depth+1);
  8085. }
  8086. return $normalized;
  8087. }
  8088. if ($data instanceof \DateTime) {
  8089. return $data->format($this->dateFormat);
  8090. }
  8091. if (is_object($data)) {
  8092. if ($data instanceof Exception || (PHP_VERSION_ID > 70000 && $data instanceof \Throwable)) {
  8093. return $this->normalizeException($data);
  8094. }
  8095. if (method_exists($data,'__toString') && !$data instanceof \JsonSerializable) {
  8096. $value = $data->__toString();
  8097. } else {
  8098. $value = $this->toJson($data, true);
  8099. }
  8100. return sprintf("[object] (%s: %s)", Utils::getClass($data), $value);
  8101. }
  8102. if (is_resource($data)) {
  8103. return sprintf('[resource] (%s)', get_resource_type($data));
  8104. }
  8105. return'[unknown('.gettype($data).')]';
  8106. }
  8107. protected function normalizeException($e)
  8108. {
  8109. if (!$e instanceof Exception && !$e instanceof \Throwable) {
  8110. throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
  8111. }
  8112. $data = array('class'=> Utils::getClass($e),'message'=> $e->getMessage(),'code'=> (int) $e->getCode(),'file'=> $e->getFile().':'.$e->getLine(),
  8113. );
  8114. if ($e instanceof \SoapFault) {
  8115. if (isset($e->faultcode)) {
  8116. $data['faultcode'] = $e->faultcode;
  8117. }
  8118. if (isset($e->faultactor)) {
  8119. $data['faultactor'] = $e->faultactor;
  8120. }
  8121. if (isset($e->detail)) {
  8122. if (is_string($e->detail)) {
  8123. $data['detail'] = $e->detail;
  8124. } elseif (is_object($e->detail) || is_array($e->detail)) {
  8125. $data['detail'] = $this->toJson($e->detail, true);
  8126. }
  8127. }
  8128. }
  8129. $trace = $e->getTrace();
  8130. foreach ($trace as $frame) {
  8131. if (isset($frame['file'])) {
  8132. $data['trace'][] = $frame['file'].':'.$frame['line'];
  8133. }
  8134. }
  8135. if ($previous = $e->getPrevious()) {
  8136. $data['previous'] = $this->normalizeException($previous);
  8137. }
  8138. return $data;
  8139. }
  8140. protected function toJson($data, $ignoreErrors = false)
  8141. {
  8142. return Utils::jsonEncode($data, null, $ignoreErrors);
  8143. }
  8144. }}
  8145. namespace Monolog\Formatter
  8146. {
  8147. use Monolog\Utils;
  8148. class LineFormatter extends NormalizerFormatter
  8149. {
  8150. const SIMPLE_FORMAT ="[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
  8151. protected $format;
  8152. protected $allowInlineLineBreaks;
  8153. protected $ignoreEmptyContextAndExtra;
  8154. protected $includeStacktraces;
  8155. public function __construct($format = null, $dateFormat = null, $allowInlineLineBreaks = false, $ignoreEmptyContextAndExtra = false)
  8156. {
  8157. $this->format = $format ?: static::SIMPLE_FORMAT;
  8158. $this->allowInlineLineBreaks = $allowInlineLineBreaks;
  8159. $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra;
  8160. parent::__construct($dateFormat);
  8161. }
  8162. public function includeStacktraces($include = true)
  8163. {
  8164. $this->includeStacktraces = $include;
  8165. if ($this->includeStacktraces) {
  8166. $this->allowInlineLineBreaks = true;
  8167. }
  8168. }
  8169. public function allowInlineLineBreaks($allow = true)
  8170. {
  8171. $this->allowInlineLineBreaks = $allow;
  8172. }
  8173. public function ignoreEmptyContextAndExtra($ignore = true)
  8174. {
  8175. $this->ignoreEmptyContextAndExtra = $ignore;
  8176. }
  8177. public function format(array $record)
  8178. {
  8179. $vars = parent::format($record);
  8180. $output = $this->format;
  8181. foreach ($vars['extra'] as $var => $val) {
  8182. if (false !== strpos($output,'%extra.'.$var.'%')) {
  8183. $output = str_replace('%extra.'.$var.'%', $this->stringify($val), $output);
  8184. unset($vars['extra'][$var]);
  8185. }
  8186. }
  8187. foreach ($vars['context'] as $var => $val) {
  8188. if (false !== strpos($output,'%context.'.$var.'%')) {
  8189. $output = str_replace('%context.'.$var.'%', $this->stringify($val), $output);
  8190. unset($vars['context'][$var]);
  8191. }
  8192. }
  8193. if ($this->ignoreEmptyContextAndExtra) {
  8194. if (empty($vars['context'])) {
  8195. unset($vars['context']);
  8196. $output = str_replace('%context%','', $output);
  8197. }
  8198. if (empty($vars['extra'])) {
  8199. unset($vars['extra']);
  8200. $output = str_replace('%extra%','', $output);
  8201. }
  8202. }
  8203. foreach ($vars as $var => $val) {
  8204. if (false !== strpos($output,'%'.$var.'%')) {
  8205. $output = str_replace('%'.$var.'%', $this->stringify($val), $output);
  8206. }
  8207. }
  8208. if (false !== strpos($output,'%')) {
  8209. $output = preg_replace('/%(?:extra|context)\..+?%/','', $output);
  8210. }
  8211. return $output;
  8212. }
  8213. public function formatBatch(array $records)
  8214. {
  8215. $message ='';
  8216. foreach ($records as $record) {
  8217. $message .= $this->format($record);
  8218. }
  8219. return $message;
  8220. }
  8221. public function stringify($value)
  8222. {
  8223. return $this->replaceNewlines($this->convertToString($value));
  8224. }
  8225. protected function normalizeException($e)
  8226. {
  8227. if (!$e instanceof \Exception && !$e instanceof \Throwable) {
  8228. throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
  8229. }
  8230. $previousText ='';
  8231. if ($previous = $e->getPrevious()) {
  8232. do {
  8233. $previousText .=', '.Utils::getClass($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
  8234. } while ($previous = $previous->getPrevious());
  8235. }
  8236. $str ='[object] ('.Utils::getClass($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')';
  8237. if ($this->includeStacktraces) {
  8238. $str .="\n[stacktrace]\n".$e->getTraceAsString()."\n";
  8239. }
  8240. return $str;
  8241. }
  8242. protected function convertToString($data)
  8243. {
  8244. if (null === $data || is_bool($data)) {
  8245. return var_export($data, true);
  8246. }
  8247. if (is_scalar($data)) {
  8248. return (string) $data;
  8249. }
  8250. if (version_compare(PHP_VERSION,'5.4.0','>=')) {
  8251. return $this->toJson($data, true);
  8252. }
  8253. return str_replace('\\/','/', $this->toJson($data, true));
  8254. }
  8255. protected function replaceNewlines($str)
  8256. {
  8257. if ($this->allowInlineLineBreaks) {
  8258. if (0 === strpos($str,'{')) {
  8259. return str_replace(array('\r','\n'), array("\r","\n"), $str);
  8260. }
  8261. return $str;
  8262. }
  8263. return str_replace(array("\r\n","\r","\n"),' ', $str);
  8264. }
  8265. }
  8266. }
  8267. namespace Monolog\Handler
  8268. {
  8269. use Monolog\Formatter\FormatterInterface;
  8270. interface HandlerInterface
  8271. {
  8272. public function isHandling(array $record);
  8273. public function handle(array $record);
  8274. public function handleBatch(array $records);
  8275. public function pushProcessor($callback);
  8276. public function popProcessor();
  8277. public function setFormatter(FormatterInterface $formatter);
  8278. public function getFormatter();
  8279. }
  8280. }
  8281. namespace Monolog
  8282. {
  8283. interface ResettableInterface
  8284. {
  8285. public function reset();
  8286. }
  8287. }
  8288. namespace Monolog\Handler
  8289. {
  8290. use Monolog\Formatter\FormatterInterface;
  8291. use Monolog\Formatter\LineFormatter;
  8292. use Monolog\Logger;
  8293. use Monolog\ResettableInterface;
  8294. abstract class AbstractHandler implements HandlerInterface, ResettableInterface
  8295. {
  8296. protected $level = Logger::DEBUG;
  8297. protected $bubble = true;
  8298. protected $formatter;
  8299. protected $processors = array();
  8300. public function __construct($level = Logger::DEBUG, $bubble = true)
  8301. {
  8302. $this->setLevel($level);
  8303. $this->bubble = $bubble;
  8304. }
  8305. public function isHandling(array $record)
  8306. {
  8307. return $record['level'] >= $this->level;
  8308. }
  8309. public function handleBatch(array $records)
  8310. {
  8311. foreach ($records as $record) {
  8312. $this->handle($record);
  8313. }
  8314. }
  8315. public function close()
  8316. {
  8317. }
  8318. public function pushProcessor($callback)
  8319. {
  8320. if (!is_callable($callback)) {
  8321. throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
  8322. }
  8323. array_unshift($this->processors, $callback);
  8324. return $this;
  8325. }
  8326. public function popProcessor()
  8327. {
  8328. if (!$this->processors) {
  8329. throw new \LogicException('You tried to pop from an empty processor stack.');
  8330. }
  8331. return array_shift($this->processors);
  8332. }
  8333. public function setFormatter(FormatterInterface $formatter)
  8334. {
  8335. $this->formatter = $formatter;
  8336. return $this;
  8337. }
  8338. public function getFormatter()
  8339. {
  8340. if (!$this->formatter) {
  8341. $this->formatter = $this->getDefaultFormatter();
  8342. }
  8343. return $this->formatter;
  8344. }
  8345. public function setLevel($level)
  8346. {
  8347. $this->level = Logger::toMonologLevel($level);
  8348. return $this;
  8349. }
  8350. public function getLevel()
  8351. {
  8352. return $this->level;
  8353. }
  8354. public function setBubble($bubble)
  8355. {
  8356. $this->bubble = $bubble;
  8357. return $this;
  8358. }
  8359. public function getBubble()
  8360. {
  8361. return $this->bubble;
  8362. }
  8363. public function __destruct()
  8364. {
  8365. try {
  8366. $this->close();
  8367. } catch (\Exception $e) {
  8368. } catch (\Throwable $e) {
  8369. }
  8370. }
  8371. public function reset()
  8372. {
  8373. foreach ($this->processors as $processor) {
  8374. if ($processor instanceof ResettableInterface) {
  8375. $processor->reset();
  8376. }
  8377. }
  8378. }
  8379. protected function getDefaultFormatter()
  8380. {
  8381. return new LineFormatter();
  8382. }
  8383. }
  8384. }
  8385. namespace Monolog\Handler
  8386. {
  8387. use Monolog\ResettableInterface;
  8388. abstract class AbstractProcessingHandler extends AbstractHandler
  8389. {
  8390. public function handle(array $record)
  8391. {
  8392. if (!$this->isHandling($record)) {
  8393. return false;
  8394. }
  8395. $record = $this->processRecord($record);
  8396. $record['formatted'] = $this->getFormatter()->format($record);
  8397. $this->write($record);
  8398. return false === $this->bubble;
  8399. }
  8400. abstract protected function write(array $record);
  8401. protected function processRecord(array $record)
  8402. {
  8403. if ($this->processors) {
  8404. foreach ($this->processors as $processor) {
  8405. $record = call_user_func($processor, $record);
  8406. }
  8407. }
  8408. return $record;
  8409. }
  8410. }
  8411. }
  8412. namespace Monolog\Handler
  8413. {
  8414. use Monolog\Logger;
  8415. use Monolog\Utils;
  8416. class StreamHandler extends AbstractProcessingHandler
  8417. {
  8418. const CHUNK_SIZE = 524288;
  8419. protected $stream;
  8420. protected $url;
  8421. private $errorMessage;
  8422. protected $filePermission;
  8423. protected $useLocking;
  8424. private $dirCreated;
  8425. public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
  8426. {
  8427. parent::__construct($level, $bubble);
  8428. if (is_resource($stream)) {
  8429. $this->stream = $stream;
  8430. $this->streamSetChunkSize();
  8431. } elseif (is_string($stream)) {
  8432. $this->url = Utils::canonicalizePath($stream);
  8433. } else {
  8434. throw new \InvalidArgumentException('A stream must either be a resource or a string.');
  8435. }
  8436. $this->filePermission = $filePermission;
  8437. $this->useLocking = $useLocking;
  8438. }
  8439. public function close()
  8440. {
  8441. if ($this->url && is_resource($this->stream)) {
  8442. fclose($this->stream);
  8443. }
  8444. $this->stream = null;
  8445. $this->dirCreated = null;
  8446. }
  8447. public function getStream()
  8448. {
  8449. return $this->stream;
  8450. }
  8451. public function getUrl()
  8452. {
  8453. return $this->url;
  8454. }
  8455. protected function write(array $record)
  8456. {
  8457. if (!is_resource($this->stream)) {
  8458. if (null === $this->url ||''=== $this->url) {
  8459. throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
  8460. }
  8461. $this->createDir();
  8462. $this->errorMessage = null;
  8463. set_error_handler(array($this,'customErrorHandler'));
  8464. $this->stream = fopen($this->url,'a');
  8465. if ($this->filePermission !== null) {
  8466. @chmod($this->url, $this->filePermission);
  8467. }
  8468. restore_error_handler();
  8469. if (!is_resource($this->stream)) {
  8470. $this->stream = null;
  8471. throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url));
  8472. }
  8473. $this->streamSetChunkSize();
  8474. }
  8475. if ($this->useLocking) {
  8476. flock($this->stream, LOCK_EX);
  8477. }
  8478. $this->streamWrite($this->stream, $record);
  8479. if ($this->useLocking) {
  8480. flock($this->stream, LOCK_UN);
  8481. }
  8482. }
  8483. protected function streamWrite($stream, array $record)
  8484. {
  8485. fwrite($stream, (string) $record['formatted']);
  8486. }
  8487. protected function streamSetChunkSize()
  8488. {
  8489. if (version_compare(PHP_VERSION,'5.4.0','>=')) {
  8490. return stream_set_chunk_size($this->stream, self::CHUNK_SIZE);
  8491. }
  8492. return false;
  8493. }
  8494. private function customErrorHandler($code, $msg)
  8495. {
  8496. $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }','', $msg);
  8497. }
  8498. private function getDirFromStream($stream)
  8499. {
  8500. $pos = strpos($stream,'://');
  8501. if ($pos === false) {
  8502. return dirname($stream);
  8503. }
  8504. if ('file://'=== substr($stream, 0, 7)) {
  8505. return dirname(substr($stream, 7));
  8506. }
  8507. return null;
  8508. }
  8509. private function createDir()
  8510. {
  8511. if ($this->dirCreated) {
  8512. return;
  8513. }
  8514. $dir = $this->getDirFromStream($this->url);
  8515. if (null !== $dir && !is_dir($dir)) {
  8516. $this->errorMessage = null;
  8517. set_error_handler(array($this,'customErrorHandler'));
  8518. $status = mkdir($dir, 0777, true);
  8519. restore_error_handler();
  8520. if (false === $status && !is_dir($dir)) {
  8521. throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir));
  8522. }
  8523. }
  8524. $this->dirCreated = true;
  8525. }
  8526. }
  8527. }
  8528. namespace Monolog\Handler
  8529. {
  8530. use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
  8531. use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
  8532. use Monolog\Logger;
  8533. use Monolog\ResettableInterface;
  8534. use Monolog\Formatter\FormatterInterface;
  8535. class FingersCrossedHandler extends AbstractHandler
  8536. {
  8537. protected $handler;
  8538. protected $activationStrategy;
  8539. protected $buffering = true;
  8540. protected $bufferSize;
  8541. protected $buffer = array();
  8542. protected $stopBuffering;
  8543. protected $passthruLevel;
  8544. public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null)
  8545. {
  8546. if (null === $activationStrategy) {
  8547. $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
  8548. }
  8549. if (!$activationStrategy instanceof ActivationStrategyInterface) {
  8550. $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy);
  8551. }
  8552. $this->handler = $handler;
  8553. $this->activationStrategy = $activationStrategy;
  8554. $this->bufferSize = $bufferSize;
  8555. $this->bubble = $bubble;
  8556. $this->stopBuffering = $stopBuffering;
  8557. if ($passthruLevel !== null) {
  8558. $this->passthruLevel = Logger::toMonologLevel($passthruLevel);
  8559. }
  8560. if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
  8561. throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
  8562. }
  8563. }
  8564. public function isHandling(array $record)
  8565. {
  8566. return true;
  8567. }
  8568. public function activate()
  8569. {
  8570. if ($this->stopBuffering) {
  8571. $this->buffering = false;
  8572. }
  8573. $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
  8574. $this->buffer = array();
  8575. }
  8576. public function handle(array $record)
  8577. {
  8578. if ($this->processors) {
  8579. foreach ($this->processors as $processor) {
  8580. $record = call_user_func($processor, $record);
  8581. }
  8582. }
  8583. if ($this->buffering) {
  8584. $this->buffer[] = $record;
  8585. if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
  8586. array_shift($this->buffer);
  8587. }
  8588. if ($this->activationStrategy->isHandlerActivated($record)) {
  8589. $this->activate();
  8590. }
  8591. } else {
  8592. $this->getHandler($record)->handle($record);
  8593. }
  8594. return false === $this->bubble;
  8595. }
  8596. public function close()
  8597. {
  8598. $this->flushBuffer();
  8599. }
  8600. public function reset()
  8601. {
  8602. $this->flushBuffer();
  8603. parent::reset();
  8604. if ($this->getHandler() instanceof ResettableInterface) {
  8605. $this->getHandler()->reset();
  8606. }
  8607. }
  8608. public function clear()
  8609. {
  8610. $this->buffer = array();
  8611. $this->reset();
  8612. }
  8613. private function flushBuffer()
  8614. {
  8615. if (null !== $this->passthruLevel) {
  8616. $level = $this->passthruLevel;
  8617. $this->buffer = array_filter($this->buffer, function ($record) use ($level) {
  8618. return $record['level'] >= $level;
  8619. });
  8620. if (count($this->buffer) > 0) {
  8621. $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
  8622. }
  8623. }
  8624. $this->buffer = array();
  8625. $this->buffering = true;
  8626. }
  8627. public function getHandler(array $record = null)
  8628. {
  8629. if (!$this->handler instanceof HandlerInterface) {
  8630. $this->handler = call_user_func($this->handler, $record, $this);
  8631. if (!$this->handler instanceof HandlerInterface) {
  8632. throw new \RuntimeException("The factory callable should return a HandlerInterface");
  8633. }
  8634. }
  8635. return $this->handler;
  8636. }
  8637. public function setFormatter(FormatterInterface $formatter)
  8638. {
  8639. $this->getHandler()->setFormatter($formatter);
  8640. return $this;
  8641. }
  8642. public function getFormatter()
  8643. {
  8644. return $this->getHandler()->getFormatter();
  8645. }
  8646. }
  8647. }
  8648. namespace Monolog\Handler
  8649. {
  8650. use Monolog\Logger;
  8651. use Monolog\Formatter\FormatterInterface;
  8652. class FilterHandler extends AbstractHandler
  8653. {
  8654. protected $handler;
  8655. protected $acceptedLevels;
  8656. protected $bubble;
  8657. public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true)
  8658. {
  8659. $this->handler = $handler;
  8660. $this->bubble = $bubble;
  8661. $this->setAcceptedLevels($minLevelOrList, $maxLevel);
  8662. if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
  8663. throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
  8664. }
  8665. }
  8666. public function getAcceptedLevels()
  8667. {
  8668. return array_flip($this->acceptedLevels);
  8669. }
  8670. public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY)
  8671. {
  8672. if (is_array($minLevelOrList)) {
  8673. $acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList);
  8674. } else {
  8675. $minLevelOrList = Logger::toMonologLevel($minLevelOrList);
  8676. $maxLevel = Logger::toMonologLevel($maxLevel);
  8677. $acceptedLevels = array_values(array_filter(Logger::getLevels(), function ($level) use ($minLevelOrList, $maxLevel) {
  8678. return $level >= $minLevelOrList && $level <= $maxLevel;
  8679. }));
  8680. }
  8681. $this->acceptedLevels = array_flip($acceptedLevels);
  8682. }
  8683. public function isHandling(array $record)
  8684. {
  8685. return isset($this->acceptedLevels[$record['level']]);
  8686. }
  8687. public function handle(array $record)
  8688. {
  8689. if (!$this->isHandling($record)) {
  8690. return false;
  8691. }
  8692. if ($this->processors) {
  8693. foreach ($this->processors as $processor) {
  8694. $record = call_user_func($processor, $record);
  8695. }
  8696. }
  8697. $this->getHandler($record)->handle($record);
  8698. return false === $this->bubble;
  8699. }
  8700. public function handleBatch(array $records)
  8701. {
  8702. $filtered = array();
  8703. foreach ($records as $record) {
  8704. if ($this->isHandling($record)) {
  8705. $filtered[] = $record;
  8706. }
  8707. }
  8708. if (count($filtered) > 0) {
  8709. $this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered);
  8710. }
  8711. }
  8712. public function getHandler(array $record = null)
  8713. {
  8714. if (!$this->handler instanceof HandlerInterface) {
  8715. $this->handler = call_user_func($this->handler, $record, $this);
  8716. if (!$this->handler instanceof HandlerInterface) {
  8717. throw new \RuntimeException("The factory callable should return a HandlerInterface");
  8718. }
  8719. }
  8720. return $this->handler;
  8721. }
  8722. public function setFormatter(FormatterInterface $formatter)
  8723. {
  8724. $this->getHandler()->setFormatter($formatter);
  8725. return $this;
  8726. }
  8727. public function getFormatter()
  8728. {
  8729. return $this->getHandler()->getFormatter();
  8730. }
  8731. }
  8732. }
  8733. namespace Monolog\Handler
  8734. {
  8735. class TestHandler extends AbstractProcessingHandler
  8736. {
  8737. protected $records = array();
  8738. protected $recordsByLevel = array();
  8739. private $skipReset = false;
  8740. public function getRecords()
  8741. {
  8742. return $this->records;
  8743. }
  8744. public function clear()
  8745. {
  8746. $this->records = array();
  8747. $this->recordsByLevel = array();
  8748. }
  8749. public function reset()
  8750. {
  8751. if (!$this->skipReset) {
  8752. $this->clear();
  8753. }
  8754. }
  8755. public function setSkipReset($skipReset)
  8756. {
  8757. $this->skipReset = $skipReset;
  8758. }
  8759. public function hasRecords($level)
  8760. {
  8761. return isset($this->recordsByLevel[$level]);
  8762. }
  8763. public function hasRecord($record, $level)
  8764. {
  8765. if (is_string($record)) {
  8766. $record = array('message'=> $record);
  8767. }
  8768. return $this->hasRecordThatPasses(function ($rec) use ($record) {
  8769. if ($rec['message'] !== $record['message']) {
  8770. return false;
  8771. }
  8772. if (isset($record['context']) && $rec['context'] !== $record['context']) {
  8773. return false;
  8774. }
  8775. return true;
  8776. }, $level);
  8777. }
  8778. public function hasRecordThatContains($message, $level)
  8779. {
  8780. return $this->hasRecordThatPasses(function ($rec) use ($message) {
  8781. return strpos($rec['message'], $message) !== false;
  8782. }, $level);
  8783. }
  8784. public function hasRecordThatMatches($regex, $level)
  8785. {
  8786. return $this->hasRecordThatPasses(function ($rec) use ($regex) {
  8787. return preg_match($regex, $rec['message']) > 0;
  8788. }, $level);
  8789. }
  8790. public function hasRecordThatPasses($predicate, $level)
  8791. {
  8792. if (!is_callable($predicate)) {
  8793. throw new \InvalidArgumentException("Expected a callable for hasRecordThatSucceeds");
  8794. }
  8795. if (!isset($this->recordsByLevel[$level])) {
  8796. return false;
  8797. }
  8798. foreach ($this->recordsByLevel[$level] as $i => $rec) {
  8799. if (call_user_func($predicate, $rec, $i)) {
  8800. return true;
  8801. }
  8802. }
  8803. return false;
  8804. }
  8805. protected function write(array $record)
  8806. {
  8807. $this->recordsByLevel[$record['level']][] = $record;
  8808. $this->records[] = $record;
  8809. }
  8810. public function __call($method, $args)
  8811. {
  8812. if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
  8813. $genericMethod = $matches[1] . ('Records'!== $matches[3] ?'Record':'') . $matches[3];
  8814. $level = constant('Monolog\Logger::'. strtoupper($matches[2]));
  8815. if (method_exists($this, $genericMethod)) {
  8816. $args[] = $level;
  8817. return call_user_func_array(array($this, $genericMethod), $args);
  8818. }
  8819. }
  8820. throw new \BadMethodCallException('Call to undefined method '. get_class($this) .'::'. $method .'()');
  8821. }
  8822. }
  8823. }
  8824. namespace Monolog
  8825. {
  8826. use Monolog\Handler\HandlerInterface;
  8827. use Monolog\Handler\StreamHandler;
  8828. use Psr\Log\LoggerInterface;
  8829. use Psr\Log\InvalidArgumentException;
  8830. use Exception;
  8831. class Logger implements LoggerInterface, ResettableInterface
  8832. {
  8833. const DEBUG = 100;
  8834. const INFO = 200;
  8835. const NOTICE = 250;
  8836. const WARNING = 300;
  8837. const ERROR = 400;
  8838. const CRITICAL = 500;
  8839. const ALERT = 550;
  8840. const EMERGENCY = 600;
  8841. const API = 1;
  8842. protected static $levels = array(
  8843. self::DEBUG =>'DEBUG',
  8844. self::INFO =>'INFO',
  8845. self::NOTICE =>'NOTICE',
  8846. self::WARNING =>'WARNING',
  8847. self::ERROR =>'ERROR',
  8848. self::CRITICAL =>'CRITICAL',
  8849. self::ALERT =>'ALERT',
  8850. self::EMERGENCY =>'EMERGENCY',
  8851. );
  8852. protected static $timezone;
  8853. protected $name;
  8854. protected $handlers;
  8855. protected $processors;
  8856. protected $microsecondTimestamps = true;
  8857. protected $exceptionHandler;
  8858. public function __construct($name, array $handlers = array(), array $processors = array())
  8859. {
  8860. $this->name = $name;
  8861. $this->setHandlers($handlers);
  8862. $this->processors = $processors;
  8863. }
  8864. public function getName()
  8865. {
  8866. return $this->name;
  8867. }
  8868. public function withName($name)
  8869. {
  8870. $new = clone $this;
  8871. $new->name = $name;
  8872. return $new;
  8873. }
  8874. public function pushHandler(HandlerInterface $handler)
  8875. {
  8876. array_unshift($this->handlers, $handler);
  8877. return $this;
  8878. }
  8879. public function popHandler()
  8880. {
  8881. if (!$this->handlers) {
  8882. throw new \LogicException('You tried to pop from an empty handler stack.');
  8883. }
  8884. return array_shift($this->handlers);
  8885. }
  8886. public function setHandlers(array $handlers)
  8887. {
  8888. $this->handlers = array();
  8889. foreach (array_reverse($handlers) as $handler) {
  8890. $this->pushHandler($handler);
  8891. }
  8892. return $this;
  8893. }
  8894. public function getHandlers()
  8895. {
  8896. return $this->handlers;
  8897. }
  8898. public function pushProcessor($callback)
  8899. {
  8900. if (!is_callable($callback)) {
  8901. throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
  8902. }
  8903. array_unshift($this->processors, $callback);
  8904. return $this;
  8905. }
  8906. public function popProcessor()
  8907. {
  8908. if (!$this->processors) {
  8909. throw new \LogicException('You tried to pop from an empty processor stack.');
  8910. }
  8911. return array_shift($this->processors);
  8912. }
  8913. public function getProcessors()
  8914. {
  8915. return $this->processors;
  8916. }
  8917. public function useMicrosecondTimestamps($micro)
  8918. {
  8919. $this->microsecondTimestamps = (bool) $micro;
  8920. }
  8921. public function addRecord($level, $message, array $context = array())
  8922. {
  8923. if (!$this->handlers) {
  8924. $this->pushHandler(new StreamHandler('php://stderr', static::DEBUG));
  8925. }
  8926. $levelName = static::getLevelName($level);
  8927. $handlerKey = null;
  8928. reset($this->handlers);
  8929. while ($handler = current($this->handlers)) {
  8930. if ($handler->isHandling(array('level'=> $level))) {
  8931. $handlerKey = key($this->handlers);
  8932. break;
  8933. }
  8934. next($this->handlers);
  8935. }
  8936. if (null === $handlerKey) {
  8937. return false;
  8938. }
  8939. if (!static::$timezone) {
  8940. static::$timezone = new \DateTimeZone(date_default_timezone_get() ?:'UTC');
  8941. }
  8942. if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) {
  8943. $ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone);
  8944. } else {
  8945. $ts = new \DateTime('now', static::$timezone);
  8946. }
  8947. $ts->setTimezone(static::$timezone);
  8948. $record = array('message'=> (string) $message,'context'=> $context,'level'=> $level,'level_name'=> $levelName,'channel'=> $this->name,'datetime'=> $ts,'extra'=> array(),
  8949. );
  8950. try {
  8951. foreach ($this->processors as $processor) {
  8952. $record = call_user_func($processor, $record);
  8953. }
  8954. while ($handler = current($this->handlers)) {
  8955. if (true === $handler->handle($record)) {
  8956. break;
  8957. }
  8958. next($this->handlers);
  8959. }
  8960. } catch (Exception $e) {
  8961. $this->handleException($e, $record);
  8962. }
  8963. return true;
  8964. }
  8965. public function close()
  8966. {
  8967. foreach ($this->handlers as $handler) {
  8968. if (method_exists($handler,'close')) {
  8969. $handler->close();
  8970. }
  8971. }
  8972. }
  8973. public function reset()
  8974. {
  8975. foreach ($this->handlers as $handler) {
  8976. if ($handler instanceof ResettableInterface) {
  8977. $handler->reset();
  8978. }
  8979. }
  8980. foreach ($this->processors as $processor) {
  8981. if ($processor instanceof ResettableInterface) {
  8982. $processor->reset();
  8983. }
  8984. }
  8985. }
  8986. public function addDebug($message, array $context = array())
  8987. {
  8988. return $this->addRecord(static::DEBUG, $message, $context);
  8989. }
  8990. public function addInfo($message, array $context = array())
  8991. {
  8992. return $this->addRecord(static::INFO, $message, $context);
  8993. }
  8994. public function addNotice($message, array $context = array())
  8995. {
  8996. return $this->addRecord(static::NOTICE, $message, $context);
  8997. }
  8998. public function addWarning($message, array $context = array())
  8999. {
  9000. return $this->addRecord(static::WARNING, $message, $context);
  9001. }
  9002. public function addError($message, array $context = array())
  9003. {
  9004. return $this->addRecord(static::ERROR, $message, $context);
  9005. }
  9006. public function addCritical($message, array $context = array())
  9007. {
  9008. return $this->addRecord(static::CRITICAL, $message, $context);
  9009. }
  9010. public function addAlert($message, array $context = array())
  9011. {
  9012. return $this->addRecord(static::ALERT, $message, $context);
  9013. }
  9014. public function addEmergency($message, array $context = array())
  9015. {
  9016. return $this->addRecord(static::EMERGENCY, $message, $context);
  9017. }
  9018. public static function getLevels()
  9019. {
  9020. return array_flip(static::$levels);
  9021. }
  9022. public static function getLevelName($level)
  9023. {
  9024. if (!isset(static::$levels[$level])) {
  9025. throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels)));
  9026. }
  9027. return static::$levels[$level];
  9028. }
  9029. public static function toMonologLevel($level)
  9030. {
  9031. if (is_string($level)) {
  9032. $upper = strtr($level,'abcdefgilmnortuwy','ABCDEFGILMNORTUWY');
  9033. if (defined(__CLASS__.'::'.$upper)) {
  9034. return constant(__CLASS__ .'::'. $upper);
  9035. }
  9036. }
  9037. return $level;
  9038. }
  9039. public function isHandling($level)
  9040. {
  9041. $record = array('level'=> $level,
  9042. );
  9043. foreach ($this->handlers as $handler) {
  9044. if ($handler->isHandling($record)) {
  9045. return true;
  9046. }
  9047. }
  9048. return false;
  9049. }
  9050. public function setExceptionHandler($callback)
  9051. {
  9052. if (!is_callable($callback)) {
  9053. throw new \InvalidArgumentException('Exception handler must be valid callable (callback or object with an __invoke method), '.var_export($callback, true).' given');
  9054. }
  9055. $this->exceptionHandler = $callback;
  9056. return $this;
  9057. }
  9058. public function getExceptionHandler()
  9059. {
  9060. return $this->exceptionHandler;
  9061. }
  9062. protected function handleException(Exception $e, array $record)
  9063. {
  9064. if (!$this->exceptionHandler) {
  9065. throw $e;
  9066. }
  9067. call_user_func($this->exceptionHandler, $e, $record);
  9068. }
  9069. public function log($level, $message, array $context = array())
  9070. {
  9071. $level = static::toMonologLevel($level);
  9072. return $this->addRecord($level, $message, $context);
  9073. }
  9074. public function debug($message, array $context = array())
  9075. {
  9076. return $this->addRecord(static::DEBUG, $message, $context);
  9077. }
  9078. public function info($message, array $context = array())
  9079. {
  9080. return $this->addRecord(static::INFO, $message, $context);
  9081. }
  9082. public function notice($message, array $context = array())
  9083. {
  9084. return $this->addRecord(static::NOTICE, $message, $context);
  9085. }
  9086. public function warn($message, array $context = array())
  9087. {
  9088. return $this->addRecord(static::WARNING, $message, $context);
  9089. }
  9090. public function warning($message, array $context = array())
  9091. {
  9092. return $this->addRecord(static::WARNING, $message, $context);
  9093. }
  9094. public function err($message, array $context = array())
  9095. {
  9096. return $this->addRecord(static::ERROR, $message, $context);
  9097. }
  9098. public function error($message, array $context = array())
  9099. {
  9100. return $this->addRecord(static::ERROR, $message, $context);
  9101. }
  9102. public function crit($message, array $context = array())
  9103. {
  9104. return $this->addRecord(static::CRITICAL, $message, $context);
  9105. }
  9106. public function critical($message, array $context = array())
  9107. {
  9108. return $this->addRecord(static::CRITICAL, $message, $context);
  9109. }
  9110. public function alert($message, array $context = array())
  9111. {
  9112. return $this->addRecord(static::ALERT, $message, $context);
  9113. }
  9114. public function emerg($message, array $context = array())
  9115. {
  9116. return $this->addRecord(static::EMERGENCY, $message, $context);
  9117. }
  9118. public function emergency($message, array $context = array())
  9119. {
  9120. return $this->addRecord(static::EMERGENCY, $message, $context);
  9121. }
  9122. public static function setTimezone(\DateTimeZone $tz)
  9123. {
  9124. self::$timezone = $tz;
  9125. }
  9126. }
  9127. }
  9128. namespace Symfony\Component\HttpKernel\Log
  9129. {
  9130. interface DebugLoggerInterface
  9131. {
  9132. public function getLogs();
  9133. public function countErrors();
  9134. }
  9135. }
  9136. namespace Symfony\Bridge\Monolog
  9137. {
  9138. use Monolog\Logger as BaseLogger;
  9139. use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
  9140. class Logger extends BaseLogger implements DebugLoggerInterface
  9141. {
  9142. public function getLogs()
  9143. {
  9144. if ($logger = $this->getDebugLogger()) {
  9145. return $logger->getLogs();
  9146. }
  9147. return [];
  9148. }
  9149. public function countErrors()
  9150. {
  9151. if ($logger = $this->getDebugLogger()) {
  9152. return $logger->countErrors();
  9153. }
  9154. return 0;
  9155. }
  9156. public function clear()
  9157. {
  9158. if (($logger = $this->getDebugLogger()) && method_exists($logger,'clear')) {
  9159. $logger->clear();
  9160. }
  9161. }
  9162. private function getDebugLogger()
  9163. {
  9164. foreach ($this->processors as $processor) {
  9165. if ($processor instanceof DebugLoggerInterface) {
  9166. return $processor;
  9167. }
  9168. }
  9169. foreach ($this->handlers as $handler) {
  9170. if ($handler instanceof DebugLoggerInterface) {
  9171. return $handler;
  9172. }
  9173. }
  9174. return null;
  9175. }
  9176. }
  9177. }
  9178. namespace Monolog\Handler\FingersCrossed
  9179. {
  9180. interface ActivationStrategyInterface
  9181. {
  9182. public function isHandlerActivated(array $record);
  9183. }
  9184. }
  9185. namespace Monolog\Handler\FingersCrossed
  9186. {
  9187. use Monolog\Logger;
  9188. class ErrorLevelActivationStrategy implements ActivationStrategyInterface
  9189. {
  9190. private $actionLevel;
  9191. public function __construct($actionLevel)
  9192. {
  9193. $this->actionLevel = Logger::toMonologLevel($actionLevel);
  9194. }
  9195. public function isHandlerActivated(array $record)
  9196. {
  9197. return $record['level'] >= $this->actionLevel;
  9198. }
  9199. }
  9200. }
  9201. namespace Sensio\Bundle\FrameworkExtraBundle\EventListener
  9202. {
  9203. use Doctrine\Common\Annotations\Reader;
  9204. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  9205. use Symfony\Component\HttpKernel\KernelEvents;
  9206. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9207. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
  9208. use Doctrine\Common\Util\ClassUtils;
  9209. class ControllerListener implements EventSubscriberInterface
  9210. {
  9211. protected $reader;
  9212. public function __construct(Reader $reader)
  9213. {
  9214. $this->reader = $reader;
  9215. }
  9216. public function onKernelController(FilterControllerEvent $event)
  9217. {
  9218. $controller = $event->getController();
  9219. if (!is_array($controller) && method_exists($controller,'__invoke')) {
  9220. $controller = array($controller,'__invoke');
  9221. }
  9222. if (!is_array($controller)) {
  9223. return;
  9224. }
  9225. $className = class_exists('Doctrine\Common\Util\ClassUtils') ? ClassUtils::getClass($controller[0]) : get_class($controller[0]);
  9226. $object = new \ReflectionClass($className);
  9227. $method = $object->getMethod($controller[1]);
  9228. $classConfigurations = $this->getConfigurations($this->reader->getClassAnnotations($object));
  9229. $methodConfigurations = $this->getConfigurations($this->reader->getMethodAnnotations($method));
  9230. $configurations = array();
  9231. foreach (array_merge(array_keys($classConfigurations), array_keys($methodConfigurations)) as $key) {
  9232. if (!array_key_exists($key, $classConfigurations)) {
  9233. $configurations[$key] = $methodConfigurations[$key];
  9234. } elseif (!array_key_exists($key, $methodConfigurations)) {
  9235. $configurations[$key] = $classConfigurations[$key];
  9236. } else {
  9237. if (is_array($classConfigurations[$key])) {
  9238. if (!is_array($methodConfigurations[$key])) {
  9239. throw new \UnexpectedValueException('Configurations should both be an array or both not be an array');
  9240. }
  9241. $configurations[$key] = array_merge($classConfigurations[$key], $methodConfigurations[$key]);
  9242. } else {
  9243. $configurations[$key] = $methodConfigurations[$key];
  9244. }
  9245. }
  9246. }
  9247. $request = $event->getRequest();
  9248. foreach ($configurations as $key => $attributes) {
  9249. $request->attributes->set($key, $attributes);
  9250. }
  9251. }
  9252. protected function getConfigurations(array $annotations)
  9253. {
  9254. $configurations = array();
  9255. foreach ($annotations as $configuration) {
  9256. if ($configuration instanceof ConfigurationInterface) {
  9257. if ($configuration->allowArray()) {
  9258. $configurations['_'.$configuration->getAliasName()][] = $configuration;
  9259. } elseif (!isset($configurations['_'.$configuration->getAliasName()])) {
  9260. $configurations['_'.$configuration->getAliasName()] = $configuration;
  9261. } else {
  9262. throw new \LogicException(sprintf('Multiple "%s" annotations are not allowed.', $configuration->getAliasName()));
  9263. }
  9264. }
  9265. }
  9266. return $configurations;
  9267. }
  9268. public static function getSubscribedEvents()
  9269. {
  9270. return array(
  9271. KernelEvents::CONTROLLER =>'onKernelController',
  9272. );
  9273. }
  9274. }
  9275. }
  9276. namespace Sensio\Bundle\FrameworkExtraBundle\EventListener
  9277. {
  9278. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  9279. use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterManager;
  9280. use Symfony\Component\HttpFoundation\Request;
  9281. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  9282. use Symfony\Component\HttpKernel\KernelEvents;
  9283. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9284. class ParamConverterListener implements EventSubscriberInterface
  9285. {
  9286. protected $manager;
  9287. protected $autoConvert;
  9288. private $isParameterTypeSupported;
  9289. public function __construct(ParamConverterManager $manager, $autoConvert = true)
  9290. {
  9291. $this->manager = $manager;
  9292. $this->autoConvert = $autoConvert;
  9293. $this->isParameterTypeSupported = method_exists('ReflectionParameter','getType');
  9294. }
  9295. public function onKernelController(FilterControllerEvent $event)
  9296. {
  9297. $controller = $event->getController();
  9298. $request = $event->getRequest();
  9299. $configurations = array();
  9300. if ($configuration = $request->attributes->get('_converters')) {
  9301. foreach (is_array($configuration) ? $configuration : array($configuration) as $configuration) {
  9302. $configurations[$configuration->getName()] = $configuration;
  9303. }
  9304. }
  9305. if (is_array($controller)) {
  9306. $r = new \ReflectionMethod($controller[0], $controller[1]);
  9307. } elseif (is_object($controller) && is_callable($controller,'__invoke')) {
  9308. $r = new \ReflectionMethod($controller,'__invoke');
  9309. } else {
  9310. $r = new \ReflectionFunction($controller);
  9311. }
  9312. if ($this->autoConvert) {
  9313. $configurations = $this->autoConfigure($r, $request, $configurations);
  9314. }
  9315. $this->manager->apply($request, $configurations);
  9316. }
  9317. private function autoConfigure(\ReflectionFunctionAbstract $r, Request $request, $configurations)
  9318. {
  9319. foreach ($r->getParameters() as $param) {
  9320. if ($param->getClass() && $param->getClass()->isInstance($request)) {
  9321. continue;
  9322. }
  9323. $name = $param->getName();
  9324. $class = $param->getClass();
  9325. $hasType = $this->isParameterTypeSupported && $param->hasType();
  9326. if ($class || $hasType) {
  9327. if (!isset($configurations[$name])) {
  9328. $configuration = new ParamConverter(array());
  9329. $configuration->setName($name);
  9330. $configurations[$name] = $configuration;
  9331. }
  9332. if ($class && null === $configurations[$name]->getClass()) {
  9333. $configurations[$name]->setClass($class->getName());
  9334. }
  9335. }
  9336. if (isset($configurations[$name])) {
  9337. $configurations[$name]->setIsOptional($param->isOptional() || $param->isDefaultValueAvailable() || $hasType && $param->getType()->allowsNull());
  9338. }
  9339. }
  9340. return $configurations;
  9341. }
  9342. public static function getSubscribedEvents()
  9343. {
  9344. return array(
  9345. KernelEvents::CONTROLLER =>'onKernelController',
  9346. );
  9347. }
  9348. }
  9349. }
  9350. namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter
  9351. {
  9352. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  9353. use Symfony\Component\HttpFoundation\Request;
  9354. interface ParamConverterInterface
  9355. {
  9356. public function apply(Request $request, ParamConverter $configuration);
  9357. public function supports(ParamConverter $configuration);
  9358. }
  9359. }
  9360. namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter
  9361. {
  9362. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  9363. use Symfony\Component\HttpFoundation\Request;
  9364. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  9365. use DateTime;
  9366. class DateTimeParamConverter implements ParamConverterInterface
  9367. {
  9368. public function apply(Request $request, ParamConverter $configuration)
  9369. {
  9370. $param = $configuration->getName();
  9371. if (!$request->attributes->has($param)) {
  9372. return false;
  9373. }
  9374. $options = $configuration->getOptions();
  9375. $value = $request->attributes->get($param);
  9376. if (!$value && $configuration->isOptional()) {
  9377. return false;
  9378. }
  9379. if (isset($options['format'])) {
  9380. $date = DateTime::createFromFormat($options['format'], $value);
  9381. if (!$date) {
  9382. throw new NotFoundHttpException(sprintf('Invalid date given for parameter "%s".', $param));
  9383. }
  9384. } else {
  9385. if (false === strtotime($value)) {
  9386. throw new NotFoundHttpException(sprintf('Invalid date given for parameter "%s".', $param));
  9387. }
  9388. $date = new DateTime($value);
  9389. }
  9390. $request->attributes->set($param, $date);
  9391. return true;
  9392. }
  9393. public function supports(ParamConverter $configuration)
  9394. {
  9395. if (null === $configuration->getClass()) {
  9396. return false;
  9397. }
  9398. return'DateTime'=== $configuration->getClass();
  9399. }
  9400. }
  9401. }
  9402. namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter
  9403. {
  9404. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  9405. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  9406. use Symfony\Component\HttpFoundation\Request;
  9407. use Doctrine\Common\Persistence\ManagerRegistry;
  9408. use Doctrine\ORM\NoResultException;
  9409. class DoctrineParamConverter implements ParamConverterInterface
  9410. {
  9411. protected $registry;
  9412. public function __construct(ManagerRegistry $registry = null)
  9413. {
  9414. $this->registry = $registry;
  9415. }
  9416. public function apply(Request $request, ParamConverter $configuration)
  9417. {
  9418. $name = $configuration->getName();
  9419. $class = $configuration->getClass();
  9420. $options = $this->getOptions($configuration);
  9421. if (null === $request->attributes->get($name, false)) {
  9422. $configuration->setIsOptional(true);
  9423. }
  9424. if (false === $object = $this->find($class, $request, $options, $name)) {
  9425. if (false === $object = $this->findOneBy($class, $request, $options)) {
  9426. if ($configuration->isOptional()) {
  9427. $object = null;
  9428. } else {
  9429. throw new \LogicException(sprintf('Unable to guess how to get a Doctrine instance from the request information for parameter "%s".', $name));
  9430. }
  9431. }
  9432. }
  9433. if (null === $object && false === $configuration->isOptional()) {
  9434. throw new NotFoundHttpException(sprintf('%s object not found.', $class));
  9435. }
  9436. $request->attributes->set($name, $object);
  9437. return true;
  9438. }
  9439. protected function find($class, Request $request, $options, $name)
  9440. {
  9441. if ($options['mapping'] || $options['exclude']) {
  9442. return false;
  9443. }
  9444. $id = $this->getIdentifier($request, $options, $name);
  9445. if (false === $id || null === $id) {
  9446. return false;
  9447. }
  9448. if (isset($options['repository_method'])) {
  9449. $method = $options['repository_method'];
  9450. } else {
  9451. $method ='find';
  9452. }
  9453. try {
  9454. return $this->getManager($options['entity_manager'], $class)->getRepository($class)->$method($id);
  9455. } catch (NoResultException $e) {
  9456. return;
  9457. }
  9458. }
  9459. protected function getIdentifier(Request $request, $options, $name)
  9460. {
  9461. if (isset($options['id'])) {
  9462. if (!is_array($options['id'])) {
  9463. $name = $options['id'];
  9464. } elseif (is_array($options['id'])) {
  9465. $id = array();
  9466. foreach ($options['id'] as $field) {
  9467. $id[$field] = $request->attributes->get($field);
  9468. }
  9469. return $id;
  9470. }
  9471. }
  9472. if ($request->attributes->has($name)) {
  9473. return $request->attributes->get($name);
  9474. }
  9475. if ($request->attributes->has('id') && !isset($options['id'])) {
  9476. return $request->attributes->get('id');
  9477. }
  9478. return false;
  9479. }
  9480. protected function findOneBy($class, Request $request, $options)
  9481. {
  9482. if (!$options['mapping']) {
  9483. $keys = $request->attributes->keys();
  9484. $options['mapping'] = $keys ? array_combine($keys, $keys) : array();
  9485. }
  9486. foreach ($options['exclude'] as $exclude) {
  9487. unset($options['mapping'][$exclude]);
  9488. }
  9489. if (!$options['mapping']) {
  9490. return false;
  9491. }
  9492. if (isset($options['id']) && null === $request->attributes->get($options['id'])) {
  9493. return false;
  9494. }
  9495. $criteria = array();
  9496. $em = $this->getManager($options['entity_manager'], $class);
  9497. $metadata = $em->getClassMetadata($class);
  9498. $mapMethodSignature = isset($options['repository_method'])
  9499. && isset($options['map_method_signature'])
  9500. && $options['map_method_signature'] === true;
  9501. foreach ($options['mapping'] as $attribute => $field) {
  9502. if ($metadata->hasField($field)
  9503. || ($metadata->hasAssociation($field) && $metadata->isSingleValuedAssociation($field))
  9504. || $mapMethodSignature) {
  9505. $criteria[$field] = $request->attributes->get($attribute);
  9506. }
  9507. }
  9508. if ($options['strip_null']) {
  9509. $criteria = array_filter($criteria, function ($value) { return !is_null($value); });
  9510. }
  9511. if (!$criteria) {
  9512. return false;
  9513. }
  9514. if (isset($options['repository_method'])) {
  9515. $repositoryMethod = $options['repository_method'];
  9516. } else {
  9517. $repositoryMethod ='findOneBy';
  9518. }
  9519. try {
  9520. if ($mapMethodSignature) {
  9521. return $this->findDataByMapMethodSignature($em, $class, $repositoryMethod, $criteria);
  9522. }
  9523. return $em->getRepository($class)->$repositoryMethod($criteria);
  9524. } catch (NoResultException $e) {
  9525. return;
  9526. }
  9527. }
  9528. private function findDataByMapMethodSignature($em, $class, $repositoryMethod, $criteria)
  9529. {
  9530. $arguments = array();
  9531. $repository = $em->getRepository($class);
  9532. $ref = new \ReflectionMethod($repository, $repositoryMethod);
  9533. foreach ($ref->getParameters() as $parameter) {
  9534. if (array_key_exists($parameter->name, $criteria)) {
  9535. $arguments[] = $criteria[$parameter->name];
  9536. } elseif ($parameter->isDefaultValueAvailable()) {
  9537. $arguments[] = $parameter->getDefaultValue();
  9538. } else {
  9539. throw new \InvalidArgumentException(sprintf('Repository method "%s::%s" requires that you provide a value for the "$%s" argument.', get_class($repository), $repositoryMethod, $parameter->name));
  9540. }
  9541. }
  9542. return $ref->invokeArgs($repository, $arguments);
  9543. }
  9544. public function supports(ParamConverter $configuration)
  9545. {
  9546. if (null === $this->registry || !count($this->registry->getManagers())) {
  9547. return false;
  9548. }
  9549. if (null === $configuration->getClass()) {
  9550. return false;
  9551. }
  9552. $options = $this->getOptions($configuration);
  9553. $em = $this->getManager($options['entity_manager'], $configuration->getClass());
  9554. if (null === $em) {
  9555. return false;
  9556. }
  9557. return !$em->getMetadataFactory()->isTransient($configuration->getClass());
  9558. }
  9559. protected function getOptions(ParamConverter $configuration)
  9560. {
  9561. return array_replace(array('entity_manager'=> null,'exclude'=> array(),'mapping'=> array(),'strip_null'=> false,
  9562. ), $configuration->getOptions());
  9563. }
  9564. private function getManager($name, $class)
  9565. {
  9566. if (null === $name) {
  9567. return $this->registry->getManagerForClass($class);
  9568. }
  9569. return $this->registry->getManager($name);
  9570. }
  9571. }
  9572. }
  9573. namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter
  9574. {
  9575. use Symfony\Component\HttpFoundation\Request;
  9576. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
  9577. class ParamConverterManager
  9578. {
  9579. protected $converters = array();
  9580. protected $namedConverters = array();
  9581. public function apply(Request $request, $configurations)
  9582. {
  9583. if (is_object($configurations)) {
  9584. $configurations = array($configurations);
  9585. }
  9586. foreach ($configurations as $configuration) {
  9587. $this->applyConverter($request, $configuration);
  9588. }
  9589. }
  9590. protected function applyConverter(Request $request, ConfigurationInterface $configuration)
  9591. {
  9592. $value = $request->attributes->get($configuration->getName());
  9593. $className = $configuration->getClass();
  9594. if (is_object($value) && $value instanceof $className) {
  9595. return;
  9596. }
  9597. if ($converterName = $configuration->getConverter()) {
  9598. if (!isset($this->namedConverters[$converterName])) {
  9599. throw new \RuntimeException(sprintf("No converter named '%s' found for conversion of parameter '%s'.",
  9600. $converterName, $configuration->getName()
  9601. ));
  9602. }
  9603. $converter = $this->namedConverters[$converterName];
  9604. if (!$converter->supports($configuration)) {
  9605. throw new \RuntimeException(sprintf("Converter '%s' does not support conversion of parameter '%s'.",
  9606. $converterName, $configuration->getName()
  9607. ));
  9608. }
  9609. $converter->apply($request, $configuration);
  9610. return;
  9611. }
  9612. foreach ($this->all() as $converter) {
  9613. if ($converter->supports($configuration)) {
  9614. if ($converter->apply($request, $configuration)) {
  9615. return;
  9616. }
  9617. }
  9618. }
  9619. }
  9620. public function add(ParamConverterInterface $converter, $priority = 0, $name = null)
  9621. {
  9622. if ($priority !== null) {
  9623. if (!isset($this->converters[$priority])) {
  9624. $this->converters[$priority] = array();
  9625. }
  9626. $this->converters[$priority][] = $converter;
  9627. }
  9628. if (null !== $name) {
  9629. $this->namedConverters[$name] = $converter;
  9630. }
  9631. }
  9632. public function all()
  9633. {
  9634. krsort($this->converters);
  9635. $converters = array();
  9636. foreach ($this->converters as $all) {
  9637. $converters = array_merge($converters, $all);
  9638. }
  9639. return $converters;
  9640. }
  9641. }
  9642. }
  9643. namespace Sensio\Bundle\FrameworkExtraBundle\EventListener
  9644. {
  9645. use Symfony\Component\DependencyInjection\ContainerInterface;
  9646. use Symfony\Component\HttpFoundation\Request;
  9647. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  9648. use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
  9649. use Symfony\Component\HttpKernel\KernelEvents;
  9650. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9651. use Symfony\Component\HttpFoundation\StreamedResponse;
  9652. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  9653. class TemplateListener implements EventSubscriberInterface
  9654. {
  9655. protected $container;
  9656. public function __construct(ContainerInterface $container)
  9657. {
  9658. $this->container = $container;
  9659. }
  9660. public function onKernelController(FilterControllerEvent $event)
  9661. {
  9662. $request = $event->getRequest();
  9663. $template = $request->attributes->get('_template');
  9664. if (!$template instanceof Template) {
  9665. return;
  9666. }
  9667. $template->setOwner($controller = $event->getController());
  9668. if (null === $template->getTemplate()) {
  9669. $guesser = $this->container->get('sensio_framework_extra.view.guesser');
  9670. $template->setTemplate($guesser->guessTemplateName($controller, $request, $template->getEngine()));
  9671. }
  9672. }
  9673. public function onKernelView(GetResponseForControllerResultEvent $event)
  9674. {
  9675. $request = $event->getRequest();
  9676. $template = $request->attributes->get('_template');
  9677. if (!$template instanceof Template) {
  9678. return;
  9679. }
  9680. $parameters = $event->getControllerResult();
  9681. $owner = $template->getOwner();
  9682. list($controller, $action) = $owner;
  9683. if (null === $parameters) {
  9684. $parameters = $this->resolveDefaultParameters($request, $template, $controller, $action);
  9685. }
  9686. $templating = $this->container->get('templating');
  9687. if ($template->isStreamable()) {
  9688. $callback = function () use ($templating, $template, $parameters) {
  9689. return $templating->stream($template->getTemplate(), $parameters);
  9690. };
  9691. $event->setResponse(new StreamedResponse($callback));
  9692. } else {
  9693. $event->setResponse($templating->renderResponse($template->getTemplate(), $parameters));
  9694. }
  9695. $template->setOwner(array());
  9696. }
  9697. public static function getSubscribedEvents()
  9698. {
  9699. return array(
  9700. KernelEvents::CONTROLLER => array('onKernelController', -128),
  9701. KernelEvents::VIEW =>'onKernelView',
  9702. );
  9703. }
  9704. private function resolveDefaultParameters(Request $request, Template $template, $controller, $action)
  9705. {
  9706. $parameters = array();
  9707. $arguments = $template->getVars();
  9708. if (0 === count($arguments)) {
  9709. $r = new \ReflectionObject($controller);
  9710. $arguments = array();
  9711. foreach ($r->getMethod($action)->getParameters() as $param) {
  9712. $arguments[] = $param;
  9713. }
  9714. }
  9715. foreach ($arguments as $argument) {
  9716. if ($argument instanceof \ReflectionParameter) {
  9717. $parameters[$name = $argument->getName()] = !$request->attributes->has($name) && $argument->isDefaultValueAvailable() ? $argument->getDefaultValue() : $request->attributes->get($name);
  9718. } else {
  9719. $parameters[$argument] = $request->attributes->get($argument);
  9720. }
  9721. }
  9722. return $parameters;
  9723. }
  9724. }
  9725. }
  9726. namespace Sensio\Bundle\FrameworkExtraBundle\EventListener
  9727. {
  9728. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  9729. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  9730. use Symfony\Component\HttpKernel\KernelEvents;
  9731. use Symfony\Component\HttpFoundation\Response;
  9732. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9733. use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
  9734. class HttpCacheListener implements EventSubscriberInterface
  9735. {
  9736. private $lastModifiedDates;
  9737. private $etags;
  9738. private $expressionLanguage;
  9739. public function __construct()
  9740. {
  9741. $this->lastModifiedDates = new \SplObjectStorage();
  9742. $this->etags = new \SplObjectStorage();
  9743. }
  9744. public function onKernelController(FilterControllerEvent $event)
  9745. {
  9746. $request = $event->getRequest();
  9747. if (!$configuration = $request->attributes->get('_cache')) {
  9748. return;
  9749. }
  9750. $response = new Response();
  9751. $lastModifiedDate ='';
  9752. if ($configuration->getLastModified()) {
  9753. $lastModifiedDate = $this->getExpressionLanguage()->evaluate($configuration->getLastModified(), $request->attributes->all());
  9754. $response->setLastModified($lastModifiedDate);
  9755. }
  9756. $etag ='';
  9757. if ($configuration->getETag()) {
  9758. $etag = hash('sha256', $this->getExpressionLanguage()->evaluate($configuration->getETag(), $request->attributes->all()));
  9759. $response->setETag($etag);
  9760. }
  9761. if ($response->isNotModified($request)) {
  9762. $event->setController(function () use ($response) {
  9763. return $response;
  9764. });
  9765. $event->stopPropagation();
  9766. } else {
  9767. if ($etag) {
  9768. $this->etags[$request] = $etag;
  9769. }
  9770. if ($lastModifiedDate) {
  9771. $this->lastModifiedDates[$request] = $lastModifiedDate;
  9772. }
  9773. }
  9774. }
  9775. public function onKernelResponse(FilterResponseEvent $event)
  9776. {
  9777. $request = $event->getRequest();
  9778. if (!$configuration = $request->attributes->get('_cache')) {
  9779. return;
  9780. }
  9781. $response = $event->getResponse();
  9782. if (!in_array($response->getStatusCode(), array(200, 203, 300, 301, 302, 304, 404, 410))) {
  9783. return;
  9784. }
  9785. if (null !== $age = $configuration->getSMaxAge()) {
  9786. if (!is_numeric($age)) {
  9787. $now = microtime(true);
  9788. $age = ceil(strtotime($configuration->getSMaxAge(), $now) - $now);
  9789. }
  9790. $response->setSharedMaxAge($age);
  9791. }
  9792. if (null !== $age = $configuration->getMaxAge()) {
  9793. if (!is_numeric($age)) {
  9794. $now = microtime(true);
  9795. $age = ceil(strtotime($configuration->getMaxAge(), $now) - $now);
  9796. }
  9797. $response->setMaxAge($age);
  9798. }
  9799. if (null !== $configuration->getExpires()) {
  9800. $date = \DateTime::createFromFormat('U', strtotime($configuration->getExpires()), new \DateTimeZone('UTC'));
  9801. $response->setExpires($date);
  9802. }
  9803. if (null !== $configuration->getVary()) {
  9804. $response->setVary($configuration->getVary());
  9805. }
  9806. if ($configuration->isPublic()) {
  9807. $response->setPublic();
  9808. }
  9809. if ($configuration->isPrivate()) {
  9810. $response->setPrivate();
  9811. }
  9812. if (isset($this->lastModifiedDates[$request])) {
  9813. $response->setLastModified($this->lastModifiedDates[$request]);
  9814. unset($this->lastModifiedDates[$request]);
  9815. }
  9816. if (isset($this->etags[$request])) {
  9817. $response->setETag($this->etags[$request]);
  9818. unset($this->etags[$request]);
  9819. }
  9820. }
  9821. public static function getSubscribedEvents()
  9822. {
  9823. return array(
  9824. KernelEvents::CONTROLLER =>'onKernelController',
  9825. KernelEvents::RESPONSE =>'onKernelResponse',
  9826. );
  9827. }
  9828. private function getExpressionLanguage()
  9829. {
  9830. if (null === $this->expressionLanguage) {
  9831. if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
  9832. throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
  9833. }
  9834. $this->expressionLanguage = new ExpressionLanguage();
  9835. }
  9836. return $this->expressionLanguage;
  9837. }
  9838. }
  9839. }
  9840. namespace Sensio\Bundle\FrameworkExtraBundle\EventListener
  9841. {
  9842. use Sensio\Bundle\FrameworkExtraBundle\Security\ExpressionLanguage;
  9843. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  9844. use Symfony\Component\HttpKernel\KernelEvents;
  9845. use Symfony\Component\HttpFoundation\Request;
  9846. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9847. use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
  9848. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  9849. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  9850. use Symfony\Component\Security\Core\SecurityContextInterface;
  9851. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  9852. use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
  9853. class SecurityListener implements EventSubscriberInterface
  9854. {
  9855. private $tokenStorage;
  9856. private $authChecker;
  9857. private $language;
  9858. private $trustResolver;
  9859. private $roleHierarchy;
  9860. public function __construct(SecurityContextInterface $securityContext = null, ExpressionLanguage $language = null, AuthenticationTrustResolverInterface $trustResolver = null, RoleHierarchyInterface $roleHierarchy = null, TokenStorageInterface $tokenStorage = null, AuthorizationCheckerInterface $authChecker = null)
  9861. {
  9862. $this->tokenStorage = $tokenStorage ?: $securityContext;
  9863. $this->authChecker = $authChecker ?: $securityContext;
  9864. $this->language = $language;
  9865. $this->trustResolver = $trustResolver;
  9866. $this->roleHierarchy = $roleHierarchy;
  9867. }
  9868. public function onKernelController(FilterControllerEvent $event)
  9869. {
  9870. $request = $event->getRequest();
  9871. if (!$configuration = $request->attributes->get('_security')) {
  9872. return;
  9873. }
  9874. if (null === $this->tokenStorage || null === $this->trustResolver) {
  9875. throw new \LogicException('To use the @Security tag, you need to install the Symfony Security bundle.');
  9876. }
  9877. if (null === $this->tokenStorage->getToken()) {
  9878. throw new \LogicException('To use the @Security tag, your controller needs to be behind a firewall.');
  9879. }
  9880. if (null === $this->language) {
  9881. throw new \LogicException('To use the @Security tag, you need to use the Security component 2.4 or newer and install the ExpressionLanguage component.');
  9882. }
  9883. if (!$this->language->evaluate($configuration->getExpression(), $this->getVariables($request))) {
  9884. throw new AccessDeniedException(sprintf('Expression "%s" denied access.', $configuration->getExpression()));
  9885. }
  9886. }
  9887. private function getVariables(Request $request)
  9888. {
  9889. $token = $this->tokenStorage->getToken();
  9890. if (null !== $this->roleHierarchy) {
  9891. $roles = $this->roleHierarchy->getReachableRoles($token->getRoles());
  9892. } else {
  9893. $roles = $token->getRoles();
  9894. }
  9895. $variables = array('token'=> $token,'user'=> $token->getUser(),'object'=> $request,'subject'=> $request,'request'=> $request,'roles'=> array_map(function ($role) { return $role->getRole(); }, $roles),'trust_resolver'=> $this->trustResolver,'auth_checker'=> $this->authChecker,
  9896. );
  9897. return array_merge($request->attributes->all(), $variables);
  9898. }
  9899. public static function getSubscribedEvents()
  9900. {
  9901. return array(KernelEvents::CONTROLLER =>'onKernelController');
  9902. }
  9903. }
  9904. }
  9905. namespace Sensio\Bundle\FrameworkExtraBundle\Configuration
  9906. {
  9907. interface ConfigurationInterface
  9908. {
  9909. public function getAliasName();
  9910. public function allowArray();
  9911. }
  9912. }
  9913. namespace Sensio\Bundle\FrameworkExtraBundle\Configuration
  9914. {
  9915. abstract class ConfigurationAnnotation implements ConfigurationInterface
  9916. {
  9917. public function __construct(array $values)
  9918. {
  9919. foreach ($values as $k => $v) {
  9920. if (!method_exists($this, $name ='set'.$k)) {
  9921. throw new \RuntimeException(sprintf('Unknown key "%s" for annotation "@%s".', $k, get_class($this)));
  9922. }
  9923. $this->$name($v);
  9924. }
  9925. }
  9926. }
  9927. }