Completed
Push — master ( 19a332...a0a812 )
by Chin
01:02
created

PhpWeekday::getLocale()   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
namespace ChinLeung\PhpWeekday;
4
5
use InvalidArgumentException;
6
7
class PhpWeekday
8
{
9
    /**
10
     * The locale of the application.
11
     *
12
     * @var string
13
     */
14
    protected $locale;
15
16
    /**
17
     * The name of the weekday.
18
     *
19
     * @var string
20
     */
21
    protected $name;
22
23
    /**
24
     * The value of the weekday.
25
     *
26
     * @var int
27
     */
28
    protected $value;
29
30
    /**
31
     * The list of supported locales.
32
     *
33
     * @var array
34
     */
35
    protected static $locales = [];
36
37
    /**
38
     * Constructor of the class.
39
     *
40
     * @param  string|int  $value
41
     * @param  string  $locale
42
     * @param  bool  $force
43
     * @return self
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
44
     */
45
    public function __construct($value, string $locale, bool $force = false)
46
    {
47
        if ($force || $this->hasNotLoadedLocales()) {
48
            static::refreshLocales();
49
        }
50
51
        $this->setLocale($locale)
52
             ->set($value);
53
54
        return $this;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
55
    }
56
57
    /**
58
     * Retrieve the current locale.
59
     *
60
     * @return string
61
     */
62
    public function getLocale() : string
63
    {
64
        return $this->locale;
65
    }
66
67
    /**
68
     * Retrieve the supported locales.
69
     *
70
     * @return array
71
     */
72
    public static function getLocales() : array
73
    {
74
        return static::$locales ?: static::refreshLocales();
75
    }
76
77
    /**
78
     * Retrieve the name of the weekday.
79
     *
80
     * @param  string  $locale
81
     * @return string
82
     */
83
    public function getName(string $locale = null) : string
84
    {
85
        if ($locale && $locale != $this->locale) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $locale of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
86
            return $this->parseName($this->getValue(), $locale);
87
        }
88
89
        if (is_null($this->name)) {
90
            $this->name = $this->parseName($this->getValue());
91
        }
92
93
        return $this->name;
94
    }
95
96
    /**
97
     * Retrieve the name from a value.
98
     *
99
     * @param  int  $value
100
     * @param  string  $locale
101
     * @return string
102
     */
103
    public static function getNameFromValue(int $value, string $locale) : string
104
    {
105
        return static::parse($value, $locale)->getName();
106
    }
107
108
    /**
109
     * Retrieve the names of every weekday for a locale.
110
     *
111
     * @param  string  $locale
112
     * @return array
113
     */
114
    public static function getNames(string $locale) : array
115
    {
116
        $path = __DIR__."/../resources/lang/$locale/names.php";
117
118
        if (! file_exists($path)) {
119
            static::throwNotSupportedLocaleException($locale);
120
        }
121
122
        return require $path;
123
    }
124
125
    /**
126
     * Retrieve the value of the weekday.
127
     *
128
     * @return int
129
     */
130
    public function getValue() : int
131
    {
132
        if (is_null($this->value)) {
133
            $this->value = $this->parseValue($this->getName());
134
        }
135
136
        return $this->value;
137
    }
138
139
    /**
140
     * Retrieve the value from a name.
141
     *
142
     * @param  string  $name
143
     * @param  string  $locale
144
     * @return string
145
     */
146
    public static function getValueFromName(string $name, string $locale) : string
147
    {
148
        return static::parse($name, $locale)->getValue();
149
    }
150
151
    /**
152
     * Check if the locales has been loaded.
153
     *
154
     * @return bool
155
     */
156
    public function hasLoadedLocales() : bool
157
    {
158
        return ! $this->hasNotLoadedLocales();
159
    }
160
161
    /**
162
     * Check if the locales has not been loaded yet.
163
     *
164
     * @return bool
165
     */
166
    public function hasNotLoadedLocales() : bool
167
    {
168
        return empty(static::$locales);
169
    }
