PageRenderTime 51ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/fuel/core/classes/asset/instance.php

https://bitbucket.org/trujka/codegrounds
PHP | 531 lines | 286 code | 70 blank | 175 comment | 25 complexity | 738e6332eadbf4cd0225b5ef02752059 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.6
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * The Asset class allows you to easily work with your apps assets.
  15. * It allows you to specify multiple paths to be searched for the
  16. * assets.
  17. *
  18. * You can configure the paths by copying the core/config/asset.php
  19. * config file into your app/config folder and changing the settings.
  20. *
  21. * @package Fuel
  22. * @subpackage Core
  23. */
  24. class Asset_Instance
  25. {
  26. /**
  27. * @var array the asset paths to be searched
  28. */
  29. protected $_asset_paths = array(
  30. 'css' => array(),
  31. 'js' => array(),
  32. 'img' => array(),
  33. );
  34. /**
  35. * @var array the sub-folders to be searched
  36. */
  37. protected $_path_folders = array(
  38. 'css' => 'css/',
  39. 'js' => 'js/',
  40. 'img' => 'img/',
  41. );
  42. /**
  43. * @var string the URL to be prepended to all assets
  44. */
  45. protected $_asset_url = '/';
  46. /**
  47. * @var bool whether to append the file mtime to the url
  48. */
  49. protected $_add_mtime = true;
  50. /**
  51. * @var array holds the groups of assets
  52. */
  53. protected $_groups = array();
  54. /**
  55. * @var string prefix for generated output to provide proper indentation
  56. */
  57. protected $_ident = '';
  58. /**
  59. * @var bool if true, directly renders the output of no group name is given
  60. */
  61. protected $_auto_render = true;
  62. /**
  63. * @var bool if true the 'not found' exception will not be thrown and the asset is ignored.
  64. */
  65. protected $_fail_silently = false;
  66. /**
  67. * Parse the config and initialize the object instance
  68. *
  69. * @return void
  70. */
  71. public function __construct($config)
  72. {
  73. //global search path folders
  74. isset($config['css_dir']) and $this->_path_folders['css'] = $this->_unify_path($config['css_dir']);
  75. isset($config['js_dir']) and $this->_path_folders['js'] = $this->_unify_path($config['js_dir']);
  76. isset($config['img_dir']) and $this->_path_folders['img'] = $this->_unify_path($config['img_dir']);
  77. // global search paths
  78. foreach ($config['paths'] as $path)
  79. {
  80. $this->add_path($path);
  81. }
  82. // per-type search paths
  83. foreach ($config['folders'] as $type => $folders)
  84. {
  85. is_array($folders) or $folders = array($folders);
  86. foreach ($folders as $path)
  87. {
  88. $this->add_path($path, $type);
  89. }
  90. }
  91. $this->_add_mtime = $config['add_mtime'];
  92. $this->_asset_url = $config['url'];
  93. $this->_indent = str_repeat($config['indent_with'], $config['indent_level']);
  94. $this->_auto_render = $config['auto_render'];
  95. $this->_fail_silently = $config['fail_silently'];
  96. }
  97. /**
  98. * Adds a new asset type to the list so we can load files of this type
  99. *
  100. * @param string new path type
  101. * @param string optional default path
  102. * @return object current instance
  103. */
  104. public function add_type($type, $path = null)
  105. {
  106. isset($this->_asset_paths[$type]) or $this->_asset_paths[$type] = array();
  107. isset($this->_path_folders[$type]) or $this->_path_folders[$type] = $type.'/';
  108. if ( ! is_null($path))
  109. {
  110. $path = $this->_unify_path($path);
  111. $this->_asset_paths[$type][] = $path;
  112. }
  113. return $this;
  114. }
  115. /**
  116. * Adds the given path to the front of the asset paths array. It adds paths
  117. * in a way so that asset paths are used First in Last Out.
  118. *
  119. * @param string the path to add
  120. * @param string optional path type (js, css or img)
  121. * @return object current instance
  122. */
  123. public function add_path($path, $type = null)
  124. {
  125. is_null($type) and $type = $this->_path_folders;
  126. empty($path) and $path = DOCROOT;
  127. if( is_array($type))
  128. {
  129. foreach ($type as $key => $folder)
  130. {
  131. is_numeric($key) and $key = $folder;
  132. $folder = $this->_unify_path($path).ltrim($this->_unify_path($folder),DS);
  133. array_unshift($this->_asset_paths[$key], $folder);
  134. }
  135. }
  136. else
  137. {
  138. // create the asset type if it doesn't exist
  139. if ( ! isset($this->_asset_paths[$type]))
  140. {
  141. $this->_asset_paths[$type] = array();
  142. $this->_path_folders[$type] = $type.'/';
  143. }
  144. $path = $this->_unify_path($path);
  145. array_unshift($this->_asset_paths[$type], $path);
  146. }
  147. return $this;
  148. }
  149. /**
  150. * Removes the given path from the asset paths array
  151. *
  152. * @param string the path to remove
  153. * @param string optional path type (js, css or img)
  154. * @return object current instance
  155. */
  156. public function remove_path($path, $type = null)
  157. {
  158. is_null($type) and $type = $this->_path_folders;
  159. if( is_array($type))
  160. {
  161. foreach ($type as $key => $folder)
  162. {
  163. is_numeric($key) and $key = $folder;
  164. $folder = $this->_unify_path($path).ltrim($this->_unify_path($folder),DS);
  165. if (($found = array_search($folder, $this->_asset_paths[$key])) !== false)
  166. {
  167. unset($this->_asset_paths[$key][$found]);
  168. }
  169. }
  170. }
  171. else
  172. {
  173. $path = $this->_unify_path($path);
  174. if (($key = array_search($path, $this->_asset_paths[$type])) !== false)
  175. {
  176. unset($this->_asset_paths[$type][$key]);
  177. }
  178. }
  179. return $this;
  180. }
  181. /**
  182. * Renders the given group. Each tag will be separated by a line break.
  183. * You can optionally tell it to render the files raw. This means that
  184. * all CSS and JS files in the group will be read and the contents included
  185. * in the returning value.
  186. *
  187. * @param mixed the group to render
  188. * @param bool whether to return the raw file or not
  189. * @return string the group's output
  190. */
  191. public function render($group = null, $raw = false)
  192. {
  193. is_null($group) and $group = '_default_';
  194. if (is_string($group))
  195. {
  196. isset($this->_groups[$group]) and $group = $this->_groups[$group];
  197. }
  198. is_array($group) or $group = array();
  199. $css = '';
  200. $js = '';
  201. $img = '';
  202. foreach ($group as $key => $item)
  203. {
  204. $type = $item['type'];
  205. $filename = $item['file'];
  206. $attr = $item['attr'];
  207. // only do a file search if the asset is not a URI
  208. if ( ! preg_match('|^(\w+:)?//|', $filename))
  209. {
  210. // and only if the asset is local to the applications base_url
  211. if ( ! preg_match('|^(\w+:)?//|', $this->_asset_url) or strpos($this->_asset_url, \Config::get('base_url')) === 0)
  212. {
  213. if ( ! ($file = $this->find_file($filename, $type)))
  214. {
  215. if ($this->_fail_silently)
  216. {
  217. continue;
  218. }
  219. throw new \FuelException('Could not find asset: '.$filename);
  220. }
  221. $raw or $file = $this->_asset_url.$file.($this->_add_mtime ? '?'.filemtime($file) : '');
  222. }
  223. else
  224. {
  225. $raw or $file = $this->_asset_url.$this->_path_folders[$type].$filename;
  226. }
  227. }
  228. else
  229. {
  230. $file = $filename;
  231. }
  232. switch($type)
  233. {
  234. case 'css':
  235. $attr['type'] = 'text/css';
  236. if ($raw)
  237. {
  238. $css .= html_tag('style', $attr, PHP_EOL.file_get_contents($file).PHP_EOL).PHP_EOL;
  239. }
  240. else
  241. {
  242. if ( ! isset($attr['rel']) or empty($attr['rel']))
  243. {
  244. $attr['rel'] = 'stylesheet';
  245. }
  246. $attr['href'] = $file;
  247. $css .= $this->_indent.html_tag('link', $attr).PHP_EOL;
  248. }
  249. break;
  250. case 'js':
  251. $attr['type'] = 'text/javascript';
  252. if ($raw)
  253. {
  254. $js .= html_tag('script', $attr, PHP_EOL.file_get_contents($file).PHP_EOL).PHP_EOL;
  255. }
  256. else
  257. {
  258. $attr['src'] = $file;
  259. $js .= $this->_indent.html_tag('script', $attr, '').PHP_EOL;
  260. }
  261. break;
  262. case 'img':
  263. $attr['src'] = $file;
  264. $attr['alt'] = isset($attr['alt']) ? $attr['alt'] : '';
  265. $img .= html_tag('img', $attr );
  266. break;
  267. }
  268. }
  269. // return them in the correct order
  270. return $css.$js.$img;
  271. }
  272. // --------------------------------------------------------------------
  273. /**
  274. * CSS
  275. *
  276. * Either adds the stylesheet to the group, or returns the CSS tag.
  277. *
  278. * @access public
  279. * @param mixed The file name, or an array files.
  280. * @param array An array of extra attributes
  281. * @param string The asset group name
  282. * @return string|object Rendered asset or current instance when adding to group
  283. */
  284. public function css($stylesheets = array(), $attr = array(), $group = null, $raw = false)
  285. {
  286. static $temp_group = 1000000;
  287. if ($group === null)
  288. {
  289. $render = $this->_auto_render;
  290. $group = $render ? (string) (++$temp_group) : '_default_';
  291. }
  292. else
  293. {
  294. $render = false;
  295. }
  296. $this->_parse_assets('css', $stylesheets, $attr, $group);
  297. if ($render)
  298. {
  299. return $this->render($group, $raw);
  300. }
  301. return $this;
  302. }
  303. // --------------------------------------------------------------------
  304. /**
  305. * JS
  306. *
  307. * Either adds the javascript to the group, or returns the script tag.
  308. *
  309. * @access public
  310. * @param mixed The file name, or an array files.
  311. * @param array An array of extra attributes
  312. * @param string The asset group name
  313. * @return string|object Rendered asset or current instance when adding to group
  314. */
  315. public function js($scripts = array(), $attr = array(), $group = null, $raw = false)
  316. {
  317. static $temp_group = 2000000;
  318. if ( ! isset($group))
  319. {
  320. $render = $this->_auto_render;
  321. $group = $render ? (string) (++$temp_group) : '_default_';
  322. }
  323. else
  324. {
  325. $render = false;
  326. }
  327. $this->_parse_assets('js', $scripts, $attr, $group);
  328. if ($render)
  329. {
  330. return $this->render($group, $raw);
  331. }
  332. return $this;
  333. }
  334. // --------------------------------------------------------------------
  335. /**
  336. * Img
  337. *
  338. * Either adds the image to the group, or returns the image tag.
  339. *
  340. * @access public
  341. * @param mixed The file name, or an array files.
  342. * @param array An array of extra attributes
  343. * @param string The asset group name
  344. * @return string|object Rendered asset or current instance when adding to group
  345. */
  346. public function img($images = array(), $attr = array(), $group = null)
  347. {
  348. static $temp_group = 3000000;
  349. if ( ! isset($group))
  350. {
  351. $render = $this->_auto_render;
  352. $group = $render ? (string) (++$temp_group) : '_default_';
  353. }
  354. else
  355. {
  356. $render = false;
  357. }
  358. $this->_parse_assets('img', $images, $attr, $group);
  359. if ($render)
  360. {
  361. return $this->render($group);
  362. }
  363. return $this;
  364. }
  365. // --------------------------------------------------------------------
  366. /**
  367. * Find File
  368. *
  369. * Locates a file in all the asset paths.
  370. *
  371. * @access public
  372. * @param string The filename to locate
  373. * @param string The sub-folder to look in (optional)
  374. * @return mixed Either the path to the file or false if not found
  375. */
  376. public function find_file($file, $type, $folder = '')
  377. {
  378. foreach ($this->_asset_paths[$type] as $path)
  379. {
  380. empty($folder) or $folder = $this->_unify_path($folder);
  381. if (is_file($newfile = $path.$folder.$this->_unify_path($file, null, false)))
  382. {
  383. strpos($newfile, DOCROOT) === 0 and $newfile = substr($newfile, strlen(DOCROOT));
  384. // return the file found, make sure it uses forward slashes on Windows
  385. return str_replace(DS, '/', $newfile);
  386. }
  387. }
  388. return false;
  389. }
  390. // --------------------------------------------------------------------
  391. /**
  392. * Get File
  393. *
  394. * Locates a file in all the asset paths, and return it relative to the docroot
  395. *
  396. * @access public
  397. * @param string The filename to locate
  398. * @param string The sub-folder to look in (optional)
  399. * @return mixed Either the path to the file or false if not found
  400. */
  401. public function get_file($file, $type, $folder = '')
  402. {
  403. if ($file = $this->find_file($file, $type, $folder))
  404. {
  405. return $this->_asset_url.$file;
  406. }
  407. return false;
  408. }
  409. // --------------------------------------------------------------------
  410. /**
  411. * Parse Assets
  412. *
  413. * Pareses the assets and adds them to the group
  414. *
  415. * @access private
  416. * @param string The asset type
  417. * @param mixed The file name, or an array files.
  418. * @param array An array of extra attributes
  419. * @param string The asset group name
  420. * @return string
  421. */
  422. protected function _parse_assets($type, $assets, $attr, $group)
  423. {
  424. if ( ! is_array($assets))
  425. {
  426. $assets = array($assets);
  427. }
  428. foreach ($assets as $key => $asset)
  429. {
  430. // Prevent duplicate files in a group.
  431. if (\Arr::get($this->_groups, "$group.$key.file") == $asset)
  432. {
  433. continue;
  434. }
  435. $this->_groups[$group][] = array(
  436. 'type' => $type,
  437. 'file' => $asset,
  438. 'attr' => (array) $attr
  439. );
  440. }
  441. }
  442. // --------------------------------------------------------------------
  443. /**
  444. * Unify the path
  445. *
  446. * make sure the directory separator in the path is correct for the
  447. * platform used, is terminated with a directory separator, and all
  448. * relative path references are removed
  449. *
  450. * @access private
  451. * @param string The path
  452. * @param mixed Optional directory separator
  453. * @return string
  454. */
  455. protected function _unify_path($path, $ds = null, $trailing = true)
  456. {
  457. $ds === null and $ds = DS;
  458. return rtrim(str_replace(array('\\', '/'), $ds, $path), $ds).($trailing ? $ds : '');
  459. }
  460. }