PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

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