170
171
    /**
172
     * Check if the locale is supported.
173
     *
174
     * @param  string  $locales
0 ignored issues
show
Documentation introduced by
There is no parameter named $locales. Did you maybe mean $locale?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
175
     * @return bool
176
     */
177
    public function isSupported(string $locale) : bool
178
    {
179
        return in_array($locale, static::$locales);
180
    }
181
182
    /**
183
     * Check if the locale is not supported.
184
     *
185
     * @param  string  $locales
0 ignored issues
show
Documentation introduced by
There is no parameter named $locales. Did you maybe mean $locale?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
186
     * @return bool
187
     */
188
    public function isNotSupported(string $locale) : bool
189
    {
190
        return ! $this->isSupported($locale);
191
    }
192
193
    /**
194
     * Create a new instance from a value.
195
     *
196
     * @param  string|int  $value
197
     * @param  string  $locale
198
     * @param  bool  $force
199
     * @return self
200
     */
201
    public static function parse($value, string $locale, bool $force = false)
202
    {
203
        return new static($value, $locale, $force);
204
    }
205
206
    /**
207
     * Parse the name of the weekday based on the value.
208
     *
209
     * @param  int  $value
210
     * @param  string  $locale
211
     * @return string
212
     */
213
    public function parseName(int $value, string $locale = null) : string
214
    {
215
        if ($value < 0 || $value > 6) {
216
            throw new InvalidArgumentException(
217
                "The provided value ($value) is not a valid weekday."
218
            );
219
        }
220
221
        return array_values(static::getNames($locale ?: $this->locale))[$value];
222
    }
223
224
    /**
225
     * Parse the value from the weekday name.
226
     *
227
     * @param  string  $name
228
     * @param  string  $locale
229
     * @return int
230
     */
231
    public function parseValue(string $name, string $locale = null) : int
232
    {
233
        $names = array_map(
234
            'strtolower',
235
            static::getNames($locale ?: $this->locale)
236
        );
237
238
        $value = array_search(
239
            strtolower($name),
240
            array_values($names)
241
        );
242
243
        if ($value === false) {
244
            throw new InvalidArgumentException(
245
                sprintf(
246
                    'The value could not be parsed for %s in %s.',
247
                    $name,
248
                    $locale ?: $this->locale
249
                )
250
            );
251
        }
252
253
        return $value;
254
    }
255
256
    /**
257
     * Refresh the list of supported locales.
258
     *
259
     * @return array
260
     */
261
    protected static function refreshLocales() : array
262
    {
263
        static::$locales = array_map(
264
            'basename',
265
            glob(__DIR__.'/../resources/lang/*') ?: []
266
        );
267
268
        return static::$locales;
269
    }
270
271
    /**
272
     * Set the weekday based on the integer or string value.
273
     *
274
     * @param  string|int  $value
275
     * @return self
276
     */
277
    public function set($value) : self
278
    {
279
        if (is_numeric($value)) {
280
            $this->value = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value can also be of type double or string. However, the property $value is declared as type integer. 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...
281
            $this->name = null;
282
        } else {
283
            $this->name = $value;
284
            $this->value = null;
285
        }
286
287
        return $this;
288
    }
289
290
    /**
291
     * Set the locale of the instance.
292
     *
293
     * @param  string  $locale
294
     * @return self
295
     */
296
    public function setLocale(string $locale) : self
297
    {
298
        if ($locale != $this->locale) {
299
            if ($this->isNotSupported($locale)) {
300
                static::throwNotSupportedLocaleException($locale);
301
            }
302
303
            $this->name = null;
304
            $this->locale = $locale;
305
        }
306
307
        return $this;
308
    }
309
310
    /**
311
     * Throw an exception to let the user know that the locale is not yet
312
     * supported.
313
     *
314
     * @param  string  $locale
315
     * @return void
316
     */
317
    protected static function throwNotSupportedLocaleException(string $locale) : void
318
    {
319
        throw new InvalidArgumentException(
320
            "The locale ($locale) is not yet supported."
321
        );
322
    }
323
}
324