Resolver::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 5
rs 9.4286
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
/*
3
 * This file is part of the Borobudur-DependencyInjection package.
4
 *
5
 * (c) Hexacodelabs <http://hexacodelabs.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Borobudur\DependencyInjection\ParameterBag;
12
13
use Borobudur\DependencyInjection\Exception\InvalidArgumentException;
14
use Borobudur\DependencyInjection\Exception\ParameterNotFoundException;
15
use Borobudur\DependencyInjection\ParameterBag;
16
17
/**
18
 * @author      Iqbal Maulana <[email protected]>
19
 * @created     8/8/15
20
 */
21
class Resolver
22
{
23
    /**
24
     * @var bool
25
     */
26
    private $resolved;
27
28
    /**
29
     * @var ParameterBagInterface
30
     */
31
    private $parameter;
32
33
    /**
34
     * Constructor.
35
     *
36
     * @param ParameterBagInterface $parameter
37
     * @param bool                  $resolved
38
     */
39
    public function __construct(ParameterBagInterface $parameter, $resolved = false)
40
    {
41
        $this->parameter = $parameter;
42
        $this->resolved = (bool) $resolved;
43
    }
44
45
    /**
46
     * Normalize (escape / unescape) value.
47
     *
48
     * @param mixed $value
49
     * @param array $search
50
     * @param array $replace
51
     * @param array $callback
52
     *
53
     * @return array|mixed
54
     */
55
    private static function normalizeValue($value, $search, $replace, array $callback)
56
    {
57
        if (is_string($value)) {
58
            return str_replace($search, $replace, $value);
59
        }
60
61
        if (is_array($value)) {
62
            return array_map($callback, $value);
63
        }
64
65
        return $value;
66
    }
67
68
    /**
69
     * Resolve parameters.
70
     */
71
    public function resolve()
72
    {
73
        if (true === $this->resolved) {
74
            return;
75
        }
76
77
        $parameters = array();
78
        foreach ($this->parameter->all() as $name => $value) {
79
            try {
80
                $name = $this->resolveString($name);
81
                $value = $this->resolveValue($value);
82
                $parameters[$name] = $this->unescapeValue($value);
83
            } catch (ParameterNotFoundException $e) {
84
                $e->setSource($name);
85
86
                throw $e;
87
            }
88
        }
89
90
        $this->parameter->replace($parameters);
91
        $this->resolved = true;
92
    }
93
94
    /**
95
     * Resolve parameter placeholders by their values.
96
     *
97
     * @param mixed $value
98
     *
99
     * @return array|mixed
100
     */
101
    public function resolveValue($value)
102
    {
103
        if (is_array($value)) {
104
            $parameters = array();
105
            foreach ($value as $name => $val) {
106
                $name = $this->resolveString($name);
107
                $parameters[$name] = $this->resolveValue($val);
108
            }
109
110
            return $parameters;
111
        }
112
113
        if (!is_string($value)) {
114
            return $value;
115
        }
116
117
        return $this->resolveString($value);
118
    }
119
120
    /**
121
     * Resolve parameter inside string.
122
     *
123
     * @param string $value
124
     *
125
     * @return mixed
126
     */
127
    public function resolveString($value)
128
    {
129
        if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
130
            return $this->parameter->get(strtolower($match[1]));
131
        }
132
133
        return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($value) {
134
            if (!isset($match[1])) {
135
                return '%%';
136
            }
137
138
            return $this->resolveString($this->computeStringParameter($match[1], $value));
139
        }, $value);
140
    }
141
142
    /**
143
     * Check if parameter has been resolved.
144
     *
145
     * @return bool
146
     */
147
    public function isResolved()
148
    {
149
        return $this->resolved;
150
    }
151
152
    /**
153
     * Escape parameter value.
154
     *
155
     * @param mixed $value
156
     *
157
     * @return array|mixed
158
     */
159
    public function escapeValue($value)
160
    {
161
        return self::normalizeValue($value, array('%', '@'), array('%%', '@@'), array($this, 'escapeValue'));
162
    }
163
164
    /**
165
     * Un-escape parameter value.
166
     *
167
     * @param mixed $value
168
     *
169
     * @return array|mixed
170
     */
171
    public function unescapeValue($value)
172
    {
173
        return self::normalizeValue($value, array('%%', '@@'), array('%', '@'), array($this, 'unescapeValue'));
174
    }
175
176
    /**
177
     * Compute string parameter.
178
     *
179
     * @param mixed $name
180
     * @param mixed $value
181
     *
182
     * @return string
183
     */
184
    private function computeStringParameter($name, $value)
185
    {
186
        $name = strtolower($name);
187
        $resolved = $this->parameter->get($name);
188
189
        // Only scalar type can be used in string value.
190
        if (!is_scalar($resolved)) {
191
            throw new InvalidArgumentException(sprintf(
192
                'Parameter "%s" cannot use type %s inside string value "%s".',
193
                $name,
194
                gettype($resolved),
195
                $value
196
            ));
197
        }
198
199
        return (string) $resolved;
200
    }
201
}
202