Completed
Branch master (e8947e)
by Andreas
15:09
created

midcom_helper_datamanager2_datamanager   C

Complexity

Total Complexity 72

Size/Duplication

Total Lines 590
Duplicated Lines 9.49 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
dl 56
loc 590
rs 5.5667
c 0
b 0
f 0
wmc 72
lcom 1
cbo 10

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A set_schema() 0 18 3
B set_storage() 0 29 4
A _load_types() 0 18 3
B _load_type() 0 25 5
C autoset_storage() 0 36 8
A recreate() 0 18 4
A save() 0 12 2
A validate() 0 18 4
A _schema_field_is_broken() 0 13 2
B get_content_html() 0 28 5
B get_content_xml() 0 26 5
A get_content_csv() 13 13 3
A get_content_email() 13 13 3
A get_content_raw() 13 13 3
D display_view() 17 101 17

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like midcom_helper_datamanager2_datamanager 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 midcom_helper_datamanager2_datamanager, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package midcom.helper.datamanager2
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * Datamanager 2 Data Manager core class.
11
 *
12
 * This class controls all type I/O operations, including entering and exiting
13
 * editing operations and creation support. It brings Types, Schemas and Storage objects
14
 * together.
15
 *
16
 * @package midcom.helper.datamanager2
17
 */
