Issues (81)

components/Helper.php (5 issues)

1
<?php
2
3
namespace toir427\admin\components;
4
5
use toir427\admin\models\Route;
6
use Yii;
7
use yii\caching\TagDependency;
8
use yii\helpers\ArrayHelper;
9
use yii\web\User;
10
11
/**
12
 * Description of Helper
13
 *
14
 * @author Misbahul D Munir <[email protected]>
15
 * @since 2.3
16
 */
17
class Helper
18
{
19
    private static $_userRoutes = [];
20
    private static $_defaultRoutes;
21
    private static $_routes;
22
23
    public static function getRegisteredRoutes()
24
    {
25
        if (self::$_routes === null) {
26
            self::$_routes = [];
27
            $manager = Configs::authManager();
28
            foreach ($manager->getPermissions() as $item) {
29
                if ($item->name[0] === '/') {
30
                    self::$_routes[$item->name] = $item->name;
31
                }
32
            }
33
        }
34
        return self::$_routes;
35
    }
36
37
    /**
38
     * Get assigned routes by default roles
39
     * @return array
40
     */
41
    protected static function getDefaultRoutes()
42
    {
43
        if (self::$_defaultRoutes === null) {
44
            $manager = Configs::authManager();
45
            $roles = $manager->defaultRoles;
0 ignored issues
show
Accessing defaultRoles on the interface yii\rbac\ManagerInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
46
            $cache = Configs::cache();
47
            if ($cache && ($routes = $cache->get($roles)) !== false) {
48
                self::$_defaultRoutes = $routes;
49
            } else {
50
                $permissions = self::$_defaultRoutes = [];
51
                foreach ($roles as $role) {
52
                    $permissions = array_merge($permissions, $manager->getPermissionsByRole($role));
53
                }
54
                foreach ($permissions as $item) {
55
                    if ($item->name[0] === '/') {
56
                        self::$_defaultRoutes[$item->name] = true;
57
                    }
58
                }
59
                if ($cache) {
0 ignored issues
show
$cache is of type yii\caching\Cache, thus it always evaluated to true.
Loading history...
60
                    $cache->set($roles, self::$_defaultRoutes, Configs::cacheDuration(), new TagDependency([
61
                        'tags' => Configs::CACHE_TAG,
62
                    ]));
63
                }
64
            }
65
        }
66
        return self::$_defaultRoutes;
67
    }
68
69
    /**
70
     * Get assigned routes of user.
71
     * @param integer $userId
72
     * @return array
73
     */
74
    public static function getRoutesByUser($userId)
75
    {
76
        if (!isset(self::$_userRoutes[$userId])) {
77
            $cache = Configs::cache();
78
            if ($cache && ($routes = $cache->get([__METHOD__, $userId])) !== false) {
79
                self::$_userRoutes[$userId] = $routes;
80
            } else {
81
                $routes = static::getDefaultRoutes();
82
                $manager = Configs::authManager();
83
                foreach ($manager->getPermissionsByUser($userId) as $item) {
84
                    if ($item->name[0] === '/') {
85
                        $routes[$item->name] = true;
86
                    }
87
                }
88
                self::$_userRoutes[$userId] = $routes;
89
                if ($cache) {
0 ignored issues
show
$cache is of type yii\caching\Cache, thus it always evaluated to true.
Loading history...
90
                    $cache->set([__METHOD__, $userId], $routes, Configs::cacheDuration(), new TagDependency([
91
                        'tags' => Configs::CACHE_TAG,
92
                    ]));
93
                }
94
            }
95
        }
96
        return self::$_userRoutes[$userId];
97
    }
98
99
    /**
100
     * Check access route for user.
101
     * @param string|array $route
102
     * @param integer|User $user
103
     * @return boolean
104
     */
105
    public static function checkRoute($route, $params = [], $user = null)
106
    {
107
        $config = Configs::instance();
108
        $r = static::normalizeRoute($route, $config->advanced);
0 ignored issues
show
It seems like $route can also be of type array; however, parameter $route of toir427\admin\components\Helper::normalizeRoute() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

108
        $r = static::normalizeRoute(/** @scrutinizer ignore-type */ $route, $config->advanced);
Loading history...
109
        if ($config->onlyRegisteredRoute && !isset(static::getRegisteredRoutes()[$r])) {
110
            return true;
111
        }
112
113
        if ($user === null) {
114
            $user = Yii::$app->getUser();
115
        }
116
        $userId = $user instanceof User ? $user->getId() : $user;
117
118
        if ($config->strict) {
119
            if ($user->can($r, $params)) {
120
                return true;
121
            }
122
            while (($pos = strrpos($r, '/')) > 0) {
123
                $r = substr($r, 0, $pos);
124
                if ($user->can($r . '/*', $params)) {
125
                    return true;
126
                }
127
            }
128
            return $user->can('/*', $params);
129
        } else {
130
            $routes = static::getRoutesByUser($userId);
0 ignored issues
show
It seems like $userId can also be of type string; however, parameter $userId of toir427\admin\components\Helper::getRoutesByUser() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

130
            $routes = static::getRoutesByUser(/** @scrutinizer ignore-type */ $userId);
Loading history...
131
            if (isset($routes[$r])) {
132
                return true;
133
            }
134
            while (($pos = strrpos($r, '/')) > 0) {
135
                $r = substr($r, 0, $pos);
136
                if (isset($routes[$r . '/*'])) {
137
                    return true;
138
                }
139
            }
140
            return isset($routes['/*']);
141
        }
142
    }
143
144
    /**
145
     * Normalize route
146
     * @param  string  $route    Plain route string
147
     * @param  boolean|array $advanced Array containing the advanced configuration. Defaults to false.
148
     * @return string            Normalized route string
149
     */
150
    protected static function normalizeRoute($route, $advanced = false)
151
    {
152
        if ($route === '') {
153
            $normalized = '/' . Yii::$app->controller->getRoute();
154
        } elseif (strncmp($route, '/', 1) === 0) {
155
            $normalized = $route;
156
        } elseif (strpos($route, '/') === false) {
157
            $normalized = '/' . Yii::$app->controller->getUniqueId() . '/' . $route;
158
        } elseif (($mid = Yii::$app->controller->module->getUniqueId()) !== '') {
159
            $normalized = '/' . $mid . '/' . $route;
160
        } else {
161
            $normalized = '/' . $route;
162
        }
163
        // Prefix @app-id to route.
164
        if ($advanced) {
165
            $normalized = Route::PREFIX_ADVANCED . Yii::$app->id . $normalized;
166
        }
167
        return $normalized;
168
    }
169
170
    /**
171
     * Filter menu items
172
     * @param array $items
173
     * @param integer|User $user
174
     */
175
    public static function filter($items, $user = null)
176
    {
177
        if ($user === null) {
178
            $user = Yii::$app->getUser();
179
        }
180
        return static::filterRecursive($items, $user);
181
    }
182
183
    /**
184
     * Filter menu recursive
185
     * @param array $items
186
     * @param integer|User $user
187
     * @return array
188
     */
189
    protected static function filterRecursive($items, $user)
190
    {
191
        $result = [];
192
        foreach ($items as $i => $item) {
193
            $url = ArrayHelper::getValue($item, 'url', '#');
194
            $allow = is_array($url) ? static::checkRoute($url[0], array_slice($url, 1), $user) : true;
195
196
            if (isset($item['items']) && is_array($item['items'])) {
197
                $subItems = self::filterRecursive($item['items'], $user);
198
                if (count($subItems)) {
199
                    $allow = true;
200
                }
201
                $item['items'] = $subItems;
202
            }
203
            if ($allow && !($url == '#' && empty($item['items']))) {
204
                $result[$i] = $item;
205
            }
206
        }
207
        return $result;
208
    }
209
210
    /**
211
     * Filter action column button. Use with [[yii\grid\GridView]]
212
     * ```php
213
     * 'columns' => [
214
     *     ...
215
     *     [
216
     *         'class' => 'yii\grid\ActionColumn',
217
     *         'template' => Helper::filterActionColumn(['view','update','activate'])
218
     *     ]
219
     * ],
220
     * ```
221
     * @param array|string $buttons
222
     * @param integer|User $user
223
     * @return string
224
     */
225
    public static function filterActionColumn($buttons = [], $user = null)
226
    {
227
        if (is_array($buttons)) {
228
            $result = [];
229
            foreach ($buttons as $button) {
230
                if (static::checkRoute($button, [], $user)) {
231
                    $result[] = "{{$button}}";
232
                }
233
            }
234
            return implode(' ', $result);
235
        }
236
        return preg_replace_callback('/\\{([\w\-\/]+)\\}/', function ($matches) use ($user) {
237
            return static::checkRoute($matches[1], [], $user) ? "{{$matches[1]}}" : '';
238
        }, $buttons);
239
    }
240
241
    /**
242
     * Use to invalidate cache.
243
     */
244
    public static function invalidate()
245
    {
246
        if (Configs::cache() !== null) {
247
            TagDependency::invalidate(Configs::cache(), Configs::CACHE_TAG);
248
        }
249
    }
250
}
251