1 <?php
2
3 /*
4 * This file is part of the Brickrouge package.
5 *
6 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Brickrouge;
13
14 /**
15 * A `<FIELDSET>` element with an optional `<LEGEND>` element.
16 *
17 * The direct children of the element are wrapped in a `DIV.field` element, see the
18 * {@link render_child()} method for more information.
19 *
20 * Localization:
21 *
22 * - Labels defined using the {@link Form::LABEL} attribute are translated within the
23 * 'group.label|element.label' scope.
24 * - Legends defined using the {@link LEGEND} attribute are translated within the 'group.legend'
25 * scope.
26 */
27 class Group extends Element
28 {
29 const LABEL = '#form-label';
30
31 /**
32 * Creates a `<FIELDSET.group>` element.
33 *
34 * @param array $attributes
35 */
36 public function __construct(array $attributes=array())
37 {
38 parent::__construct('fieldset', $attributes + array('class' => 'group'));
39 }
40
41 /**
42 * Adds the `no-legend` class name if the group has no legend (the {@link LEGEND} attribute
43 * is empty).
44 */
45 protected function alter_class_names(array $class_names)
46 {
47 $name = $this['name'];
48
49 return parent::alter_class_names($class_names) + array
50 (
51 'group' => true,
52 'group-name' => $name ? 'group--' . normalize($name) : null,
53 'no-legend' => !$this[self::LEGEND]
54 );
55 }
56
57 /**
58 * Override the method to render the child in a `<DIV.field>` wrapper:
59 *
60 * <div class="field [{normalized_field_name}][required]">
61 * [<label for="{element_id}" class="input-label [required]">{element_form_label}</label>]
62 * <div class="input">{child}</div>
63 * </div>
64 */
65 protected function render_child($child)
66 {
67 $control_group_class = 'control-group';
68
69 $name = $child['name'];
70
71 if ($name)
72 {
73 $control_group_class .= ' control-group--' . normalize($name);
74 }
75
76 if ($child[self::REQUIRED])
77 {
78 $control_group_class .= ' required';
79 }
80
81 $state = $child[Element::STATE];
82
83 if ($state)
84 {
85 $control_group_class .= ' ' . $state;
86 }
87
88 $label = $child[Form::LABEL];
89
90 if ($label)
91 {
92 if (!($label instanceof Element))
93 {
94 $label = t
95 (
96 $label, array(), array
97 (
98 'scope' => 'group.label',
99 'default' => t($label, array(), array('scope' => 'element.label'))
100 )
101 );
102 }
103
104 $label = '<label for="' . $child->id . '" class="controls-label">' . $label . '</label>' . PHP_EOL;
105 }
106
107 return <<<EOT
108 <div class="$control_group_class">
109 $label<div class="controls">$child</div>
110 </div>
111 EOT;
112 }
113
114 /**
115 * Prepends the inner HTML with a description and a legend.
116 *
117 * If the {@link DESCRIPTION} attribute is defined the HTML is prepend with a
118 * `DIV.group-description>DIV.group-description-inner` element. The description is translated
119 * within the "group.description" scope. The description is not escaped.
120 *
121 * If the {@link LEGEND} attribute is defined the HTML is prenpend with a `<LEGEND>` element.
122 * The legend can be provided as an object in which it is used _as is_, otherwise the legend
123 * is translated within the "group.legend" scope, then escaped.
124 *
125 * The legend element is rendered using the {@link render_group_legend()} method.
126 */
127 protected function render_inner_html()
128 {
129 $html = parent::render_inner_html();
130
131 $description = $this[self::DESCRIPTION];
132
133 if ($description)
134 {
135 $description = t($description, array(), array('scope' => 'group.description'));
136 $html = $this->render_group_description($description) . $html;
137 }
138
139 $legend = $this[self::LEGEND];
140
141 if ($legend)
142 {
143 if (is_object($legend))
144 {
145 $legend = (string) $legend;
146 }
147 else
148 {
149 $legend = escape(t($legend, array(), array('scope' => 'group.legend')));
150 }
151
152 $html = $this->render_group_legend($legend) . $html;
153 }
154
155 return $html;
156 }
157
158 /**
159 * Renders the group legend.
160 *
161 * @param string $legend The legend to render.
162 *
163 * @return string a `legend.group-legend` HTML element.
164 */
165 protected function render_group_legend($legend)
166 {
167 return '<legend class="group-legend">' . $legend . '</legend>';
168 }
169
170 /**
171 * Renders the group description
172 *
173 * @param string $description
174 *
175 * @return string a `div.group-description>div.group-description-inner` element.
176 */
177 protected function render_group_description($description)
178 {
179 return '<div class="group-description"><div class="group-description-inner">' . $description . '</div></div>';
180 }
181
182 /**
183 * The description decoration is disabled because the {@link DESCRIPTION} attribute is rendered
184 * by the {@link render_inner_html()} method to prepend the inner HTML.
185 */
186 protected function decorate_with_description($html, $description)
187 {
188 return $html;
189 }
190
191 /**
192 * The legend decoration is disabled because the {@link LEGEND} attribute is rendered
193 * by the {@link render_inner_html()} method to prepend the inner HTML.
194 */
195 protected function decorate_with_legend($html, $legend)
196 {
197 return $html;
198 }
199 }