18
class midcom_helper_datamanager2_datamanager extends midcom_baseclasses_components_purecode
1 ignored issue
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
19
{
20
    /**
21
     * The schema database to use for operation. This variable will always contain a parsed
22
     * representation of the schema, so that one can swiftly switch between individual schemas
23
     * of the Database. This is a list of midcom_helper_datamanager2_schema
24
     * instances, indexed by their name.
25
     *
26
     * @var Array
27
     */
28
    private $_schemadb = null;
29
30
    /**
31
     * This variable holds the schema currently in use, it has been created from the array
32
     * stored in the $_schemadb member.
33
     *
34
     * This object can be modified as long as the types are not initialized. If you change
35
     * the schema afterwards, the changes will not propagate to any dependant object until
36
     * you reinitialize the class.
37
     *
38
     * @var midcom_helper_datamanager2_schema
39
     */
40
    public $schema = null;
41
42
    /**
43
     * The id (array index) of the current schema
44
     * @var string schema_name
45
     */
46
    var $schema_name = '';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $schema_name.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
47
48
    /**
49
     * This is the storage implementation which is used for operation on the types. It encapsulates
50
     * the storage target.
51
     *
52
     * @var midcom_helper_datamanager2_storage
53
     */
54
    public $storage = null;
55
56
    /**
57
     * This is a listing of all types that have been loaded from the storage object. You may
58
     * manipulate these types and their values at will, and then store them back to the database
59
     * using the functions available in this class.
60
     *
61
     * @var Array
62
     */
63
    var $types = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $types.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
64
65
    /**
66
     * This variable contains an Array of all validation errors that have occurred
67
     * during saving. As outlined in the type, these messages my have inline-html
68
     * in it and it is assumed to be localized.
69
     *
70
     * The errors are indexed by field name.
71
     *
72
     * @var Array
73
     * @see midcom_helper_datamanager2_type::$validation_error
74
     */
75
    var $validation_errors = Array();
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $validation_errors.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
76
77
    /**
78
     * Reference to the form manager instance which is currently in use. Usually, it is created and referenced here by the controller
79
     * class during initialization.
80
     *
81
     * @var midcom_helper_datamanager2_formmanager
82
     */
83
    var $formmanager = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $formmanager.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
84
85
    /**
86
     * The constructor loads the schema database to use but does nothing else
87
     * so far.
88
     *
89
     * @param array &$schemadb A list of midcom_helper_datamanager2_schema instances,
90
     *     indexed by their schema name. This member is taken by reference.
91
     * @see midcom_helper_datamanager2_schema::load_database()
92
     */
93
    public function __construct(array &$schemadb)
94
    {
95
         parent::__construct();
96
         $this->_schemadb =& $schemadb;
97
    }
98
99
    /**
100
     * This function activates the given schema. This will drop all existing types
101
     * and create a new set of them which are in the default state at this point.
102
     *
103
     * This will reset the existing schema and type listing. If a storage object
104
     * exists, the change of the schema will be propagated implicitly, as it will
105
     * reference the schema member of ours.
106
     *
107
     * @param string $name The name of the schema to use, omit this to use the default
108
     *     schema.
109
     * @return boolean Indicating success.
110
     */
111
    function set_schema($name = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
112
    {
113
        if ($name === null)
114
        {
115
            reset($this->_schemadb);
116
            $name = key($this->_schemadb);
117
        }
118
        if (!array_key_exists($name, $this->_schemadb))
119
        {
120
            debug_add("The schema {$name} was not found in the active schema database.", MIDCOM_LOG_INFO);
121
            return false;
122
        }
123
124
        $this->schema =& $this->_schemadb[$name];
125
        $this->schema_name = $name;
126
127
        return $this->_load_types();
128
    }
129
130
    /**
131
     * This function sets the system to use a specific storage object. You can pass
132
     * either a MidCOM DBA object or a fully initialized storage subclass. The former
133
     * is automatically wrapped in a midcom storage object. If you pass your own
134
     * storage object, ensure that it uses the same schema as this class. Ideally,
135
     * you should use references for this.
136
     *
137
     * This call will fail if there is no schema set. All types will be set and
138
     * initialized to the new storage object. Thus, it is possible to call set_storage
139
     * repeatedly thus switching an existing DM instance over to a new storage object
140
     * as long as you work with the same schema.
141
     *
142
     * @param mixed $object A reference to either a MidCOM DBA class or a subclass of
143
     *     midcom_helper_datamanager2_storage.
144
     * @return boolean Indicating success.
145
     */
146
    function set_storage($object)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
147
    {
148
        if ($this->schema === null)
149
        {
150
            debug_add('Cannot initialize to a storage object if the schema is not yet set.', MIDCOM_LOG_INFO);
151
            return false;
152
        }
153
154
        if (! is_a($object, 'midcom_helper_datamanager2_storage'))
155
        {
156
            $this->storage = new midcom_helper_datamanager2_storage_midgard($this->schema, $object);
157
        }
158
        else
159
        {
160
            $this->storage = $object;
161
        }
162
163
        // For reasons I do not completely comprehend, PHP drops the storage references into the types
164
        // in the lines above. Right now the only solution (except debugging this 5 hours long line
165
        // by line) I see is explicitly setting the storage references in the types.
166
        foreach ($this->types as $type)
167
        {
168
            $type->set_storage($this->storage);
169
        }
170
171
        $this->storage->load($this->types);
172
173
        return true;
174
    }
175
176
    /**
177
     * This function will create all type objects for the current schema. It will load class
178
     * files where necessary (using require_once), and then create a set of instances
179
     * based on the schema.
180
     *
181
     * @return boolean Indicating success
182
     */
183
    private function _load_types()
184
    {
185
        $this->types = Array();
186
187
        if (!$this->schema)
188
        {
189
            debug_add("Failed to initialize the types, schema not defined.",
190
                MIDCOM_LOG_INFO);
191
            return false;
192
        }
193
194
        foreach ($this->schema->fields as $name => $config)
195
        {
196
            $this->_load_type($name, $config);
197
        }
198
199
        return true;
200
    }
201
202
    private function _load_type($name, $config)
203
    {
204
        if (!isset($config['type']))
205
        {
206
            throw new midcom_error("The field {$name} is missing type");
207
        }
208
209
        $classname = $config['type'];
210
        if (strpos($classname, '_') === false)
211
        {
212
            // Built-in type called using the shorthand notation
213
            $classname = "midcom_helper_datamanager2_type_{$config['type']}";
214
        }
215
216
        $this->types[$name] = new $classname();
217
        if (!$this->types[$name] instanceof midcom_helper_datamanager2_type)
218
        {
219
            throw new midcom_error("{$classname} is not a valid DM2 type");
220
        }
221
222
        if ($this->types[$name]->initialize($name, $config['type_config'], $this->storage, $this) === false)
223
        {
224
            throw new midcom_error("Failed to initialize the type for {$name}");
225
        }
226
    }
227
228
    /**
229
     * This function is a shortcut that combines set_schema and set_storage together.
230
     * The schema name is looked up in the parameter 'midcom.helper.datamanager2/schema_name',
231
     * if it is not found, the first schema from the schema database is used implicitly.
232
     *
233
     * @see set_schema()
234
     * @see set_storage()
235
     * @param mixed $object Either a MidCOM DBA class or a subclass of midcom_helper_datamanager2_storage.
236
     * @param boolean $strict Whether we should strictly use only the schema given by object params
237
     * @return boolean Indicating success.
238
     */
239
    function autoset_storage($object, $strict = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
240
    {
241
        if (is_a($object, 'midcom_helper_datamanager2_storage'))
242
        {
243
            $schema = $object->object->get_parameter('midcom.helper.datamanager2', 'schema_name');
244
        }
245
        else
246
        {
247
            if (!is_object($object))
248
            {
249
                return false;
250
            }
251
            $schema = $object->get_parameter('midcom.helper.datamanager2', 'schema_name');
252
        }
253
254
        if (! $schema)
255
        {
256
            $schema = null;
257
        }
258
259
        if (!$this->set_schema($schema))
260
        {
261
            if (   $strict
262
                || $schema == null)
263
            {
264
                return false;
265
            }
266
            debug_add("Given schema name {$schema} was not found, reverting to default.", MIDCOM_LOG_INFO);
267
            // Schema database has probably changed so we should be graceful here
268
            if (!$this->set_schema(null))
269
            {
270
                return false;
271
            }
272
        }
273
        return $this->set_storage($object);
274
    }
275
276
    /**
277
     * This function will cycle through all fields of the loaded schema, and run a "recreate" method for the
278
     * type, if it has one.
279
     *
280
     * This can be used for regenerating all images or converted files of a given object when for instance
281
     * schema changes.
282
     *
283
     * @return boolean
284
     */
285
    function recreate()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
286
    {
287
        $stat = true;
288
        foreach ($this->types as $type)
289
        {
290
            if (!method_exists($type, 'recreate'))
291
            {
292
                // This type doesn't support recreation
293
                continue;
294
            }
295
            if (!$type->recreate())
296
            {
297
                $stat = false;
298
            }
299
        }
300
301
        return $stat;
302
    }
303
304
    /**
305
     * This function will save the current state of all types to disk. A full
306
     * validation cycle is done beforehand, if any validation fails, the function
307
     * aborts and sets the $validation_errors member variable accordingly.
308
     *
309
     * @return boolean Indicating success
310
     */
311
    function save()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
312
    {
313
        if (! $this->validate())
314
        {
315
            debug_add(count($this->validation_errors) . ' fields have failed validation, cannot save.',
316
                MIDCOM_LOG_WARN);
317
            debug_print_r('Validation errors:', $this->validation_errors);
318
            return false;
319
        }
320
321
        return $this->storage->store($this->types);
322
    }
323
324
    /**
325
     * Validate the current object state. It will populate $validation_errors
326
     * accordingly.
327
     *
328
     * @return boolean Indicating validation success.
329
     */
330
    function validate()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
331
    {
332
        $this->validation_errors = Array();
333
        $validated = true;
334
        foreach (array_keys($this->schema->fields) as $name)
335
        {
336
            if ($this->_schema_field_is_broken($name))
337
            {
338
                continue;
339
            }
340
            if (! $this->types[$name]->validate())
341
            {
342
                $this->validation_errors[$name] = $this->types[$name]->validation_error;
343
                $validated = false;
344
            }
345
        }
346
        return $validated;
347
    }
348
349
    /**
350
     * Very basic schema sanity checking, raises messages as needed
351
     *
352
     * @param string $name field name
353
     * @return boolean indicating b0rkedness
354
     */
355
    function _schema_field_is_broken($name)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
356
    {
357
        if (isset($this->types[$name]))
358
        {
359
            return false;
360
        }
361
        $msg = "DM2->types['{$name}'] is not set (but was present in field_order/fields array), current instance of schema '{$this->schema_name}' is somehow broken";
362
        midcom::get()->uimessages->add($this->_l10n->get($this->_component), $msg, 'error');
363
        debug_add($msg, MIDCOM_LOG_ERROR);
364
        debug_print_r('DM2->schema->field_order', $this->schema->field_order);
365
366
        return true;
367
    }
368
369
    /**
370
     * Little helper function returning an associative array of all field values converted to HTML
371
     * using their default convert_to_html option.
372
     *
373
     * @return Array All field values in their HTML representation indexed by their name.
374
     */
375
    function get_content_html()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
376
    {
377
        if (is_null($this->formmanager))
378
        {
379
            $this->formmanager = new midcom_helper_datamanager2_formmanager($this->schema, $this->types);
380
            $this->formmanager->initialize();
381
        }
382
383
        $result = Array();
384
        foreach ($this->schema->field_order as $name)
385
        {
386
            if ($this->_schema_field_is_broken($name))
387
            {
388
                continue;
389
            }
390
            if (empty($this->formmanager->widgets[$name]))
391
            {
392
                //This field seems to be hidden, i.e. DM has not loaded the widget
393
                $result[$name] = $this->types[$name]->convert_to_html();
394
            }
395
            else
396
            {
397
                $this->formmanager->widgets[$name]->_type = $this->types[$name];
398
                $result[$name] = $this->formmanager->widgets[$name]->render_content();
399
            }
400
        }
401
        return $result;
402
    }
403
404
    /**
405
     * Little helper function returning an associative array of all field values converted to XML
406
     * using their default convert_to_csv or convert_to_raw options.
407
     *
408
     * @return Array All field values in their XML representation indexed by their name.
409
     */
410
    function get_content_xml()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
411
    {
412
        $result = Array();
413
        foreach ($this->schema->field_order as $name)
414
        {
415
            if ($this->_schema_field_is_broken($name))
416
            {
417
                continue;
418
            }
419
            if (is_a($this->types[$name], 'midcom_helper_datamanager2_type_blobs'))
420
            {
421
                $result[$name] = explode(',', $this->types[$name]->convert_to_csv());
422
            }
423
            elseif (is_a($this->types[$name], 'midcom_helper_datamanager2_type_select'))
424
            {
425
                $this->types[$name]->csv_export_key = true;
426
                $this->types[$name]->multiple_storagemode = 'array';
427
                $result[$name] = $this->types[$name]->convert_to_storage();
428
            }
429
            else
430
            {
431
                $result[$name] = $this->types[$name]->convert_to_storage();
432
            }
433
        }
434
        return $result;
435
    }
436
437
    /**
438
     * Little helper function returning an associative array of all field values converted to CSV
439
     * using their default convert_to_csv option.
440
     *
441
     * @return Array All field values in their CSV representation indexed by their name.
442
     */
443 View Code Duplication
    function get_content_csv()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
444
    {
445
        $result = Array();
446
        foreach ($this->schema->field_order as $name)
447
        {
448
            if ($this->_schema_field_is_broken($name))
449
            {
450
                continue;
451
            }
452
            $result[$name] = $this->types[$name]->convert_to_csv();
453
        }
454
        return $result;
455
    }
456
457
    /**
458
     * Little helper function returning an associative array of all field values converted to email-friendly format
459
     * using their default convert_to_email option.
460
     *
461
     * @return Array All field values in their CSV representation indexed by their name.
462
     */
463 View Code Duplication
    function get_content_email()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
464
    {
465
        $result = Array();
466
        foreach ($this->schema->field_order as $name)
467
        {
468
            if ($this->_schema_field_is_broken($name))
469
            {
470
                continue;
471
            }
472
            $result[$name] = $this->types[$name]->convert_to_email();
473
        }
474
        return $result;
475
    }
476
477
    /**
478
     * Get all field values converted to their raw storage representation
479
     *
480
     * @return Array All field values in their raw storage representation indexed by their name.
481
     */
482 View Code Duplication
    function get_content_raw()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
483
    {
484
        $result = Array();
485
        foreach ($this->schema->field_order as $name)
486
        {
487
            if ($this->_schema_field_is_broken($name))
488
            {
489
                continue;
490
            }
491
            $result[$name] = $this->types[$name]->convert_to_raw();
492
        }
493
        return $result;
494
    }
495
496
    /**
497
     * This function displays a quick view of the record, using some simple div based layout,
498
     * which can be formatted using CSS.
499
     *
500
     * Be aware that this is only geared for simple administration interfaces, it will provide
501
     * *no* editing capabilities (like AJAX) etc. If you want that to work, you need a formmanger
502
     * instance instead.
503
     *
504
     * @param boolean $skip_empty Should empty fields be rendered or not
505
     */
506
    function display_view($skip_empty = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
507
    {
508
        $values = $this->get_content_html();
509
        // iterate over all types so that they can add their piece to the form
510
        echo "<div class=\"midcom_helper_datamanager2_view\">\n";
511
        $fieldset_count = 0;
512
        foreach ($this->schema->field_order as $name)
513
        {
514
            $config =& $this->schema->fields[$name];
515
            if (!empty($config['hidden']))
516
            {
517
                continue;
518
            }
519
520
            if (isset($config['start_fieldset']))
521
            {
522 View Code Duplication
                if (isset($config['start_fieldset']['title']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
523
                {
524
                    $fieldsets = array();
525
                    $fieldsets[] = $config['start_fieldset'];
526
                }
527
                else
528
                {
529
                    $fieldsets = $config['start_fieldset'];
530
                }
531
                foreach ($fieldsets as $fieldset)
532
                {
533
                    if (isset($fieldset['css_group']))
534
                    {
535
                        $class = $fieldset['css_group'];
536
                    }
537
                    else
538
                    {
539
                        $class = $name;
540
                    }
541
                }
542
                echo "<div class=\"fieldset {$class}\">\n";
0 ignored issues
show
Bug introduced by
The variable $class does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
543
                if (isset($fieldset['title']))
544
                {
545 View Code Duplication
                    if (isset($fieldset['css_title']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
546
                    {
547
                        $class = " class=\"{$fieldset['css_title']}\"";
548
                    }
549
                    else
550
                    {
551
                        $class = " class=\"{$name}\"";
552
                    }
553
554
                    echo "    <h2{$class}>\n";
555
                    echo "        ". $this->schema->translate_schema_string($fieldset['title']) ."\n";
556
                    echo "    </h2>\n";
557
                }
558
                if (isset($fieldset['description']))
559
                {
560
                    echo "<p>". $this->schema->translate_schema_string($fieldset['description']) . "</p>\n";
561
                }
562
                $fieldset_count++;
563
            }
564
565
            $field_value = $values[$name];
566
            if (   !$skip_empty
567
                || trim($field_value) !== '')
568
            {
569
                echo "<div class=\"field\">\n";
570
                echo '<div class="title">' . $this->schema->translate_schema_string($this->schema->fields[$name]['title']) . "</div>\n";
571
                echo '<div class="value">';
572
573
                echo $field_value;
574
575
                echo "</div>\n";
576
                echo "</div>\n";
577
            }
578
579
            if (   !isset($config['end_fieldset'])
580
                || $fieldset_count <= 0)
581
            {
582
                // No more fieldsets to close
583
                continue;
584
            }
585
586
            if (is_numeric($config['end_fieldset']))
587
            {
588
                for ($i = 0; $i < $config['end_fieldset']; $i++)
589
                {
590
                    echo "</div>\n";
591
                    $fieldset_count--;
592
593
                    if ($fieldset_count <= 0)
594
                    {
595
                        break;
596
                    }
597
                }
598
            }
599
            else
600
            {
601
                echo "</div>\n";
602
                $fieldset_count--;
603
            }
604
        }
605
        echo "</div>\n";
606
    }
607
}
608