Completed
Branch master (44f723)
by Michael
11:35 queued 08:26
created

ZervWizard::getFirstIncompleteStep()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 15
rs 9.2
cc 4
eloc 8
nc 3
nop 0
1
<?php
2
/**
3
 *  Copyright 2005 Zervaas Enterprises (www.zervaas.com.au)
4
 *
5
 *  Licensed under the Apache License, Version 2.0 (the "License");
6
 *  you may not use this file except in compliance with the License.
7
 *  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 *  Unless required by applicable law or agreed to in writing, software
12
 *  distributed under the License is distributed on an "AS IS" BASIS,
13
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 *  See the License for the specific language governing permissions and
15
 *  limitations under the License.
16
 */
17
18
/**
19
 * ZervWizard
20
 *
21
 * A class to manage multi-step forms or wizards. This involves managing
22
 * the various steps, storing its values and switching between each
23
 * step
24
 *
25
 * @author  Quentin Zervaas
26
 */
27
class ZervWizard
0 ignored issues
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...
28
{
29
    // whether or not all steps of the form are complete
30
    public $_complete = false;
31
32
    // internal array to store the various steps
33
    public $_steps = array();
34
35
    // the current step
36
    public $_currentStep = null;
37
38
    // the prefix of the container key where form values are stored
39
    public $_containerPrefix = '__wiz_';
40
41
    // an array of any errors that have occurred
42
    public $_errors = array();
43
44
    // key in container where step status is stored
45
    public $_step_status_key = '__step_complete';
46
47
    // key in container where expected action is stored
48
    public $_step_expected_key = '__expected_action';
49
50
    // options to use for the wizard
51
    public $options = array('redirectAfterPost' => true);
52
53
    // action that resets the container
54
    public $resetAction = '__reset';
55
56
    /**
57
     * ZervWizard
58
     *
59
     * Constructor. Primarily sets up the container
60
     *
61
     * @param array  &$container Reference to container array
62
     * @param string $name       A unique name for the wizard for container storage
63
     */
64
    public function __construct($container, $name)
65
    {
66
        if (!is_array($container)) {
67
            $this->addError('container', 'Container not valid');
68
69
            return;
70
        }
71
72
        $containerKey = $this->_containerPrefix . $name;
73
        if (!array_key_exists($containerKey, $container)) {
74
            $container[$containerKey] = array();
75
        }
76
77
        $this->container = &$container[$containerKey];
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
78
79
        if (!array_key_exists('_errors', $this->container)) {
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
80
            $this->container['_errors'] = array();
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
81
        }
82
        $this->_errors = &$this->container['_errors'];
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
83
    }
84
85
    /**
86
     * process
87
     *
88
     * Processes the form for the specified step. If the processed step
89
     * is complete, then the wizard is set to use the next step. If this
90
     * is the initial call to process, then the wizard is set to use the
91
     * first step. Once the next step is determined, the prepare method
92
     * is called for the step. This has the method name prepare_[step name]()
93
     *
94
     * @todo    Need a way to jump between steps, e.g. from step 2 to 4 and validating all data
95
     *
96
     * @param string $action  The step being processed. This should correspond
97
     *                        to a step created in addStep()
98
     * @param array  &$form   The unmodified form values to process
99
     * @param bool   $process True if the step is being processed, false if being prepared
100
     */
101
    public function process($action, $form, $process = true)
102
    {
103
        if ($action == $this->resetAction) {
104
            $this->clearContainer();
105
            $this->setCurrentStep($this->getFirstIncompleteStep());
106
        } elseif (isset($form['reset'])) {
107
            $this->clearContainer();
108
            $this->setCurrentStep($this->getFirstIncompleteStep());
109
        } elseif (isset($form['previous']) && !$this->isFirstStep()) {
110
            // clear out errors
111
            $this->_errors = array();
112
113
            $this->setCurrentStep($this->getPreviousStep($action));
114
            $this->doRedirect();
115
        } elseif (isset($form['addvalue']) && !$this->isFirstStep()) {
116
            // clear out errors
117
            $this->_errors = array();
118
119
            // processing callback must exist and validate to proceed
120
            $callback = 'process' . $action;
121
            $complete = method_exists($this, $callback) && $this->$callback($form);
122
123
            $this->container[$this->_step_status_key][$action] = $complete;
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
124
            $this->setCurrentStep($action);
125
        } else {
126
            $proceed = false;
127
128
            // check if the step to be processed is valid
129
            if ('' === $action) {
130
                $action = $this->getExpectedStep();
131
            }
132
133
            if ($this->stepCanBeProcessed($action)) {
134
                if ($this->getStepNumber($action) <= $this->getStepNumber($this->getExpectedStep())) {
135
                    $proceed = true;
136
                } else {
137
                    $proceed = false;
138
                }
139
            }
140
141
            if ($proceed) {
142
                if ($process) {
143
                    // clear out errors
144
                    $this->_errors = array();
145
146
                    // processing callback must exist and validate to proceed
147
                    $callback = 'process' . $action;
148
                    $complete = method_exists($this, $callback) && $this->$callback($form);
149
150
                    $this->container[$this->_step_status_key][$action] = $complete;
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
151
152
                    if ($complete) {
153
                        $this->setCurrentStep($this->getFollowingStep($action));
154
                    } // all ok, go to next step
155
                    else {
156
                        $this->setCurrentStep($action);
157
                    } // error occurred, redo step
158
159
                    // final processing once complete
160
                    if ($this->isComplete()) {
161
                        $this->completeCallback();
162
                    }
163
164
                    $this->doRedirect();
165
                } else {
166
                    $this->setCurrentStep($action);
167
                }
168
            } else {
169
                // when initally starting the wizard
170
171
                $this->setCurrentStep($this->getFirstIncompleteStep());
172
            }
173
        }
174
175
        // setup any required data for this step
176
        $callback = 'prepare' . $this->getStepName();
177
        if (method_exists($this, $callback)) {
178
            $this->$callback();
179
        }
180
    }
181
182
    /**
183
     * completeCallback
184
     *
185
     * Function to run once the final step has been processed and is valid.
186
     * This should be overwritten in child classes
187
     */
188
    public function completeCallback()
189
    {
190
    }
191
192
    public function doRedirect()
0 ignored issues
show
Coding Style introduced by
doRedirect uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
193
    {
194
        if ($this->coalesce($this->options['redirectAfterPost'], false)) {
195
            $redir = $_SERVER['REQUEST_URI'];
196
            $redir = preg_replace('/\?' . preg_quote($_SERVER['QUERY_STRING'], '/') . '$/', '', $redir);
197
            header('Location: ' . $redir);
198
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method doRedirect() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
199
        }
200
    }
201
202
    /**
203
     * isComplete
204
     *
205
     * Check if the form is complete. This can only be properly determined
206
     * after process() has been called.
207
     *
208
     * @return bool True if the form is complete and valid, false if not
209
     */
210
    public function isComplete()
211
    {
212
        return $this->_complete;
213
    }
214
215
    /**
216
     * setCurrentStep
217
     *
218
     * Sets the current step in the form. This should generally only be
219
     * called internally but you may have reason to change the current
220
     * step.
221
     *
222
     * @param string $step The step to set as current
223
     */
224
    public function setCurrentStep($step)
225
    {
226
        if (is_null($step) || !$this->stepExists($step)) {
227
            $this->_complete                            = true;
228
            $this->container[$this->_step_expected_key] = null;
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
229
        } else {
230
            $this->_currentStep                         = $step;
231
            $this->container[$this->_step_expected_key] = $step;
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
232
        }
233
    }
234
235
    /**
236
     * @return mixed|null
237
     */
238
    public function getExpectedStep()
239
    {
240
        $step = $this->coalesce($this->container[$this->_step_expected_key], null);
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
241
        if ($this->stepExists($step)) {
242
            return $step;
243
        }
244
245
        return null;
246
    }
247
248
    /**
249
     * stepExists
250
     *
251
     * Check if the given step exists
252
     *
253
     * @param string $stepname The name of the step to check for
254
     *
255
     * @return bool True if the step exists, false if not
256
     */
257
    public function stepExists($stepname)
258
    {
259
        return array_key_exists($stepname, $this->_steps);
260
    }
261
262
    /**
263
     * getStepName
264
     *
265
     * Get the name of the current step
266
     *
267
     * @return string The name of the current step
268
     */
269
    public function getStepName()
270
    {
271
        return $this->_currentStep;
272
    }
273
274
    /**
275
     * getStepNumber
276
     *
277
     * Gets the step number (from 1 to N where N is the number of steps
278
     * in the wizard) of the current step
279
     *
280
     * @param string $step Optional. The step to get the number for. If null then uses current step
0 ignored issues
show
Documentation introduced by
Should the type for parameter $step not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
281
     *
282
     * @return int The number of the step. 0 if something went wrong
283
     */
284
    public function getStepNumber($step = null)
285
    {
286
        $steps    = array_keys($this->_steps);
287
        $numSteps = count($steps);
288
289
        if ('' === $step) {
290
            $step = $this->getStepName();
291
        }
292
293
        $ret = 0;
294
        for ($n = 1; $n <= $numSteps && $ret == 0; ++$n) {
295
            if ($step == $steps[$n - 1]) {
296
                $ret = $n;
297
            }
298
        }
299
300
        return $ret;
301
    }
302
303
    /**
304
     * @param $step
305
     *
306
     * @return bool
307
     */
308
    public function stepCanBeProcessed($step)
309
    {
310
        $steps    = array_keys($this->_steps);
311
        $numSteps = count($steps);
312
313
        for ($i = 0; $i < $numSteps; ++$i) {
314
            $_step = $steps[$i];
315
            if ($_step == $step) {
316
                break;
317
            }
318
319
            if (!$this->container[$this->_step_status_key][$_step]) {
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
320
                return false;
321
            }
322
        }
323
324
        return true;
325
    }
326
327
    /**
328
     * getStepProperty
329
     *
330
     * Retrieve a property for a given step. At this stage, the only
331
     * property steps have is a title property.
332
     *
333
     * @param string $key     The key to get a property for
334
     * @param mixed  $default The value to return if the key isn't found
335
     *
336
     * @return mixed The property value or the default value
337
     */
338
    public function getStepProperty($key, $default = null)
339
    {
340
        $step = $this->getStepName();
341
        if (isset($this->_steps[$step][$key])) {
342
            return $this->_steps[$step][$key];
343
        }
344
345
        return $default;
346
    }
347
348
    /**
349
     * getFirstStep
350
     *
351
     * Get the step name of the first step
352
     *
353
     * @return string The name of the first step, or null if no steps
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
354
     */
355
    public function getFirstStep()
356
    {
357
        $steps = array_keys($this->_steps);
358
359
        return count($steps) > 0 ? $steps[0] : null;
360
    }
361
362
    /**
363
     * @return null
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
364
     */
365
    public function getFirstIncompleteStep()
366
    {
367
        $steps    = array_keys($this->_steps);
368
        $numSteps = count($steps);
369
370
        for ($i = 0; $i < $numSteps; ++$i) {
371
            $_step = $steps[$i];
372
373
            if (!array_key_exists($this->_step_status_key, $this->container) || !$this->container[$this->_step_status_key][$_step]) {
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
374
                return $_step;
375
            }
376
        }
377
378
        return null;
379
    }
380
381
    /**
382
     * getPreviousStep
383
     *
384
     * Gets the step name of the previous step. If the current
385
     * step is the first step, then null is returned
386
     *
387
     * @param $step
388
     *
389
     * @return string The name of the previous step, or null
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
390
     */
391 View Code Duplication
    public function getPreviousStep($step)
0 ignored issues
show
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...
392
    {
393
        $ret   = null;
394
        $steps = array_keys($this->_steps);
395
396
        $done = false;
0 ignored issues
show
Unused Code introduced by
$done is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
397
        foreach ($steps as $s) {
398
            if ($s == $step) {
399
                $done = true;
0 ignored issues
show
Unused Code introduced by
$done is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
400
                break;
401
            }
402
            $ret = $s;
403
        }
404
405
        return $ret;
406
    }
407
408
    /**
409
     * getFollowingStep
410
     *
411
     * Get the step name of the next step. If the current
412
     * step is the last step, returns null
413
     *
414
     * @param $step
415
     *
416
     * @return string The name of the next step, or null
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
417
     */
418 View Code Duplication
    public function getFollowingStep($step)
0 ignored issues
show
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...
419
    {
420
        $ret   = null;
421
        $steps = array_keys($this->_steps);
422
423
        $ready = false;
424
        foreach ($steps as $s) {
425
            if ($s == $step) {
426
                $ready = true;
427
            } else {
428
                if ($ready) {
429
                    $ret = $s;
430
                    break;
431
                }
432
            }
433
        }
434
435
        return $ret;
436
    }
437
438
    /**
439
     * addStep
440
     *
441
     * Adds a step to the wizard
442
     *
443
     * @param string $stepname The name of the step
444
     * @param string $title    The title of the current step
445
     */
446
    public function addStep($stepname, $title)
447
    {
448
        if (array_key_exists($stepname, $this->_steps)) {
449
            $this->addError('step', 'Step with name ' . $stepname . ' already exists');
450
451
            return;
452
        }
453
454
        $this->_steps[$stepname] = array('title' => $title);
455
456
        if (!array_key_exists($this->_step_status_key, $this->container)) {
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
457
            $this->container[$this->_step_status_key] = array();
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
458
        }
459
460
        if (!array_key_exists($stepname, $this->container[$this->_step_status_key])) {
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
461
            $this->container[$this->_step_status_key][$stepname] = false;
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
462
        }
463
    }
464
465
    /**
466
     * isFirstStep
467
     *
468
     * Check if the current step is the first step
469
     *
470
     * @return bool True if the current step is the first step
471
     */
472
    public function isFirstStep()
473
    {
474
        $steps = array_keys($this->_steps);
475
476
        return count($steps) > 0 && $steps[0] == $this->getStepName();
477
    }
478
479
    /**
480
     * isLastStep
481
     *
482
     * Check if the current step is the last step
483
     *
484
     * @return bool True if the current step is the last step
485
     */
486
    public function isLastStep()
487
    {
488
        $steps = array_keys($this->_steps);
489
490
        return count($steps) > 0 && array_pop($steps) == $this->getStepName();
491
    }
492
493
    /**
494
     * setValue
495
     *
496
     * Sets a value in the container
497
     *
498
     * @param string $key The key for the value to set
499
     * @param mixed  $val The value
500
     */
501
    public function setValue($key, $val)
502
    {
503
        $this->container[$key] = $val;
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
504
    }
505
506
    /**
507
     * getValue
508
     *
509
     * Gets a value from the container
510
     *
511
     * @param string $key     The key for the value to get
512
     * @param mixed  $default The value to return if the key doesn't exist
513
     *
514
     * @return mixed Either the key's value or the default value
515
     */
516
    public function getValue($key, $default = null)
517
    {
518
        return $this->coalesce($this->container[$key], $default);
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
519
    }
520
521
    /**
522
     * clearContainer
523
     *
524
     * Removes all data from the container. This is primarily used
525
     * to reset the wizard data completely
526
     */
527
    public function clearContainer()
528
    {
529
        foreach ($this->container as $k => $v) {
0 ignored issues
show
Bug introduced by
The property container does not seem to exist. Did you mean _containerPrefix?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
530
            unset($this->container[$k]);
531
        }
532
    }
533
534
    /**
535
     * coalesce
536
     *
537
     * Initializes a variable, by returning either the variable
538
     * or a default value
539
     *
540
     * @param mixed &$var    The variable to fetch
541
     * @param mixed $default The value to return if variable doesn't exist or is null
542
     *
543
     * @return mixed The variable value or the default value
544
     */
545
    public function coalesce(&$var, $default = null)
546
    {
547
        return isset($var) && !is_null($var) ? $var : $default;
548
    }
549
550
    /**
551
     * addError
552
     *
553
     * Add an error
554
     *
555
     * @param string $key An identifier for the error (e.g. the field name)
556
     * @param string $val An error message
557
     */
558
    public function addError($key, $val)
559
    {
560
        $this->_errors[$key] = $val;
561
    }
562
563
    /**
564
     * isError
565
     *
566
     * Check if an error has occurred
567
     *
568
     * @param string $key The field to check for error. If none specified checks for any error
0 ignored issues
show
Documentation introduced by
Should the type for parameter $key not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
569
     *
570
     * @return bool True if an error has occurred, false if not
571
     */
572
    public function isError($key = null)
573
    {
574
        if (!is_null($key)) {
575
            return array_key_exists($key, $this->_errors);
576
        }
577
578
        return count($this->_errors) > 0;
579
    }
580
581
    /**
582
     * @param $key
583
     *
584
     * @return null
585
     */
586
    public function getError($key)
587
    {
588
        return array_key_exists($key, $this->_errors) ? $this->_errors[$key] : null;
589
    }
590
}
591