diff options
Diffstat (limited to 'vendor/symfony/form/Symfony/Component/Form/FormRenderer.php')
-rw-r--r-- | vendor/symfony/form/Symfony/Component/Form/FormRenderer.php | 304 |
1 files changed, 0 insertions, 304 deletions
diff --git a/vendor/symfony/form/Symfony/Component/Form/FormRenderer.php b/vendor/symfony/form/Symfony/Component/Form/FormRenderer.php deleted file mode 100644 index 09b01056..00000000 --- a/vendor/symfony/form/Symfony/Component/Form/FormRenderer.php +++ /dev/null | |||
@@ -1,304 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of the Symfony package. | ||
5 | * | ||
6 | * (c) Fabien Potencier <fabien@symfony.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 Symfony\Component\Form; | ||
13 | |||
14 | use Symfony\Component\Form\Exception\LogicException; | ||
15 | use Symfony\Component\Form\Exception\BadMethodCallException; | ||
16 | use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; | ||
17 | |||
18 | /** | ||
19 | * Renders a form into HTML using a rendering engine. | ||
20 | * | ||
21 | * @author Bernhard Schussek <bschussek@gmail.com> | ||
22 | */ | ||
23 | class FormRenderer implements FormRendererInterface | ||
24 | { | ||
25 | const CACHE_KEY_VAR = 'unique_block_prefix'; | ||
26 | |||
27 | /** | ||
28 | * @var FormRendererEngineInterface | ||
29 | */ | ||
30 | private $engine; | ||
31 | |||
32 | /** | ||
33 | * @var CsrfProviderInterface | ||
34 | */ | ||
35 | private $csrfProvider; | ||
36 | |||
37 | /** | ||
38 | * @var array | ||
39 | */ | ||
40 | private $blockNameHierarchyMap = array(); | ||
41 | |||
42 | /** | ||
43 | * @var array | ||
44 | */ | ||
45 | private $hierarchyLevelMap = array(); | ||
46 | |||
47 | /** | ||
48 | * @var array | ||
49 | */ | ||
50 | private $variableStack = array(); | ||
51 | |||
52 | public function __construct(FormRendererEngineInterface $engine, CsrfProviderInterface $csrfProvider = null) | ||
53 | { | ||
54 | $this->engine = $engine; | ||
55 | $this->csrfProvider = $csrfProvider; | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * {@inheritdoc} | ||
60 | */ | ||
61 | public function getEngine() | ||
62 | { | ||
63 | return $this->engine; | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * {@inheritdoc} | ||
68 | */ | ||
69 | public function setTheme(FormView $view, $themes) | ||
70 | { | ||
71 | $this->engine->setTheme($view, $themes); | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * {@inheritdoc} | ||
76 | */ | ||
77 | public function renderCsrfToken($intention) | ||
78 | { | ||
79 | if (null === $this->csrfProvider) { | ||
80 | throw new BadMethodCallException('CSRF token can only be generated if a CsrfProviderInterface is injected in the constructor.'); | ||
81 | } | ||
82 | |||
83 | return $this->csrfProvider->generateCsrfToken($intention); | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * {@inheritdoc} | ||
88 | */ | ||
89 | public function renderBlock(FormView $view, $blockName, array $variables = array()) | ||
90 | { | ||
91 | $resource = $this->engine->getResourceForBlockName($view, $blockName); | ||
92 | |||
93 | if (!$resource) { | ||
94 | throw new LogicException(sprintf('No block "%s" found while rendering the form.', $blockName)); | ||
95 | } | ||
96 | |||
97 | $viewCacheKey = $view->vars[self::CACHE_KEY_VAR]; | ||
98 | |||
99 | // The variables are cached globally for a view (instead of for the | ||
100 | // current suffix) | ||
101 | if (!isset($this->variableStack[$viewCacheKey])) { | ||
102 | $this->variableStack[$viewCacheKey] = array(); | ||
103 | |||
104 | // The default variable scope contains all view variables, merged with | ||
105 | // the variables passed explicitly to the helper | ||
106 | $scopeVariables = $view->vars; | ||
107 | |||
108 | $varInit = true; | ||
109 | } else { | ||
110 | // Reuse the current scope and merge it with the explicitly passed variables | ||
111 | $scopeVariables = end($this->variableStack[$viewCacheKey]); | ||
112 | |||
113 | $varInit = false; | ||
114 | } | ||
115 | |||
116 | // Merge the passed with the existing attributes | ||
117 | if (isset($variables['attr']) && isset($scopeVariables['attr'])) { | ||
118 | $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']); | ||
119 | } | ||
120 | |||
121 | // Merge the passed with the exist *label* attributes | ||
122 | if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) { | ||
123 | $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']); | ||
124 | } | ||
125 | |||
126 | // Do not use array_replace_recursive(), otherwise array variables | ||
127 | // cannot be overwritten | ||
128 | $variables = array_replace($scopeVariables, $variables); | ||
129 | |||
130 | $this->variableStack[$viewCacheKey][] = $variables; | ||
131 | |||
132 | // Do the rendering | ||
133 | $html = $this->engine->renderBlock($view, $resource, $blockName, $variables); | ||
134 | |||
135 | // Clear the stack | ||
136 | array_pop($this->variableStack[$viewCacheKey]); | ||
137 | |||
138 | if ($varInit) { | ||
139 | unset($this->variableStack[$viewCacheKey]); | ||
140 | } | ||
141 | |||
142 | return $html; | ||
143 | } | ||
144 | |||
145 | /** | ||
146 | * {@inheritdoc} | ||
147 | */ | ||
148 | public function searchAndRenderBlock(FormView $view, $blockNameSuffix, array $variables = array()) | ||
149 | { | ||
150 | $renderOnlyOnce = 'row' === $blockNameSuffix || 'widget' === $blockNameSuffix; | ||
151 | |||
152 | if ($renderOnlyOnce && $view->isRendered()) { | ||
153 | return ''; | ||
154 | } | ||
155 | |||
156 | // The cache key for storing the variables and types | ||
157 | $viewCacheKey = $view->vars[self::CACHE_KEY_VAR]; | ||
158 | $viewAndSuffixCacheKey = $viewCacheKey.$blockNameSuffix; | ||
159 | |||
160 | // In templates, we have to deal with two kinds of block hierarchies: | ||
161 | // | ||
162 | // +---------+ +---------+ | ||
163 | // | Theme B | -------> | Theme A | | ||
164 | // +---------+ +---------+ | ||
165 | // | ||
166 | // form_widget -------> form_widget | ||
167 | // ^ | ||
168 | // | | ||
169 | // choice_widget -----> choice_widget | ||
170 | // | ||
171 | // The first kind of hierarchy is the theme hierarchy. This allows to | ||
172 | // override the block "choice_widget" from Theme A in the extending | ||
173 | // Theme B. This kind of inheritance needs to be supported by the | ||
174 | // template engine and, for example, offers "parent()" or similar | ||
175 | // functions to fall back from the custom to the parent implementation. | ||
176 | // | ||
177 | // The second kind of hierarchy is the form type hierarchy. This allows | ||
178 | // to implement a custom "choice_widget" block (no matter in which theme), | ||
179 | // or to fallback to the block of the parent type, which would be | ||
180 | // "form_widget" in this example (again, no matter in which theme). | ||
181 | // If the designer wants to explicitly fallback to "form_widget" in his | ||
182 | // custom "choice_widget", for example because he only wants to wrap | ||
183 | // a <div> around the original implementation, he can simply call the | ||
184 | // widget() function again to render the block for the parent type. | ||
185 | // | ||
186 | // The second kind is implemented in the following blocks. | ||
187 | if (!isset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey])) { | ||
188 | // INITIAL CALL | ||
189 | // Calculate the hierarchy of template blocks and start on | ||
190 | // the bottom level of the hierarchy (= "_<id>_<section>" block) | ||
191 | $blockNameHierarchy = array(); | ||
192 | foreach ($view->vars['block_prefixes'] as $blockNamePrefix) { | ||
193 | $blockNameHierarchy[] = $blockNamePrefix.'_'.$blockNameSuffix; | ||
194 | } | ||
195 | $hierarchyLevel = count($blockNameHierarchy) - 1; | ||
196 | |||
197 | $hierarchyInit = true; | ||
198 | } else { | ||
199 | // RECURSIVE CALL | ||
200 | // If a block recursively calls searchAndRenderBlock() again, resume rendering | ||
201 | // using the parent type in the hierarchy. | ||
202 | $blockNameHierarchy = $this->blockNameHierarchyMap[$viewAndSuffixCacheKey]; | ||
203 | $hierarchyLevel = $this->hierarchyLevelMap[$viewAndSuffixCacheKey] - 1; | ||
204 | |||
205 | $hierarchyInit = false; | ||
206 | } | ||
207 | |||
208 | // The variables are cached globally for a view (instead of for the | ||
209 | // current suffix) | ||
210 | if (!isset($this->variableStack[$viewCacheKey])) { | ||
211 | $this->variableStack[$viewCacheKey] = array(); | ||
212 | |||
213 | // The default variable scope contains all view variables, merged with | ||
214 | // the variables passed explicitly to the helper | ||
215 | $scopeVariables = $view->vars; | ||
216 | |||
217 | $varInit = true; | ||
218 | } else { | ||
219 | // Reuse the current scope and merge it with the explicitly passed variables | ||
220 | $scopeVariables = end($this->variableStack[$viewCacheKey]); | ||
221 | |||
222 | $varInit = false; | ||
223 | } | ||
224 | |||
225 | // Load the resource where this block can be found | ||
226 | $resource = $this->engine->getResourceForBlockNameHierarchy($view, $blockNameHierarchy, $hierarchyLevel); | ||
227 | |||
228 | // Update the current hierarchy level to the one at which the resource was | ||
229 | // found. For example, if looking for "choice_widget", but only a resource | ||
230 | // is found for its parent "form_widget", then the level is updated here | ||
231 | // to the parent level. | ||
232 | $hierarchyLevel = $this->engine->getResourceHierarchyLevel($view, $blockNameHierarchy, $hierarchyLevel); | ||
233 | |||
234 | // The actually existing block name in $resource | ||
235 | $blockName = $blockNameHierarchy[$hierarchyLevel]; | ||
236 | |||
237 | // Escape if no resource exists for this block | ||
238 | if (!$resource) { | ||
239 | throw new LogicException(sprintf( | ||
240 | 'Unable to render the form as none of the following blocks exist: "%s".', | ||
241 | implode('", "', array_reverse($blockNameHierarchy)) | ||
242 | )); | ||
243 | } | ||
244 | |||
245 | // Merge the passed with the existing attributes | ||
246 | if (isset($variables['attr']) && isset($scopeVariables['attr'])) { | ||
247 | $variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']); | ||
248 | } | ||
249 | |||
250 | // Merge the passed with the exist *label* attributes | ||
251 | if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) { | ||
252 | $variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']); | ||
253 | } | ||
254 | |||
255 | // Do not use array_replace_recursive(), otherwise array variables | ||
256 | // cannot be overwritten | ||
257 | $variables = array_replace($scopeVariables, $variables); | ||
258 | |||
259 | // In order to make recursive calls possible, we need to store the block hierarchy, | ||
260 | // the current level of the hierarchy and the variables so that this method can | ||
261 | // resume rendering one level higher of the hierarchy when it is called recursively. | ||
262 | // | ||
263 | // We need to store these values in maps (associative arrays) because within a | ||
264 | // call to widget() another call to widget() can be made, but for a different view | ||
265 | // object. These nested calls should not override each other. | ||
266 | $this->blockNameHierarchyMap[$viewAndSuffixCacheKey] = $blockNameHierarchy; | ||
267 | $this->hierarchyLevelMap[$viewAndSuffixCacheKey] = $hierarchyLevel; | ||
268 | |||
269 | // We also need to store the variables for the view so that we can render other | ||
270 | // blocks for the same view using the same variables as in the outer block. | ||
271 | $this->variableStack[$viewCacheKey][] = $variables; | ||
272 | |||
273 | // Do the rendering | ||
274 | $html = $this->engine->renderBlock($view, $resource, $blockName, $variables); | ||
275 | |||
276 | // Clear the stack | ||
277 | array_pop($this->variableStack[$viewCacheKey]); | ||
278 | |||
279 | // Clear the caches if they were filled for the first time within | ||
280 | // this function call | ||
281 | if ($hierarchyInit) { | ||
282 | unset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey]); | ||
283 | unset($this->hierarchyLevelMap[$viewAndSuffixCacheKey]); | ||
284 | } | ||
285 | |||
286 | if ($varInit) { | ||
287 | unset($this->variableStack[$viewCacheKey]); | ||
288 | } | ||
289 | |||
290 | if ($renderOnlyOnce) { | ||
291 | $view->setRendered(); | ||
292 | } | ||
293 | |||
294 | return $html; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * {@inheritdoc} | ||
299 | */ | ||
300 | public function humanize($text) | ||
301 | { | ||
302 | return ucfirst(trim(strtolower(preg_replace(array('/([A-Z])/', '/[_\s]+/'), array('_$1', ' '), $text)))); | ||
303 | } | ||
304 | } | ||