3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Form\View\Helper
;
12 use Zend\Form\ElementInterface
;
13 use Zend\I18n\View\Helper\AbstractTranslatorHelper
as BaseAbstractHelper
;
14 use Zend\View\Helper\Doctype
;
15 use Zend\View\Helper\EscapeHtml
;
16 use Zend\View\Helper\EscapeHtmlAttr
;
19 * Base functionality for all form view helpers
21 abstract class AbstractHelper
extends BaseAbstractHelper
24 * Standard boolean attributes, with expected values for enabling/disabling
28 protected $booleanAttributes = array(
29 'autocomplete' => array('on' => 'on', 'off' => 'off'),
30 'autofocus' => array('on' => 'autofocus', 'off' => ''),
31 'checked' => array('on' => 'checked', 'off' => ''),
32 'disabled' => array('on' => 'disabled', 'off' => ''),
33 'multiple' => array('on' => 'multiple', 'off' => ''),
34 'readonly' => array('on' => 'readonly', 'off' => ''),
35 'required' => array('on' => 'required', 'off' => ''),
36 'selected' => array('on' => 'selected', 'off' => ''),
40 * Translatable attributes
44 protected $translatableAttributes = array(
45 'placeholder' => true,
52 protected $doctypeHelper;
57 protected $escapeHtmlHelper;
62 protected $escapeHtmlAttrHelper;
65 * Attributes globally valid for all tags
69 protected $validGlobalAttributes = array(
72 'contenteditable' => true,
73 'contextmenu' => true,
83 'oncanplaythrough' => true,
86 'oncontextmenu' => true,
90 'ondragenter' => true,
91 'ondragleave' => true,
93 'ondragstart' => true,
95 'ondurationchange' => true,
103 'onkeypress' => true,
106 'onloadeddata' => true,
107 'onloadedmetadata' => true,
108 'onloadstart' => true,
109 'onmousedown' => true,
110 'onmousemove' => true,
111 'onmouseout' => true,
112 'onmouseover' => true,
114 'onmousewheel' => true,
118 'onprogress' => true,
119 'onratechange' => true,
120 'onreadystatechange' => true,
130 'ontimeupdate' => true,
131 'onvolumechange' => true,
134 'spellcheck' => true,
144 * Attributes valid for the tag represented by this helper
146 * This should be overridden in extending classes
150 protected $validTagAttributes = array(
154 * Set value for doctype
156 * @param string $doctype
157 * @return AbstractHelper
159 public function setDoctype($doctype)
161 $this->getDoctypeHelper()->setDoctype($doctype);
166 * Get value for doctype
170 public function getDoctype()
172 return $this->getDoctypeHelper()->getDoctype();
176 * Set value for character encoding
178 * @param string $encoding
179 * @return AbstractHelper
181 public function setEncoding($encoding)
183 $this->getEscapeHtmlHelper()->setEncoding($encoding);
188 * Get character encoding
192 public function getEncoding()
194 return $this->getEscapeHtmlHelper()->getEncoding();
198 * Create a string of all attribute/value pairs
200 * Escapes all attribute values
202 * @param array $attributes
205 public function createAttributesString(array $attributes)
207 $attributes = $this->prepareAttributes($attributes);
208 $escape = $this->getEscapeHtmlHelper();
210 foreach ($attributes as $key => $value) {
211 $key = strtolower($key);
212 if (!$value && isset($this->booleanAttributes
[$key])) {
213 // Skip boolean attributes that expect empty string as false value
214 if ('' === $this->booleanAttributes
[$key]['off']) {
219 //check if attribute is translatable
220 if (isset($this->translatableAttributes
[$key]) && !empty($value)) {
221 if (($translator = $this->getTranslator()) !== null) {
222 $value = $translator->translate(
223 $value, $this->getTranslatorTextDomain()
228 //@TODO Escape event attributes like AbstractHtmlElement view helper does in htmlAttribs ??
229 $strings[] = sprintf('%s="%s"', $escape($key), $escape($value));
231 return implode(' ', $strings);
235 * Get the ID of an element
237 * If no ID attribute present, attempts to use the name attribute.
238 * If no name attribute is present, either, returns null.
240 * @param ElementInterface $element
241 * @return null|string
243 public function getId(ElementInterface
$element)
245 $id = $element->getAttribute('id');
250 return $element->getName();
254 * Get the closing bracket for an inline tag
256 * Closes as either "/>" for XHTML doctypes or ">" otherwise.
260 public function getInlineClosingBracket()
262 $doctypeHelper = $this->getDoctypeHelper();
263 if ($doctypeHelper->isXhtml()) {
270 * Retrieve the doctype helper
274 protected function getDoctypeHelper()
276 if ($this->doctypeHelper
) {
277 return $this->doctypeHelper
;
280 if (method_exists($this->view
, 'plugin')) {
281 $this->doctypeHelper
= $this->view
->plugin('doctype');
284 if (!$this->doctypeHelper
instanceof Doctype
) {
285 $this->doctypeHelper
= new Doctype();
288 return $this->doctypeHelper
;
292 * Retrieve the escapeHtml helper
296 protected function getEscapeHtmlHelper()
298 if ($this->escapeHtmlHelper
) {
299 return $this->escapeHtmlHelper
;
302 if (method_exists($this->view
, 'plugin')) {
303 $this->escapeHtmlHelper
= $this->view
->plugin('escapehtml');
306 if (!$this->escapeHtmlHelper
instanceof EscapeHtml
) {
307 $this->escapeHtmlHelper
= new EscapeHtml();
310 return $this->escapeHtmlHelper
;
314 * Retrieve the escapeHtmlAttr helper
316 * @return EscapeHtmlAttr
318 protected function getEscapeHtmlAttrHelper()
320 if ($this->escapeHtmlAttrHelper
) {
321 return $this->escapeHtmlAttrHelper
;
324 if (method_exists($this->view
, 'plugin')) {
325 $this->escapeHtmlAttrHelper
= $this->view
->plugin('escapehtmlattr');
328 if (!$this->escapeHtmlAttrHelper
instanceof EscapeHtmlAttr
) {
329 $this->escapeHtmlAttrHelper
= new EscapeHtmlAttr();
332 return $this->escapeHtmlAttrHelper
;
336 * Prepare attributes for rendering
338 * Ensures appropriate attributes are present (e.g., if "name" is present,
339 * but no "id", sets the latter to the former).
341 * Removes any invalid attributes
343 * @param array $attributes
346 protected function prepareAttributes(array $attributes)
348 foreach ($attributes as $key => $value) {
349 $attribute = strtolower($key);
351 if (!isset($this->validGlobalAttributes
[$attribute])
352 && !isset($this->validTagAttributes
[$attribute])
353 && 'data-' != substr($attribute, 0, 5)
355 // Invalid attribute for the current tag
356 unset($attributes[$key]);
360 // Normalize attribute key, if needed
361 if ($attribute != $key) {
362 unset($attributes[$key]);
363 $attributes[$attribute] = $value;
366 // Normalize boolean attribute values
367 if (isset($this->booleanAttributes
[$attribute])) {
368 $attributes[$attribute] = $this->prepareBooleanAttributeValue($attribute, $value);
376 * Prepare a boolean attribute value
378 * Prepares the expected representation for the boolean attribute specified.
380 * @param string $attribute
381 * @param mixed $value
384 protected function prepareBooleanAttributeValue($attribute, $value)
386 if (!is_bool($value) && in_array($value, $this->booleanAttributes
[$attribute])) {
390 $value = (bool) $value;
392 ?
$this->booleanAttributes
[$attribute]['on']
393 : $this->booleanAttributes
[$attribute]['off']