recursivelyBuildConfigurationDefaults()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 12
cts 12
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 4
nop 2
crap 4
1
<?php
2
3
namespace Habu\ComposerScriptUtils\Configuration;
4
5
use Habu\ComposerScriptUtils\Interfaces\ConfigurationInterface;
6
use Habu\ComposerScriptUtils\Interfaces\ConfigurationHandlerInterface;
7
8
/**
9
 * Class AbstractConfiguration.
10
 *
11
 * @author Ruben Knol <[email protected]>
12
 */
13
abstract class AbstractConfiguration implements ConfigurationInterface
14
{
15
    /**
16
     * @const string
17
     */
18
    const EXTRAS_KEY = 'extras';
19
20
    /**
21
     * @var array
22
     */
23
    private $configs;
24
25
    /**
26
     * @var array
27
     */
28
    private $defaults;
29
30
    /**
31
     * AbstractConfiguration constructor.
32
     *
33
     * @param array $configs
34
     */
35 11
    public function __construct(array $configs)
36
    {
37 11
        $this->configs = $configs;
38 11
        $this->defaults = $this->buildConfigurationDefaults(self::EXTRAS_KEY);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->buildConfiguratio...aults(self::EXTRAS_KEY) can also be of type object<Habu\ComposerScri...rationHandlerInterface>. However, the property $defaults is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
39 11
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44 3
    public function get($key)
45
    {
46 3
        $val = $this->getConfigValue($key);
47 3
        $default = $this->getDefault($key);
48
49 3
        if (is_null($default)) {
50 1
            throw new \InvalidArgumentException(sprintf('Configuration key %s is not defined in the defaults', $key));
51
        }
52
53 2
        return $default->get($val);
54
    }
55
56
    /**
57
     * Compile configuration defaults.
58
     *
59
     * @param string $key
60
     *
61
     * @return array
62
     */
63 11
    private function buildConfigurationDefaults($key)
64
    {
65 11
        $defaults = $this->getConfigurationDefaults();
66
67 11
        return $this->recursivelyBuildConfigurationDefaults($key, $defaults);
68
    }
69
70
    /**
71
     * Recursively build and validate our configuration defaults.
72
     *
73
     * @param string $key
74
     * @param mixed $value
75
     *
76
     * @return array
77
     */
78 11
    private function recursivelyBuildConfigurationDefaults($key, $value)
79
    {
80 11
        $data = [];
81
82 11
        if (is_array($value)) {
83 11
            foreach ($value as $k => $v) {
84 9
                $data[$k] = $this->recursivelyBuildConfigurationDefaults($key . '.' . $k, $v);
85 11
            }
86 11
        } else {
87 9
            if (!$value instanceof ConfigurationHandlerInterface) {
88 1
                throw new \InvalidArgumentException(sprintf('Default configuration parameter %s is not an instance of AbstractHandler.', $key));
89
            }
90
91 8
            $value->setKey($key);
92 8
            $data = $value;
93
        }
94
95 11
        return $data;
96
    }
97
98
    /**
99
     *Retrieve a value by dot-notated key from a multi-dimensional array.
100
     *
101
     * @param string $key
102
     * @param array $arr
103
     *
104
     * @return mixed
105
     */
106 6
    private function getNodeByKey($key, $arr)
107
    {
108 6
        $key = explode('.', $key);
109
110 6
        $ref = $arr;
111
112 6
        foreach ($key as $part) {
113 6
            if (!isset($ref[$part])) {
114 3
                return null;
115
            } else {
116 5
                $ref = $ref[$part];
117
            }
118 5
        }
119
120 5
        return $ref;
121
    }
122
123
    /**
124
     * Retrieve a value by dot-notated key from our configuration array.
125
     *
126
     * @param string $key
127
     * @return mixed
128
     */
129 4
    private function getConfigValue($key)
130
    {
131 4
        return $this->getNodeByKey($key, $this->configs);
132
    }
133
134
    /**
135
     * Retrieve a value by dot-notated key from our defaults array.
136
     *
137
     * @param string $key
138
     * @return mixed
139
     */
140 4
    private function getDefault($key)
141
    {
142 4
        return $this->getNodeByKey($key, $this->defaults);
143
    }
144
145
    /**
146
     * Define the configuration defaults.
147
     * You must implement this in your concrete implementation class.
148
     *
149
     * @return mixed
150
     */
151
    abstract protected function getConfigurationDefaults();
152
}
153