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