Completed
Push — master ( 431e36...3578ad )
by Alex
24s queued 20s
created

AbstractStepAction::stepName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the PierstovalCharacterManagerBundle package.
7
 *
8
 * (c) Alexandre Rock Ancelet <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Pierstoval\Bundle\CharacterManagerBundle\Action;
15
16
use Doctrine\Common\Persistence\ObjectManager;
17
use Pierstoval\Bundle\CharacterManagerBundle\Model\CharacterInterface;
18
use Pierstoval\Bundle\CharacterManagerBundle\Model\StepInterface;
19
use Pierstoval\Bundle\CharacterManagerBundle\Resolver\StepResolverInterface;
20
use Symfony\Component\HttpFoundation\RedirectResponse;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\Session\Session;
23
use Symfony\Component\Routing\RouterInterface;
24
use Symfony\Contracts\Translation\TranslatorInterface;
25
use Twig\Environment;
26
27
abstract class AbstractStepAction implements StepActionInterface
28
{
29
    /**
30
     * Used when you need to change the translation domain used in controller-generated messages.
31
     */
32
    protected static $translationDomain = 'PierstovalCharacterBundle';
33
34
    /** @var string */
35
    protected $class;
36
37
    /** @var Request */
38
    protected $request;
39
40
    /** @var StepInterface */
41
    protected $step;
42
43
    /** @var StepInterface[] */
44
    protected $steps = [];
45
46
    /** @var string */
47
    protected $stepName;
48
49
    /** @var string */
50
    protected $managerName;
51
52
    /** @var RouterInterface */
53
    protected $router;
54
55
    /** @var ObjectManager */
56
    protected $em;
57
58
    /** @var Environment */
59
    protected $twig;
60
61
    /** @var TranslatorInterface */
62
    protected $translator;
63
64
    private $configured = false;
65
66
    public function configure(string $managerName, string $stepName, string $characterClassName, StepResolverInterface $resolver): void
67
    {
68
        if ($this->configured) {
69
            throw new \RuntimeException('Cannot reconfigure an already configured step action.');
70
        }
71
72
        if (!\class_exists($characterClassName) || !\is_subclass_of($characterClassName, CharacterInterface::class, true)) {
73
            throw new \InvalidArgumentException(\sprintf(
74
                'Step action must be a valid class implementing %s. "%s" given.',
75
                CharacterInterface::class,
76
                \class_exists($characterClassName) ? $characterClassName : \gettype($characterClassName)
77
            ));
78
        }
79
80
        $this->class = $characterClassName;
81
        $this->managerName = $managerName;
82
        $this->step = $resolver->resolve($stepName, $managerName);
83
        $this->setSteps($resolver->getManagerSteps($managerName));
84
85
        $this->configured = true;
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91
    public function setRequest(Request $request): void
92
    {
93
        $this->request = $request;
94
    }
95
96
    public function setRouter(RouterInterface $router): void
97
    {
98
        $this->router = $router;
99
    }
100
101
    public function setObjectManager(ObjectManager $em): void
102
    {
103
        $this->em = $em;
104
    }
105
106
    public function setTwig(Environment $twig): void
107
    {
108
        $this->twig = $twig;
109
    }
110
111
    public function setTranslator(TranslatorInterface $translator): void
112
    {
113
        $this->translator = $translator;
114
    }
115
116
    public function getStep(): StepInterface
117
    {
118
        if (!$this->step) {
119
            throw new \RuntimeException('Step is not defined in current step action. Did you run the "configure()" method?');
120
        }
121
122
        return $this->step;
123
    }
124
125
    public function stepName(): string
126
    {
127
        return $this->step->getName();
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133
    protected function getCurrentCharacter(): array
134
    {
135
        return $this->getSession()->get('character.'.$this->managerName, []) ?: [];
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    protected function getCharacterProperty(string $key = null)
142
    {
143
        if (null === $key) {
144
            $key = $this->getStep()->getName();
145
        }
146
147
        $character = $this->getCurrentCharacter();
148
149
        return $character[$key] ?? null;
150
    }
151
152
    protected function nextStep(): RedirectResponse
153
    {
154
        return $this->goToStep($this->getStep()->getNumber() + 1);
155
    }
156
157
    /**
158
     * Redirects to a specific step and updates the session.
159
     */
160
    protected function goToStep(int $stepNumber): RedirectResponse
161
    {
162
        if (!$this->router) {
163
            throw new \InvalidArgumentException('Cannot use '.__METHOD__.' if no router is injected in AbstractStepAction.');
164
        }
165
166
        foreach ($this->steps as $step) {
167
            if ($step->getNumber() === $stepNumber) {
168
                $this->getSession()->set('step.'.$this->managerName, $stepNumber);
169
170
                return new RedirectResponse($this->router->generate('pierstoval_character_generator_step', ['requestStep' => $step->getName()]));
171
            }
172
        }
173
174
        throw new \InvalidArgumentException('Invalid step: '.$stepNumber);
175
    }
176
177
    protected function updateCharacterStep($value): void
178
    {
179
        $character = $this->getCurrentCharacter();
180
181
        $character[$this->getStep()->getName()] = $value;
182
183
        foreach ($this->getStep()->getOnchangeClear() as $stepToDisable) {
184
            unset($character[$stepToDisable]);
185
        }
186
187
        $this->getSession()->set('step.'.$this->managerName, $this->getStep()->getNumber());
188
        $this->getSession()->set('character.'.$this->managerName, $character);
189
    }
190
191
    /**
192
     * Adds a new flash message.
193
     */
194
    protected function flashMessage(string $msg, string $type = null, array $msgParams = []): self
195
    {
196
        // Allows not knowing about the default type in the method signature.
197
        if (null === $type) {
198
            $type = 'error';
199
        }
200
201
        $msg = $this->translator
202
            ? $this->translator->trans($msg, $msgParams, static::$translationDomain)
203
            : \strtr($msg, $msgParams)
204
        ;
205
206
        $flashbag = $this->getSession()->getFlashBag();
207
208
        // Add the message manually.
209
        $existingMessages = $flashbag->peek($type);
210
        $existingMessages[] = $msg;
211
212
        // And avoid having the same message multiple times.
213
        $flashbag->set($type, \array_unique($existingMessages));
214
215
        return $this;
216
    }
217
218
    protected function getRequest(): Request
219
    {
220
        if (!$this->request) {
221
            throw new \RuntimeException('Request is not set in step action.');
222
        }
223
224
        return $this->request;
225
    }
226
227
    protected function getSession(): Session
228
    {
229
        $session = $this->getRequest()->getSession();
230
231
        if (!($session instanceof Session)) {
232
            throw new \RuntimeException('The session must be available to manage characters. Did you forget to enable the session in the framework?');
233
        }
234
235
        return $session;
236
    }
237
238
    /**
239
     * {@inheritdoc}
240
     */
241
    private function setSteps(array $steps): void
242
    {
243
        foreach ($steps as $step) {
244 View Code Duplication
            if (!$step instanceof StepInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
245
                throw new \InvalidArgumentException(\sprintf(
246
                    'Expected %s instance, "%s" given.',
247
                    StepActionInterface::class,
248
                    \is_object($step) ? \get_class($step) : \gettype($step)
249
                ));
250
            }
251
        }
252
253
        $this->steps = $steps;
254
    }
255
}
256