Completed
Push — master ( 5a40d9...1fc46b )
by Andrii
03:05
created

Factory::extractKeys()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 6
rs 10
c 1
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 Money\Parser\DecimalMoneyParser;
16
use Money\Currencies\ISOCurrencies;
17
18
/**
19
 * Generalized entity factory.
20
 *
21
 * @author Andrii Vasyliev <[email protected]>
22
 */
23
class Factory
24
{
25
    private $entities = [];
26
27
    private $factories = [];
28
29
    protected $moneyParser;
30
31
    public function __construct(array $factories)
32
    {
33
        $this->factories = $factories;
34
        $this->moneyParser = new DecimalMoneyParser(new ISOCurrencies());
35
    }
36
37
    public function getMoney($data)
38
    {
39
        return $this->get('money', $data);
40
    }
41
42
    public function parseMoney($str)
43
    {
44
        [$amount, $currency] = explode(' ', $str);
45
46
        return [
47
            'amount' => $amount,
48
            'currency' => $currency,
49
        ];
50
    }
51
52
    public function createMoney($data)
53
    {
54
        return $this->moneyParser->parse($data['amount'], $data['currency']);
55
    }
56
57
    public function getCurrency($data)
58
    {
59
        return new Currency($data);
60
    }
61
62
    public function getQuantity($data)
63
    {
64
        return $this->get('quantity', $data);
65
    }
66
67
    public function parseQuantity($str)
68
    {
69
        [$quantity, $unit] = explode(' ', $str);
70
71
        return [
72
            'quantity' => $quantity,
73
            'unit' => $unit,
74
        ];
75
    }
76
77
    public function createQuantity($data)
78
    {
79
        return Quantity::create($data['unit'], $data['quantity']);
80
    }
81
82
83
    public function getType($data)
84
    {
85
        return $this->get('type', $data);
86
    }
87
88
    public function getTarget($data)
89
    {
90
        return $this->get('target', $data);
91
    }
92
93
    public function getPlan($data)
94
    {
95
        return $this->get('plan', $data);
96
    }
97
98
    public function getCustomer($data)
99
    {
100
        return $this->get('customer', $data);
101
    }
102
103
    public function get(string $entity, $data)
104
    {
105
        if (is_scalar($data)) {
106
            $data = $this->parse($entity, $data);
107
        }
108
109
        $keys = $this->extractKeys($entity, $data);
110
111
        $res = $this->find($entity, $keys) ?: $this->create($entity, $data);
112
113
        foreach ($keys as $key) {
114
            $this->entities[$entity][$key] = $res;
115
        }
116
117
        return $res;
118
    }
119
120
    public function parse(string $entity, $str)
121
    {
122
        $method = $this->getMethod($entity, 'parse');
123
124
        return $method ? $this->{$method}($str) : $this->parseByUnique($entity, $str);
125
    }
126
127
    public function parseByUnique(string $entity, $str)
128
    {
129
        $keys = $this->getEntityUniqueKeys($entity);
130
        if (count($keys) === 1) {
131
            return [reset($keys) => $str];
132
        }
133
134
        return ['id' => $str];
135
    }
136
137
    public function find(string $entity, array $keys)
138
    {
139
        foreach ($keys as $key) {
140
            if (!empty($this->entities[$entity][$key])) {
141
                return $this->entities[$entity][$key];
142
            }
143
        }
144
145
        return null;
146
    }
147
148
    public function create(string $entity, $data)
149
    {
150
        $method = $this->getMethod($entity, 'create');
151
        if ($method) {
152
            return $this->{$method}($data);
153
        }
154
155
        if (empty($this->factories[$entity])) {
156
            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...
157
        }
158
159
        $factory = $this->factories[$entity];
160
161
        return $factory->create($this->createDto($entity, $data));
162
    }
163
164
    public function createDto(string $entity, array $data)
165
    {
166
        $class = $this->getDtoClass($entity);
167
        $dto = new $class();
168
169
        foreach ($data as $key => $value) {
170
            $dto->{$key} = $this->prepareValue($entity, $key, $value);
171
        }
172
173
        return $dto;
174
    }
175
176
    public function getDtoClass(string $entity)
177
    {
178
        return $this->getEntityClass($entity) . 'CreationDto';
179
    }
180
181
    public function prepareValue($entity, $key, $value)
182
    {
183
        $method = $this->getPrepareMethod($entity, $key);
184
185
        return $method ? $this->{$method}($value) : $value;
186
    }
187
188
    private function getMethod(string $entity, string $op)
189
    {
190
        $method = $op . ucfirst($entity);
191
192
        return method_exists($this, $method) ? $method : null;
193
    }
194
195
    private function getPrepareMethod(string $entity, string $key)
196
    {
197
        switch ($key) {
198
            case 'seller':
199
                return 'getCustomer';
200
            case 'plan':
201
                return 'getPlan';
202
            case 'type':
203
                return 'getType';
204
            case 'target':
205
                return 'getTarget';
206
            case 'price':
207
                return 'getMoney';
208
            case 'currency':
209
                return 'getCurrency';
210
            case 'prepaid':
211
                return 'getQuantity';
212
        }
213
214
        return null;
215
    }
216
217
    public function getEntityClass(string $entity)
218
    {
219
        $parts = explode('\\', __NAMESPACE__);
220
        array_pop($parts);
221
        $parts[] = $entity;
222
        $parts[] = ucfirst($entity);
223
224
        return implode('\\', $parts);
225
    }
226
227
    public function extractKeys(string $entity, $data)
228
    {
229
        $id = $data['id'] ?? null;
230
        $unique = $this->extractUnique($entity, $data);
231
232
        return array_filter(['id' => $id, 'unique' => $unique]);
233
    }
234
235
    public function extractUnique(string $entity, $data)
236
    {
237
        $keys = $this->getEntityUniqueKeys($entity);
238
        if (empty($keys)) {
239
            return null;
240
        }
241
242
        $values = [];
243
        foreach ($keys as $key) {
244
            if (empty($data[$key])) {
245
                return null;
246
            }
247
            $values[$key] = $data[$key];
248
        }
249
250
        return implode(' ', $values);
251
    }
252
253
    public function getEntityUniqueKeys(string $entity): array
254
    {
255
        switch ($entity) {
256
            case 'customer':
257
                return ['login'];
258
            case 'type':
259
                return ['name'];
260
            case 'plan':
261
                return ['name', 'seller'];
262
            case 'price':
263
                return [];
264
            case 'target':
265
                return ['type', 'name'];
266
            case 'money':
267
                return ['amount', 'currency'];
268
            case 'quantity':
269
                return ['quantity', 'unit'];
270
        }
271
272
        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...
273
    }
274
}
275