AbstractDataBuilder::buildDependency()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
nc 2
nop 3
dl 0
loc 8
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
5
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
6
 */
7
8
namespace Spryker\Shared\Testify;
9
10
use Faker\Factory;
11
use Spryker\Shared\Kernel\Transfer\AbstractTransfer;
12
use Spryker\Shared\Testify\Exception\DependencyNotDefinedException;
13
use Spryker\Shared\Testify\Exception\FieldNotDefinedException;
14
use Spryker\Shared\Testify\Exception\RuleNotDefinedException;
15
16
abstract class AbstractDataBuilder
17
{
18
    /**
19
     * @var \Faker\Generator
20
     */
21
    protected static $faker;
22
23
    /**
24
     * @var array<string, string>
25
     */
26
    protected $defaultRules = [];
27
28
    /**
29
     * @var array<string, string>
30
     */
31
    protected $rules = [];
32
33
    /**
34
     * @var array<string, string>
35
     */
36
    protected $dependencies = [];
37
38
    /**
39
     * @var array<mixed>
40
     */
41
    protected $nestedBuilders = [];
42
43
    /**
44
     * @var array<string, mixed>
45
     */
46
    protected $seedData = [];
47
48
    /**
49
     * @return \Spryker\Shared\Kernel\Transfer\AbstractTransfer
50
     */
51
    abstract protected function getTransfer();
52
53
    /**
54
     * @param string $builder
55
     *
56
     * @throws \Exception
57
     *
58
     * @return \Spryker\Shared\Testify\AbstractDataBuilder
59
     */
60
    abstract protected function locateDataBuilder($builder);
61
62
    /**
63
     * @param array<string, mixed> $seed
64
     */
65
    public function __construct($seed = [])
66
    {
67
        $this->seedData = $seed;
68
        $this->rules = $this->defaultRules;
69
70
        if (static::$faker === null) {
71
            static::$faker = Factory::create();
72
        }
73
    }
74
75
    /**
76
     * Removes all rules
77
     *
78
     * @return $this
79
     */
80
    public function makeEmpty()
81
    {
82
        $this->rules = [];
83
84
        return $this;
85
    }
86
87
    /**
88
     * @return $this
89
     */
90
    public function resetData()
91
    {
92
        $this->seedData = [];
93
94
        return $this;
95
    }
96
97
    /**
98
     * @param array<string, mixed> $seed
99
     *
100
     * @return $this
101
     */
102
    public function seed(array $seed = [])
103
    {
104
        $this->seedData += $seed;
105
106
        return $this;
107
    }
108
109
    /**
110
     * @param array<string>|string $rules
111
     *
112
     * @throws \Spryker\Shared\Testify\Exception\RuleNotDefinedException
113
     *
114
     * @return $this
115
     */
116
    public function with($rules)
117
    {
118
        if (!is_array($rules)) {
119
            $rules = [];
120
        }
121
        foreach ($rules as $rule) {
122
            if (!isset($this->defaultRules[$rule])) {
123
                throw new RuleNotDefinedException(sprintf('No rule for "%s" defined', $rule));
124
            }
125
            $this->rules[$rule] = $this->defaultRules[$rule];
126
        }
127
128
        return $this;
129
    }
130
131
    /**
132
     * @param array<string>|string $rules
133
     *
134
     * @return $this
135
     */
136
    public function except($rules)
137
    {
138
        if (!is_array($rules)) {
139
            $rules = [];
140
        }
141
        foreach ($rules as $rule) {
142
            unset($this->rules[$rule]);
143
        }
144
145
        return $this;
146
    }
147
148
    /**
149
     * @return \Spryker\Shared\Kernel\Transfer\AbstractTransfer
150
     */
151
    public function build()
152
    {
153
        $seedData = array_merge($this->generateFields(), $this->seedData);
154
        $transfer = $this->getTransfer()->fromArray($seedData, true);
155
156
        if ($this->nestedBuilders !== []) {
157
            $this->generateDependencies($transfer);
158
        }
159
160
        return $transfer;
161
    }
162
163
    /**
164
     * @return array<bool|string>
165
     */
166
    protected function generateFields()
167
    {
168
        $data = [];
169
        foreach ($this->rules as $field => $rule) {
170
            $data[$field] = $this->generateFromRule($rule);
171
        }
172
173
        return $data;
174
    }
175
176
    /**
177
     * @param string $field
178
     * @param array<string, mixed> $override
179
     * @param bool $randomize
180
     *
181
     * @throws \Spryker\Shared\Testify\Exception\FieldNotDefinedException
182
     *
183
     * @return void
184
     */
185
    protected function buildDependency($field, $override = [], $randomize = false)
186
    {
187
        if (!isset($this->dependencies[$field])) {
188
            throw new FieldNotDefinedException(sprintf('Field "%s" not defined in dependencies list', $field));
189
        }
190
        $builder = $this->locateDataBuilder($this->dependencies[$field]);
191
        $builder->seed($override);
192
        $this->addDependencyBuilder($field, $builder, $randomize);
193
    }
194
195
    /**
196
     * @param string $field
197
     * @param \Spryker\Shared\Testify\AbstractDataBuilder $builder
198
     * @param bool $randomize
199
     *
200
     * @return void
201
     */
202
    protected function addDependencyBuilder($field, $builder, $randomize)
203
    {
204
        $this->nestedBuilders[] = [$field, $builder, $randomize];
205
    }
206
207
    /**
208
     * @param \Spryker\Shared\Kernel\Transfer\AbstractTransfer $transfer
209
     *
210
     * @throws \Spryker\Shared\Testify\Exception\DependencyNotDefinedException
211
     *
212
     * @return void
213
     */
214
    protected function generateDependencies(AbstractTransfer $transfer)
215
    {
216
        foreach ($this->nestedBuilders as $builderInfo) {
217
            [$name, $dependencyBuilder, $randomize] = $builderInfo;
218
219
            if (!$randomize) {
220
                $parentSeedData = $this->seedData[$name] ?? [];
221
                $parentSeedData = $parentSeedData instanceof AbstractTransfer ? $parentSeedData->toArray() : $parentSeedData;
222
                $dependencySeedData = array_merge($dependencyBuilder->getSeedData(), $parentSeedData);
223
224
                $dependencyBuilder->seed($dependencySeedData);
225
            }
226
227
            $nestedTransfer = $dependencyBuilder->build();
228
229
            if (method_exists($transfer, 'add' . $name)) {
230
                /** @var callable $callable */
231
                $callable = [$transfer, 'add' . $name];
232
                call_user_func($callable, $nestedTransfer);
233
234
                continue;
235
            }
236
237
            if (method_exists($transfer, 'set' . $name)) {
238
                /** @var callable $callable */
239
                $callable = [$transfer, 'set' . $name];
240
                call_user_func($callable, $nestedTransfer);
241
242
                continue;
243
            }
244
245
            throw new DependencyNotDefinedException(sprintf('Dependency "%s" not defined in "%s"', $name, static::class));
246
        }
247
    }
248
249
    /**
250
     * @SuppressWarning(PHPMD.EvalSniff)
251
     *
252
     * @param string $rule
253
     *
254
     * @return string|bool
255
     */
256
    protected function generateFromRule($rule)
257
    {
258
        if (strpos($rule, '=') === 0) {
259
            return substr($rule, 1);
260
        }
261
262
        // @codingStandardsIgnoreStart
263
        if (strpos($rule, '(') !== false) {
264
            return eval("return static::\$faker->$rule;");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
265
        }
266
        return eval("return static::\$faker->$rule();");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
267
        // @codingStandardsIgnoreEnd
268
    }
269
270
    /**
271
     * @return array<string, mixed>
272
     */
273
    public function getSeedData()
274
    {
275
        return $this->seedData;
276
    }
277
}
278