Completed
Push — 3.x ( c5d559...0e9506 )
by Jordi Sala
04:22
created

BaseFieldDescription   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 357
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 0
Metric Value
wmc 55
lcom 2
cbo 3
dl 0
loc 357
rs 6.8
c 0
b 0
f 0

36 Methods

Rating   Name   Duplication   Size   Complexity  
A setFieldName() 0 4 1
A getFieldName() 0 4 1
A setName() 0 8 2
A getName() 0 4 1
A getOption() 0 4 2
A setOption() 0 4 1
B setOptions() 0 31 6
A getOptions() 0 4 1
A setTemplate() 0 4 1
A getTemplate() 0 4 1
A setType() 0 4 1
A getType() 0 4 1
A setParent() 0 4 1
A getParent() 0 4 1
A getAssociationMapping() 0 4 1
A getFieldMapping() 0 4 1
A getParentAssociationMappings() 0 4 1
A setAssociationAdmin() 0 5 1
A getAssociationAdmin() 0 4 1
A hasAssociationAdmin() 0 4 1
D getFieldValue() 0 42 10
A setAdmin() 0 4 1
A getAdmin() 0 4 1
A mergeOption() 0 12 3
A mergeOptions() 0 4 1
A setMappingType() 0 4 1
A getMappingType() 0 4 1
A camelize() 0 13 1
A setHelp() 0 4 1
A getHelp() 0 4 1
A getLabel() 0 4 1
A isSortable() 0 4 1
A getSortFieldMapping() 0 4 1
A getSortParentAssociationMapping() 0 4 1
A getTranslationDomain() 0 4 2
A isVirtual() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like BaseFieldDescription often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BaseFieldDescription, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the Sonata Project package.
5
 *
6
 * (c) Thomas Rabaix <[email protected]>
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 Sonata\AdminBundle\Admin;
13
14
use Doctrine\Common\Inflector\Inflector;
15
use Sonata\AdminBundle\Exception\NoValueException;
16
17
/**
18
 * A FieldDescription hold the information about a field. A typical
19
 * admin instance contains different collections of fields.
20
 *
21
 * - form: used by the form
22
 * - list: used by the list
23
 * - filter: used by the list filter
24
 *
25
 * Some options are global across the different contexts, other are
26
 * context specifics.
27
 *
28
 * Global options :
29
 *   - type (m): define the field type (use to tweak the form or the list)
30
 *   - template (o) : the template used to render the field
31
 *   - name (o) : the name used (label in the form, title in the list)
32
 *   - link_parameters (o) : add link parameter to the related Admin class when
33
 *                           the Admin.generateUrl is called
34
 *   - code : the method name to retrieve the related value
35
 *   - associated_tostring : (deprecated, use associated_property option)
36
 *                           the method to retrieve the "string" representation
37
 *                           of the collection element.
38
 *   - associated_property : property path to retrieve the "string" representation
39
 *                           of the collection element.
40
 *
41
 * Form Field options :
42
 *   - field_type (o): the widget class to use to render the field
43
 *   - field_options (o): the options to give to the widget
44
 *   - edit (o) : list|inline|standard (only used for associated admin)
45
 *      - list : open a popup where the user can search, filter and click on one field
46
 *               to select one item
47
 *      - inline : the associated form admin is embedded into the current form
48
 *      - standard : the associated admin is created through a popup
49
 *
50
 * List Field options :
51
 *   - identifier (o): if set to true a link appear on to edit the element
52
 *
53
 * Filter Field options :
54
 *   - options (o): options given to the Filter object
55
 *   - field_type (o): the widget class to use to render the field
56
 *   - field_options (o): the options to give to the widget
57
 *
58
 * @author Thomas Rabaix <[email protected]>
59
 */
