Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Make attribute formatting part of StringTemplate

Since attributes are basically string templates with a tiny bit of logic it felt
that these methods would belong here. In the long term I hope to remove them from
Helper and have Helper use these methods instead.
  • Loading branch information...
commit 5855bda48a55f331d076501d4165188dcb5579e6 1 parent b5b151e
@markstory markstory authored
View
100 Cake/View/StringTemplate.php
@@ -28,11 +28,25 @@
class StringTemplate {
/**
+ * List of attributes that can be made compact.
+ *
+ * @var array
+ */
+ protected $_compactAttributes = array(
+ 'compact', 'checked', 'declare', 'readonly', 'disabled', 'selected',
+ 'defer', 'ismap', 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize',
+ 'autoplay', 'controls', 'loop', 'muted', 'required', 'novalidate', 'formnovalidate'
+ );
+
+/**
* The templates this instance holds.
*
* @var array
*/
- protected $_templates = [];
+ protected $_templates = [
+ 'attribute' => '{{name}}="{{value}}"',
+ 'compactAttribute' => '{{name}}="{{value}}"',
+ ];
/**
* Load a config file containing templates.
@@ -111,4 +125,88 @@ public function format($name, array $data) {
return strtr($template, $replace);
}
+/**
+ * Returns a space-delimited string with items of the $options array. If a key
+ * of $options array happens to be one of those listed
+ * in `StringTemplate::$_compactAttributes` and its value is one of:
+ *
+ * - '1' (string)
+ * - 1 (integer)
+ * - true (boolean)
+ * - 'true' (string)
+ *
+ * Then the value will be reset to be identical with key's name.
+ * If the value is not one of these 4, the parameter is not output.
+ *
+ * 'escape' is a special option in that it controls the conversion of
+ * attributes to their html-entity encoded equivalents. Set to false to disable html-encoding.
+ *
+ * If value for any option key is set to `null` or `false`, that option will be excluded from output.
+ *
+ * This method uses the 'attribute' and 'compactAttribute' templates. Each of
+ * these templates uses the `name` and `value` variables. You can modify these
+ * templates to change how attributes are formatted.
+ *
+ * @param array $options Array of options.
+ * @param array $exclude Array of options to be excluded, the options here will not be part of the return.
+ * @param string $insertBefore String to be inserted before options.
+ * @return string Composed attributes.
+ */
+ public function formatAttributes($options, $exclude = null) {
+ $insertBefore = ' ';
+ $options = (array)$options + ['escape' => true];
+
+ if (!is_array($exclude)) {
+ $exclude = [];
+ }
+
+ $exclude = ['escape' => true] + array_flip($exclude);
+ $escape = $options['escape'];
+ $attributes = [];
+
+ foreach ($options as $key => $value) {
+ if (!isset($exclude[$key]) && $value !== false && $value !== null) {
+ $attributes[] = $this->_formatAttribute($key, $value, $escape);
+ }
+ }
+ $out = trim(implode(' ', $attributes));
+ return $out ? $insertBefore . $out : '';
+ }
+
+/**
+ * Formats an individual attribute, and returns the string value of the composed attribute.
+ * Works with minimized attributes that have the same value as their name such as 'disabled' and 'checked'
+ *
+ * @param string $key The name of the attribute to create
+ * @param string $value The value of the attribute to create.
+ * @param boolean $escape Define if the value must be escaped
+ * @return string The composed attribute.
+ */
+ protected function _formatAttribute($key, $value, $escape = true) {
+ if (is_array($value)) {
+ $value = implode(' ', $value);
+ }
+ if (is_numeric($key)) {
+ return $this->format('compactAttribute', [
+ 'name' => $value,
+ 'value' => $value
+ ]);
+ }
+ $truthy = [1, '1', true, 'true', $key];
+ $isMinimized = in_array($key, $this->_compactAttributes);
+ if ($isMinimized && in_array($value, $truthy, true)) {
+ return $this->format('compactAttribute', [
+ 'name' => $key,
+ 'value' => $key
+ ]);
+ }
+ if ($isMinimized) {
+ return '';
+ }
+ return $this->format('attribute', [
+ 'name' => $key,
+ 'value' => $escape ? h($value) : $value
+ ]);
+ }
+
}
View
65 Test/TestCase/View/StringTemplateTest.php
@@ -86,6 +86,8 @@ public function testFormat() {
* @return void
*/
public function testLoad() {
+ $this->template->remove('attribute');
+ $this->template->remove('compactAttribute');
$this->assertEquals([], $this->template->get());
$this->assertNull($this->template->load('test_templates'));
$this->assertEquals('<a href="{{url}}">{{text}}</a>', $this->template->get('link'));
@@ -112,4 +114,67 @@ public function testLoadErrorNoFile() {
$this->template->load('no_such_file');
}
+/**
+ * Test formatting compact attributes.
+ *
+ * @return void
+ */
+ public function testFormatAttributesCompact() {
+ $attrs = ['disabled' => true, 'selected' => 1, 'checked' => '1', 'multiple' => 'multiple'];
+ $result = $this->template->formatAttributes($attrs);
+ $this->assertEquals(
+ ' disabled="disabled" selected="selected" checked="checked" multiple="multiple"',
+ $result
+ );
+
+ $attrs = ['disabled' => false, 'selected' => 0, 'checked' => '0', 'multiple' => null];
+ $result = $this->template->formatAttributes($attrs);
+ $this->assertEquals(
+ '',
+ $result
+ );
+ }
+
+/**
+ * Test formatting normal attributes.
+ *
+ * @return void
+ */
+ public function testFormatAttributes() {
+ $attrs = ['name' => 'bruce', 'data-hero' => '<batman>'];
+ $result = $this->template->formatAttributes($attrs);
+ $this->assertEquals(
+ ' name="bruce" data-hero="&lt;batman&gt;"',
+ $result
+ );
+
+ $attrs = ['escape' => false, 'name' => 'bruce', 'data-hero' => '<batman>'];
+ $result = $this->template->formatAttributes($attrs);
+ $this->assertEquals(
+ ' name="bruce" data-hero="<batman>"',
+ $result
+ );
+
+ $attrs = ['name' => 'bruce', 'data-hero' => '<batman>'];
+ $result = $this->template->formatAttributes($attrs, ['name']);
+ $this->assertEquals(
+ ' data-hero="&lt;batman&gt;"',
+ $result
+ );
+ }
+
+/**
+ * Test formatting array attributes.
+ *
+ * @return void
+ */
+ public function testFormatAttributesArray() {
+ $attrs = ['name' => ['bruce', 'wayne']];
+ $result = $this->template->formatAttributes($attrs);
+ $this->assertEquals(
+ ' name="bruce wayne"',
+ $result
+ );
+ }
+
}
Please sign in to comment.
Something went wrong with that request. Please try again.