Completed
Push — master ( c4e600...6d356d )
by Ben
02:25
created

AbstractFormatterProvider::formats()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 0
loc 18
rs 8.8571
cc 5
eloc 11
nc 5
nop 0
1
<?php
2
3
namespace Benrowe\Formatter;
4
5
use ReflectionClass;
6
use ReflectionMethod;
7
use InvalidArgumentException;
8
9
/**
10
 * AbstractFormatterProvider
11
 *
12
 * Base level functionality for any FormatterProvider that wants to implement
13
 * the standard formatting convention of `public function asFormatType($value)`
14
 *
15
 * @package Benrowe\Formatter
16
 */
17
abstract class AbstractFormatterProvider implements FormatterProvider
18
{
19
    protected $defaultFormatter;
20
    /**
21
     * method prefix
22
     */
23
    const METHOD_PATTERN_MATCH = '/^as([A-Z]\w+)$/';
24
25
    public $nullValue = '<span>Not Set</span>';
26
27
    /**
28
     * Provide a list of formatters this that are available from this provider
29
     *
30
     * @return array
31
     */
32
    public function formats()
33
    {
34
        // get a list of all public non-static methods that start with
35
        // METHOD_PREFIX
36
        $reflect = new ReflectionClass($this);
37
        $formats = [];
38
        foreach ($reflect->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
39
            $isFormatter =
40
                !$method->isStatic() &&
41
                preg_match(self::METHOD_PATTERN_MATCH, $method->getName(), $match);
42
            if (!$isFormatter || !$match) {
0 ignored issues
show
Bug introduced by
The variable $match 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...
Bug Best Practice introduced by
The expression $match of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
43
                continue;
44
            }
45
            $formats[] = strtolower($match[1]);
46
        }
47
48
        return $formats;
49
    }
50
51
    /**
52
     * Combine the value & params
53
     * @param  mixed $value  the value (first argument of the format method)
54
     * @param  string|array $format the name of the formatter, or an array of
55
     *                              the formatter and its addtional params
56
     * @return array of two elements, format and the params for the formatter
57
     *                  method
58
     * @throws InvalidArgumentException if the format is incorrect
59
     */
60
    protected function extractFormatAndParams($value, $format)
61
    {
62
        $params = [$value];
63
64
        if (is_array($format)) {
65
            if (!isset($format[0])) {
66
                throw new InvalidArgumentException(
67
                    'The $format must contain at least one element'
68
                );
69
            }
70
            $params = $format;
71
            $format = array_shift($params);
72
            array_unshift($params, $value);
73
        }
74
75
        return [$format, $params];
76
    }
77
78
    /**
79
     * Format the supplied value, based on the desired format + configuration
80
     *
81
     * @param  mixed $value The value to format
82
     * @param  string|array|null $format either the formatter name, or the formatter
83
     *                              config as an array. If it's an array, the
84
     *                              first item must be the same of the formatter
85
     * @return mixed
86
     * @throws InvalidArgumentException if the format is incorrect
87
     */
88
    public function format($value, $format = null)
89
    {
90
        $format = $format ?: $this->defaultFormatter;
91
92
        list($format, $params) = $this->extractFormatAndParams($value, $format);
93
94
        if (!$this->hasFormat($format)) {
95
            throw new InvalidArgumentException(
96
                'Unknown format: "' . $format . '"'
97
            );
98
        }
99
100
        // is the formatter in a custom defined
101
102
        $func = [$this, 'as'.$format];
103
104
        return call_user_func_array($func, $params);
105
    }
106
107
    /**
108
     * Check if the requested format exists in this provider
109
     *
110
     * @param  string  $format The formatter name you want to check for
111
     * @return boolean
112
     */
113
    public function hasFormat($format)
114
    {
115
        if (!preg_match("/^[A-Za-z]+$/", $format)) {
116
            throw new InvalidArgumentException(
117
                'Format "' . $format . '" is not provided in correct format'
118
            );
119
        }
120
        $formats = $this->formats();
121
122
        return in_array($format, $formats);
123
    }
124
}
125