Completed
Pull Request — master (#18)
by Patrick
02:39
created

SQLAuthenticator::getPendingDataSet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace Auth;
3
4
class SQLAuthenticator extends Authenticator
5
{
6
    public $dataSet = null;
7
    public $pendingDataSet = null;
8
    private $dataTables = array();
9
    private $params;
10
11
    public function __construct($params)
12
    {
13
        parent::__construct($params);
14
        $this->params = $params;
15
        if($this->current)
16
        {
17
            $this->dataSet = $this->getCurrentDataSet();
18
        }
19
        if($this->pending)
20
        {
21
            $this->pendingDataSet = $this->getPendingDataSet();
22
        }
23
    }
24
25
    /**
26
     * @SuppressWarnings("StaticAccess")
27
     */
28
    private function getCurrentDataSet()
29
    {
30
        if(isset($this->params['current_data_set']))
31
        {
32
            return \DataSetFactory::getDataSetByName($this->params['current_data_set']);
33
        }
34
        return \DataSetFactory::getDataSetByName('authentication');
35
    }
36
37
    /**
38
     * @SuppressWarnings("StaticAccess")
39
     */
40
    private function getPendingDataSet()
41
    {
42
        if(isset($this->params['pending_data_set']))
43
        {
44
            return \DataSetFactory::getDataSetByName($this->params['pending_data_set']);
45
        }
46
        return \DataSetFactory::getDataSetByName('pending_authentication');
47
    }
48
49
    private function getDataTable($name, $pending = false)
50
    {
51
        if(isset($this->dataTables[$name]) && isset($this->dataTables[$name][$pending]))
52
        {
53
            return $this->dataTables[$name][$pending];
54
        }
55
        $dataSet = $this->dataSet;
56
        if($pending)
57
        {
58
            $dataSet = $this->pendingDataSet;
59
        }
60
        if($dataSet === null)
61
        {
62
            throw new \Exception('Unable to obtain dataset for SQL Authentication!');
63
        }
64
        $dataTable = $dataSet[$name];
65
        if(!isset($this->dataTables[$name]))
66
        {
67
            $this->dataTables[$name] = array();
68
        }
69
        $this->dataTables[$name][$pending] = $dataTable;
70
        return $dataTable;
71
    }
72
73
    /**
74
     * Get the data table for Pending Users
75
     *
76
     * @return boolean|\Data\DataTable The Pending User Data Table
77
     */
78
    private function getPendingUserDataTable()
79
    {
80
        if(isset($this->params['pending_user_table']))
81
        {
82
            return $this->getDataTable($this->params['pending_user_table'], true);
83
        }
84
        return $this->getDataTable('users', true);
85
    }
86
87
    public function login($username, $password)
88
    {
89
        if($this->current === false)
90
        {
91
            return false;
92
        }
93
        $userDataTable = $this->getDataTable('user');
94
        $filter = new \Data\Filter("uid eq '$username'");
95
        $users = $userDataTable->read($filter);
96
        if($users === false || !isset($users[0]))
97
        {
98
            return false;
99
        }
100
        if(password_verify($password, $users[0]['pass']))
101
        {
102
            return array('res'=>true, 'extended'=>$users[0]);
103
        }
104
        return false;
105
    }
106
107
    public function isLoggedIn($data)
108
    {
109
        if(isset($data['res']))
110
        {
111
            return $data['res'];
112
        }
113
        return false;
114
    }
115
116
    public function getUser($data)
117
    {
118
        if(isset($this->params['current_data_set']))
119
        {
120
            $data['current_data_set'] = $this->params['current_data_set'];
121
        }
122
        return new SQLUser($data, $this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Auth\SQLAuthenticator>, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
123
    }
124
125
    private function getEntityByFilter($tableName, $filterStr, $className)
126
    {
127
        $dataTable = $this->getDataTable($tableName);
128
        $filter = new \Data\Filter($filterStr);
129
        $entities = $dataTable->read($filter);
130
        if(empty($entities))
131
        {
132
            return null;
133
        }
134
        return new $className($entities[0], $this);
135
    }
136
137
    public function getGroupByName($name)
138
    {
139
        return $this->getEntityByFilter('group', "gid eq '$name'", '\Auth\SQLGroup');
140
    }
141
142
    public function getUserByName($name)
143
    {
144
        return $this->getEntityByFilter('user', "uid eq '$name'", '\Auth\SQLUser');
145
    }
146
147
    private function getDataByFilter($dataTableName, $filter, $select, $top, $skip, $orderby)
148
    {
149
        $dataTable = $this->getDataTable($dataTableName);
150
        return $dataTable->read($filter, $select, $top, $skip, $orderby);
151
    }
152
153
    /**
154
     * @param string $dataTableName The Data Table to serach
155
     * @param string $className The class to obtain data in
156
     * @param boolean|array $select The fields to read
157
     * @param boolean|integer $top The number of entities to read
158
     * @param boolean|integer $skip The number of entities to skip
159
     * @param boolean|array $orderby The fields to sort by
160
     */
161
    private function convertDataToClass($dataTableName, $className, $filter, $select, $top, $skip, $orderby)
162
    {
163
        $data = $this->getDataByFilter($dataTableName, $filter, $select, $top, $skip, $orderby);
164
        if($data === false)
165
        {
166
            return false;
167
        }
168
        $count = count($data);
169
        for($i = 0; $i < $count; $i++)
170
        {
171
            $data[$i] = new $className($data[$i], $this);
172
        }
173
        return $data;
174
    }
175
176
    /**
177
     * @param boolean|array $select The fields to read
178
     * @param boolean|integer $top The number of entities to read
179
     * @param boolean|integer $skip The number of entities to skip
180
     * @param boolean|array $orderby The fields to sort by
181
     */
182
    public function getGroupsByFilter($filter, $select = false, $top = false, $skip = false, $orderby = false)
183
    {
184
        return $this->convertDataToClass('group', 'SQLGroup', $filter, $select, $top, $skip, $orderby);
185
    }
186
187
    /**
188
     * @param boolean|array $select The fields to read
189
     * @param boolean|integer $top The number of entities to read
190
     * @param boolean|integer $skip The number of entities to skip
191
     * @param boolean|array $orderby The fields to sort by
192
     */
193
    public function getUsersByFilter($filter, $select = false, $top = false, $skip = false, $orderby = false)
194
    {
195
        return $this->convertDataToClass('group', 'SQLUser', $filter, $select, $top, $skip, $orderby);
196
    }
197
198
    public function getPendingUserCount()
199
    {
200
        if($this->pending === false)
201
        {
202
            return 0;
203
        }
204
        $dataTable = $this->getPendingUserDataTable();
205
        if($dataTable === null)
206
        {
207
            return 0;
208
        }
209
        return $dataTable->count();
210
    }
211
212
    private function searchPendingUsers($filter, $select, $top, $skip, $orderby)
213
    {
214
        $userDataTable = $this->getPendingUserDataTable();
215
        $fieldData = $filter->to_mongo_filter();
216
        $firstFilter = new \Data\Filter('substringof(data,"'.implode($fieldData, ' ').'")');
217
        $users = $userDataTable->read($firstFilter, $select, $top, $skip, $orderby);
218
        if($users === false)
219
        {
220
            return false;
221
        }
222
        $ret = array();
223
        $count = count($users);
224
        for($i = 0; $i < $count; $i++)
225
        {
226
            $user = new SQLPendingUser($users[$i], $userDataTable);
0 ignored issues
show
Bug introduced by
It seems like $userDataTable defined by $this->getPendingUserDataTable() on line 214 can also be of type object<Data\DataTable>; however, Auth\SQLPendingUser::__construct() does only seem to accept boolean, 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...
227
            $err = false;
228
            foreach($fieldData as $field=>$data)
229
            {
230
                if(strcasecmp($user[$field], $data) !== 0)
231
                {
232
                    $err = true; break;
233
                }
234
            }
235
            if(!$err)
236
            {
237
                array_push($ret, $user);
238
            }
239
        }
240
        return $ret;
241
    }
242
243
    /**
244
     * @param \Data\Filter $filter The filter to read with
245
     * @param boolean|array $select The fields to read
246
     * @param boolean|integer $top The number of entities to read
247
     * @param boolean|integer $skip The number of entities to skip
248
     * @param boolean|array $orderby The fields to sort by
249
     */
250
    public function getPendingUsersByFilter($filter, $select = false, $top = false, $skip = false, $orderby = false)
251
    {
252
        if($this->pending === false)
253
        {
254
            return false;
255
        }
256
        if($filter !== false && !$filter->contains('hash'))
257
        {
258
            return $this->searchPendingUsers($filter, $select, $top, $skip, $orderby);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->searchPendingUser...$top, $skip, $orderby); of type false|array adds the type array to the return on line 258 which is incompatible with the return type of the parent method Auth\Authenticator::getPendingUsersByFilter of type boolean.
Loading history...
259
        }
260
        $userDataTable = $this->getPendingUserDataTable();
261
        $users = $userDataTable->read($filter, $select, $top, $skip, $orderby);
262
        if($users === false)
263
        {
264
            return false;
265
        }
266
        $count = count($users);
267
        for($i = 0; $i < $count; $i++)
268
        {
269
            $users[$i] = new SQLPendingUser($users[$i], $userDataTable);
0 ignored issues
show
Bug introduced by
It seems like $userDataTable defined by $this->getPendingUserDataTable() on line 260 can also be of type object<Data\DataTable>; however, Auth\SQLPendingUser::__construct() does only seem to accept boolean, 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...
270
        }
271
        return $users;
272
    }
273
274
    public function createPendingUser($user)
275
    {
276
        if($this->pending === false)
277
        {
278
            return false;
279
        }
280
        $userDataTable = $this->getPendingUserDataTable();
281
        if(isset($user->password2))
282
        {
283
            unset($user->password2);
284
        }
285
        $json = json_encode($user);
286
        $hash = hash('sha512', $json);
287
        $array = array('hash'=>$hash, 'data'=>$json);
288
        $ret = $userDataTable->create($array);
289
        if($ret !== false)
290
        {
291
            $users = $this->getPendingUsersByFilter(new \Data\Filter("hash eq '$hash'"));
292
            if($users === false || !isset($users[0]))
293
            {
294
                throw new \Exception('Error retreiving user object after successful create!');
295
            }
296
            $users[0]->sendEmail();
297
        }
298
        return $ret;
299
    }
300
301
    public function getTempUserByHash($hash)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
302
    {
303
        $users = $this->getPendingUsersByFilter(new \Data\Filter("hash eq '$hash'"));
304
        if($users === false || !isset($users[0]))
305
        {
306
            return false;
307
        }
308
        return $users[0];
309
    }
310
}
311
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
312