Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Commit 565fb4f

Browse files
committed
Merging develop to master in preparation for 2.12.0 release.
2 parents e30c510 + d363211 commit 565fb4f

File tree

7 files changed

+197
-18
lines changed

7 files changed

+197
-18
lines changed

CHANGELOG.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@
22

33
All notable changes to this project will be documented in this file, in reverse chronological order by release.
44

5-
## 2.11.1 - TBD
5+
## 2.12.0 - 2018-05-16
66

77
### Added
88

9+
- [#194](https://github.com/zendframework/zend-form/pull/194) adds the ability to whitelist additional HTML attributes for use with a view helper,
10+
as well as attribute prefixes. These can be enabled via the following:
11+
12+
```php
13+
$helper->addValidAttribute('attribute-name');
14+
$helper->addValidAttributePrefix('prefix-');
15+
```
16+
917
- [#188](https://github.com/zendframework/zend-form/pull/188) adds a new method to the `FormElementErrors` view helper, `setTranslateMessages(bool $flag)`.
1018
By default, the helper continues to translate error messages (if a translator
1119
is present), as introduced in 2.11.0. However, using this method, you can
@@ -23,9 +31,9 @@ All notable changes to this project will be documented in this file, in reverse
2331
### Changed
2432

2533
- [#193](https://github.com/zendframework/zend-form/pull/193) modifies how attributes are escaped. If zend-espaper raises an exception
26-
for an invalid attribute value, helpers will now catch the exception, and use a
27-
blank value for the attribute. This prevents 500 errors from being raised for
28-
such pages.
34+
for an invalid attribute value, helpers will now catch the exception, and use
35+
a blank value for the attribute. This prevents 500 errors from being raised
36+
for such pages.
2937

3038
### Deprecated
3139

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@
6666
},
6767
"extra": {
6868
"branch-alias": {
69-
"dev-master": "2.11.x-dev",
70-
"dev-develop": "2.12.x-dev"
69+
"dev-master": "2.12.x-dev",
70+
"dev-develop": "2.13.x-dev"
7171
},
7272
"zf": {
7373
"component": "Zend\\Form",

composer.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/book/helper/abstract-helper.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Method signature | Description
2525
`addTranslatableAttributePrefix(string $prefix) : self` | Marks all HTML attributes that start with the given prefix as translatable.
2626
`addDefaultTranslatableAttribute(string $attribute) : void` | Marks the given HTML attribute as translatable for all view helpers.
2727
`addDefaultTranslatableAttributePrefix(string $prefix) : void` | Marks all HTML attributes that start with the given prefix as translatable for all view helpers.
28+
`addValidAttribute(string $attribute) : self` | Add an HTML attribute to the list of valid attributes for the given element.
29+
`addValidAttributePrefix(string $prefix) : self` | Add an HTML attribute prefix to the list of valid attribute prefixes. Any attribute with this preix will be considered valid. By default, the list includes "data-", "aria-", and "x-".
2830

2931
## Translation
3032

@@ -69,3 +71,27 @@ Or you can mark them as translatable for all view helpers (e. g. the title attri
6971
// mark an prefix as translatable
7072
\Zend\Form\View\Helper\AbstractHelper->addDefaultTranslatableAttributePrefix('data-translatable-');
7173
```
74+
75+
## Allowing framework-specific attributes
76+
77+
Many JavaScript frameworks use custom attributes and/or attribute prefixes with
78+
elements, to facilitate various bindings and event listeners. Examples include
79+
`ng-` for [Angular](https://angularjs.org) elements, and `v-` for
80+
[Vue](https://vuejs.org).
81+
82+
zend-form view helpers are strict about what attributes they consider valid. If
83+
you wish to allow additional attributes, you will need to notify the helper of
84+
them.
85+
86+
The first mechanism is to add a specific attribute:
87+
88+
```php
89+
$helper->addValidAttribute('some-attribute');
90+
```
91+
92+
If you wish to allow a set of attributes with a common prefix, use the
93+
following:
94+
95+
```php
96+
$helper->addValidAttributePrefix('ng-');
97+
```

docs/book/helper/form-element-errors.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,5 @@ Method signature | Descripti
7070
`getMessageCloseString() : string` | Returns the string used to close message representation.
7171
`setAttributes(array $attributes) : void` | Set the attributes that will go on the message open format as key/value pairs.
7272
`getAttributes() : array` | Returns the attributes that will go on the message open format.
73+
`setTranslateMessages(bool $flag) : self` | Indicate whether or not element validation error messages should be translated during `render()`. Default is to translate them.
7374
`render(ElementInterface $element [, array $attributes = array()]) : string` | Renders validation errors for the provided `$element`. Attributes provided will be used in the `messageOpenFormat`, and merged with any provided previously via `setAttributes()`.

src/View/Helper/AbstractHelper.php

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use Zend\Escaper\Exception\RuntimeException as EscaperException;
1111
use Zend\Form\ElementInterface;
12+
use Zend\Form\Exception\InvalidArgumentException;
1213
use Zend\I18n\View\Helper\AbstractTranslatorHelper as BaseAbstractHelper;
1314
use Zend\View\Helper\Doctype;
1415
use Zend\View\Helper\EscapeHtml;
@@ -160,6 +161,17 @@ abstract class AbstractHelper extends BaseAbstractHelper
160161
'xml:space' => true,
161162
];
162163

164+
/**
165+
* Attribute prefixes valid for all tags
166+
*
167+
* @var array
168+
*/
169+
protected $validTagAttributePrefixes = [
170+
'data-',
171+
'aria-',
172+
'x-',
173+
];
174+
163175
/**
164176
* Attributes valid for the tag represented by this helper
165177
*
@@ -375,11 +387,8 @@ protected function prepareAttributes(array $attributes)
375387

376388
if (! isset($this->validGlobalAttributes[$attribute])
377389
&& ! isset($this->validTagAttributes[$attribute])
378-
&& 0 !== strpos($attribute, 'data-')
379-
&& 0 !== strpos($attribute, 'aria-')
380-
&& 0 !== strpos($attribute, 'x-')
390+
&& ! $this->hasAllowedPrefix($attribute)
381391
) {
382-
// Invalid attribute for the current tag
383392
unset($attributes[$key]);
384393
continue;
385394
}
@@ -455,6 +464,42 @@ protected function translateHtmlAttributeValue($key, $value)
455464
return $value;
456465
}
457466

467+
/**
468+
* Adds an HTML attribute to the list of valid attributes
469+
*
470+
* @param string $attribute
471+
* @return AbstractHelper
472+
* @throws InvalidArgumentException for attribute names that are invalid
473+
* per the HTML specifications.
474+
*/
475+
public function addValidAttribute($attribute)
476+
{
477+
if (! $this->isValidAttributeName($attribute)) {
478+
throw new InvalidArgumentException(sprintf('%s is not a valid attribute name', $attribute));
479+
}
480+
481+
$this->validTagAttributes[$attribute] = true;
482+
return $this;
483+
}
484+
485+
/**
486+
* Adds a prefix to the list of valid attribute prefixes
487+
*
488+
* @param string $prefix
489+
* @return AbstractHelper
490+
* @throws InvalidArgumentException for attribute prefixes that are invalid
491+
* per the HTML specifications for attribute names.
492+
*/
493+
public function addValidAttributePrefix($prefix)
494+
{
495+
if (! $this->isValidAttributeName($prefix)) {
496+
throw new InvalidArgumentException(sprintf('%s is not a valid attribute prefix', $prefix));
497+
}
498+
499+
$this->validTagAttributePrefixes[] = $prefix;
500+
return $this;
501+
}
502+
458503
/**
459504
* Adds an HTML attribute to the list of translatable attributes
460505
*
@@ -502,4 +547,34 @@ public static function addDefaultTranslatableAttributePrefix($prefix)
502547
{
503548
self::$defaultTranslatableHtmlAttributePrefixes[] = $prefix;
504549
}
550+
551+
/**
552+
* Whether the passed attribute is valid or not
553+
*
554+
* @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
555+
* Description of valid attributes
556+
* @param string $attribute
557+
* @return bool
558+
*/
559+
protected function isValidAttributeName($attribute)
560+
{
561+
return preg_match('/^[^\t\n\f \/>"\'=]+$/', $attribute);
562+
}
563+
564+
/**
565+
* Whether the passed attribute has a valid prefix or not
566+
*
567+
* @param string $attribute
568+
* @return bool
569+
*/
570+
protected function hasAllowedPrefix($attribute)
571+
{
572+
foreach ($this->validTagAttributePrefixes as $prefix) {
573+
if (substr($attribute, 0, strlen($prefix)) === $prefix) {
574+
return true;
575+
}
576+
}
577+
578+
return false;
579+
}
505580
}

test/View/Helper/AbstractHelperTest.php

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
<?php
22
/**
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
3+
* @see https://github.com/zendframework/zend-form for the canonical source repository
4+
* @copyright Copyright (c) 2005-2018 Zend Technologies USA Inc. (https://www.zend.com)
5+
* @license https://github.com/zendframework/zend-form/blob/master/LICENSE.md New BSD License
86
*/
97

108
namespace ZendTest\Form\View\Helper;
119

1210
use Zend\Escaper\Escaper;
11+
use Zend\Form\Exception\InvalidArgumentException;
1312
use Zend\Form\View\Helper\AbstractHelper;
1413
use Zend\I18n\Translator\Translator;
1514

@@ -23,7 +22,6 @@ class AbstractHelperTest extends CommonTestCase
2322
public function setUp()
2423
{
2524
$this->helper = $this->getMockForAbstractClass('Zend\Form\View\Helper\AbstractHelper');
26-
2725
parent::setUp();
2826
}
2927

@@ -60,6 +58,77 @@ public function testWillNotEncodeValueAttributeValuesCorrectly()
6058
);
6159
}
6260

61+
public function addAttributesData()
62+
{
63+
return [
64+
'valid' => ['valid', 'valid="value"'],
65+
'valid-prefix' => ['px-custom', 'px-custom="value"'],
66+
'xml-ns' => ['xlink:custom', 'xlink:custom="value"'],
67+
'invalid-slash' => ['attr/', null, true],
68+
'invalid-double-quote' => ['attr"', null, true],
69+
'invalid-quote' => ['attr\'', null, true],
70+
'invalid-gt' => ['attr>', null, true],
71+
'invalid-equals' => ['attr=value', null, true],
72+
'invalid-space' => ['at tr', null, true],
73+
'invalid-newline' => ["at\ntr", null, true],
74+
'invalid-tab' => ["at\ttr", null, true],
75+
'invalid-formfeed' => ["at\ftr", null, true],
76+
];
77+
}
78+
79+
/**
80+
* @dataProvider addAttributesData
81+
*/
82+
public function testWillIncludeAdditionalAttributes($attribute, $expected = null, $exception = null)
83+
{
84+
if ($exception) {
85+
$this->expectException(InvalidArgumentException::class);
86+
}
87+
88+
$this->helper->addValidAttribute($attribute);
89+
90+
$this->assertSame(
91+
$expected,
92+
$this->helper->createAttributesString([$attribute => 'value'])
93+
);
94+
}
95+
96+
public function addAttributesPrefixData()
97+
{
98+
return [
99+
'valid' => ['v-', 'v-attr="value"'],
100+
'valid-dash' => ['custom-', 'custom-attr="value"'],
101+
'xml-ns' => ['xlink:', 'xlink:attr="value"'],
102+
'valid-nodash' => ['abc', 'abcattr="value"'],
103+
'invalid-slash' => ['custom/', null, true],
104+
'invalid-double-quote' => ['custom"', null, true],
105+
'invalid-quote' => ['custom\'', null, true],
106+
'invalid-gt' => ['custom>', null, true],
107+
'invalid-equals' => ['custom=', null, true],
108+
'invalid-space' => ['custom ', null, true],
109+
'invalid-newline' => ["cus\ntom", null, true],
110+
'invalid-tab' => ["cus\ttom", null, true],
111+
'invalid-formfeed' => ["cus\ftom", null, true],
112+
];
113+
}
114+
115+
/**
116+
* @dataProvider addAttributesPrefixData
117+
*/
118+
public function testWillIncludeAdditionalAttributesByPrefix($prefix, $expected = null, $exception = null)
119+
{
120+
if ($exception) {
121+
$this->expectException(InvalidArgumentException::class);
122+
}
123+
124+
$this->helper->addValidAttributePrefix($prefix);
125+
126+
$this->assertSame(
127+
$expected,
128+
$this->helper->createAttributesString([$prefix . 'attr' => 'value'])
129+
);
130+
}
131+
63132
public function testWillTranslateAttributeValuesCorrectly()
64133
{
65134
$translator = self::getMockBuilder(Translator::class)

0 commit comments

Comments
 (0)