Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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
Mark Story markstory authored
100 Cake/View/StringTemplate.php
View
@@ -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
+ ]);
+ }
+
}
65 Test/TestCase/View/StringTemplateTest.php
View
@@ -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.