Completed
Branch develop (598d0f)
by Benjamin
03:23
created

RuleConfigBuilder::prepareInducementTable()   B

Complexity

Conditions 7
Paths 24

Size

Total Lines 28
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 20
c 1
b 0
f 0
nc 24
nop 2
dl 0
loc 28
rs 8.6666
1
<?php
2
3
namespace Obblm\Core\Helper\Rule;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Doctrine\Common\Collections\Criteria;
7
use Doctrine\Common\Collections\Expr\CompositeExpression;
8
use Obblm\Core\Contracts\InducementInterface;
9
use Obblm\Core\Contracts\RosterInterface;
10
use Obblm\Core\Contracts\Rule\RuleBuilderInterface;
11
use Obblm\Core\Entity\Team;
12
use Obblm\Core\Exception\NotFoundRuleKeyExcepion;
13
use Obblm\Core\Helper\CoreTranslation;
14
use Obblm\Core\Helper\Rule\Config\ConfigResolver;
15
use Obblm\Core\Helper\Rule\Config\RuleConfigResolver;
16
use Obblm\Core\Helper\Rule\Inducement\Inducement;
17
use Obblm\Core\Helper\Rule\Inducement\InducementType;
18
use Obblm\Core\Helper\Rule\Inducement\MultipleStarPlayer;
19
use Obblm\Core\Helper\Rule\Inducement\StarPlayer;
20
use Obblm\Core\Helper\Rule\Roster\Roster;
21
use Obblm\Core\Helper\Rule\Skill\Skill;
22
23
class RuleConfigBuilder extends RuleConfigResolver implements RuleBuilderInterface
24
{
25
    /** @var ArrayCollection */
26
    private $injuries;
27
    /** @var ArrayCollection|Skill[] */
28
    private $skills;
29
    /** @var ArrayCollection|InducementType[] */
30
    private $inducement_types;
31
    /** @var ArrayCollection */
32
    private $spp_levels;
33
    /** @var ArrayCollection|InducementInterface[] */
34
    private $inducements;
35
    /** @var ArrayCollection|RosterInterface[] */
36
    private $rosters;
37
38
    protected function build(string $rule_key, array $rule) {
39
40
        $treeResolver = new ConfigResolver($this);
41
        $rule = $treeResolver->resolve($rule);
42
        $this->prepareInjuriesTable($rule_key, $rule);
43
        $this->prepareSppTable($rule_key, $rule);
44
        $this->prepareSkillsTable($rule_key, $rule);
45
        $this->prepareInducementTypes($rule_key, $rule);
46
        $this->prepareInducementTable($rule_key, $rule);
47
        $this->prepareRosterTable($rule_key, $rule);
48
    }
49
50
    public function getInjuries():ArrayCollection
51
    {
52
        return $this->injuries;
53
    }
54
55
    public function setInjuries(ArrayCollection $injuries):self
56
    {
57
        $this->injuries = $injuries;
58
        return $this;
59
    }
60
61
    public function getInducementTypes():ArrayCollection
62
    {
63
        return $this->inducement_types;
64
    }
65
66
    public function setInducementTypes(ArrayCollection $inducement_types):self
67
    {
68
        $this->inducement_types = $inducement_types;
69
        return $this;
70
    }
71
72
    public function getSppLevels():ArrayCollection
73
    {
74
        return $this->spp_levels;
75
    }
76
77
    public function setSppLevels(ArrayCollection $spp_levels):self
78
    {
79
        $this->spp_levels = $spp_levels;
80
        return $this;
81
    }
82
83
    public function getInducementTable():ArrayCollection
84
    {
85
        return $this->inducements;
86
    }
87
88
    public function setInducementTable(ArrayCollection $inducements):self
89
    {
90
        $this->inducements = $inducements;
91
        return $this;
92
    }
93
94
    public function getRosters():ArrayCollection
95
    {
96
        return $this->rosters;
97
    }
98
99
    public function setRosters(ArrayCollection $rosters):self
100
    {
101
        $this->rosters = $rosters;
102
        return $this;
103
    }
104
105
    public function getSkills():ArrayCollection
106
    {
107
        return $this->skills;
108
    }
109
110
    public function setSkills(ArrayCollection $skills):self
111
    {
112
        $this->skills = $skills;
113
        return $this;
114
    }
115
116
    private function prepareInjuriesTable(string $rule_key, array $rule)
117
    {
118
        $this->injuries = new ArrayCollection();
119
        foreach ($rule['injuries'] as $key => $injury) {
120
            $label = CoreTranslation::getInjuryKey($rule_key, $key);
121
            $effect_label = CoreTranslation::getInjuryEffect($rule_key, $key);
122
            if (isset($injury['to'])) {
123
                for ($i = $injury['from']; $i <= $injury['to']; $i++) {
124
                    $this->injuries->set(
125
                        $i,
126
                        (object) ['value' => $i, 'label' => $label, 'effect_label' => $effect_label, 'effects' => $injury['effects']]
127
                    );
128
                }
129
            } else {
130
                $this->injuries->set(
131
                    $injury['from'],
132
                    (object) ['value' => $injury['from'], 'label' => $label, 'effect_label' => $effect_label, 'effects' => $injury['effects']]
133
                );
134
            }
135
        }
136
    }
137
138
    private function prepareInducementTypes(string $rule_key, array $rule)
139
    {
140
        $this->inducement_types = new ArrayCollection();
141
        $this->inducement_types->set('star_players', new InducementType([
142
            'key' => 'star_players',
143
            'translation_key' => CoreTranslation::getStarPlayerTitle($rule_key),
144
            'translation_domain' => $rule_key,
145
        ]));
146
        $this->inducement_types->set('inducements', new InducementType([
147
            'key' => 'inducements',
148
            'translation_key' => CoreTranslation::getInducementTitle($rule_key),
149
            'translation_domain' => $rule_key,
150
        ]));
151
        $this->inducement_types->set('mercenary', new InducementType([
152
            'key' => 'mercenary',
153
            'translation_key' => CoreTranslation::getMercenaryTitle($rule_key),
154
            'translation_domain' => $rule_key,
155
        ]));
156
    }
157
158
    private function prepareSppTable(string $rule_key, array $rule)
159
    {
160
        $spps = new ArrayCollection($rule['spp_levels']);
161
        foreach ($spps as $from => $level) {
162
            $to = $spps->next();
163
            if ($to) {
164
                for ($i = $from; $i < $spps->indexOf($to); $i++) {
165
                    if (!isset($spps[$i])) {
166
                        $spps[$i] = $level;
167
                    }
168
                }
169
            }
170
        }
171
        $spps = $spps->toArray();
172
        ksort($spps);
173
        $this->spp_levels = new ArrayCollection($spps);
174
    }
175
176
    private function prepareSkillsTable(string $rule_key, array $rule)
177
    {
178
        $this->skills = new ArrayCollection();
179
        foreach ($rule['skills'] as $type => $skills) {
180
            foreach ($skills as $skill) {
181
                $key = join(CoreTranslation::TRANSLATION_GLUE, [$type, $skill]);
182
                $this->skills->set(
183
                    $key,
184
                    new Skill([
185
                        'key' => $skill,
186
                        'type' => $type,
187
                        'translation_key' => CoreTranslation::getSkillNameKey($rule_key, $skill),
188
                        'type_translation_key' => CoreTranslation::getSkillType($rule_key, $type),
189
                        'translation_domain' => $rule_key,
190
                    ])
191
                );
192
            }
193
        }
194
    }
195
196
    private function prepareInducementTable(string $rule_key, array $rule)
197
    {
198
        $this->inducements = new ArrayCollection();
199
200
        foreach ($rule['inducements'] as $key => $value) {
201
            if ($key !== 'star_players') {
202
                $inducement = new Inducement([
203
                    'type' => $this->inducement_types['inducements'],
204
                    'key' => join(CoreTranslation::TRANSLATION_GLUE, [$rule_key, 'inducements', $key]),
205
                    'translation_domain' => $rule_key,
206
                    'translation_key' => CoreTranslation::getInducementName($rule_key, $key),
207
                    'max' => $value['max'] ?? 0,
208
                    'rosters' => $value['rosters'] ?? null,
209
                    'value' => $value['cost'],
210
                    'discount_cost' => $value['discount_cost'] ?? null,
211
                ]);
212
                if (!$this->inducements->contains($inducement)) {
213
                    $this->inducements->add($inducement);
214
                }
215
            }
216
        }
217
        foreach ($rule['star_players'] as $key => $star_player) {
218
            try {
219
                $inducement = $this->createStarPlayerInducement($rule_key, $key, $star_player);
220
                if (!$this->inducements->contains($inducement)) {
221
                    $this->inducements->add($inducement);
222
                }
223
            } catch (NotFoundRuleKeyExcepion $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
224
            }
225
        }
226
    }
227
228
    private function prepareRosterTable(string $rule_key, array $rule)
229
    {
230
        $this->rosters = new ArrayCollection();
231
        foreach ($rule['rosters'] as $key => $roster) {
232
            $this->rosters->set(
233
                $key,
234
                new Roster([
235
                    'key' => $key,
236
                    'translation_key' => CoreTranslation::getRosterKey($rule_key, $key),
237
                    'translation_domain' => $rule_key,
238
                    'player_types' => $roster['players'],
239
                    'reroll_cost' => $roster['reroll_cost'] ?? 0,
240
                    'can_have_apothecary' => $roster['options']['can_have_apothecary'] ?? true,
241
                    'inducement_options' => $roster['options']['inducements'] ?? [],
242
                ])
243
            );
244
        }
245
    }
246
247
    private function createStarPlayerInducement(string $rule_key, string $key, array $star_player):InducementInterface
248
    {
249
        $options = [
250
            'type' => $this->inducement_types['star_players'],
251
            'key' => join(CoreTranslation::TRANSLATION_GLUE, [$rule_key, 'star_players', $key]),
252
            'value' => $star_player['cost'],
253
            'discount_cost' => $value['discount_cost'] ?? null,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $value seems to never exist and therefore isset should always be false.
Loading history...
254
            'characteristics' => $star_player['characteristics'] ?? null,
255
            'skills' => $star_player['skills'] ?? null,
256
            'rosters' => $star_player['rosters'] ?? null,
257
            'translation_domain' => $rule_key,
258
            'translation_key' => CoreTranslation::getStarPlayerName($rule_key, $key),
259
            'max' => $options['max'] ?? 1,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $options seems to never exist and therefore isset should always be false.
Loading history...
260
        ];
261
        if (isset($star_player['multi_parts']) && $star_player['multi_parts']) {
262
            $options['parts'] = [];
263
            $first = true;
264
            foreach ($star_player['multi_parts'] as $key => $part) {
265
                $part['cost'] = $first ? $star_player['cost'] : 0;
266
                $options['parts'][] = $this->createStarPlayerInducement($rule_key, $key, $part);
267
                $first = false;
268
            }
269
            $inducement = new MultipleStarPlayer($options);
270
        } else {
271
            $inducement = new StarPlayer($options);
272
        }
273
        return $inducement;
274
    }
275
276
    protected function getInducementExpression($options = ['type' => 'inducements']):CompositeExpression
277
    {
278
        $sub_expressions = [];
279
        if (isset($options['type'])) {
280
            // Criteria by inducement type
281
            if (is_array($options['type'])) {
282
                $types = [];
283
                foreach ($options['type'] as $type) {
284
                    if (is_string($type)) {
285
                        $inducementType = $this->getInducementType($type);
0 ignored issues
show
Bug introduced by
The method getInducementType() does not exist on Obblm\Core\Helper\Rule\RuleConfigBuilder. Did you maybe mean getInducementTypes()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

285
                        /** @scrutinizer ignore-call */ 
286
                        $inducementType = $this->getInducementType($type);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
286
                        $types[] = Criteria::expr()->eq('type', $inducementType);
287
                    }
288
                }
289
                $sub_expressions['type'] = new CompositeExpression(CompositeExpression::TYPE_OR, $types);
290
                ;
291
            } elseif (is_string($options['type'])) {
292
                $inducementType = $this->getInducementType($options['type']);
293
                $sub_expressions['type'] = Criteria::expr()->eq('type', $inducementType);
294
            }
295
        }
296
        if (isset($options['cost_limit'])) {
297
            // Criteria by cost limit
298
            if (is_int($options['cost_limit'])) {
299
                $sub_expressions['cost'] = Criteria::expr()->lte('value', $options['cost_limit']);
300
            }
301
        }
302
        if (isset($options['roster'])) {
303
            // Criteria by roster
304
            if (is_string($options['roster'])) {
305
                $sub_expressions['roster'] = Criteria::expr()->orX(
306
                    Criteria::expr()->memberOf('rosters', $options['roster']),
307
                    Criteria::expr()->eq('rosters', [])
308
                );
309
            }
310
        }
311
        $composite = new CompositeExpression(CompositeExpression::TYPE_AND, $sub_expressions);
312
        return $composite;
313
    }
314
315
    public function getInducementsFor(Team $team, ?int $budget = null):array
316
    {
317
        $criteria = Criteria::create();
318
        $expr = [
319
            'type' => [
320
                'inducements',
321
                'star_players'
322
            ],
323
            'roster' => $team->getRoster()
324
        ];
325
        if ($budget !== null) {
326
            $expr['cost_limit'] = $budget;
327
        }
328
        $criteria->where(Criteria::expr()->andX(
329
            $this->getInducementExpression($expr)
330
        ));
331
        $available_inducements = $this->getInducements()->matching($criteria);
0 ignored issues
show
Bug introduced by
The method getInducements() does not exist on Obblm\Core\Helper\Rule\RuleConfigBuilder. Did you maybe mean getInducementsFor()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

331
        $available_inducements = $this->/** @scrutinizer ignore-call */ getInducements()->matching($criteria);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
332
        return $available_inducements->toArray();
333
    }
334
335
    public function getAllStarPlayers():array
336
    {
337
        $criteria = Criteria::create();
338
339
        $criteria->where(Criteria::expr()->andX(
340
            $this->getInducementExpression([
341
                'type' => 'star_players'
342
            ])
343
        ));
344
        return $this->getInducementTable()->matching($criteria)->toArray();
345
    }
346
}
347