Completed
Push — master ( 087d89...83ffdf )
by
unknown
02:32
created

FeaturedFlagsImpl::_compareParams()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.2
cc 4
eloc 5
nc 4
nop 2
1
<?php
2
3
namespace FeaturedFlags;
4
5
use PDO;
6
use Redis;
7
8
class FeaturedFlagsImpl implements FeaturedFlags
9
{
10
    protected $_pdo;
11
    protected $_redis;
12
    protected $_date;
13
14
    CONST TABLE_NAME = 'featured_flags';
15
16
    /**
17
     * FeaturedFlags constructor.
18
     * @param PDO $pdo
19
     * @param Redis|null $redis
20
     * @param string|null $date
21
     */
22
    public function __construct(PDO $pdo, Redis $redis = null, $date = null)
23
    {
24
        $this->_pdo = $pdo;
25
        if ($redis) {
26
            $this->_redis = $redis;
27
        }
28
        if ($date) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $date of type string|null 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...
29
            $this->_date = $date;
30
        }
31
    }
32
33
    /**
34
     * @param PDO $pdo
35
     * @param Redis $redis
36
     * @return FeaturedFlags
37
     */
38
    public static function getInstance(PDO $pdo, Redis $redis = null) {
39
        return new self($pdo, $redis);
40
    }
41
42
    /**
43
     * @param string $flagName
44
     * @param array $filterParams
45
     * @return boolean
46
     */
47
    public function isEnabled($flagName, $filterParams = null)
48
    {
49
        $cacheKey = "isEnabled_".$this->_getKey($flagName, $filterParams);
0 ignored issues
show
Bug introduced by
It seems like $filterParams defined by parameter $filterParams on line 47 can also be of type null; however, FeaturedFlags\FeaturedFlagsImpl::_getKey() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
50
        if ($this->_redis->get($cacheKey))
51
        {
52
            return $this->_redis->get($cacheKey);
53
        }
54
55
        $flagsData = $this->_getDBFlagsData($flagName);
56
        foreach($flagsData as $flag){
57
            if ($this->_checkParams($flag['params'], $filterParams))
58
            {
59
                $this->_redis->set($cacheKey, true, $this->_getTimeout($flag['end_date']));
60
                return true;
61
            }
62
        }
63
64
        $this->_redis->set($cacheKey, false);
65
        return false;
66
    }
67
68
    /**
69
     * @param $flagName
70
     * @param $filterParams
71
     * @return null|array
72
     */
73
    public function getEnabledValues($flagName, $filterParams = null)
74
    {
75
        $cacheKey = "getEnabledValues_".$this->_getKey($flagName, $filterParams);
76
        if ($this->_redis->get($cacheKey))
77
        {
78
            return $this->_redis->get($cacheKey);
79
        }
80
81
        $flagsData = $this->_getDBFlagsData($flagName);
82
        foreach($flagsData as $flag){
83
            if ($this->_checkParams($flag['params'], $filterParams))
84
            {
85
                $returnParams = json_decode($flag['return_params'], true);
86
                $this->_redis->set($cacheKey, $returnParams, $this->_getTimeout($flag['end_date']));
87
                return $returnParams;
88
            }
89
        }
90
91
        $this->_redis->set($cacheKey, null);
92
        return null;
93
    }
94
95
    /**
96
     * @param Redis $redis
97
     */
98
    public function setRedis(Redis $redis)
99
    {
100
        $this->_redis = $redis;
101
    }
102
103
    /**
104
     * @return string
105
     */
106
    private function _getDate() {
107
        if ($this->_date) {
108
            return $this->_date;
109
        }
110
111
        return date("Y-m-d H:i:s");
112
    }
113
114
    /**
115
     * @param string $query
116
     * @param array $params
117
     * @return \mysqli_stmt
118
     */
119
    private function _getStmt($query, $params)
120
    {
121
        $stmt = $this->_pdo->prepare($query);
122
        foreach ($params as $field => $value) {
123
            $stmt->bindValue(":$field", $value);
124
        }
125
        return $stmt;
126
    }
127
128
    /**
129
     * @param string $flagName
130
     * @return array
131
     */
132
    private function _getDBFlagsData($flagName)
133
    {
134
        $query = "SELECT * FROM ".self::TABLE_NAME." WHERE 
135
        name = :flag AND 
136
        status = 1 AND
137
        (   (start_date IS NULL AND end_date IS NULL)
138
                OR
139
            (start_date <= :now AND :now <= end_date)
140
                OR
141
            (:now <= end_date AND (start_date IS NULL OR start_date = ''))
142
                OR
143
            (start_date <= :now AND (end_date IS NULL OR end_date = ''))
144
        )";
145
146
        $params = array(
147
            'flag' => $flagName,
148
            'now'  =>  $this->_getDate()
149
        );
150
151
        return $this->_executeForSelect($query, $params);
152
    }
153
154
    /**
155
     * @param string $query
156
     * @param array $params
157
     * @return array
158
     */
159
    private function _executeForSelect($query, $params = array())
160
    {
161
        $stmt = $this->_getStmt($query, $params);
162
        $stmt->execute();
163
        return $stmt->fetchAll();
164
    }
165
166
    /**
167
     * @param array $flagParams
168
     * @param array $filterParams
169
     * @return boolean
170
     */
171
    private function _compareParams($flagParams, $filterParams)
172
    {
173
        $checkParams = true;
174
        foreach($filterParams as $key => $value)
175
        {
176
            $checkParams = $checkParams && isset($flagParams[$key]) && $flagParams[$key] == $value;
177
        }
178
179
        return $checkParams;
180
    }
181
182
    /**
183
     * @param string $flagParamsJson
184
     * @param array $filterParams
185
     * @return boolean
186
     */
187
    private function _checkParams($flagParamsJson, $filterParams = null)
188
    {
189
        if (!$filterParams) {
190
            return true;
191
        }
192
193
        $flagParamsData = json_decode($flagParamsJson, true);
194
        if (!is_array($flagParamsData) || count($flagParamsData) === 0) {
195
            return false;
196
        }
197
198
        return $this->_compareParams($flagParamsData, $filterParams);
199
    }
200
201
    /**
202
     * @param string $flagName
203
     * @param array $filterParams
204
     * @return boolean
205
     */
206
    private function _getKey($flagName, $filterParams)
207
    {
208
        return "FF_".$flagName.json_encode($filterParams);
209
    }
210
211
    /**
212
     * @param string $endDate
213
     * @return int
214
     */
215
    private function _getTimeout($endDate)
216
    {
217
        if (!$endDate) {
218
            return 0;
219
        }
220
221
        return strtotime($endDate) - strtotime($this->_getDate());
222
    }
223
}
224