Passed
Push — master ( 24437a...678089 )
by Andrii
02:55
created

Factory::parseByUnique()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * PHP Billing Library
4
 *
5
 * @link      https://github.com/hiqdev/php-billing
6
 * @package   php-billing
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2017-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\php\billing\tools;
12
13
use Money\Currency;
14
use hiqdev\php\units\Quantity;
15
use hiqdev\php\units\Unit;
16
use Money\Parser\DecimalMoneyParser;
17
use Money\Currencies\ISOCurrencies;
18
19
/**
20
 * Generalized entity factory.
21
 *
22
 * @author Andrii Vasyliev <[email protected]>
23
 */
24
class Factory
25
{
26
    private $entities = [];
27
28
    private $factories = [];
29
30
    protected $moneyParser;
31
32
    public function __construct(array $factories)
33
    {
34
        $this->factories = $factories;
35
        $this->moneyParser = new DecimalMoneyParser(new ISOCurrencies());
36
    }
37
38
    public function getMoney($data)
39
    {
40
        return $this->get('money', $data);
41
    }
42
43
    public function parseMoney($str)
44
    {
45
        [$amount, $currency] = explode(' ', $str);
46
47
        return [
48
            'amount' => $amount,
49
            'currency' => $currency,
50
        ];
51
    }
52
53
    public function createMoney($data)
54
    {
55
        return $this->moneyParser->parse($data['amount'], $data['currency']);
56
    }
57
58
    public function getCurrency($data)
59
    {
60
        return new Currency($data);
61
    }
62
63
    public function getQuantity($data)
64
    {
65
        return $this->get('quantity', $data);
66
    }
67
68
    public function parseQuantity($str)
69
    {
70
        [$quantity, $unit] = explode(' ', $str);
71
72
        return [
73
            'quantity' => $quantity,
74
            'unit' => $unit,
75
        ];
76
    }
77
78
    public function createQuantity($data)
79
    {
80
        return Quantity::create($data['unit'], $data['quantity']);
81
    }
82
83
    public function getUnit($data)
84
    {
85
        return $this->get('unit', $data);
86
    }
87
88
    public function createUnit($data)
89
    {
90
        return Unit::create($data['name']);
91
    }
92
93
    public function getType($data)
94
    {
95
        return $this->get('type', $data);
96
    }
97
98
    public function getTarget($data)
99
    {
100
        return $this->get('target', $data);
101
    }
102
103
    public function getPlan($data)
104
    {
105
        return $this->get('plan', $data);
106
    }
107
108
    public function getCustomer($data)
109
    {
110
        return $this->get('customer', $data);
111
    }
112
113
    public function get(string $entity, $data)
114
    {
115
        if (is_scalar($data)) {
116
            $data = $this->parse($entity, $data);
117
        }
118
119
        $keys = $this->extractKeys($entity, $data);
120
121
        $res = $this->find($entity, $keys) ?: $this->create($entity, $data);
122
123
        foreach ($keys as $key) {
124
            $this->entities[$entity][$key] = $res;
125
        }
126
127
        return $res;
128
    }
129
130
    public function parse(string $entity, $str)
131
    {
132
        $method = $this->getMethod($entity, 'parse');
133
134
        return $method ? $this->{$method}($str) : $this->parseByUnique($entity, $str);
135
    }
136
137
    public function parseByUnique(string $entity, $str)
138
    {
139
        $keys = $this->getEntityUniqueKeys($entity);
140
        if (count($keys) === 1) {
141
            return [reset($keys) => $str];
142
        }
143
144
        return ['id' => $str];
145
    }
146
147
    public function find(string $entity, array $keys)
148
    {
149
        foreach ($keys as $key) {
150
            if (!empty($this->entities[$entity][$key])) {
151
                return $this->entities[$entity][$key];
152
            }
153
        }
154
155
        return null;
156
    }
157
158
    public function create(string $entity, $data)
159
    {
160
        $method = $this->getMethod($entity, 'create');
161
        if ($method) {
162
            return $this->{$method}($data);
163
        }
164
165
        if (empty($this->factories[$entity])) {
166
            throw new FactoryNotFoundException($entity);
0 ignored issues
show
Bug introduced by
The type hiqdev\php\billing\tools\FactoryNotFoundException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
167
        }
168
169
        $factory = $this->factories[$entity];
170
171
        return $factory->create($this->createDto($entity, $data));
172
    }
173
174
    public function createDto(string $entity, array $data)
175
    {
176
        $class = $this->getDtoClass($entity);
177
        $dto = new $class();
178
179
        foreach ($data as $key => $value) {
180
            $dto->{$key} = $this->prepareValue($entity, $key, $value);
181
        }
182
183
        return $dto;
184
    }
185
186
    public function getDtoClass(string $entity)
187
    {
188
        return $this->getEntityClass($entity) . 'CreationDto';
189
    }
190
191
    public function prepareValue($entity, $key, $value)
192
    {
193
        $method = $this->getPrepareMethod($entity, $key);
194
195
        return $method ? $this->{$method}($value) : $value;
196
    }
197
198
    private function getMethod(string $entity, string $op)
199
    {
200
        $method = $op . ucfirst($entity);
201
202
        return method_exists($this, $method) ? $method : null;
203
    }
204
205
    private function getPrepareMethod(string $entity, string $key)
206
    {
207
        switch ($key) {
208
            case 'seller':
209
                return 'getCustomer';
210
            case 'plan':
211
                return 'getPlan';
212
            case 'type':
213
                return 'getType';
214
            case 'target':
215
                return 'getTarget';
216
            case 'price':
217
                return 'getMoney';
218
            case 'currency':
219
                return 'getCurrency';
220
            case 'prepaid':
221
                return 'getQuantity';
222
            case 'unit':
223
                return 'getUnit';
224
        }
225
226
        return null;
227
    }
228
229
    public function getEntityClass(string $entity)
230
    {
231
        $parts = explode('\\', __NAMESPACE__);
232
        array_pop($parts);
233
        $parts[] = $entity;
234
        $parts[] = ucfirst($entity);
235
236
        return implode('\\', $parts);
237
    }
238
239
    public function extractKeys(string $entity, $data)
240
    {
241
        $id = $data['id'] ?? null;
242
        $unique = $this->extractUnique($entity, $data);
243
244
        return array_filter(['id' => $id, 'unique' => $unique]);
245
    }
246
247
    public function extractUnique(string $entity, $data)
248
    {
249
        $keys = $this->getEntityUniqueKeys($entity);
250
        if (empty($keys)) {
251
            return null;
252
        }
253
254
        $values = [];
255
        foreach ($keys as $key) {
256
            if (empty($data[$key])) {
257
                return null;
258
            }
259
            $values[$key] = $data[$key];
260
        }
261
262
        return implode(' ', $values);
263
    }
264
265
    public function getEntityUniqueKeys(string $entity): array
266
    {
267
        switch ($entity) {
268
            case 'customer':
269
                return ['login'];
270
            case 'type':
271
                return ['name'];
272
            case 'plan':
273
                return ['name', 'seller'];
274
            case 'price':
275
                return [];
276
            case 'target':
277
                return ['type', 'name'];
278
            case 'money':
279
                return ['amount', 'currency'];
280
            case 'unit':
281
                return ['name'];
282
            case 'quantity':
283
                return ['quantity', 'unit'];
284
        }
285
286
        throw new UnknownEntityException($entity);
0 ignored issues
show
Bug introduced by
The type hiqdev\php\billing\tools\UnknownEntityException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
287
    }
288
}
289