Completed
Push — locale-in-url ( f95194...93251b )
by Kamil
21:02
created

FlashHelper::addSuccessFlash()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 17
nc 4
nop 3
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
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 Sylius\Bundle\ResourceBundle\Controller;
13
14
use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent;
15
use Sylius\Component\Resource\Model\ResourceInterface;
16
use Symfony\Component\HttpFoundation\Session\SessionInterface;
17
use Symfony\Component\Translation\TranslatorBagInterface;
18
use Symfony\Component\Translation\TranslatorInterface;
19
20
/**
21
 * @author Paweł Jędrzejewski <[email protected]>
22
 * @author Jan Góralski <[email protected]>
23
 */
24
final class FlashHelper implements FlashHelperInterface
25
{
26
    /**
27
     * @var SessionInterface
28
     */
29
    private $session;
30
31
    /**
32
     * @var TranslatorInterface
33
     */
34
    private $translator;
35
36
    /**
37
     * @var string
38
     */
39
    private $defaultLocale;
40
41
    /**
42
     * @param SessionInterface $session
43
     * @param TranslatorInterface $translator
44
     * @param string $defaultLocale
45
     */
46
    public function __construct(SessionInterface $session, TranslatorInterface $translator, $defaultLocale)
47
    {
48
        $this->session = $session;
49
        $this->translator = $translator;
50
        $this->defaultLocale = $defaultLocale;
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function addSuccessFlash(RequestConfiguration $requestConfiguration, $actionName, ResourceInterface $resource = null)
57
    {
58
        $metadata = $requestConfiguration->getMetadata();
59
        $metadataName = ucfirst($metadata->getHumanizedName());
60
        $parameters = ['%resource%' => $metadataName];
61
62
        $message = $requestConfiguration->getFlashMessage($actionName);
63
        if (false === $message) {
64
            return;
65
        }
66
67
        if ($this->isTranslationDefined($message, $this->defaultLocale, $parameters)) {
68
            if (!$this->translator instanceof TranslatorBagInterface) {
69
                $this->addFlash('success', $message, $parameters);
70
71
                return;
72
            }
73
74
            $this->addFlash('success', $message);
75
76
            return;
77
        }
78
79
        $this->addFlash(
80
            'success',
81
            $this->getResourceMessage($actionName),
82
            $parameters
83
        );
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89
    public function addFlashFromEvent(RequestConfiguration $requestConfiguration, ResourceControllerEvent $event)
90
    {
91
        $this->addFlash($event->getMessageType(), $event->getMessage(), $event->getMessageParameters());
92
    }
93
94
    /**
95
     * @param string $type
96
     * @param string $message
97
     * @param array $parameters
98
     */
99
    private function addFlash($type, $message, array $parameters = [])
100
    {
101
        if (!empty($parameters)) {
102
            $message = $this->prepareMessage($message, $parameters);
103
        }
104
105
        $this->session->getBag('flashes')->add($type, $message);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\HttpFo...ion\SessionBagInterface as the method add() does only exist in the following implementations of said interface: Symfony\Component\HttpFo...lash\AutoExpireFlashBag, Symfony\Component\HttpFo...\Session\Flash\FlashBag.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
106
    }
107
108
    /**
109
     * @param string $message
110
     * @param array $parameters
111
     *
112
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
113
     */
114
    private function prepareMessage($message, array $parameters)
115
    {
116
        return [
117
            'message' => $message,
118
            'parameters' => $parameters,
119
        ];
120
    }
121
122
    /**
123
     * @param string $actionName
124
     *
125
     * @return string
126
     */
127
    private function getResourceMessage($actionName)
128
    {
129
        return sprintf('sylius.resource.%s', $actionName);
130
    }
131
132
    /**
133
     * @param string $message
134
     * @param string $locale
135
     * @param array $parameters
136
     *
137
     * @return bool
138
     */
139
    private function isTranslationDefined($message, $locale, array $parameters)
140
    {
141
        if ($this->translator instanceof TranslatorBagInterface) {
142
            $defaultCatalogue = $this->translator->getCatalogue($locale);
143
144
            return $defaultCatalogue->has($message, 'flashes');
145
        }
146
147
        return $message !== $this->translator->trans($message, $parameters,'flashes');
148
    }
149
}
150