Completed
Push — master ( ed7dd5...fd34d3 )
by Maxim
15:34
created

ContentTypeDataMatcher::parseContentType()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace Weew\Http;
4
5
use Weew\Http\Data\JsonData;
6
use Weew\Http\Data\UrlEncodedData;
7
use Weew\Http\Exceptions\InvalidDataClassException;
8
9
class ContentTypeDataMatcher implements IContentTypeDataMatcher {
10
    /**
11
     * @var array
12
     */
13
    protected $mappings = [];
14
15
    /**
16
     * ContentTypeDataMatcher constructor.
17
     */
18
    public function __construct() {
19
        $this->registerDefaultMappings();
20
    }
21
22
    /**
23
     * @param IContentHolder $holder
24
     * @param string $contentType
25
     *
26
     * @return IHttpData
27
     */
28
    public function createDataForContentType(IContentHolder $holder, $contentType) {
29
        $parts = $this->parseContentType($contentType);
30
31
        foreach ($parts as $part) {
32
            $class = array_get($this->getMappings(), $part);
33
34
            if ($class !== null) {
35
                break;
36
            }
37
        }
38
39
        if ($class === null) {
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...
40
            $class = $this->getDefaultDataClass();
41
        }
42
43
        return new $class($holder);
44
    }
45
46
    /**
47
     * @return array
48
     */
49
    public function getMappings() {
50
        return $this->mappings;
51
    }
52
53
    /**
54
     * @param array $mappings
55
     *
56
     * @throws InvalidDataClassException
57
     */
58
    public function setMappings(array $mappings) {
59
        $this->mappings = [];
60
61
        foreach ($mappings as $contentType => $dataClass) {
62
            $this->addMapping($contentType, $dataClass);
63
        }
64
    }
65
66
    /**
67
     * @param string $contentType
68
     * @param string $dataClass
69
     *
70
     * @throws InvalidDataClassException
71
     */
72
    public function addMapping($contentType, $dataClass) {
73
        if ( ! class_exists($dataClass)
74
            || ! array_contains(class_implements($dataClass), IHttpData::class)) {
75
            throw new InvalidDataClassException(
76
                s('Class "%s" must implement the "%s" interface.',
77
                    $dataClass, IHttpData::class)
78
            );
79
        }
80
81
        $this->mappings[$contentType] = $dataClass;
82
    }
83
84
    /**
85
     * @param string $contentType
86
     *
87
     * @return array
88
     */
89
    protected function parseContentType($contentType) {
90
        $parts = explode(';', $contentType);
91
92
        foreach ($parts as $key => $value) {
93
            $parts[$key] = trim($value);
94
        }
95
96
        return $parts;
97
    }
98
99
    /**
100
     * @throws InvalidDataClassException
101
     */
102
    protected function registerDefaultMappings() {
103
        $this->addMapping('application/json', JsonData::class);
104
    }
105
106
    /**
107
     * @return string
108
     */
109
    protected function getDefaultDataClass() {
110
        return UrlEncodedData::class;
111
    }
112
}
113