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

/vendor/kriswallsmith/assetic/src/Assetic/Factory/AssetFactory.php

https://gitlab.com/mohamedchiheb.bida/workshopFOS
PHP | 424 lines | 243 code | 60 blank | 121 comment | 42 complexity | 565280ef2ec5ecd81efbea81721eadb7 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Assetic package, an OpenSky project.
  4. *
  5. * (c) 2010-2014 OpenSky Project Inc
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Assetic\Factory;
  11. use Assetic\Asset\AssetCollection;
  12. use Assetic\Asset\AssetCollectionInterface;
  13. use Assetic\Asset\AssetInterface;
  14. use Assetic\Asset\AssetReference;
  15. use Assetic\Asset\FileAsset;
  16. use Assetic\Asset\GlobAsset;
  17. use Assetic\Asset\HttpAsset;
  18. use Assetic\AssetManager;
  19. use Assetic\Factory\Worker\WorkerInterface;
  20. use Assetic\Filter\DependencyExtractorInterface;
  21. use Assetic\FilterManager;
  22. /**
  23. * The asset factory creates asset objects.
  24. *
  25. * @author Kris Wallsmith <kris.wallsmith@gmail.com>
  26. */
  27. class AssetFactory
  28. {
  29. private $root;
  30. private $debug;
  31. private $output;
  32. private $workers;
  33. private $am;
  34. private $fm;
  35. /**
  36. * Constructor.
  37. *
  38. * @param string $root The default root directory
  39. * @param Boolean $debug Filters prefixed with a "?" will be omitted in debug mode
  40. */
  41. public function __construct($root, $debug = false)
  42. {
  43. $this->root = rtrim($root, '/');
  44. $this->debug = $debug;
  45. $this->output = 'assetic/*';
  46. $this->workers = array();
  47. }
  48. /**
  49. * Sets debug mode for the current factory.
  50. *
  51. * @param Boolean $debug Debug mode
  52. */
  53. public function setDebug($debug)
  54. {
  55. $this->debug = $debug;
  56. }
  57. /**
  58. * Checks if the factory is in debug mode.
  59. *
  60. * @return Boolean Debug mode
  61. */
  62. public function isDebug()
  63. {
  64. return $this->debug;
  65. }
  66. /**
  67. * Sets the default output string.
  68. *
  69. * @param string $output The default output string
  70. */
  71. public function setDefaultOutput($output)
  72. {
  73. $this->output = $output;
  74. }
  75. /**
  76. * Adds a factory worker.
  77. *
  78. * @param WorkerInterface $worker A worker
  79. */
  80. public function addWorker(WorkerInterface $worker)
  81. {
  82. $this->workers[] = $worker;
  83. }
  84. /**
  85. * Returns the current asset manager.
  86. *
  87. * @return AssetManager|null The asset manager
  88. */
  89. public function getAssetManager()
  90. {
  91. return $this->am;
  92. }
  93. /**
  94. * Sets the asset manager to use when creating asset references.
  95. *
  96. * @param AssetManager $am The asset manager
  97. */
  98. public function setAssetManager(AssetManager $am)
  99. {
  100. $this->am = $am;
  101. }
  102. /**
  103. * Returns the current filter manager.
  104. *
  105. * @return FilterManager|null The filter manager
  106. */
  107. public function getFilterManager()
  108. {
  109. return $this->fm;
  110. }
  111. /**
  112. * Sets the filter manager to use when adding filters.
  113. *
  114. * @param FilterManager $fm The filter manager
  115. */
  116. public function setFilterManager(FilterManager $fm)
  117. {
  118. $this->fm = $fm;
  119. }
  120. /**
  121. * Creates a new asset.
  122. *
  123. * Prefixing a filter name with a question mark will cause it to be
  124. * omitted when the factory is in debug mode.
  125. *
  126. * Available options:
  127. *
  128. * * output: An output string
  129. * * name: An asset name for interpolation in output patterns
  130. * * debug: Forces debug mode on or off for this asset
  131. * * root: An array or string of more root directories
  132. *
  133. * @param array|string $inputs An array of input strings
  134. * @param array|string $filters An array of filter names
  135. * @param array $options An array of options
  136. *
  137. * @return AssetCollection An asset collection
  138. */
  139. public function createAsset($inputs = array(), $filters = array(), array $options = array())
  140. {
  141. if (!is_array($inputs)) {
  142. $inputs = array($inputs);
  143. }
  144. if (!is_array($filters)) {
  145. $filters = array($filters);
  146. }
  147. if (!isset($options['output'])) {
  148. $options['output'] = $this->output;
  149. }
  150. if (!isset($options['vars'])) {
  151. $options['vars'] = array();
  152. }
  153. if (!isset($options['debug'])) {
  154. $options['debug'] = $this->debug;
  155. }
  156. if (!isset($options['root'])) {
  157. $options['root'] = array($this->root);
  158. } else {
  159. if (!is_array($options['root'])) {
  160. $options['root'] = array($options['root']);
  161. }
  162. $options['root'][] = $this->root;
  163. }
  164. if (!isset($options['name'])) {
  165. $options['name'] = $this->generateAssetName($inputs, $filters, $options);
  166. }
  167. $asset = $this->createAssetCollection(array(), $options);
  168. $extensions = array();
  169. // inner assets
  170. foreach ($inputs as $input) {
  171. if (is_array($input)) {
  172. // nested formula
  173. $asset->add(call_user_func_array(array($this, 'createAsset'), $input));
  174. } else {
  175. $asset->add($this->parseInput($input, $options));
  176. $extensions[pathinfo($input, PATHINFO_EXTENSION)] = true;
  177. }
  178. }
  179. // filters
  180. foreach ($filters as $filter) {
  181. if ('?' != $filter[0]) {
  182. $asset->ensureFilter($this->getFilter($filter));
  183. } elseif (!$options['debug']) {
  184. $asset->ensureFilter($this->getFilter(substr($filter, 1)));
  185. }
  186. }
  187. // append variables
  188. if (!empty($options['vars'])) {
  189. $toAdd = array();
  190. foreach ($options['vars'] as $var) {
  191. if (false !== strpos($options['output'], '{'.$var.'}')) {
  192. continue;
  193. }
  194. $toAdd[] = '{'.$var.'}';
  195. }
  196. if ($toAdd) {
  197. $options['output'] = str_replace('*', '*.'.implode('.', $toAdd), $options['output']);
  198. }
  199. }
  200. // append consensus extension if missing
  201. if (1 == count($extensions) && !pathinfo($options['output'], PATHINFO_EXTENSION) && $extension = key($extensions)) {
  202. $options['output'] .= '.'.$extension;
  203. }
  204. // output --> target url
  205. $asset->setTargetPath(str_replace('*', $options['name'], $options['output']));
  206. // apply workers and return
  207. return $this->applyWorkers($asset);
  208. }
  209. public function generateAssetName($inputs, $filters, $options = array())
  210. {
  211. foreach (array_diff(array_keys($options), array('output', 'debug', 'root')) as $key) {
  212. unset($options[$key]);
  213. }
  214. ksort($options);
  215. return substr(sha1(serialize($inputs).serialize($filters).serialize($options)), 0, 7);
  216. }
  217. public function getLastModified(AssetInterface $asset)
  218. {
  219. $mtime = 0;
  220. foreach ($asset instanceof AssetCollectionInterface ? $asset : array($asset) as $leaf) {
  221. $mtime = max($mtime, $leaf->getLastModified());
  222. if (!$filters = $leaf->getFilters()) {
  223. continue;
  224. }
  225. $prevFilters = array();
  226. foreach ($filters as $filter) {
  227. $prevFilters[] = $filter;
  228. if (!$filter instanceof DependencyExtractorInterface) {
  229. continue;
  230. }
  231. // extract children from leaf after running all preceeding filters
  232. $clone = clone $leaf;
  233. $clone->clearFilters();
  234. foreach (array_slice($prevFilters, 0, -1) as $prevFilter) {
  235. $clone->ensureFilter($prevFilter);
  236. }
  237. $clone->load();
  238. foreach ($filter->getChildren($this, $clone->getContent(), $clone->getSourceDirectory()) as $child) {
  239. $mtime = max($mtime, $this->getLastModified($child));
  240. }
  241. }
  242. }
  243. return $mtime;
  244. }
  245. /**
  246. * Parses an input string string into an asset.
  247. *
  248. * The input string can be one of the following:
  249. *
  250. * * A reference: If the string starts with an "at" sign it will be interpreted as a reference to an asset in the asset manager
  251. * * An absolute URL: If the string contains "://" or starts with "//" it will be interpreted as an HTTP asset
  252. * * A glob: If the string contains a "*" it will be interpreted as a glob
  253. * * A path: Otherwise the string is interpreted as a filesystem path
  254. *
  255. * Both globs and paths will be absolutized using the current root directory.
  256. *
  257. * @param string $input An input string
  258. * @param array $options An array of options
  259. *
  260. * @return AssetInterface An asset
  261. */
  262. protected function parseInput($input, array $options = array())
  263. {
  264. if ('@' == $input[0]) {
  265. return $this->createAssetReference(substr($input, 1));
  266. }
  267. if (false !== strpos($input, '://') || 0 === strpos($input, '//')) {
  268. return $this->createHttpAsset($input, $options['vars']);
  269. }
  270. if (self::isAbsolutePath($input)) {
  271. if ($root = self::findRootDir($input, $options['root'])) {
  272. $path = ltrim(substr($input, strlen($root)), '/');
  273. } else {
  274. $path = null;
  275. }
  276. } else {
  277. $root = $this->root;
  278. $path = $input;
  279. $input = $this->root.'/'.$path;
  280. }
  281. if (false !== strpos($input, '*')) {
  282. return $this->createGlobAsset($input, $root, $options['vars']);
  283. }
  284. return $this->createFileAsset($input, $root, $path, $options['vars']);
  285. }
  286. protected function createAssetCollection(array $assets = array(), array $options = array())
  287. {
  288. return new AssetCollection($assets, array(), null, isset($options['vars']) ? $options['vars'] : array());
  289. }
  290. protected function createAssetReference($name)
  291. {
  292. if (!$this->am) {
  293. throw new \LogicException('There is no asset manager.');
  294. }
  295. return new AssetReference($this->am, $name);
  296. }
  297. protected function createHttpAsset($sourceUrl, $vars)
  298. {
  299. return new HttpAsset($sourceUrl, array(), false, $vars);
  300. }
  301. protected function createGlobAsset($glob, $root = null, $vars)
  302. {
  303. return new GlobAsset($glob, array(), $root, $vars);
  304. }
  305. protected function createFileAsset($source, $root = null, $path = null, $vars)
  306. {
  307. return new FileAsset($source, array(), $root, $path, $vars);
  308. }
  309. protected function getFilter($name)
  310. {
  311. if (!$this->fm) {
  312. throw new \LogicException('There is no filter manager.');
  313. }
  314. return $this->fm->get($name);
  315. }
  316. /**
  317. * Filters an asset collection through the factory workers.
  318. *
  319. * Each leaf asset will be processed first, followed by the asset
  320. * collection itself.
  321. *
  322. * @param AssetCollectionInterface $asset An asset collection
  323. *
  324. * @return AssetCollectionInterface
  325. */
  326. private function applyWorkers(AssetCollectionInterface $asset)
  327. {
  328. foreach ($asset as $leaf) {
  329. foreach ($this->workers as $worker) {
  330. $retval = $worker->process($leaf, $this);
  331. if ($retval instanceof AssetInterface && $leaf !== $retval) {
  332. $asset->replaceLeaf($leaf, $retval);
  333. }
  334. }
  335. }
  336. foreach ($this->workers as $worker) {
  337. $retval = $worker->process($asset, $this);
  338. if ($retval instanceof AssetInterface) {
  339. $asset = $retval;
  340. }
  341. }
  342. return $asset instanceof AssetCollectionInterface ? $asset : $this->createAssetCollection(array($asset));
  343. }
  344. private static function isAbsolutePath($path)
  345. {
  346. return '/' == $path[0] || '\\' == $path[0] || (3 < strlen($path) && ctype_alpha($path[0]) && $path[1] == ':' && ('\\' == $path[2] || '/' == $path[2]));
  347. }
  348. /**
  349. * Loops through the root directories and returns the first match.
  350. *
  351. * @param string $path An absolute path
  352. * @param array $roots An array of root directories
  353. *
  354. * @return string|null The matching root directory, if found
  355. */
  356. private static function findRootDir($path, array $roots)
  357. {
  358. foreach ($roots as $root) {
  359. if (0 === strpos($path, $root)) {
  360. return $root;
  361. }
  362. }
  363. }
  364. }