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