Test Failed
Push — master ( 5851fa...90c56e )
by Maximo
02:00
created

Manager::allow()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 4
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style introduced by
End of line character is invalid; expected "\n" but found "\r\n"
Loading history...
2
declare(strict_types=1);
3
4
namespace Gewaer\Acl;
5
6
use Phalcon\Db;
7
use Phalcon\Db\AdapterInterface as DbAdapter;
8
use Phalcon\Acl\Exception;
9
use Phalcon\Acl\Resource;
10
use Phalcon\Acl;
11
use Phalcon\Acl\Role;
12
use Phalcon\Acl\RoleInterface;
13
use Gewaer\Models\Companies;
14
use Gewaer\Models\Apps;
15
use Phalcon\Acl\Adapter\Database as PhalconAclDatabaseAdapter;
16
use Phalcon\Acl\Adapter;
17
use BadMethodCallException;
18
19
/**
20
 * Phalcon\Acl\Adapter\Database
21
 * Manages Geweaer Multi tenant ACL lists in database
22
 *
23
 * #extends PhalconAclDatabaseAdapter #had to comments it out testing breaking
24
 */
25
class Manager extends Adapter
26
{
27
    /**
28
     * @var DbAdapter
29
     */
30
    protected $connection;
31
32
    /**
33
     * Roles table
34
     * @var string
35
     */
36
    protected $roles;
37
38
    /**
39
     * Resources table
40
     * @var string
41
     */
42
    protected $resources;
43
44
    /**
45
     * Resources Accesses table
46
     * @var string
47
     */
48
    protected $resourcesAccesses;
49
50
    /**
51
     * Access List table
52
     * @var string
53
     */
54
    protected $accessList;
55
56
    /**
57
     * Roles Inherits table
58
     * @var string
59
     */
60
    protected $rolesInherits;
61
62
    /**
63
     * Default action for no arguments is allow
64
     * @var int
65
     */
66
    protected $noArgumentsDefaultAction = Acl::ALLOW;
67
68
    /**
69
     * Company Object
70
     *
71
     * @var Companies
72
     */
73
    protected $company;
74
75
    /**
76
     * App Objc
77
     *
78
     * @var Apps
79
     */
80
    protected $app;
81
82
    /**
83
     * Class constructor.
84
     *
85
     * @param  array $options Adapter config
86
     * @throws Exception
87
     */
88 7
    public function __construct(array $options)
89
    {
90 7
        if (!isset($options['db']) || !$options['db'] instanceof DbAdapter) {
91
            throw new Exception(
92
                'Parameter "db" is required and it must be an instance of Phalcon\Acl\AdapterInterface'
93
            );
94
        }
95
96 7
        $this->connection = $options['db'];
97
98 7
        foreach (['roles', 'resources', 'resourcesAccesses', 'accessList', 'rolesInherits'] as $table) {
99 7
            if (!isset($options[$table]) || empty($options[$table]) || !is_string($options[$table])) {
100
                throw new Exception("Parameter '{$table}' is required and it must be a non empty string");
101
            }
102
103 7
            $this->{$table} = $this->connection->escapeIdentifier($options[$table]);
104
        }
105 7
    }
106
107
    /**
108
     * Set current user Company
109
     *
110
     * @param Companies $company
111
     * @return void
112
     */
113
    public function setCompany(Companies $company): void
114
    {
115
        $this->company = $company;
116
    }
117
118
    /**
119
     * Set current user app
120
     *
121
     * @param Apps $app
122
     * @return void
123
     */
124
    public function setApp(Apps $app): void
125
    {
126
        $this->app = $app;
127
    }
128
129
    /**
130
     * Get the current App
131
     *
132
     * @return void
133
     */
134
    public function getApp(): Apps
135
    {
136
        if (!is_object($this->app)) {
137
            $this->app = new Apps();
138
            $this->app->id = 0;
139
            $this->app->name = 'Canvas';
140
        }
141
142
        return $this->app;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $this->app returns the type Gewaer\Models\Apps which is incompatible with the documented return type void.
Loading history...
143
    }
144
145
    /**
146
     * Get the current App
147
     *
148
     * @return void
149
     */
150
    public function getCompany() : Companies
151
    {
152
        if (!is_object($this->company)) {
153
            $this->company = new Companies();
154
            $this->company->id = 0;
155
            $this->company->name = 'Canvas';
156
        }
157
158
        return $this->company;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $this->company returns the type Gewaer\Models\Companies which is incompatible with the documented return type void.
Loading history...
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     *
164
     * Example:
165
     * <code>
166
     * $acl->addRole(new Phalcon\Acl\Role('administrator'), 'consultor');
167
     * $acl->addRole('administrator', 'consultor');
168
     * </code>
169
     *
170
     * @param  \Phalcon\Acl\Role|string $role
171
     * @param  int   $scope
172
     * @param  string                   $accessInherits
173
     * @return boolean
174
     * @throws \Phalcon\Acl\Exception
175
     */
176 1
    public function addRole($role, $scope = 0, $accessInherits = null): bool
177
    {
178 1
        if (is_string($role)) {
179
            $role = new Role($role, ucwords($role) . ' Role');
180
        }
181 1
        if (!$role instanceof RoleInterface) {
1 ignored issue
show
introduced by
$role is always a sub-type of Phalcon\Acl\RoleInterface.
Loading history...
182
            throw new Exception('Role must be either an string or implement RoleInterface');
183
        }
184
185 1
        $exists = $this->connection->fetchOne(
186 1
            "SELECT COUNT(*) FROM {$this->roles} WHERE name = ?",
187 1
            null,
188 1
            [$role->getName()]
1 ignored issue
show
Bug introduced by
array($role->getName()) of type array<integer,string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

188
            /** @scrutinizer ignore-type */ [$role->getName()]
Loading history...
189
        );
190
191
        if (!$exists[0]) {
192
            $this->connection->execute(
193
                "INSERT INTO {$this->roles} (name, description, company_id, apps_id, scope, created_at) VALUES (?, ?, ?, ?, ?, ?)",
194
                [$role->getName(), $role->getDescription(), $this->getCompany()->getId(), $this->getApp()->getId(), $scope, date('Y-m-d H:i:s')]
195
            );
196
            $this->connection->execute(
197
                "INSERT INTO {$this->accessList} (roles_name, resources_name, access_name, allowed, apps_id, created_at) VALUES (?, ?, ?, ?, ?, ?)",
198
                [$role->getName(), '*', '*', $this->_defaultAccess, $this->getApp()->getId(), date('Y-m-d H:i:s')]
199
            );
200
        }
201
        if ($accessInherits) {
202
            return $this->addInherit($role->getName(), $accessInherits);
203
        }
204
        return true;
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     *
210
     * @param  string $roleName
211
     * @param  string $roleToInherit
212
     * @throws \Phalcon\Acl\Exception
213
     */
214
    public function addInherit($roleName, $roleToInherit): bool
215
    {
216
        $sql = "SELECT COUNT(*) FROM {$this->roles} WHERE name = ?";
217
        $exists = $this->connection->fetchOne($sql, null, [$roleName]);
0 ignored issues
show
Bug introduced by
array($roleName) of type array<integer,string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

217
        $exists = $this->connection->fetchOne($sql, null, /** @scrutinizer ignore-type */ [$roleName]);
Loading history...
218
        if (!$exists[0]) {
219
            throw new Exception("Role '{$roleName}' does not exist in the role list");
220
        }
221
        $exists = $this->connection->fetchOne(
222
            "SELECT COUNT(*) FROM {$this->rolesInherits} WHERE roles_name = ? AND roles_inherit = ?",
223
            null,
224
            [$roleName, $roleToInherit]
0 ignored issues
show
Bug introduced by
array($roleName, $roleToInherit) of type array<integer,string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

224
            /** @scrutinizer ignore-type */ [$roleName, $roleToInherit]
Loading history...
225
        );
226
        if (!$exists[0]) {
227
            $this->connection->execute(
228
                "INSERT INTO {$this->rolesInherits} VALUES (?, ?)",
229
                [$roleName, $roleToInherit]
230
            );
1 ignored issue
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
231
        }
232
    }
233
234
    /**
235
     * {@inheritdoc}
236
     *
237
     * @param  string  $roleName
238
     * @return boolean
239
     */
240 2
    public function isRole($roleName): bool
241
    {
242 2
        $exists = $this->connection->fetchOne(
243 2
            "SELECT COUNT(*) FROM {$this->roles} WHERE name = ?",
244 2
            null,
245 2
            [$roleName]
0 ignored issues
show
Bug introduced by
array($roleName) of type array<integer,string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

245
            /** @scrutinizer ignore-type */ [$roleName]
Loading history...
246
        );
247
        return (bool) $exists[0];
248
    }
249
250
    /**
251
     * {@inheritdoc}
252
     *
253
     * @param  string  $resourceName
254
     * @return boolean
255
     */
256
    public function isResource($resourceName): bool
257
    {
258
        $exists = $this->connection->fetchOne(
259
            "SELECT COUNT(*) FROM {$this->resources} WHERE name = ?",
260
            null,
261
            [$resourceName]
0 ignored issues
show
Bug introduced by
array($resourceName) of type array<integer,string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

261
            /** @scrutinizer ignore-type */ [$resourceName]
Loading history...
262
        );
263
        return (bool) $exists[0];
264
    }
265
266
    /**
267
     * Given a resource with a dot CRM.Leads , it will set the app
268
     *
269
     * @param string $resource
270
     * @return void
271
     */
272 3
    protected function setAppByResource(string $resource): string
273
    {
274
        //echeck if we have a dot , taht means we are sending the specific app to use
275 3
        if (strpos($resource, '.') !== false) {
276 3
            $appResource = explode('.', $resource);
277 3
            $resource = $appResource[1];
278 3
            $appName = $appResource[0];
279
280
            //look for the app and set it
281 3
            if ($app = Apps::findFirstByName($appName)) {
0 ignored issues
show
Bug introduced by
The method findFirstByName() does not exist on Gewaer\Models\Apps. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

281
            if ($app = Apps::/** @scrutinizer ignore-call */ findFirstByName($appName)) {
Loading history...
282
                $this->setApp($app);
283
            }
284
        }
285
286
        return $resource;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $resource returns the type string which is incompatible with the documented return type void.
Loading history...
287
    }
288
289
    /**
290
     * {@inheritdoc}
291
     * Example:
292
     * <code>
293
     * //Add a resource to the the list allowing access to an action
294
     * $acl->addResource(new Phalcon\Acl\Resource('customers'), 'search');
295
     * $acl->addResource('customers', 'search');
296
     * //Add a resource  with an access list
297
     * $acl->addResource(new Phalcon\Acl\Resource('customers'), ['create', 'search']);
298
     * $acl->addResource('customers', ['create', 'search']);
299
     * $acl->addResource('App.customers', ['create', 'search']);
300
     * </code>
301
     *
302
     * @param  \Phalcon\Acl\Resource|string $resource
303
     * @param  array|string                 $accessList
304
     * @return boolean
305
     */
306 1
    public function addResource($resource, $accessList = null): bool
307
    {
308 1
        if (!is_object($resource)) {
309
            //echeck if we have a dot , taht means we are sending the specific app to use
310 1
            $resource = $this->setAppByResource($resource);
311
312
            $resource = new Resource($resource);
313
        }
314
315
        $exists = $this->connection->fetchOne(
316
            "SELECT COUNT(*) FROM {$this->resources} WHERE name = ?",
317
            null,
318
            [$resource->getName()]
0 ignored issues
show
Bug introduced by
array($resource->getName()) of type array<integer,string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

318
            /** @scrutinizer ignore-type */ [$resource->getName()]
Loading history...
319
        );
320
321
        if (!$exists[0]) {
322
            $this->connection->execute(
323
                "INSERT INTO {$this->resources} (name, description, apps_id, created_at) VALUES (?, ?, ?, ?)",
324
                [$resource->getName(), $resource->getDescription(), $this->getApp()->getId(), date('Y-m-d H:i:s')]
325
            );
326
        }
327
328
        if ($accessList) {
329
            return $this->addResourceAccess($resource->getName(), $accessList);
330
        }
331
332
        return true;
333
    }
334
335
    /**
336
     * {@inheritdoc}
337
     *
338
     * @param  string       $resourceName
339
     * @param  array|string $accessList
340
     * @return boolean
341
     * @throws \Phalcon\Acl\Exception
342
     */
343
    public function addResourceAccess($resourceName, $accessList): bool
344
    {
345
        if (!$this->isResource($resourceName)) {
346
            throw new Exception("Resource '{$resourceName}' does not exist in ACL");
347
        }
348
349
        $sql = "SELECT COUNT(*) FROM {$this->resourcesAccesses} WHERE resources_name = ? AND access_name = ? AND apps_id = ?";
350
        if (!is_array($accessList)) {
351
            $accessList = [$accessList];
352
        }
353
354
        foreach ($accessList as $accessName) {
355
            $exists = $this->connection->fetchOne($sql, null, [$resourceName, $accessName, $this->getApp()->getId()]);
0 ignored issues
show
Bug introduced by
array($resourceName, $ac...his->getApp()->getId()) of type array<integer,integer|mixed|string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

355
            $exists = $this->connection->fetchOne($sql, null, /** @scrutinizer ignore-type */ [$resourceName, $accessName, $this->getApp()->getId()]);
Loading history...
356
            if (!$exists[0]) {
357
                $this->connection->execute(
358
                    'INSERT INTO ' . $this->resourcesAccesses . ' (resources_name, access_name, apps_id, created_at) VALUES (?, ?, ?, ?)',
359
                    [$resourceName, $accessName, $this->getApp()->getId(), date('Y-m-d H:i:s')]
360
                );
361
            }
362
        }
363
        return true;
364
    }
365
366
    /**
367
     * {@inheritdoc}
368
     *
369
     * @return \Phalcon\Acl\Resource[]
370
     */
371
    public function getResources(): \Phalcon\Acl\ResourceInterface
372
    {
373
        $resources = [];
374
        $sql = "SELECT * FROM {$this->resources}";
375
        foreach ($this->connection->fetchAll($sql, Db::FETCH_ASSOC) as $row) {
376
            $resources[] = new Resource($row['name'], $row['description']);
377
        }
378
        return $resources;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $resources returns the type Phalcon\Acl\Resource[]|array which is incompatible with the type-hinted return Phalcon\Acl\ResourceInterface.
Loading history...
379
    }
380
381
    /**
382
     * {@inheritdoc}
383
     *
384
     * @return RoleInterface[]
385
     */
386
    public function getRoles(): \Phalcon\Acl\RoleInterface
387
    {
388
        $roles = [];
389
        $sql = "SELECT * FROM {$this->roles}";
390
        foreach ($this->connection->fetchAll($sql, Db::FETCH_ASSOC) as $row) {
391
            $roles[] = new Role($row['name'], $row['description']);
392
        }
393
        return $roles;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $roles returns the type Phalcon\Acl\Role[]|array which is incompatible with the type-hinted return Phalcon\Acl\RoleInterface.
Loading history...
394
    }
395
396
    /**
397
     * {@inheritdoc}
398
     *
399
     * @param string       $resourceName
400
     * @param array|string $accessList
401
     */
402
    public function dropResourceAccess($resourceName, $accessList)
403
    {
404
        throw new BadMethodCallException('Not implemented yet.');
405
    }
406
407
    /**
408
     * {@inheritdoc}
409
     * You can use '*' as wildcard
410
     * Example:
411
     * <code>
412
     * //Allow access to guests to search on customers
413
     * $acl->allow('guests', 'customers', 'search');
414
     * //Allow access to guests to search or create on customers
415
     * $acl->allow('guests', 'customers', ['search', 'create']);
416
     * //Allow access to any role to browse on products
417
     * $acl->allow('*', 'products', 'browse');
418
     * //Allow access to any role to browse on any resource
419
     * $acl->allow('*', '*', 'browse');
420
     * </code>
421
     *
422
     * @param string       $roleName
423
     * @param string       $resourceName
424
     * @param array|string $access
425
     * @param mixed $func
426
     */
427 1
    public function allow($roleName, $resourceName, $access, $func = null)
428
    {
429 1
        return $this->allowOrDeny($roleName, $resourceName, $access, Acl::ALLOW);
430
    }
431
432
    /**
433
     * {@inheritdoc}
434
     * You can use '*' as wildcard
435
     * Example:
436
     * <code>
437
     * //Deny access to guests to search on customers
438
     * $acl->deny('guests', 'customers', 'search');
439
     * //Deny access to guests to search or create on customers
440
     * $acl->deny('guests', 'customers', ['search', 'create']);
441
     * //Deny access to any role to browse on products
442
     * $acl->deny('*', 'products', 'browse');
443
     * //Deny access to any role to browse on any resource
444
     * $acl->deny('*', '*', 'browse');
445
     * </code>
446
     *
447
     * @param  string       $roleName
448
     * @param  string       $resourceName
449
     * @param  array|string $access
450
     * @param  mixed $func
451
     * @return boolean
452
     */
453 1
    public function deny($roleName, $resourceName, $access, $func = null)
454
    {
455 1
        return $this->allowOrDeny($roleName, $resourceName, $access, Acl::DENY);
456
    }
457
458
    /**
459
     * {@inheritdoc}
460
     * Example:
461
     * <code>
462
     * //Does Andres have access to the customers resource to create?
463
     * $acl->isAllowed('Andres', 'Products', 'create');
464
     * //Do guests have access to any resource to edit?
465
     * $acl->isAllowed('guests', '*', 'edit');
466
     * </code>
467
     *
468
     * @param string $role
469
     * @param string $resource
470
     * @param string $access
471
     * @param array  $parameters
472
     * @return bool
473
     */
474 2
    public function isAllowed($role, $resource, $access, array $parameters = null): bool
475
    {
476 2
        $resource = $this->setAppByResource($resource);
477
478
        $sql = implode(' ', [
479
            'SELECT ' . $this->connection->escapeIdentifier('allowed') . " FROM {$this->accessList} AS a",
480
            // role_name in:
481
            'WHERE roles_name IN (',
482
                // given 'role'-parameter
483
            'SELECT ? ',
484
                // inherited role_names
485
            "UNION SELECT roles_inherit FROM {$this->rolesInherits} WHERE roles_name = ?",
486
                // or 'any'
487
            "UNION SELECT '*'",
488
            ')',
489
            // resources_name should be given one or 'any'
490
            "AND resources_name IN (?, '*')",
491
            // access_name should be given one or 'any'
492
            //"AND access_name IN (?, '*')", you need to specify * , we are forcing to check always for permisions
493
            "AND access_name IN (?)",
494
            'AND apps_id = ? ',
495
            // order be the sum of bools for 'literals' before 'any'
496
            'ORDER BY ' . $this->connection->escapeIdentifier('allowed') . ' DESC',
497
            // get only one...
498
            'LIMIT 1'
499
        ]);
500
        
501
502
        // fetch one entry...
503
        $allowed = $this->connection->fetchOne($sql, Db::FETCH_NUM, [$role, $role, $resource, $access, $this->getApp()->getId()]);
1 ignored issue
show
Bug introduced by
array($role, $role, $res...his->getApp()->getId()) of type array<integer,integer|string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

503
        $allowed = $this->connection->fetchOne($sql, Db::FETCH_NUM, /** @scrutinizer ignore-type */ [$role, $role, $resource, $access, $this->getApp()->getId()]);
Loading history...
504
505
        if (is_array($allowed)) {
1 ignored issue
show
introduced by
The condition is_array($allowed) is always true.
Loading history...
506
            return (bool) $allowed[0];
507
        }
508
        
509
        /**
510
         * Return the default access action
511
         */
512
        return (bool) $this->_defaultAccess;
513
    }
514
515
    /**
516
     * Returns the default ACL access level for no arguments provided
517
     * in isAllowed action if there exists func for accessKey
518
     *
519
     * @return int
520
     */
521
    public function getNoArgumentsDefaultAction(): int
522
    {
523
        return $this->noArgumentsDefaultAction;
524
    }
525
526
    /**
527
     * Sets the default access level for no arguments provided
528
     * in isAllowed action if there exists func for accessKey
529
     *
530
     * @param int $defaultAccess Phalcon\Acl::ALLOW or Phalcon\Acl::DENY
531
     */
532
    public function setNoArgumentsDefaultAction($defaultAccess)
533
    {
534
        $this->noArgumentsDefaultAction = intval($defaultAccess);
535
    }
536
537
    /**
538
     * Inserts/Updates a permission in the access list
539
     *
540
     * @param  string  $roleName
541
     * @param  string  $resourceName
542
     * @param  string  $accessName
543
     * @param  integer $action
544
     * @return boolean
545
     * @throws \Phalcon\Acl\Exception
546
     */
547
    protected function insertOrUpdateAccess($roleName, $resourceName, $accessName, $action)
548
    {
549
        $resourceName = $this->setAppByResource($resourceName);
550
551
        /**
552
         * Check if the access is valid in the resource unless wildcard
553
         */
554
        if ($resourceName !== '*' && $accessName !== '*') {
555
            $sql = "SELECT COUNT(*) FROM {$this->resourcesAccesses} WHERE resources_name = ? AND access_name = ? and apps_id  = ?";
556
            $exists = $this->connection->fetchOne($sql, null, [$resourceName, $accessName, $this->getApp()->getId()]);
1 ignored issue
show
Bug introduced by
array($resourceName, $ac...his->getApp()->getId()) of type array<integer,integer|string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

556
            $exists = $this->connection->fetchOne($sql, null, /** @scrutinizer ignore-type */ [$resourceName, $accessName, $this->getApp()->getId()]);
Loading history...
557
            if (!$exists[0]) {
558
                throw new Exception(
559
                    "Access '{$accessName}' does not exist in resource '{$resourceName}' in ACL"
560
                );
561
            }
562
        }
563
        /**
564
         * Update the access in access_list
565
         */
566
        $sql = "SELECT COUNT(*) FROM {$this->accessList} "
567
            . ' WHERE roles_name = ? AND resources_name = ? AND access_name = ? AND apps_id = ?';
568
        $exists = $this->connection->fetchOne($sql, null, [$roleName, $resourceName, $accessName, $this->getApp()->getId()]);
1 ignored issue
show
Bug introduced by
array($roleName, $resour...his->getApp()->getId()) of type array<integer,integer|string> is incompatible with the type integer expected by parameter $placeholders of Phalcon\Db\AdapterInterface::fetchOne(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

568
        $exists = $this->connection->fetchOne($sql, null, /** @scrutinizer ignore-type */ [$roleName, $resourceName, $accessName, $this->getApp()->getId()]);
Loading history...
569
        if (!$exists[0]) {
570
            $sql = "INSERT INTO {$this->accessList} (roles_name, resources_name, access_name, allowed, apps_id, created_at) VALUES (?, ?, ?, ?, ?, ?)";
571
            $params = [$roleName, $resourceName, $accessName, $action, $this->getApp()->getId(), date('Y-m-d H:i:s')];
572
        } else {
573
            $sql = "UPDATE {$this->accessList} SET allowed = ? " .
574
                'WHERE roles_name = ? AND resources_name = ? AND access_name = ? AND apps_id = ?';
575
            $params = [$action, $roleName, $resourceName, $accessName, $this->getApp()->getId()];
576
        }
577
        $this->connection->execute($sql, $params);
578
579
        /**
580
         * Update the access '*' in access_list
581
         */
582
        $sql = "SELECT COUNT(*) FROM {$this->accessList} " .
583
            'WHERE roles_name = ? AND resources_name = ? AND access_name = ? and apps_id = ?';
584
        $exists = $this->connection->fetchOne($sql, null, [$roleName, $resourceName, '*', $this->getApp()->getId()]);
585
        if (!$exists[0]) {
586
            $sql = "INSERT INTO {$this->accessList} (roles_name, resources_name, access_name, allowed, apps_id, created_at) VALUES (?, ?, ?, ?, ? , ?)";
587
            $this->connection->execute($sql, [$roleName, $resourceName, '*', $this->_defaultAccess, $this->getApp()->getId(), date('Y-m-d H:i:s')]);
588
        }
589
590
        return true;
591
    }
592
593
    /**
594
     * Inserts/Updates a permission in the access list
595
     *
596
     * @param  string       $roleName
597
     * @param  string       $resourceName
598
     * @param  array|string $access
599
     * @param  integer      $action
600
     * @throws \Phalcon\Acl\Exception
601
     */
602 2
    protected function allowOrDeny($roleName, $resourceName, $access, $action)
603
    {
604 2
        if (!$this->isRole($roleName)) {
605
            throw new Exception("Role '{$roleName}' does not exist in the list");
606
        }
607
        if (!is_array($access)) {
608
            $access = [$access];
609
        }
610
        foreach ($access as $accessName) {
611
            $this->insertOrUpdateAccess($roleName, $resourceName, $accessName, $action);
612
        }
613
614
        return true;
615
    }
616
}
617