1<?php 2 3/* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Twig\Loader; 13 14use Twig\Error\LoaderError; 15use Twig\Source; 16 17/** 18 * Loads templates from other loaders. 19 * 20 * @final 21 * 22 * @author Fabien Potencier <fabien@symfony.com> 23 */ 24class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface 25{ 26 private $hasSourceCache = []; 27 protected $loaders = []; 28 29 /** 30 * @param LoaderInterface[] $loaders 31 */ 32 public function __construct(array $loaders = []) 33 { 34 foreach ($loaders as $loader) { 35 $this->addLoader($loader); 36 } 37 } 38 39 public function addLoader(LoaderInterface $loader) 40 { 41 $this->loaders[] = $loader; 42 $this->hasSourceCache = []; 43 } 44 45 /** 46 * @return LoaderInterface[] 47 */ 48 public function getLoaders() 49 { 50 return $this->loaders; 51 } 52 53 public function getSource($name) 54 { 55 @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', \get_class($this)), E_USER_DEPRECATED); 56 57 $exceptions = []; 58 foreach ($this->loaders as $loader) { 59 if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { 60 continue; 61 } 62 63 try { 64 return $loader->getSource($name); 65 } catch (LoaderError $e) { 66 $exceptions[] = $e->getMessage(); 67 } 68 } 69 70 throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); 71 } 72 73 public function getSourceContext($name) 74 { 75 $exceptions = []; 76 foreach ($this->loaders as $loader) { 77 if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { 78 continue; 79 } 80 81 try { 82 if ($loader instanceof SourceContextLoaderInterface) { 83 return $loader->getSourceContext($name); 84 } 85 86 return new Source($loader->getSource($name), $name); 87 } catch (LoaderError $e) { 88 $exceptions[] = $e->getMessage(); 89 } 90 } 91 92 throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); 93 } 94 95 public function exists($name) 96 { 97 $name = (string) $name; 98 99 if (isset($this->hasSourceCache[$name])) { 100 return $this->hasSourceCache[$name]; 101 } 102 103 foreach ($this->loaders as $loader) { 104 if ($loader instanceof ExistsLoaderInterface) { 105 if ($loader->exists($name)) { 106 return $this->hasSourceCache[$name] = true; 107 } 108 109 continue; 110 } 111 112 try { 113 if ($loader instanceof SourceContextLoaderInterface) { 114 $loader->getSourceContext($name); 115 } else { 116 $loader->getSource($name); 117 } 118 119 return $this->hasSourceCache[$name] = true; 120 } catch (LoaderError $e) { 121 } 122 } 123 124 return $this->hasSourceCache[$name] = false; 125 } 126 127 public function getCacheKey($name) 128 { 129 $exceptions = []; 130 foreach ($this->loaders as $loader) { 131 if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { 132 continue; 133 } 134 135 try { 136 return $loader->getCacheKey($name); 137 } catch (LoaderError $e) { 138 $exceptions[] = \get_class($loader).': '.$e->getMessage(); 139 } 140 } 141 142 throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); 143 } 144 145 public function isFresh($name, $time) 146 { 147 $exceptions = []; 148 foreach ($this->loaders as $loader) { 149 if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { 150 continue; 151 } 152 153 try { 154 return $loader->isFresh($name, $time); 155 } catch (LoaderError $e) { 156 $exceptions[] = \get_class($loader).': '.$e->getMessage(); 157 } 158 } 159 160 throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); 161 } 162} 163 164class_alias('Twig\Loader\ChainLoader', 'Twig_Loader_Chain'); 165