1 | <?php |
||
17 | class Configuration extends SiteAccessConfiguration |
||
18 | { |
||
19 | /** |
||
20 | * @var \eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ParserInterface |
||
21 | */ |
||
22 | private $mainConfigParser; |
||
23 | |||
24 | /** |
||
25 | * @var Configuration\Suggestion\Collector\SuggestionCollectorInterface |
||
26 | */ |
||
27 | private $suggestionCollector; |
||
28 | |||
29 | public function __construct(ParserInterface $mainConfigParser, SuggestionCollectorInterface $suggestionCollector) |
||
34 | |||
35 | /** |
||
36 | * Generates the configuration tree builder. |
||
37 | * |
||
38 | * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder |
||
39 | */ |
||
40 | public function getConfigTreeBuilder() |
||
57 | |||
58 | public function addRepositoriesSection(ArrayNodeDefinition $rootNode) |
||
59 | { |
||
60 | $rootNode |
||
61 | ->children() |
||
62 | ->arrayNode('repositories') |
||
63 | ->info('Content repositories configuration') |
||
64 | ->example( |
||
65 | array( |
||
66 | 'main' => array( |
||
67 | 'storage' => array( |
||
68 | 'engine' => 'legacy', |
||
69 | 'connection' => 'my_doctrine_connection_name', |
||
70 | ), |
||
71 | ), |
||
72 | ) |
||
73 | ) |
||
74 | ->useAttributeAsKey('alias') |
||
75 | ->prototype('array') |
||
76 | ->beforeNormalization() |
||
77 | ->always( |
||
78 | // Handling deprecated structure by mapping it to new one |
||
79 | function ($v) { |
||
80 | if (isset($v['storage'])) { |
||
81 | return $v; |
||
82 | } |
||
83 | |||
84 | if (isset($v['engine'])) { |
||
85 | $v['storage']['engine'] = $v['engine']; |
||
86 | unset($v['engine']); |
||
87 | } |
||
88 | |||
89 | if (isset($v['connection'])) { |
||
90 | $v['storage']['connection'] = $v['connection']; |
||
91 | unset($v['connection']); |
||
92 | } |
||
93 | |||
94 | if (isset($v['config'])) { |
||
95 | $v['storage']['config'] = $v['config']; |
||
96 | unset($v['config']); |
||
97 | } |
||
98 | |||
99 | return $v; |
||
100 | } |
||
101 | ) |
||
102 | ->end() |
||
103 | ->beforeNormalization() |
||
104 | ->always( |
||
105 | // Setting default values |
||
106 | function ($v) { |
||
107 | if ($v === null) { |
||
108 | $v = array(); |
||
109 | } |
||
110 | |||
111 | if (!isset($v['storage'])) { |
||
112 | $v['storage'] = array(); |
||
113 | } |
||
114 | |||
115 | if (!isset($v['search'])) { |
||
116 | $v['search'] = array(); |
||
117 | } |
||
118 | |||
119 | if (!isset($v['fields_groups']['list'])) { |
||
120 | $v['fields_groups']['list'] = []; |
||
121 | } |
||
122 | |||
123 | if (!isset($v['options'])) { |
||
124 | $v['options'] = []; |
||
125 | } |
||
126 | |||
127 | return $v; |
||
128 | } |
||
129 | ) |
||
130 | ->end() |
||
131 | ->children() |
||
132 | ->arrayNode('storage') |
||
133 | ->children() |
||
134 | ->scalarNode('engine') |
||
135 | ->defaultValue('%ezpublish.api.storage_engine.default%') |
||
136 | ->info('The storage engine to use') |
||
137 | ->end() |
||
138 | ->scalarNode('connection') |
||
139 | ->defaultNull() |
||
140 | ->info('The connection name, if applicable (e.g. Doctrine connection name). If not set, the default connection will be used.') |
||
141 | ->end() |
||
142 | ->arrayNode('config') |
||
143 | ->info('Arbitrary configuration options, supported by your storage engine') |
||
144 | ->useAttributeAsKey('key') |
||
145 | ->prototype('variable')->end() |
||
146 | ->end() |
||
147 | ->end() |
||
148 | ->end() |
||
149 | ->arrayNode('search') |
||
150 | ->children() |
||
151 | ->scalarNode('engine') |
||
152 | ->defaultValue('%ezpublish.api.search_engine.default%') |
||
153 | ->info('The search engine to use') |
||
154 | ->end() |
||
155 | ->scalarNode('connection') |
||
156 | ->defaultNull() |
||
157 | ->info('The connection name, if applicable (e.g. Doctrine connection name). If not set, the default connection will be used.') |
||
158 | ->end() |
||
159 | ->arrayNode('config') |
||
160 | ->info('Arbitrary configuration options, supported by your search engine') |
||
161 | ->useAttributeAsKey('key') |
||
162 | ->prototype('variable')->end() |
||
163 | ->end() |
||
164 | ->end() |
||
165 | ->end() |
||
166 | ->arrayNode('fields_groups') |
||
167 | ->info('Definitions of fields groups.') |
||
168 | ->children() |
||
169 | ->arrayNode('list')->prototype('scalar')->end()->end() |
||
170 | ->scalarNode('default')->defaultValue('%ezsettings.default.content.field_groups.default%')->end() |
||
171 | ->end() |
||
172 | ->end() |
||
173 | ->arrayNode('options') |
||
174 | ->info('Options for repository.') |
||
175 | ->children() |
||
176 | ->scalarNode('default_version_archive_limit') |
||
177 | ->defaultValue(5) |
||
178 | ->info('Default version archive limit (0-50), only enforced on publish, not on un-publish.') |
||
179 | ->end() |
||
180 | ->end() |
||
181 | ->end() |
||
182 | ->end() |
||
183 | ->end() |
||
184 | ->end() |
||
185 | ->end(); |
||
186 | } |
||
187 | |||
188 | public function addSiteaccessSection(ArrayNodeDefinition $rootNode) |
||
189 | { |
||
190 | $rootNode |
||
191 | ->children() |
||
192 | ->arrayNode('siteaccess') |
||
193 | ->info('SiteAccess configuration') |
||
194 | ->children() |
||
195 | ->arrayNode('list') |
||
196 | ->info('Available SiteAccess list') |
||
197 | ->example(array('ezdemo_site', 'ezdemo_site_admin')) |
||
198 | ->isRequired() |
||
199 | ->requiresAtLeastOneElement() |
||
200 | ->prototype('scalar')->end() |
||
201 | ->end() |
||
202 | ->arrayNode('groups') |
||
203 | ->useAttributeAsKey('key') |
||
204 | ->info('SiteAccess groups. Useful to share settings between Siteaccess') |
||
205 | ->example(array('ezdemo_group' => array('ezdemo_site', 'ezdemo_site_admin'))) |
||
206 | ->prototype('array') |
||
207 | ->requiresAtLeastOneElement() |
||
208 | ->prototype('scalar')->end() |
||
209 | ->end() |
||
210 | ->end() |
||
211 | ->scalarNode('default_siteaccess')->isRequired()->info('Name of the default siteaccess')->end() |
||
212 | ->arrayNode('match') |
||
213 | ->info('Siteaccess match configuration. First key is the matcher class, value is passed to the matcher. Key can be a service identifier (prepended by "@"), or a FQ class name (prepended by "\\")') |
||
214 | ->example( |
||
215 | array( |
||
216 | 'Map\\URI' => array( |
||
217 | 'foo' => 'ezdemo_site', |
||
218 | 'ezdemo_site' => 'ezdemo_site', |
||
219 | 'ezdemo_site_admin' => 'ezdemo_site_admin', |
||
220 | ), |
||
221 | 'Map\\Host' => array( |
||
222 | 'ezpublish.dev' => 'ezdemo_site', |
||
223 | 'admin.ezpublish.dev' => 'ezdemo_site_admin', |
||
224 | ), |
||
225 | '\\My\\Custom\\Matcher' => array( |
||
226 | 'some' => 'configuration', |
||
227 | ), |
||
228 | '@my.custom.matcher' => array( |
||
229 | 'some' => 'other_configuration', |
||
230 | ), |
||
231 | ) |
||
232 | ) |
||
233 | ->isRequired() |
||
234 | ->useAttributeAsKey('key') |
||
235 | ->normalizeKeys(false) |
||
236 | ->prototype('array') |
||
237 | ->useAttributeAsKey('key') |
||
238 | ->beforeNormalization() |
||
239 | ->always( |
||
240 | function ($v) { |
||
241 | // Value passed to the matcher should always be an array. |
||
242 | // If value is not an array, we transform it to a hash, with 'value' as key. |
||
243 | if (!is_array($v)) { |
||
244 | return array('value' => $v); |
||
245 | } |
||
246 | |||
247 | // If passed value is a numerically indexed array, we must convert it into a hash. |
||
248 | // See https://jira.ez.no/browse/EZP-21876 |
||
249 | if (array_keys($v) === range(0, count($v) - 1)) { |
||
250 | $final = array(); |
||
251 | foreach ($v as $i => $val) { |
||
252 | $final["i$i"] = $val; |
||
253 | } |
||
254 | |||
255 | return $final; |
||
256 | } |
||
257 | |||
258 | return $v; |
||
259 | } |
||
260 | ) |
||
261 | ->end() |
||
262 | ->normalizeKeys(false) |
||
263 | ->prototype('variable')->end() |
||
264 | ->end() |
||
265 | ->end() |
||
266 | ->end() |
||
267 | ->end() |
||
268 | ->arrayNode('locale_conversion') |
||
269 | ->info('Locale conversion map between eZ Publish format (i.e. fre-FR) to POSIX (i.e. fr_FR). The key is the eZ Publish locale. Check locale.yml in EzPublishCoreBundle to see natively supported locales.') |
||
270 | ->example(array('fre-FR' => 'fr_FR')) |
||
271 | ->useAttributeAsKey('key') |
||
272 | ->normalizeKeys(false) |
||
273 | ->prototype('scalar')->end() |
||
274 | ->end() |
||
275 | ->end(); |
||
276 | } |
||
277 | |||
278 | private function addImageMagickSection(ArrayNodeDefinition $rootNode) |
||
279 | { |
||
280 | $filtersInfo = |
||
281 | <<<EOT |
||
282 | DEPRECATED. |
||
283 | This is only used for legacy injection. |
||
284 | You may use imagick/gmagick liip_imagine bundle drivers. |
||
285 | |||
286 | Hash of filters to be used for your image variations config. |
||
287 | # Key is the filter name, value is an argument passed to "convert" binary. |
||
288 | # You can use numbered placeholders (aka input variables) that will be replaced by defined parameters in your image variations config |
||
289 | EOT; |
||
290 | |||
291 | $rootNode |
||
292 | ->children() |
||
293 | ->arrayNode('imagemagick') |
||
294 | ->info('ImageMagick configuration') |
||
295 | ->children() |
||
296 | ->booleanNode('enabled')->defaultTrue()->end() |
||
297 | ->scalarNode('path') |
||
298 | ->info('Absolute path of ImageMagick / GraphicsMagick "convert" binary.') |
||
299 | ->beforeNormalization() |
||
300 | ->ifTrue( |
||
301 | function ($v) { |
||
302 | $basename = basename($v); |
||
303 | // If there is a space in the basename, just drop it and everything after it. |
||
304 | if (($wsPos = strpos($basename, ' ')) !== false) { |
||
305 | $basename = substr($basename, 0, $wsPos); |
||
306 | } |
||
307 | |||
308 | return !is_executable(dirname($v) . DIRECTORY_SEPARATOR . $basename); |
||
309 | } |
||
310 | ) |
||
311 | ->thenInvalid('Please provide full path to ImageMagick / GraphicsMagick "convert" binary. Please also check that it is executable.') |
||
312 | ->end() |
||
313 | ->end() |
||
314 | ->arrayNode('filters') |
||
315 | ->info($filtersInfo) |
||
316 | ->example(array('geometry/scaledownonly' => '"-geometry {1}x{2}>"')) |
||
317 | ->prototype('scalar')->end() |
||
318 | ->end() |
||
319 | ->end() |
||
320 | ->end() |
||
321 | ->end(); |
||
322 | } |
||
323 | |||
324 | private function addHttpCacheSection(ArrayNodeDefinition $rootNode) |
||
325 | { |
||
326 | $purgeTypeInfo = <<<EOT |
||
327 | Http cache purge type. |
||
328 | |||
329 | Cache purge for content/locations is triggered when needed (e.g. on publish) and will result in one or several Http PURGE requests. |
||
330 | Can be "local" or "http" or a valid service ID: |
||
331 | - If "local" is used, an Http PURGE request will be emulated when needed (e.g. when using Symfony internal reverse proxy). |
||
332 | - If "http" is used, only one Http BAN request will be sent, with X-Location-Id header containing locationIds to ban. |
||
333 | X-Location-Id consists in a Regexp containing locationIds to ban. |
||
334 | Examples: |
||
335 | - (123|456|789) => Purge locations #123, #456, #789. |
||
336 | - .* => Purge all locations. |
||
337 | - If a serviceId is provided, it must be defined in the ServiceContainer and must implement eZ\Publish\Core\MVC\Symfony\Cache\PurgeClientInterface. |
||
338 | EOT; |
||
339 | |||
340 | $rootNode |
||
341 | ->children() |
||
342 | ->arrayNode('http_cache') |
||
343 | ->children() |
||
344 | ->scalarNode('purge_type') |
||
345 | ->info($purgeTypeInfo) |
||
346 | ->defaultValue('local') |
||
347 | ->beforeNormalization() |
||
348 | ->ifTrue( |
||
349 | function ($v) { |
||
350 | $http = array('multiple_http' => true, 'single_http' => true); |
||
351 | |||
352 | return isset($http[$v]); |
||
353 | } |
||
354 | ) |
||
355 | ->then( |
||
356 | function () { |
||
357 | return 'http'; |
||
358 | } |
||
359 | ) |
||
360 | ->end() |
||
361 | ->end() |
||
362 | ->scalarNode('timeout')->info('DEPRECATED')->end() |
||
363 | ->end() |
||
364 | ->end() |
||
365 | ->end(); |
||
366 | } |
||
367 | |||
368 | private function addPageSection(ArrayNodeDefinition $rootNode) |
||
414 | |||
415 | private function addRouterSection(ArrayNodeDefinition $rootNode) |
||
441 | } |
||
442 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: