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

/vendor/zendframework/zend-view/src/Helper/HeadLink.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 495 lines | 269 code | 58 blank | 168 comment | 51 complexity | c41be5cb1bc540dedd2c92dfef94cd41 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\View\Helper;
  10. use stdClass;
  11. use Zend\View;
  12. use Zend\View\Exception;
  13. /**
  14. * Zend_Layout_View_Helper_HeadLink
  15. *
  16. * @see http://www.w3.org/TR/xhtml1/dtds.html
  17. *
  18. * Creates the following virtual methods:
  19. * @method HeadLink appendStylesheet($href, $media = 'screen', $conditionalStylesheet = '', $extras = array())
  20. * @method HeadLink offsetSetStylesheet($index, $href, $media = 'screen', $conditionalStylesheet = '', $extras = array())
  21. * @method HeadLink prependStylesheet($href, $media = 'screen', $conditionalStylesheet = '', $extras = array())
  22. * @method HeadLink setStylesheet($href, $media = 'screen', $conditionalStylesheet = '', $extras = array())
  23. * @method HeadLink appendAlternate($href, $type, $title, $extras = array())
  24. * @method HeadLink offsetSetAlternate($index, $href, $type, $title, $extras = array())
  25. * @method HeadLink prependAlternate($href, $type, $title, $extras = array())
  26. * @method HeadLink setAlternate($href, $type, $title, $extras = array())
  27. */
  28. class HeadLink extends Placeholder\Container\AbstractStandalone
  29. {
  30. /**
  31. * Allowed attributes
  32. *
  33. * @var string[]
  34. */
  35. protected $itemKeys = array(
  36. 'charset',
  37. 'href',
  38. 'hreflang',
  39. 'id',
  40. 'media',
  41. 'rel',
  42. 'rev',
  43. 'sizes',
  44. 'type',
  45. 'title',
  46. 'extras'
  47. );
  48. /**
  49. * Registry key for placeholder
  50. *
  51. * @var string
  52. */
  53. protected $regKey = 'Zend_View_Helper_HeadLink';
  54. /**
  55. * Constructor
  56. *
  57. * Use PHP_EOL as separator
  58. */
  59. public function __construct()
  60. {
  61. parent::__construct();
  62. $this->setSeparator(PHP_EOL);
  63. }
  64. /**
  65. * Proxy to __invoke()
  66. *
  67. * Allows calling $helper->headLink(), but, more importantly, chaining calls
  68. * like ->appendStylesheet()->headLink().
  69. *
  70. * @param array $attributes
  71. * @param string $placement
  72. * @return HeadLink
  73. */
  74. public function headLink(array $attributes = null, $placement = Placeholder\Container\AbstractContainer::APPEND)
  75. {
  76. return call_user_func_array(array($this, '__invoke'), func_get_args());
  77. }
  78. /**
  79. * headLink() - View Helper Method
  80. *
  81. * Returns current object instance. Optionally, allows passing array of
  82. * values to build link.
  83. *
  84. * @param array $attributes
  85. * @param string $placement
  86. * @return HeadLink
  87. */
  88. public function __invoke(array $attributes = null, $placement = Placeholder\Container\AbstractContainer::APPEND)
  89. {
  90. if (null !== $attributes) {
  91. $item = $this->createData($attributes);
  92. switch ($placement) {
  93. case Placeholder\Container\AbstractContainer::SET:
  94. $this->set($item);
  95. break;
  96. case Placeholder\Container\AbstractContainer::PREPEND:
  97. $this->prepend($item);
  98. break;
  99. case Placeholder\Container\AbstractContainer::APPEND:
  100. default:
  101. $this->append($item);
  102. break;
  103. }
  104. }
  105. return $this;
  106. }
  107. /**
  108. * Overload method access
  109. *
  110. * Items that may be added in the future:
  111. * - Navigation? need to find docs on this
  112. * - public function appendStart()
  113. * - public function appendContents()
  114. * - public function appendPrev()
  115. * - public function appendNext()
  116. * - public function appendIndex()
  117. * - public function appendEnd()
  118. * - public function appendGlossary()
  119. * - public function appendAppendix()
  120. * - public function appendHelp()
  121. * - public function appendBookmark()
  122. * - Other?
  123. * - public function appendCopyright()
  124. * - public function appendChapter()
  125. * - public function appendSection()
  126. * - public function appendSubsection()
  127. *
  128. * @param mixed $method
  129. * @param mixed $args
  130. * @throws Exception\BadMethodCallException
  131. * @return void
  132. */
  133. public function __call($method, $args)
  134. {
  135. if (preg_match('/^(?P<action>set|(ap|pre)pend|offsetSet)(?P<type>Stylesheet|Alternate|Prev|Next)$/', $method, $matches)) {
  136. $argc = count($args);
  137. $action = $matches['action'];
  138. $type = $matches['type'];
  139. $index = null;
  140. if ('offsetSet' == $action) {
  141. if (0 < $argc) {
  142. $index = array_shift($args);
  143. --$argc;
  144. }
  145. }
  146. if (1 > $argc) {
  147. throw new Exception\BadMethodCallException(
  148. sprintf('%s requires at least one argument', $method)
  149. );
  150. }
  151. if (is_array($args[0])) {
  152. $item = $this->createData($args[0]);
  153. } else {
  154. $dataMethod = 'createData' . $type;
  155. $item = $this->$dataMethod($args);
  156. }
  157. if ($item) {
  158. if ('offsetSet' == $action) {
  159. $this->offsetSet($index, $item);
  160. } else {
  161. $this->$action($item);
  162. }
  163. }
  164. return $this;
  165. }
  166. return parent::__call($method, $args);
  167. }
  168. /**
  169. * Check if value is valid
  170. *
  171. * @param mixed $value
  172. * @return bool
  173. */
  174. protected function isValid($value)
  175. {
  176. if (!$value instanceof stdClass) {
  177. return false;
  178. }
  179. $vars = get_object_vars($value);
  180. $keys = array_keys($vars);
  181. $intersection = array_intersect($this->itemKeys, $keys);
  182. if (empty($intersection)) {
  183. return false;
  184. }
  185. return true;
  186. }
  187. /**
  188. * append()
  189. *
  190. * @param array $value
  191. * @throws Exception\InvalidArgumentException
  192. * @return void
  193. */
  194. public function append($value)
  195. {
  196. if (!$this->isValid($value)) {
  197. throw new Exception\InvalidArgumentException(
  198. 'append() expects a data token; please use one of the custom append*() methods'
  199. );
  200. }
  201. return $this->getContainer()->append($value);
  202. }
  203. /**
  204. * offsetSet()
  205. *
  206. * @param string|int $index
  207. * @param array $value
  208. * @throws Exception\InvalidArgumentException
  209. * @return void
  210. */
  211. public function offsetSet($index, $value)
  212. {
  213. if (!$this->isValid($value)) {
  214. throw new Exception\InvalidArgumentException(
  215. 'offsetSet() expects a data token; please use one of the custom offsetSet*() methods'
  216. );
  217. }
  218. return $this->getContainer()->offsetSet($index, $value);
  219. }
  220. /**
  221. * prepend()
  222. *
  223. * @param array $value
  224. * @throws Exception\InvalidArgumentException
  225. * @return HeadLink
  226. */
  227. public function prepend($value)
  228. {
  229. if (!$this->isValid($value)) {
  230. throw new Exception\InvalidArgumentException(
  231. 'prepend() expects a data token; please use one of the custom prepend*() methods'
  232. );
  233. }
  234. return $this->getContainer()->prepend($value);
  235. }
  236. /**
  237. * set()
  238. *
  239. * @param array $value
  240. * @throws Exception\InvalidArgumentException
  241. * @return HeadLink
  242. */
  243. public function set($value)
  244. {
  245. if (!$this->isValid($value)) {
  246. throw new Exception\InvalidArgumentException(
  247. 'set() expects a data token; please use one of the custom set*() methods'
  248. );
  249. }
  250. return $this->getContainer()->set($value);
  251. }
  252. /**
  253. * Create HTML link element from data item
  254. *
  255. * @param stdClass $item
  256. * @return string
  257. */
  258. public function itemToString(stdClass $item)
  259. {
  260. $attributes = (array) $item;
  261. $link = '<link';
  262. foreach ($this->itemKeys as $itemKey) {
  263. if (isset($attributes[$itemKey])) {
  264. if (is_array($attributes[$itemKey])) {
  265. foreach ($attributes[$itemKey] as $key => $value) {
  266. $link .= sprintf(' %s="%s"', $key, ($this->autoEscape) ? $this->escape($value) : $value);
  267. }
  268. } else {
  269. $link .= sprintf(
  270. ' %s="%s"',
  271. $itemKey,
  272. ($this->autoEscape) ? $this->escape($attributes[$itemKey]) : $attributes[$itemKey]
  273. );
  274. }
  275. }
  276. }
  277. if (method_exists($this->view, 'plugin')) {
  278. $link .= ($this->view->plugin('doctype')->isXhtml()) ? ' />' : '>';
  279. } else {
  280. $link .= ' />';
  281. }
  282. if (($link == '<link />') || ($link == '<link>')) {
  283. return '';
  284. }
  285. if (isset($attributes['conditionalStylesheet'])
  286. && !empty($attributes['conditionalStylesheet'])
  287. && is_string($attributes['conditionalStylesheet'])
  288. ) {
  289. // inner wrap with comment end and start if !IE
  290. if (str_replace(' ', '', $attributes['conditionalStylesheet']) === '!IE') {
  291. $link = '<!-->' . $link . '<!--';
  292. }
  293. $link = '<!--[if ' . $attributes['conditionalStylesheet'] . ']>' . $link . '<![endif]-->';
  294. }
  295. return $link;
  296. }
  297. /**
  298. * Render link elements as string
  299. *
  300. * @param string|int $indent
  301. * @return string
  302. */
  303. public function toString($indent = null)
  304. {
  305. $indent = (null !== $indent)
  306. ? $this->getWhitespace($indent)
  307. : $this->getIndent();
  308. $items = array();
  309. $this->getContainer()->ksort();
  310. foreach ($this as $item) {
  311. $items[] = $this->itemToString($item);
  312. }
  313. return $indent . implode($this->escape($this->getSeparator()) . $indent, $items);
  314. }
  315. /**
  316. * Create data item for stack
  317. *
  318. * @param array $attributes
  319. * @return stdClass
  320. */
  321. public function createData(array $attributes)
  322. {
  323. return (object) $attributes;
  324. }
  325. /**
  326. * Create item for stylesheet link item
  327. *
  328. * @param array $args
  329. * @return stdClass|false Returns false if stylesheet is a duplicate
  330. */
  331. public function createDataStylesheet(array $args)
  332. {
  333. $rel = 'stylesheet';
  334. $type = 'text/css';
  335. $media = 'screen';
  336. $conditionalStylesheet = false;
  337. $href = array_shift($args);
  338. if ($this->isDuplicateStylesheet($href)) {
  339. return false;
  340. }
  341. if (0 < count($args)) {
  342. $media = array_shift($args);
  343. if (is_array($media)) {
  344. $media = implode(',', $media);
  345. } else {
  346. $media = (string) $media;
  347. }
  348. }
  349. if (0 < count($args)) {
  350. $conditionalStylesheet = array_shift($args);
  351. if (!empty($conditionalStylesheet) && is_string($conditionalStylesheet)) {
  352. $conditionalStylesheet = (string) $conditionalStylesheet;
  353. } else {
  354. $conditionalStylesheet = null;
  355. }
  356. }
  357. if (0 < count($args) && is_array($args[0])) {
  358. $extras = array_shift($args);
  359. $extras = (array) $extras;
  360. }
  361. $attributes = compact('rel', 'type', 'href', 'media', 'conditionalStylesheet', 'extras');
  362. return $this->createData($attributes);
  363. }
  364. /**
  365. * Is the linked stylesheet a duplicate?
  366. *
  367. * @param string $uri
  368. * @return bool
  369. */
  370. protected function isDuplicateStylesheet($uri)
  371. {
  372. foreach ($this->getContainer() as $item) {
  373. if (($item->rel == 'stylesheet') && ($item->href == $uri)) {
  374. return true;
  375. }
  376. }
  377. return false;
  378. }
  379. /**
  380. * Create item for alternate link item
  381. *
  382. * @param array $args
  383. * @throws Exception\InvalidArgumentException
  384. * @return stdClass
  385. */
  386. public function createDataAlternate(array $args)
  387. {
  388. if (3 > count($args)) {
  389. throw new Exception\InvalidArgumentException(sprintf(
  390. 'Alternate tags require 3 arguments; %s provided',
  391. count($args)
  392. ));
  393. }
  394. $rel = 'alternate';
  395. $href = array_shift($args);
  396. $type = array_shift($args);
  397. $title = array_shift($args);
  398. if (0 < count($args) && is_array($args[0])) {
  399. $extras = array_shift($args);
  400. $extras = (array) $extras;
  401. if (isset($extras['media']) && is_array($extras['media'])) {
  402. $extras['media'] = implode(',', $extras['media']);
  403. }
  404. }
  405. $href = (string) $href;
  406. $type = (string) $type;
  407. $title = (string) $title;
  408. $attributes = compact('rel', 'href', 'type', 'title', 'extras');
  409. return $this->createData($attributes);
  410. }
  411. /**
  412. * Create item for a prev relationship (mainly used for pagination)
  413. *
  414. * @param array $args
  415. * @return stdClass
  416. */
  417. public function createDataPrev(array $args)
  418. {
  419. $rel = 'prev';
  420. $href = (string) array_shift($args);
  421. $attributes = compact('rel', 'href');
  422. return $this->createData($attributes);
  423. }
  424. /**
  425. * Create item for a prev relationship (mainly used for pagination)
  426. *
  427. * @param array $args
  428. * @return stdClass
  429. */
  430. public function createDataNext(array $args)
  431. {
  432. $rel = 'next';
  433. $href = (string) array_shift($args);
  434. $attributes = compact('rel', 'href');
  435. return $this->createData($attributes);
  436. }
  437. }