AssetHelper.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
  5. * (c) 2004 David Heinemeier Hansson
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. /**
  11. * AssetHelper.
  12. *
  13. * @package symfony
  14. * @subpackage helper
  15. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  16. * @author David Heinemeier Hansson
  17. * @version SVN: $Id: AssetHelper.php 17078 2009-04-07 11:10:14Z FabianLange $
  18. */
  19. /**
  20. * Returns a <link> tag that browsers and news readers
  21. * can use to auto-detect a RSS or ATOM feed for the current page,
  22. * to be included in the <head> section of a HTML document.
  23. *
  24. * <b>Options:</b>
  25. * - rel - defaults to 'alternate'
  26. * - type - defaults to 'application/rss+xml'
  27. * - title - defaults to the feed type in upper case
  28. *
  29. * <b>Examples:</b>
  30. * <code>
  31. * echo auto_discovery_link_tag('rss', 'module/feed');
  32. * => <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/module/feed" />
  33. * echo auto_discovery_link_tag('rss', 'module/feed', array('title' => 'My RSS'));
  34. * => <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.curenthost.com/module/feed" />
  35. * </code>
  36. *
  37. * @param string $type feed type ('rss', 'atom')
  38. * @param string $url 'module/action' or '@rule' of the feed
  39. * @param array $tag_options additional HTML compliant <link> tag parameters
  40. *
  41. * @return string XHTML compliant <link> tag
  42. */
  43. function auto_discovery_link_tag($type = 'rss', $url = '', $tag_options = array())
  44. {
  45. return tag('link', array(
  46. 'rel' => isset($tag_options['rel']) ? $tag_options['rel'] : 'alternate',
  47. 'type' => isset($tag_options['type']) ? $tag_options['type'] : 'application/'.$type.'+xml',
  48. 'title' => isset($tag_options['title']) ? $tag_options['title'] : ucfirst($type),
  49. 'href' => url_for($url, true)
  50. ));
  51. }
  52. /**
  53. * Returns the path to a JavaScript asset.
  54. *
  55. * <b>Example:</b>
  56. * <code>
  57. * echo javascript_path('myscript');
  58. * => /js/myscript.js
  59. * </code>
  60. *
  61. * <b>Note:</b> The asset name can be supplied as a...
  62. * - full path, like "/my_js/myscript.css"
  63. * - file name, like "myscript.js", that gets expanded to "/js/myscript.js"
  64. * - file name without extension, like "myscript", that gets expanded to "/js/myscript.js"
  65. *
  66. * @param string $source asset name
  67. * @param bool $absolute return absolute path ?
  68. *
  69. * @return string file path to the JavaScript file
  70. * @see javascript_include_tag
  71. */
  72. function javascript_path($source, $absolute = false)
  73. {
  74. return _compute_public_path($source, 'js', 'js', $absolute);
  75. }
  76. /**
  77. * Returns a <script> include tag per source given as argument.
  78. *
  79. * <b>Examples:</b>
  80. * <code>
  81. * echo javascript_include_tag('xmlhr');
  82. * => <script language="JavaScript" type="text/javascript" src="/js/xmlhr.js"></script>
  83. * echo javascript_include_tag('common.javascript', '/elsewhere/cools');
  84. * => <script language="JavaScript" type="text/javascript" src="/js/common.javascript"></script>
  85. * <script language="JavaScript" type="text/javascript" src="/elsewhere/cools.js"></script>
  86. * </code>
  87. *
  88. * @param string asset names
  89. * @param array additional HTML compliant <link> tag parameters
  90. *
  91. * @return string XHTML compliant <script> tag(s)
  92. * @see javascript_path
  93. */
  94. function javascript_include_tag()
  95. {
  96. $sources = func_get_args();
  97. $sourceOptions = (func_num_args() > 1 && is_array($sources[func_num_args() - 1])) ? array_pop($sources) : array();
  98. $html = '';
  99. foreach ($sources as $source)
  100. {
  101. $absolute = false;
  102. if (isset($sourceOptions['absolute']))
  103. {
  104. unset($sourceOptions['absolute']);
  105. $absolute = true;
  106. }
  107. if(!isset($sourceOptions['raw_name']))
  108. {
  109. $source = javascript_path($source, $absolute);
  110. }
  111. else
  112. {
  113. unset($sourceOptions['raw_name']);
  114. }
  115. $options = array_merge(array('type' => 'text/javascript', 'src' => $source), $sourceOptions);
  116. $html .= content_tag('script', '', $options)."\n";
  117. }
  118. return $html;
  119. }
  120. /**
  121. * Returns the path to a stylesheet asset.
  122. *
  123. * <b>Example:</b>
  124. * <code>
  125. * echo stylesheet_path('style');
  126. * => /css/style.css
  127. * </code>
  128. *
  129. * <b>Note:</b> The asset name can be supplied as a...
  130. * - full path, like "/my_css/style.css"
  131. * - file name, like "style.css", that gets expanded to "/css/style.css"
  132. * - file name without extension, like "style", that gets expanded to "/css/style.css"
  133. *
  134. * @param string $source asset name
  135. * @param bool $absolute return absolute path ?
  136. *
  137. * @return string file path to the stylesheet file
  138. * @see stylesheet_tag
  139. */
  140. function stylesheet_path($source, $absolute = false)
  141. {
  142. return _compute_public_path($source, 'css', 'css', $absolute);
  143. }
  144. /**
  145. * Returns a css <link> tag per source given as argument,
  146. * to be included in the <head> section of a HTML document.
  147. *
  148. * <b>Options:</b>
  149. * - rel - defaults to 'stylesheet'
  150. * - type - defaults to 'text/css'
  151. * - media - defaults to 'screen'
  152. *
  153. * <b>Examples:</b>
  154. * <code>
  155. * echo stylesheet_tag('style');
  156. * => <link href="/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" />
  157. * echo stylesheet_tag('style', array('media' => 'all'));
  158. * => <link href="/stylesheets/style.css" media="all" rel="stylesheet" type="text/css" />
  159. * echo stylesheet_tag('style', array('raw_name' => true));
  160. * => <link href="style" media="all" rel="stylesheet" type="text/css" />
  161. * echo stylesheet_tag('random.styles', '/css/stylish');
  162. * => <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" type="text/css" />
  163. * <link href="/css/stylish.css" media="screen" rel="stylesheet" type="text/css" />
  164. * </code>
  165. *
  166. * @param string asset names
  167. * @param array additional HTML compliant <link> tag parameters
  168. *
  169. * @return string XHTML compliant <link> tag(s)
  170. * @see stylesheet_path
  171. */
  172. function stylesheet_tag()
  173. {
  174. $sources = func_get_args();
  175. $sourceOptions = (func_num_args() > 1 && is_array($sources[func_num_args() - 1])) ? array_pop($sources) : array();
  176. $html = '';
  177. foreach ($sources as $source)
  178. {
  179. $absolute = false;
  180. if (isset($sourceOptions['absolute']))
  181. {
  182. unset($sourceOptions['absolute']);
  183. $absolute = true;
  184. }
  185. if(!isset($sourceOptions['raw_name']))
  186. {
  187. $source = stylesheet_path($source, $absolute);
  188. }
  189. else
  190. {
  191. unset($sourceOptions['raw_name']);
  192. }
  193. $options = array_merge(array('rel' => 'stylesheet', 'type' => 'text/css', 'media' => 'screen', 'href' => $source), $sourceOptions);
  194. $html .= tag('link', $options)."\n";
  195. }
  196. return $html;
  197. }
  198. /**
  199. * Adds a stylesheet to the response object.
  200. *
  201. * @see sfResponse->addStylesheet()
  202. */
  203. function use_stylesheet($css, $position = '', $options = array())
  204. {
  205. sfContext::getInstance()->getResponse()->addStylesheet($css, $position, $options);
  206. }
  207. /**
  208. * Adds a javascript to the response object.
  209. *
  210. * @see sfResponse->addJavascript()
  211. */
  212. function use_javascript($js, $position = '', $options = array())
  213. {
  214. sfContext::getInstance()->getResponse()->addJavascript($js, $position, $options);
  215. }
  216. /**
  217. * Decorates the current template with a given layout.
  218. *
  219. * @param mixed $layout The layout name or path or false to disable the layout
  220. */
  221. function decorate_with($layout)
  222. {
  223. if (false === $layout)
  224. {
  225. sfContext::getInstance()->get('view_instance')->setDecorator(false);
  226. }
  227. else
  228. {
  229. sfContext::getInstance()->get('view_instance')->setDecoratorTemplate($layout);
  230. }
  231. }
  232. /**
  233. * Returns the path to an image asset.
  234. *
  235. * <b>Example:</b>
  236. * <code>
  237. * echo image_path('foobar');
  238. * => /images/foobar.png
  239. * </code>
  240. *
  241. * <b>Note:</b> The asset name can be supplied as a...
  242. * - full path, like "/my_images/image.gif"
  243. * - file name, like "rss.gif", that gets expanded to "/images/rss.gif"
  244. * - file name without extension, like "logo", that gets expanded to "/images/logo.png"
  245. *
  246. * @param string $source asset name
  247. * @param bool $absolute return absolute path ?
  248. *
  249. * @return string file path to the image file
  250. * @see image_tag
  251. */
  252. function image_path($source, $absolute = false)
  253. {
  254. return _compute_public_path($source, 'images', 'png', $absolute);
  255. }
  256. /**
  257. * Returns an <img> image tag for the asset given as argument.
  258. *
  259. * <b>Options:</b>
  260. * - 'absolute' - to output absolute file paths, useful for embedded images in emails
  261. * - 'alt' - defaults to the file name part of the asset (capitalized and without the extension)
  262. * - 'size' - Supplied as "XxY", so "30x45" becomes width="30" and height="45"
  263. *
  264. * <b>Examples:</b>
  265. * <code>
  266. * echo image_tag('foobar');
  267. * => <img src="images/foobar.png" alt="Foobar" />
  268. * echo image_tag('/my_images/image.gif', array('alt' => 'Alternative text', 'size' => '100x200'));
  269. * => <img src="/my_images/image.gif" alt="Alternative text" width="100" height="200" />
  270. * </code>
  271. *
  272. * @param string $source image asset name
  273. * @param array $options additional HTML compliant <img> tag parameters
  274. *
  275. * @return string XHTML compliant <img> tag
  276. * @see image_path
  277. */
  278. function image_tag($source, $options = array())
  279. {
  280. if (!$source)
  281. {
  282. return '';
  283. }
  284. $options = _parse_attributes($options);
  285. $absolute = false;
  286. if (isset($options['absolute']))
  287. {
  288. unset($options['absolute']);
  289. $absolute = true;
  290. }
  291. if(!isset($options['raw_name']))
  292. {
  293. $options['src'] = image_path($source, $absolute);
  294. }
  295. else
  296. {
  297. $options['src'] = $source;
  298. unset($options['raw_name']);
  299. }
  300. if (!isset($options['alt']))
  301. {
  302. $path_pos = strrpos($source, '/');
  303. $dot_pos = strrpos($source, '.');
  304. $begin = $path_pos ? $path_pos + 1 : 0;
  305. $nb_str = ($dot_pos ? $dot_pos : strlen($source)) - $begin;
  306. $options['alt'] = ucfirst(substr($source, $begin, $nb_str));
  307. }
  308. if (isset($options['size']))
  309. {
  310. list($options['width'], $options['height']) = split('x', $options['size'], 2);
  311. unset($options['size']);
  312. }
  313. return tag('img', $options);
  314. }
  315. function _compute_public_path($source, $dir, $ext, $absolute = false)
  316. {
  317. if (strpos($source, '://'))
  318. {
  319. return $source;
  320. }
  321. $request = sfContext::getInstance()->getRequest();
  322. $sf_relative_url_root = $request->getRelativeUrlRoot();
  323. if (0 !== strpos($source, '/'))
  324. {
  325. $source = $sf_relative_url_root.'/'.$dir.'/'.$source;
  326. }
  327. $query_string = '';
  328. if (false !== $pos = strpos($source, '?'))
  329. {
  330. $query_string = substr($source, $pos);
  331. $source = substr($source, 0, $pos);
  332. }
  333. if (false === strpos(basename($source), '.'))
  334. {
  335. $source .= '.'.$ext;
  336. }
  337. if ($sf_relative_url_root && 0 !== strpos($source, $sf_relative_url_root))
  338. {
  339. $source = $sf_relative_url_root.$source;
  340. }
  341. if ($absolute)
  342. {
  343. $source = 'http'.($request->isSecure() ? 's' : '').'://'.$request->getHost().$source;
  344. }
  345. return $source.$query_string;
  346. }
  347. /**
  348. * Prints a set of <meta> tags according to the response attributes,
  349. * to be included in the <head> section of a HTML document.
  350. *
  351. * <b>Examples:</b>
  352. * <code>
  353. * include_metas();
  354. * => <meta name="title" content="symfony - open-source PHP5 web framework" />
  355. * <meta name="robots" content="index, follow" />
  356. * <meta name="description" content="symfony - open-source PHP5 web framework" />
  357. * <meta name="keywords" content="symfony, project, framework, php, php5, open-source, mit, symphony" />
  358. * <meta name="language" content="en" /><link href="/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" />
  359. * </code>
  360. *
  361. * <b>Note:</b> Modify the view.yml or use sfWebResponse::addMeta() to change, add or remove metas.
  362. *
  363. * @return string XHTML compliant <meta> tag(s)
  364. * @see include_http_metas
  365. * @see sfWebResponse::addMeta()
  366. */
  367. function include_metas()
  368. {
  369. $context = sfContext::getInstance();
  370. $i18n = sfConfig::get('sf_i18n') ? $context->getI18N() : null;
  371. foreach ($context->getResponse()->getMetas() as $name => $content)
  372. {
  373. echo tag('meta', array('name' => $name, 'content' => is_null($i18n) ? $content : $i18n->__($content)))."\n";
  374. }
  375. }
  376. /**
  377. * Returns a set of <meta http-equiv> tags according to the response attributes,
  378. * to be included in the <head> section of a HTML document.
  379. *
  380. * <b>Examples:</b>
  381. * <code>
  382. * include_http_metas();
  383. * => <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  384. * </code>
  385. *
  386. * <b>Note:</b> Modify the view.yml or use sfWebResponse::addHttpMeta() to change, add or remove HTTP metas.
  387. *
  388. * @return string XHTML compliant <meta> tag(s)
  389. * @see include_metas
  390. * @see sfWebResponse::addHttpMeta()
  391. */
  392. function include_http_metas()
  393. {
  394. foreach (sfContext::getInstance()->getResponse()->getHttpMetas() as $httpequiv => $value)
  395. {
  396. echo tag('meta', array('http-equiv' => $httpequiv, 'content' => $value))."\n";
  397. }
  398. }
  399. /**
  400. * Returns the title of the current page according to the response attributes,
  401. * to be included in the <title> section of a HTML document.
  402. *
  403. * <b>Note:</b> Modify the sfResponse object or the view.yml to modify the title of a page.
  404. *
  405. * @return string page title
  406. */
  407. function include_title()
  408. {
  409. $title = sfContext::getInstance()->getResponse()->getTitle();
  410. echo content_tag('title', $title)."\n";
  411. }
  412. /**
  413. * Returns <script> tags for all javascripts configured in view.yml or added to the response object.
  414. *
  415. * You can use this helper to decide the location of javascripts in pages.
  416. * By default, if you don't call this helper, symfony will automatically include javascripts before </head>.
  417. * Calling this helper disables this behavior.
  418. *
  419. * @return string <script> tags
  420. */
  421. function get_javascripts()
  422. {
  423. $response = sfContext::getInstance()->getResponse();
  424. sfConfig::set('symfony.asset.javascripts_included', true);
  425. $already_seen = array();
  426. $html = '';
  427. foreach ($response->getPositions() as $position)
  428. {
  429. foreach ($response->getJavascripts($position) as $files => $options)
  430. {
  431. if (!is_array($files))
  432. {
  433. $files = array($files);
  434. }
  435. foreach ($files as $file)
  436. {
  437. if (isset($already_seen[$file])) continue;
  438. $already_seen[$file] = 1;
  439. $html .= javascript_include_tag($file, $options);
  440. }
  441. }
  442. }
  443. return $html;
  444. }
  445. /**
  446. * Prints <script> tags for all javascripts configured in view.yml or added to the response object.
  447. *
  448. * @see get_javascripts()
  449. */
  450. function include_javascripts()
  451. {
  452. echo get_javascripts();
  453. }
  454. /**
  455. * Returns <link> tags for all stylesheets configured in view.yml or added to the response object.
  456. *
  457. * You can use this helper to decide the location of stylesheets in pages.
  458. * By default, if you don't call this helper, symfony will automatically include stylesheets before </head>.
  459. * Calling this helper disables this behavior.
  460. *
  461. * @return string <link> tags
  462. */
  463. function get_stylesheets()
  464. {
  465. $response = sfContext::getInstance()->getResponse();
  466. sfConfig::set('symfony.asset.stylesheets_included', true);
  467. $already_seen = array();
  468. $html = '';
  469. foreach ($response->getPositions() as $position)
  470. {
  471. foreach ($response->getStylesheets($position) as $files => $options)
  472. {
  473. if (!is_array($files))
  474. {
  475. $files = array($files);
  476. }
  477. foreach ($files as $file)
  478. {
  479. if (isset($already_seen[$file])) continue;
  480. $already_seen[$file] = 1;
  481. $html .= stylesheet_tag($file, $options);
  482. }
  483. }
  484. }
  485. return $html;
  486. }
  487. /**
  488. * Prints <link> tags for all stylesheets configured in view.yml or added to the response object.
  489. *
  490. * @see get_stylesheets()
  491. */
  492. function include_stylesheets()
  493. {
  494. echo get_stylesheets();
  495. }
  496. /**
  497. * Returns a <script> include tag for the given internal URI.
  498. *
  499. * The helper automatically adds the sf_format to the internal URI, so you don't have to.
  500. *
  501. * @param string $uri The internal URI for the dynamic javascript
  502. * @param bool $absolute Whether to generate an absolute URL
  503. * @param array $options An array of options
  504. *
  505. * @return string XHTML compliant <script> tag(s)
  506. * @see javascript_include_tag
  507. */
  508. function dynamic_javascript_include_tag($uri, $absolute = false, $options = array())
  509. {
  510. $options['raw_name'] = true;
  511. return javascript_include_tag(_dynamic_path($uri, 'js', $absolute), $options);
  512. }
  513. /**
  514. * Adds a dynamic javascript to the response object.
  515. *
  516. * The first argument is an internal URI.
  517. * The helper automatically adds the sf_format to the internal URI, so you don't have to.
  518. *
  519. * @see sfResponse->addJavascript()
  520. */
  521. function use_dynamic_javascript($js, $position = '', $options = array())
  522. {
  523. $options['raw_name'] = true;
  524. return use_javascript(_dynamic_path($js, 'js'), $position, $options);
  525. }
  526. /**
  527. * Adds a dynamic stylesheet to the response object.
  528. *
  529. * The first argument is an internal URI.
  530. * The helper automatically adds the sf_format to the internal URI, so you don't have to.
  531. *
  532. * @see sfResponse->addStylesheet()
  533. */
  534. function use_dynamic_stylesheet($css, $position = '', $options = array())
  535. {
  536. $options['raw_name'] = true;
  537. return use_stylesheet(_dynamic_path($css, 'css'), $position, $options);
  538. }
  539. function _dynamic_path($uri, $format, $absolute = false)
  540. {
  541. return url_for($uri.(false === strpos($uri, '?') ? '?' : '&').'sf_format='.$format, $absolute);
  542. }