PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/jasonlewis/basset/src/Basset/Asset.php

https://bitbucket.org/larryg/powerhut
PHP | 464 lines | 191 code | 61 blank | 212 comment | 9 complexity | eccb9fdd9f6eafa34925902231c82a82 MD5 | raw file
  1. <?php namespace Basset;
  2. use Illuminate\Log\Writer;
  3. use Basset\Filter\Filterable;
  4. use InvalidArgumentException;
  5. use Assetic\Asset\StringAsset;
  6. use Basset\Factory\FilterFactory;
  7. use Assetic\Filter\FilterInterface;
  8. use Illuminate\Filesystem\Filesystem;
  9. class Asset extends Filterable {
  10. /**
  11. * Illuminate filesystem instance.
  12. *
  13. * @var \Illuminate\Filesystem\Filesystem
  14. */
  15. protected $files;
  16. /**
  17. * Basset filter factory instance.
  18. *
  19. * @var Basset\Factory\FilterFactory
  20. */
  21. protected $filterFactory;
  22. /**
  23. * Illuminate log writer instance.
  24. *
  25. * @var \Illuminate\Log\Writer
  26. */
  27. protected $log;
  28. /**
  29. * Absolute path to the asset.
  30. *
  31. * @var string
  32. */
  33. protected $absolutePath;
  34. /**
  35. * Relative path to the asset.
  36. *
  37. * @var string
  38. */
  39. protected $relativePath;
  40. /**
  41. * Indicates if the asset is to be excluded.
  42. *
  43. * @var bool
  44. */
  45. protected $excluded = false;
  46. /**
  47. * Order of the asset.
  48. *
  49. * @var int
  50. */
  51. protected $order;
  52. /**
  53. * Assets cached last modified time.
  54. *
  55. * @var int
  56. */
  57. protected $lastModified;
  58. /**
  59. * Group the asset belongs to, either stylesheets or javascripts.
  60. *
  61. * @var string
  62. */
  63. protected $group;
  64. /**
  65. * Array of allowed asset extensions.
  66. *
  67. * @var array
  68. */
  69. protected $allowedExtensions = array(
  70. 'stylesheets' => array('css', 'sass', 'scss', 'less', 'styl', 'roo', 'gss'),
  71. 'javascripts' => array('js', 'coffee', 'dart', 'ts')
  72. );
  73. /**
  74. * Create a new asset instance.
  75. *
  76. * @param \Illuminate\Filesystem\Filesystem $files
  77. * @param \Basset\Factory\FilterFactory $filterFactory
  78. * @param \Illuminate\Log\Writer $log
  79. * @param string $absolutePath
  80. * @param string $relativePath
  81. * @return void
  82. */
  83. public function __construct(Filesystem $files, FilterFactory $filterFactory, Writer $log, $absolutePath, $relativePath)
  84. {
  85. $this->files = $files;
  86. $this->filterFactory = $filterFactory;
  87. $this->log = $log;
  88. $this->absolutePath = $absolutePath;
  89. $this->relativePath = $relativePath;
  90. $this->filters = new \Illuminate\Support\Collection;
  91. }
  92. /**
  93. * Get the absolute path to the asset.
  94. *
  95. * @return string
  96. */
  97. public function getAbsolutePath()
  98. {
  99. return $this->absolutePath;
  100. }
  101. /**
  102. * Get the relative path to the asset.
  103. *
  104. * @return string
  105. */
  106. public function getRelativePath()
  107. {
  108. return $this->relativePath;
  109. }
  110. /**
  111. * Get the build path to the asset.
  112. *
  113. * @return string
  114. */
  115. public function getBuildPath()
  116. {
  117. $path = pathinfo($this->relativePath);
  118. $fingerprint = md5($this->filters->map(function($f) { return $f->getFilter(); })->toJson().$this->getLastModified());
  119. return "{$path['dirname']}/{$path['filename']}-{$fingerprint}.{$this->getBuildExtension()}";
  120. }
  121. /**
  122. * Get the build extension of the asset.
  123. *
  124. * @return string
  125. */
  126. public function getBuildExtension()
  127. {
  128. return $this->isJavascript() ? 'js' : 'css';
  129. }
  130. /**
  131. * Get the last modified time of the asset.
  132. *
  133. * @return int
  134. */
  135. public function getLastModified()
  136. {
  137. if ($this->lastModified)
  138. {
  139. return $this->lastModified;
  140. }
  141. return $this->lastModified = $this->isRemote() ? null : $this->files->lastModified($this->absolutePath);
  142. }
  143. /**
  144. * Determine if asset is a javascript.
  145. *
  146. * @return bool
  147. */
  148. public function isJavascript()
  149. {
  150. return $this->getGroup() == 'javascripts';
  151. }
  152. /**
  153. * Determine if asset is a stylesheet.
  154. *
  155. * @return bool
  156. */
  157. public function isStylesheet()
  158. {
  159. return $this->getGroup() == 'stylesheets';
  160. }
  161. /**
  162. * Determine if asset is remotely hosted.
  163. *
  164. * @return bool
  165. */
  166. public function isRemote()
  167. {
  168. return starts_with($this->absolutePath, '//') or (bool) filter_var($this->absolutePath, FILTER_VALIDATE_URL);
  169. }
  170. /**
  171. * Alias for \Basset\Asset::setOrder(1)
  172. *
  173. * @return Basset\Asset
  174. */
  175. public function first()
  176. {
  177. return $this->setOrder(1);
  178. }
  179. /**
  180. * Alias for \Basset\Asset::setOrder(2)
  181. *
  182. * @return \Basset\Asset
  183. */
  184. public function second()
  185. {
  186. return $this->setOrder(2);
  187. }
  188. /**
  189. * Alias for \Basset\Asset::setOrder(3)
  190. *
  191. * @return \Basset\Asset
  192. */
  193. public function third()
  194. {
  195. return $this->setOrder(3);
  196. }
  197. /**
  198. * Alias for \Basset\Asset::setOrder()
  199. *
  200. * @param int $order
  201. * @return \Basset\Asset
  202. */
  203. public function order($order)
  204. {
  205. return $this->setOrder($order);
  206. }
  207. /**
  208. * Set the order of the outputted asset.
  209. *
  210. * @param int $order
  211. * @return \Basset\Asset
  212. */
  213. public function setOrder($order)
  214. {
  215. $this->order = $order;
  216. return $this;
  217. }
  218. /**
  219. * Get the assets order.
  220. *
  221. * @return int|null
  222. */
  223. public function getOrder()
  224. {
  225. return $this->order;
  226. }
  227. /**
  228. * Alias for \Basset\Asset::setExcluded(true)
  229. *
  230. * @return \Basset\Asset
  231. */
  232. public function exclude()
  233. {
  234. return $this->setExcluded(true);
  235. }
  236. /**
  237. * Sets the asset to be excluded.
  238. *
  239. * @param bool $excluded
  240. * @return \Basset\Asset
  241. */
  242. public function setExcluded($excluded)
  243. {
  244. $this->excluded = $excluded;
  245. return $this;
  246. }
  247. /**
  248. * Determine if the asset is excluded.
  249. *
  250. * @return bool
  251. */
  252. public function isExcluded()
  253. {
  254. return $this->excluded;
  255. }
  256. /**
  257. * Sets the asset to be included.
  258. *
  259. * @param bool $included
  260. * @return \Basset\Asset
  261. */
  262. public function setIncluded($included)
  263. {
  264. $this->excluded = ! $included;
  265. return $this;
  266. }
  267. /**
  268. * Determine if the asset is included.
  269. *
  270. * @return bool
  271. */
  272. public function isIncluded()
  273. {
  274. return ! $this->excluded;
  275. }
  276. /**
  277. * Set the assets group.
  278. *
  279. * @param string $group
  280. * @return \Basset\Asset
  281. */
  282. public function setGroup($group)
  283. {
  284. $this->group = $group;
  285. return $this;
  286. }
  287. /**
  288. * Get the assets group.
  289. *
  290. * @return string
  291. */
  292. public function getGroup()
  293. {
  294. if ($this->group)
  295. {
  296. return $this->group;
  297. }
  298. return $this->group = $this->detectGroupFromExtension() ?: $this->detectGroupFromContentType();
  299. }
  300. /**
  301. * Detect the group from the content type using cURL.
  302. *
  303. * @return null|string
  304. */
  305. protected function detectGroupFromContentType()
  306. {
  307. if (extension_loaded('curl'))
  308. {
  309. $this->log->warning('Attempting to determine asset group using cURL. This may have a considerable effect on application speed.');
  310. $handler = curl_init($this->absolutePath);
  311. curl_setopt($handler, CURLOPT_RETURNTRANSFER, true);
  312. curl_setopt($handler, CURLOPT_FOLLOWLOCATION, true);
  313. curl_setopt($handler, CURLOPT_HEADER, true);
  314. curl_setopt($handler, CURLOPT_NOBODY, true);
  315. curl_setopt($handler, CURLOPT_SSL_VERIFYPEER, false);
  316. curl_exec($handler);
  317. if ( ! curl_errno($handler))
  318. {
  319. $contentType = curl_getinfo($handler, CURLINFO_CONTENT_TYPE);
  320. return starts_with($contentType, 'text/css') ? 'stylesheets' : 'javascripts';
  321. }
  322. }
  323. }
  324. /**
  325. * Detect group from the assets extension.
  326. *
  327. * @return string
  328. */
  329. protected function detectGroupFromExtension()
  330. {
  331. $extension = pathinfo($this->absolutePath, PATHINFO_EXTENSION);
  332. foreach (array('stylesheets', 'javascripts') as $group)
  333. {
  334. if (in_array($extension, $this->allowedExtensions[$group]))
  335. {
  336. return $group;
  337. }
  338. }
  339. }
  340. /**
  341. * A raw asset is just excluded from the build process.
  342. *
  343. * @return \Basset\Asset
  344. */
  345. public function raw()
  346. {
  347. return $this->exclude();
  348. }
  349. /**
  350. * Get the asset contents.
  351. *
  352. * @return string
  353. */
  354. public function getContent()
  355. {
  356. return $this->files->getRemote($this->absolutePath);
  357. }
  358. /**
  359. * Build the asset.
  360. *
  361. * @param bool $production
  362. * @return string
  363. */
  364. public function build($production = false)
  365. {
  366. $filters = $this->prepareFilters($production);
  367. $asset = new StringAsset($this->getContent(), $filters->all(), dirname($this->absolutePath), basename($this->absolutePath));
  368. return $asset->dump();
  369. }
  370. /**
  371. * Prepare the filters applied to the asset.
  372. *
  373. * @param bool $production
  374. * @return \Illuminate\Support\Collection
  375. */
  376. public function prepareFilters($production = false)
  377. {
  378. $filters = $this->filters->map(function($filter) use ($production)
  379. {
  380. $filter->setProduction($production);
  381. return $filter->getInstance();
  382. });
  383. return $filters->filter(function($filter) { return $filter instanceof FilterInterface; });
  384. }
  385. /**
  386. * Dynamically handle the "include" method as we can't set the method on the class.
  387. *
  388. * @param string $method
  389. * @param array $parameters
  390. * @return mixed
  391. */
  392. public function __call($method, $parameters)
  393. {
  394. // Because PHP doesn't allow us to name a method as "include" we'll revert to magically
  395. // capturing it when the method can't be resolved. If the method is "include" then we'll
  396. // simply set the asset to be included.
  397. if ($method == 'include')
  398. {
  399. return $this->setIncluded(true);
  400. }
  401. throw new InvalidArgumentException("Call to undefined method [{$method}] on Basset\Asset.");
  402. }
  403. }