60
abstract class BaseFieldDescription implements FieldDescriptionInterface
61
{
62
    /**
63
     * @var string the field name
64
     */
65
    protected $name;
66
67
    /**
68
     * @var string|int the type
69
     */
70
    protected $type;
71
72
    /**
73
     * @var string|int the original mapping type
74
     */
75
    protected $mappingType;
76
77
    /**
78
     * @var string the field name (of the form)
79
     */
80
    protected $fieldName;
81
82
    /**
83
     * @var array the ORM association mapping
84
     */
85
    protected $associationMapping;
86
87
    /**
88
     * @var array the ORM field information
89
     */
90
    protected $fieldMapping;
91
92
    /**
93
     * @var array the ORM parent mapping association
94
     */
95
    protected $parentAssociationMappings;
96
97
    /**
98
     * @var string the template name
99
     */
100
    protected $template;
101
102
    /**
103
     * @var array the option collection
104
     */
105
    protected $options = [];
106
107
    /**
108
     * @var AdminInterface|null the parent Admin instance
109
     */
110
    protected $parent = null;
111
112
    /**
113
     * @var AdminInterface the related admin instance
114
     */
115
    protected $admin;
116
117
    /**
118
     * @var AdminInterface the associated admin class if the object is associated to another entity
119
     */
120
    protected $associationAdmin;
121
122
    /**
123
     * @var string the help message to display
124
     */
125
    protected $help;
126
127
    public function setFieldName($fieldName)
128
    {
129
        $this->fieldName = $fieldName;
130
    }
131
132
    public function getFieldName()
133
    {
134
        return $this->fieldName;
135
    }
136
137
    public function setName($name)
138
    {
139
        $this->name = $name;
140
141
        if (!$this->getFieldName()) {
142
            $this->setFieldName(substr(strrchr('.'.$name, '.'), 1));
143
        }
144
    }
145
146
    public function getName()
147
    {
148
        return $this->name;
149
    }
150
151
    public function getOption($name, $default = null)
152
    {
153
        return isset($this->options[$name]) ? $this->options[$name] : $default;
154
    }
155
156
    public function setOption($name, $value)
157
    {
158
        $this->options[$name] = $value;
159
    }
160
161
    public function setOptions(array $options)
162
    {
163
        // set the type if provided
164
        if (isset($options['type'])) {
165
            $this->setType($options['type']);
166
            unset($options['type']);
167
        }
168
169
        // remove property value
170
        if (isset($options['template'])) {
171
            $this->setTemplate($options['template']);
172
            unset($options['template']);
173
        }
174
175
        // set help if provided
176
        if (isset($options['help'])) {
177
            $this->setHelp($options['help']);
178
            unset($options['help']);
179
        }
180
181
        // set default placeholder
182
        if (!isset($options['placeholder'])) {
183
            $options['placeholder'] = 'short_object_description_placeholder';
184
        }
185
186
        if (!isset($options['link_parameters'])) {
187
            $options['link_parameters'] = [];
188
        }
189
190
        $this->options = $options;
191
    }
192
193
    public function getOptions()
194
    {
195
        return $this->options;
196
    }
197
198
    public function setTemplate($template)
199
    {
200
        $this->template = $template;
201
    }
202
203
    public function getTemplate()
204
    {
205
        return $this->template;
206
    }
207
208
    public function setType($type)
209
    {
210
        $this->type = $type;
211
    }
212
213
    public function getType()
214
    {
215
        return $this->type;
216
    }
217
218
    public function setParent(AdminInterface $parent)
219
    {
220
        $this->parent = $parent;
221
    }
222
223
    public function getParent()
224
    {
225
        return $this->parent;
226
    }
227
228
    public function getAssociationMapping()
229
    {
230
        return $this->associationMapping;
231
    }
232
233
    public function getFieldMapping()
234
    {
235
        return $this->fieldMapping;
236
    }
237
238
    public function getParentAssociationMappings()
239
    {
240
        return $this->parentAssociationMappings;
241
    }
242
243
    public function setAssociationAdmin(AdminInterface $associationAdmin)
244
    {
245
        $this->associationAdmin = $associationAdmin;
246
        $this->associationAdmin->setParentFieldDescription($this);
247
    }
248
249
    public function getAssociationAdmin()
250
    {
251
        return $this->associationAdmin;
252
    }
253
254
    public function hasAssociationAdmin()
255
    {
256
        return null !== $this->associationAdmin;
257
    }
258
259
    public function getFieldValue($object, $fieldName)
260
    {
261
        if ($this->isVirtual()) {
262
            return;
263
        }
264
265
        $getters = [];
266
        $parameters = [];
267
268
        // prefer method name given in the code option
269
        if ($this->getOption('code')) {
270
            $getters[] = $this->getOption('code');
271
        }
272
        // parameters for the method given in the code option
273
        if ($this->getOption('parameters')) {
274
            $parameters = $this->getOption('parameters');
275
        }
276
277
        if (is_string($fieldName) && '' !== $fieldName) {
278
            $camelizedFieldName = Inflector::classify($fieldName);
279
280
            $getters[] = 'get'.$camelizedFieldName;
281
            $getters[] = 'is'.$camelizedFieldName;
282
            $getters[] = 'has'.$camelizedFieldName;
283
        }
284
285
        foreach ($getters as $getter) {
286
            if (method_exists($object, $getter)) {
287
                return call_user_func_array([$object, $getter], $parameters);
288
            }
289
        }
290
291
        if (method_exists($object, '__call')) {
292
            return call_user_func_array([$object, '__call'], [$fieldName, $parameters]);
293
        }
294
295
        if (isset($object->{$fieldName})) {
296
            return $object->{$fieldName};
297
        }
298
299
        throw new NoValueException(sprintf('Unable to retrieve the value of `%s`', $this->getName()));
300
    }
301
302
    public function setAdmin(AdminInterface $admin)
303
    {
304
        $this->admin = $admin;
305
    }
306
307
    public function getAdmin()
308
    {
309
        return $this->admin;
310
    }
311
312
    public function mergeOption($name, array $options = [])
313
    {
314
        if (!isset($this->options[$name])) {
315
            $this->options[$name] = [];
316
        }
317
318
        if (!is_array($this->options[$name])) {
319
            throw new \RuntimeException(sprintf('The key `%s` does not point to an array value', $name));
320
        }
321
322
        $this->options[$name] = array_merge($this->options[$name], $options);
323
    }
324
325
    public function mergeOptions(array $options = [])
326
    {
327
        $this->setOptions(array_merge_recursive($this->options, $options));
328
    }
329
330
    public function setMappingType($mappingType)
331
    {
332
        $this->mappingType = $mappingType;
333
    }
334
335
    public function getMappingType()
336
    {
337
        return $this->mappingType;
338
    }
339
340
    /**
341
     * Camelize a string.
342
     *
343
     * NEXT_MAJOR: remove this method.
344
     *
345
     * @static
346
     *
347
     * @param string $property
348
     *
349
     * @return string
350
     *
351
     * @deprecated Deprecated since version 3.1. Use \Doctrine\Common\Inflector\Inflector::classify() instead
352
     */
353
    public static function camelize($property)
354
    {
355
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
356
            sprintf(
357
                'The %s method is deprecated since 3.1 and will be removed in 4.0. '.
358
                'Use \Doctrine\Common\Inflector\Inflector::classify() instead.',
359
                __METHOD__
360
            ),
361
            E_USER_DEPRECATED
362
        );
363
364
        return Inflector::classify($property);
365
    }
