Completed
Pull Request — master (#29)
by Ozan
05:26
created

Intl::getSearchCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Propaganistas\LaravelIntl\Contracts;
4
5
abstract class Intl
6
{
7
    /**
8
     * Store previously used keywords in memory.
9
     * 
10
     * @var array
11
     */
12
    protected static $searchCache = [];
13
    
14
    /**
15
     * Get the current locale.
16
     *
17
     * @return string
18
     */
19
    abstract public function getLocale();
20
21
    /**
22
     * Set the current locale.
23
     *
24
     * @param $locale
25
     * @return $this
26
     */
27
    abstract public function setLocale($locale);
28
29
    /**
30
     * Get the fallback locale.
31
     *
32
     * @return string
33
     */
34
    abstract public function getFallbackLocale();
35
36
    /**
37
     * Set the fallback locale.
38
     *
39
     * @param $locale
40
     * @return $this
41
     */
42
    abstract public function setFallbackLocale($locale);
43
44
    /**
45
     * Get the search cache.
46
     * 
47
     * @return array
48
     */
49
    public function getSearchCache()
50
    {
51
        return static::$searchCache;
52
    }
53
54
    /**
55
     * Forget the search cache as whole or by key.
56
     *
57
     * @return array
58
     */
59
    public function forgetSearchCache($cacheKey = null)
60
    {
61
        if ($cacheKey) {
62
            unset(static::$searchCache[$cacheKey]);
63
        } else {
64
            static::$searchCache = [];
65
        }
66
67
        return $this;
68
    }
69
70
    /**
71
     * Search the data by the given keywords.
72
     * 
73
     * @param  array|string $keywords
74
     * @return array
75
     */
76
    public function search($keywords) {
77
        [$keywords, $excludeKeywords, $includeKeywords] = $this->parseKeywords($keywords);
0 ignored issues
show
Bug introduced by
The variable $excludeKeywords does not exist. Did you mean $keywords?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
Bug introduced by
The variable $includeKeywords does not exist. Did you mean $keywords?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
78
79
        $cacheKey = md5(json_encode($keywords));
80
81
        if (array_key_exists($cacheKey, static::$searchCache)) {
82
            return static::$searchCache[$cacheKey];
83
        }
84
85
        $results = $this->all();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Propaganistas\LaravelIntl\Contracts\Intl as the method all() does only exist in the following sub-classes of Propaganistas\LaravelIntl\Contracts\Intl: Propaganistas\LaravelIntl\Country, Propaganistas\LaravelIntl\Currency, Propaganistas\LaravelIntl\Language. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
86
87
        $filterCallback = function ($name) use ($includeKeywords, $excludeKeywords) {
0 ignored issues
show
Bug introduced by
The variable $includeKeywords does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $excludeKeywords does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
88
            $includeCondition = $excludeCondition = true;
89
90
            if (! empty($includeKeywords)) {
91
                $includeCondition = (bool) preg_match('/'.implode('|', $includeKeywords).'/', $name);
92
            }
93
94
            if (! empty($excludeKeywords)) {
95
                $excludeCondition = ! (bool) preg_match('/'.implode('|', $excludeKeywords).'/', $name);
96
            }
97
98
            return $includeCondition && $excludeCondition;
99
        };
100
101
        $results = array_filter($results, $filterCallback);
102
103
        return static::$searchCache[$cacheKey] = $results;
104
    }
105
    
106
    /**
107
     * Parse the given keywords into include/exclude keywords.
108
     *
109
     * @param  array|string $keywords
110
     * @return array
111
     */
112
    protected function parseKeywords($keywords)
113
    {
114
        if (is_string($keywords)) {
115
            $keywords = explode('|', $keywords);
116
        }
117
118
        $excludeKeywords = $includeKeywords = [];
119
120
        foreach ($keywords as $keyword) {
121
            if (Str::startsWith($keyword, ['-', '\\-'])) {
122
                $excludeKeywords[] = str_replace(['-', '\\'], '', $keyword);
123
            }  else {
124
                $includeKeywords[] = $keyword;
125
            }
126
        }
127
128
        return [$keywords, $excludeKeywords, $includeKeywords];
129
    }
130
131
    /**
132
     * Run the given callable while using another locale.
133
     *
134
     * @param string $locale
135
     * @param callable $callback
136
     * @param string|null $fallbackLocale
137
     * @return mixed
138
     */
139 12
    public function usingLocale($locale, callable $callback, $fallbackLocale = null)
140
    {
141 12
        $originalLocale = $this->getLocale();
142 12
        $originalFallbackLocale = $this->getFallbackLocale();
143
144 12
        $this->setLocale($locale);
145 12
        $this->setFallbackLocale($fallbackLocale ?: $originalFallbackLocale);
146
147 12
        $result = $callback($this);
148
149 12
        $this->setFallbackLocale($originalFallbackLocale);
150 12
        $this->setLocale($originalLocale);
151
152 12
        return $result;
153
    }
154
}
155