Completed
Push — master ( f4a302...e32202 )
by Alex
03:22
created

AbstractStepAction::flashMessage()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
cc 3
eloc 11
nc 4
nop 3
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\Component\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_a($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
    /**
115
     * {@inheritdoc}
116
     */
117
    protected function getCurrentCharacter(): array
118
    {
119
        return $this->getSession()->get('character.'.$this->managerName, []) ?: [];
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125
    protected function getCharacterProperty(string $key = null)
126
    {
127
        if (null === $key) {
128
            $key = $this->getStep()->getName();
129
        }
130
131
        $character = $this->getCurrentCharacter();
132
133
        return $character[$key] ?? null;
134
    }
135
136
    /**
137
     * @return RedirectResponse
138
     */
139
    protected function nextStep(): RedirectResponse
140
    {
141
        return $this->goToStep($this->getStep()->getNumber() + 1);
142
    }
143
144
    /**
145
     * Redirects to a specific step and updates the session.
146
     *
147
     * @param int $stepNumber
148
     *
149
     * @return RedirectResponse
150
     */
151
    protected function goToStep(int $stepNumber): RedirectResponse
152
    {
153
        if (!$this->router) {
154
            throw new \InvalidArgumentException('Cannot use '.__METHOD__.' if no router is injected in AbstractStepAction.');
155
        }
156
157
        foreach ($this->steps as $step) {
158
            if ($step->getNumber() === $stepNumber) {
159
                $this->getSession()->set('step.'.$this->managerName, $stepNumber);
160
161
                return new RedirectResponse($this->router->generate('pierstoval_character_generator_step', ['requestStep' => $step->getName()]));
162
            }
163
        }
164
165
        throw new \InvalidArgumentException('Invalid step: '.$stepNumber);
166
    }
167
168
    /**
169
     * @param mixed $value
170
     */
171
    protected function updateCharacterStep($value): void
172
    {
173
        $character = $this->getCurrentCharacter();
174
175
        $character[$this->getStep()->getName()] = $value;
176
177
        foreach ($this->getStep()->getOnchangeClear() as $stepToDisable) {
178
            unset($character[$stepToDisable]);
179
        }
180
181
        $this->getSession()->set('step.'.$this->managerName, $this->getStep()->getNumber());
182
        $this->getSession()->set('character.'.$this->managerName, $character);
183
    }
184
185
    /**
186
     * Adds a new flash message.
187
     */
188
    protected function flashMessage(string $msg, string $type = null, array $msgParams = []): self
189
    {
190
        // Allows not knowing about the default type in the method signature.
191
        if (null === $type) {
192
            $type = 'error';
193
        }
194
195
        $msg = $this->translator
196
            ? $this->translator->trans($msg, $msgParams, static::$translationDomain)
197
            : strtr($msg, $msgParams)
198
        ;
199
200
        $flashbag = $this->getSession()->getFlashBag();
201
202
        // Add the message manually.
203
        $existingMessages = $flashbag->peek($type);
204
        $existingMessages[] = $msg;
205
206
        // And avoid having the same message multiple times.
207
        $flashbag->set($type, array_unique($existingMessages));
208
209
        return $this;
210
    }
211
212
    protected function getRequest(): Request
213
    {
214
        if (!$this->request) {
215
            throw new \RuntimeException('Request is not set in step action.');
216
        }
217
218
        return $this->request;
219
    }
220
221
    protected function getSession(): Session
222
    {
223
        $session = $this->getRequest()->getSession();
224
225
        if (!($session instanceof Session)) {
226
            throw new \RuntimeException('The session must be available to manage characters. Did you forget to enable the session in the framework?');
227
        }
228
229
        return $session;
230
    }
231
232
    /**
233
     * {@inheritdoc}
234
     */
235
    private function setSteps(array $steps): void
236
    {
237
        foreach ($steps as $step) {
238
            if (!$step instanceof StepInterface) {
239
                throw new \InvalidArgumentException(sprintf(
240
                    'Expected %s instance, "%s" given.',
241
                    StepActionInterface::class, \is_object($step) ? \get_class($step) : \gettype($step)
242
                ));
243
            }
244
        }
245
246
        $this->steps = $steps;
247
    }
248
}
249