LanguageDetector   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 179
rs 10
c 0
b 0
f 0
wmc 22
lcom 1
cbo 3

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 3
A detectAndApply() 0 10 2
A detect() 0 4 2
A getLanguageFromCookie() 0 11 2
A addCookieToQueue() 0 9 2
A useCookies() 0 4 2
A getDriver() 0 4 1
A setDriver() 0 4 1
A apply() 0 10 2
A addCallback() 0 4 1
A applyCallbacks() 0 6 2
A routePrefix() 0 10 2
1
<?php
2
3
namespace Vluzrmos\LanguageDetector;
4
5
use Closure;
6
use Illuminate\Contracts\Translation\Translator as IlluminateTranslator;
7
use Symfony\Component\Translation\TranslatorInterface as SymfonyTranslator;
8
use Vluzrmos\LanguageDetector\Contracts\DetectorDriverInterface as Driver;
9
use Vluzrmos\LanguageDetector\Contracts\LanguageDetectorInterface;
10
use Vluzrmos\LanguageDetector\Contracts\ShouldPrefixRoutesInterface as ShouldPrefixRoute;
11
12
/**
13
 * Class LanguageDetector.
14
 */
15
class LanguageDetector implements LanguageDetectorInterface
16
{
17
    /**
18
     * Translator instance.
19
     * @var SymfonyTranslator|IlluminateTranslator
20
     */
21
    protected $translator;
22
23
    /**
24
     * Driver to detect and apply the language.
25
     * @var Driver
26
     */
27
    protected $driver;
28
29
    /**
30
     * @var array
31
     */
32
    protected $callbacks = [];
33
34
    /**
35
     * Indicates cookie name or false to do not use cookies.
36
     * @var string|false|null
37
     */
38
    protected $cookie;
39
40
    /**
41
     * @param SymfonyTranslator|IlluminateTranslator $translator
42
     * @param Driver     $driver
43
     */
44
    public function __construct($translator, Driver $driver = null)
45
    {
46
        if (!$translator instanceof SymfonyTranslator && !$translator instanceof IlluminateTranslator) {
47
            throw new \InvalidArgumentException("Translator must implement the 'Symfony\\Component\\Translation\\TranslatorInterface' or 'Illuminate\\Contracts\\Translation\\Translator' interface.");
48
        }
49
50
        $this->translator = $translator;
51
        $this->driver = $driver;
52
    }
53
54
    /**
55
     * Detect and apply the detected language.
56
     *
57
     * @return string|null Returns the detected locale or null.
58
     */
59
    public function detectAndApply()
60
    {
61
        $language = $this->detect();
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->detect(); of type string|array adds the type array to the return on line 67 which is incompatible with the return type declared by the interface Vluzrmos\LanguageDetecto...terface::detectAndApply of type string.
Loading history...
62
63
        if ($language) {
64
            $this->apply($language);
0 ignored issues
show
Bug introduced by
It seems like $language defined by $this->detect() on line 61 can also be of type array; however, Vluzrmos\LanguageDetecto...nguageDetector::apply() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
65
        }
66
67
        return $language;
68
    }
69
70
    /**
71
     * Detect the language.
72
     *
73
     * @return string
74
     */
75
    public function detect()
76
    {
77
        return $this->getLanguageFromCookie() ?: $this->getDriver()->detect();
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->getLanguageFromCo...>getDriver()->detect(); of type string|array adds the type array to the return on line 77 which is incompatible with the return type declared by the interface Vluzrmos\LanguageDetecto...tectorInterface::detect of type string.
Loading history...
78
    }
79
80
    /**
81
     * @return string
82
     */
83
    public function getLanguageFromCookie()
84
    {
85
        if ($this->cookie) {
86
            /** @var \Illuminate\Http\Request $request */
87
            $request = $this->getDriver()->getRequest();
88
89
            return $request->cookie($this->cookie);
90
        }
91
92
        return false;
93
    }
94
95
    /**
96
     * Add cookie with locale to queue.
97
     *
98
     * @param string $locale
99
     */
100
    public function addCookieToQueue($locale)
101
    {
102
        if ($this->cookie) {
103
            /** @var \Illuminate\Cookie\CookieJar $cookieJar */
104
            $cookieJar = cookie();
105
106
            $cookieJar->queue($cookieJar->forever($this->cookie, $locale));
107
        }
108
    }
109
110
    /**
111
     * Determine if should use cookies.
112
     * false or null will disable feature, string will set cookie name.
113
     *
114
     * @param string|bool|null $cookieName
115
     */
116
    public function useCookies($cookieName = 'locale')
117
    {
118
        $this->cookie = empty($cookieName) ? false : $cookieName;
0 ignored issues
show
Documentation Bug introduced by
It seems like empty($cookieName) ? false : $cookieName can also be of type boolean. However, the property $cookie is declared as type string|false|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
119
    }
120
121
    /**
122
     * Get the driver.
123
     *
124
     * @return Driver
125
     */
126
    public function getDriver()
127
    {
128
        return $this->driver;
129
    }
130
131
    /**
132
     * Set driver to detect language.
133
     *
134
     * @param Driver $driver
135
     */
136
    public function setDriver(Driver $driver)
137
    {
138
        $this->driver = $driver;
139
    }
140
141
    /**
142
     * Set locale to the application.
143
     *
144
     * @param string $locale
145
     */
146
    public function apply($locale)
147
    {
148
        $this->translator->setLocale($locale);
149
150
        if (!$this->getLanguageFromCookie()) {
151
            $this->addCookieToQueue($locale);
152
        }
153
154
        $this->applyCallbacks($locale);
155
    }
156
157
    /**
158
     * Add a callback to call after applying the detected locale.
159
     * @param Closure $callback
160
     */
161
    public function addCallback(Closure $callback)
162
    {
163
        $this->callbacks[] = $callback;
164
    }
165
166
    /**
167
     * Call all registered callbacks.
168
     *
169
     * @param string $language
170
     */
171
    protected function applyCallbacks($language)
172
    {
173
        foreach ($this->callbacks as $callback) {
174
            call_user_func($callback, $language, $this);
175
        }
176
    }
177
178
    /**
179
     * Get the route prefix.
180
     *
181
     * @return string
182
     */
183
    public function routePrefix()
184
    {
185
        $driver = $this->getDriver();
186
187
        if ($driver instanceof ShouldPrefixRoute) {
188
            return $driver->routePrefix($this->translator->getLocale());
189
        }
190
191
        return '';
192
    }
193
}
194