366
367
    /**
368
     * Defines the help message.
369
     *
370
     * @param string $help
371
     */
372
    public function setHelp($help)
373
    {
374
        $this->help = $help;
375
    }
376
377
    public function getHelp()
378
    {
379
        return $this->help;
380
    }
381
382
    public function getLabel()
383
    {
384
        return $this->getOption('label');
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->getOption('label'); of type array|null adds the type array to the return on line 384 which is incompatible with the return type declared by the interface Sonata\AdminBundle\Admin...tionInterface::getLabel of type string.
Loading history...
385
    }
386
387
    public function isSortable()
388
    {
389
        return false !== $this->getOption('sortable', false);
390
    }
391
392
    public function getSortFieldMapping()
393
    {
394
        return $this->getOption('sort_field_mapping');
395
    }
396
397
    public function getSortParentAssociationMapping()
398
    {
399
        return $this->getOption('sort_parent_association_mappings');
400
    }
401
402
    public function getTranslationDomain()
403
    {
404
        return $this->getOption('translation_domain') ?: $this->getAdmin()->getTranslationDomain();
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->getOption('transl...getTranslationDomain(); of type array|string adds the type array to the return on line 404 which is incompatible with the return type declared by the interface Sonata\AdminBundle\Admin...e::getTranslationDomain of type string.
Loading history...
405
    }
406
407
    /**
408
     * Return true if field is virtual.
409
     *
410
     * @return bool
411
     */
412
    public function isVirtual()
413
    {
414
        return false !== $this->getOption('virtual_field', false);
415
    }
416
}
417