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

Commit 7af96d9

Browse files
committed
Merge pull request #194 from Brindster/feature-add-attributes
Allow additions to view helper valid attributes Conflicts: src/View/Helper/AbstractHelper.php
2 parents c7d8eeb + a13331e commit 7af96d9

File tree

2 files changed

+149
-4
lines changed

2 files changed

+149
-4
lines changed

src/View/Helper/AbstractHelper.php

Lines changed: 77 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,40 @@ 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+
*
472+
* @return AbstractHelper
473+
*/
474+
public function addValidAttribute($attribute)
475+
{
476+
if (! $this->isValidAttributeName($attribute)) {
477+
throw new InvalidArgumentException(sprintf('%s is not a valid attribute name', $attribute));
478+
}
479+
480+
$this->validTagAttributes[$attribute] = true;
481+
return $this;
482+
}
483+
484+
/**
485+
* Adds a prefix to the list of valid attribute prefixes
486+
*
487+
* @param string $prefix
488+
*
489+
* @return AbstractHelper
490+
*/
491+
public function addValidAttributePrefix($prefix)
492+
{
493+
if (! $this->isValidAttributeName($prefix)) {
494+
throw new InvalidArgumentException(sprintf('%s is not a valid attribute prefix', $prefix));
495+
}
496+
497+
$this->validTagAttributePrefixes[] = $prefix;
498+
return $this;
499+
}
500+
458501
/**
459502
* Adds an HTML attribute to the list of translatable attributes
460503
*
@@ -502,4 +545,34 @@ public static function addDefaultTranslatableAttributePrefix($prefix)
502545
{
503546
self::$defaultTranslatableHtmlAttributePrefixes[] = $prefix;
504547
}
548+
549+
/**
550+
* Whether the passed attribute is valid or not
551+
*
552+
* @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 Description of valid attributes
553+
*
554+
* @param string $attribute
555+
*
556+
* @return bool
557+
*/
558+
protected function isValidAttributeName($attribute)
559+
{
560+
return preg_match('/^[^\t\n\f \/>"\'=]+$/', $attribute);
561+
}
562+
563+
/**
564+
* Whether the passed attribute has a valid prefix or not
565+
* @param string $attribute
566+
* @return bool
567+
*/
568+
protected function hasAllowedPrefix($attribute)
569+
{
570+
foreach ($this->validTagAttributePrefixes as $prefix) {
571+
if (substr($attribute, 0, strlen($prefix)) === $prefix) {
572+
return true;
573+
}
574+
}
575+
576+
return false;
577+
}
505578
}

test/View/Helper/AbstractHelperTest.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace ZendTest\Form\View\Helper;
1111

1212
use Zend\Escaper\Escaper;
13+
use Zend\Form\Exception\InvalidArgumentException;
1314
use Zend\Form\View\Helper\AbstractHelper;
1415
use Zend\I18n\Translator\Translator;
1516

@@ -60,6 +61,77 @@ public function testWillNotEncodeValueAttributeValuesCorrectly()
6061
);
6162
}
6263

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

0 commit comments

Comments
 (0)