Completed
Push — master ( 46d475...98d04a )
by Raffael
01:48
created

Environment::variablesToTree()   C

Complexity

Conditions 8
Paths 4

Size

Total Lines 42
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 24
nc 4
nop 1
1
<?php
2
declare(strict_types = 1);
3
4
/**
5
 * Micro
6
 *
7
 * @author    Fabian Jucker <[email protected]>
8
 * @copyright Copyright (c) 2017 gyselroth GmbH (https://gyselroth.com)
9
 * @license   MIT https://opensource.org/licenses/MIT
10
 */
11
12
namespace Micro\Config;
13
14
use \Micro\Config;
15
16
class Environment implements ConfigInterface
17
{
18
    /**
19
     * DELIMITER
20
     *
21
     * @var string
22
     */
23
    const DEFAULT_DELIMITER = '_';
24
25
26
    /**
27
     * Store
28
     *
29
     * @var Config
30
     */
31
    private $store;
32
33
34
    /**
35
     * Variable delimiter
36
     *
37
     * @var string
38
     */
39
    protected $delimiter = self::DEFAULT_DELIMITER;
40
41
42
    /**
43
     * Variable prefix
44
     *
45
     * @var string
46
     */
47
    protected $prefix;
48
49
50
    /**
51
     * Load config
52
     *
53
     * @param  string $prefix
54
     * @param  string $delimiter
55
     * @param  array $variables
56
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
57
     */
58
    public function __construct(?string $prefix=null, $delimiter=self::DEFAULT_DELIMITER, array $variables=[])
59
    {
60
        $this->delimiter = $delimiter;
61
        $this->prefix = strtolower($prefix);
62
63
        if(count($variables) === 0) {
64
            $this->store = $this->variablesToTree(array_merge($_ENV, $_SERVER));
65
        } else {
66
            $this->store = $this->variablesToTree($variables);
67
        }
68
   }
69
70
71
    /**
72
     * Get from config
73
     *
74
     * @param   string $name
75
     * @return  mixed
76
     */
77
    public function __get(string $name)
78
    {
79
        return $this->store->{$name};
80
    }
81
82
83
    /**
84
     * Return map
85
     *
86
     * @return  Config
87
     */
88
    public function map(): Config
89
    {
90
        return $this->store;
91
    }
92
93
94
    /**
95
     * Transform array of environment variables into a tree
96
     *
97
     * @param   array $variables
98
     * @return  Config
99
     */
100
    protected function variablesToTree(array $variables): Config
101
    {
102
        $variables = array_change_key_case($variables);
103
104
        $root = new Config();
105
        foreach ($variables as $name => $value) {
106
            $name = explode($this->delimiter, $name);
107
108
            if($this->prefix !== null) {
109
                if($name[0] !== $this->prefix) {
110
                    continue;
111
                } else {
112
                    array_shift($name);
113
                }
114
            }
115
116
            $tree = $root;
117
118
119
            for ($i = 0; $i < count($name); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
120
                $key = $name[$i];
121
122
                try {
123
                  // create new subtree if requested subtree already has a value
124
                  if (!($tree->$key instanceof Config)) {
125
                      $tree[$key] = new Config([$tree->$key]);
0 ignored issues
show
Documentation introduced by
array($tree->{$key}) is of type array<integer,?,{"0":"?"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
126
                  }
127
128
                  $tree = $tree->$key;
129
                } catch (Exception $e) {
130
                    // set value if last keypart or create subtree
131
                    if($i == (count($name) - 1)) {
132
                        $tree[$key] = $value;
133
                    } else {
134
                        $tree[$key] = new Config();
135
                        $tree = $tree->$key;
136
                    }
137
                }
138
            }
139
        }
140
        return $root;
141
    }
142
}
143