1
|
|
|
<?php |
|
|
|
|
2
|
|
|
namespace UserPermissions\Controller\Component; |
3
|
|
|
|
4
|
|
|
use Cake\Controller\Component; |
5
|
|
|
use Cake\Controller\ComponentRegistry; |
6
|
|
|
use Cake\Controller\Component\FlashComponent; |
7
|
|
|
use Cake\Core\Exception\Exception; |
8
|
|
|
use Cake\Datasource\ConnectionManager; |
9
|
|
|
use Cake\Log\Log; |
10
|
|
|
use Cake\ORM\TableRegistry; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* An instance of this exception should be thrown, if the |
14
|
|
|
* UserPermissionsComponent instance tries to call an handler which does not |
15
|
|
|
* exist. |
16
|
|
|
*/ |
17
|
|
|
class MissingHandlerException extends Exception |
18
|
|
|
{}; |
|
|
|
|
19
|
|
|
|
20
|
|
|
class UserPermissionsComponent extends Component { |
|
|
|
|
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Controller name |
24
|
|
|
* |
25
|
|
|
* @var string |
26
|
|
|
*/ |
27
|
|
|
public $controller = null; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Session |
31
|
|
|
* |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
public $session = null; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Components array |
38
|
|
|
* |
39
|
|
|
* @var array |
40
|
|
|
*/ |
41
|
|
|
public $components = ['Flash']; |
42
|
|
|
|
43
|
|
|
private $actions; |
44
|
|
|
|
45
|
|
|
private $allow; |
46
|
|
|
|
47
|
|
|
private $redirect; |
48
|
|
|
|
49
|
|
|
private $params; |
50
|
|
|
|
51
|
|
|
private $message; |
52
|
|
|
|
53
|
|
|
private $userType; |
54
|
|
|
|
55
|
|
|
private $action; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Boolean value which holds the configuration for the behavior in case of |
59
|
|
|
* missing handlers. |
60
|
|
|
*/ |
61
|
|
|
private $throwEx; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Initialization to get controller variable |
65
|
|
|
* |
66
|
|
|
* For this component available settings: |
67
|
|
|
* bool throwEx - default false - if set to true, an exception will be |
68
|
|
|
* thrown, if a handler is about to be called but does not exist. |
69
|
|
|
* |
70
|
|
|
* @param array $config Configuration array for the component. |
71
|
|
|
*/ |
72
|
5 |
|
public function initialize(array $config) |
73
|
|
|
{ |
74
|
5 |
|
parent::initialize($config); |
75
|
|
|
|
76
|
5 |
|
$this->controller = $this->_registry->getController(); |
|
|
|
|
77
|
5 |
|
$this->session = $this->controller->request->session(); |
78
|
|
|
|
79
|
5 |
|
$this->actions = array(); |
80
|
5 |
|
$this->allow = true; |
81
|
5 |
|
$this->redirect = ''; |
82
|
5 |
|
$this->params = ''; |
83
|
5 |
|
$this->message = ''; |
84
|
5 |
|
$this->userType = ''; |
85
|
5 |
|
$this->action = null; |
86
|
5 |
|
$this->throwEx = isset($config["throwEx"]) && $config["throwEx"]; |
87
|
5 |
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* Initialization to get controller variable |
91
|
|
|
* |
92
|
|
|
* @param array $rules Array of rules for permissions. |
93
|
|
|
* @return bool false if user / group doesn't have permission, true if has permission |
94
|
|
|
*/ |
95
|
5 |
|
public function allow ($rules) { |
96
|
5 |
|
$this->setUserValues(); |
97
|
5 |
|
$this->bindConfiguration($rules); |
98
|
|
|
|
99
|
5 |
|
if (!$this->applyGroupsRules($rules)) { |
100
|
5 |
|
$this->applyViewsRules($rules); |
101
|
|
|
} |
102
|
|
|
|
103
|
5 |
|
return $this->allow; |
104
|
|
|
} |
105
|
|
|
|
106
|
5 |
|
private function setUserValues() |
107
|
|
|
{ |
108
|
5 |
|
$userId = $this->session->read('Auth.User.id'); |
|
|
|
|
109
|
|
|
|
110
|
5 |
|
if (!isset($userId)) { |
111
|
5 |
|
$this->userType = 'guest'; |
112
|
|
|
} |
113
|
5 |
|
} |
114
|
|
|
|
115
|
5 |
|
private function bindConfiguration(array $rules) |
116
|
|
|
{ |
117
|
5 |
|
foreach($rules as $key => $value){ |
118
|
|
|
switch($key){ |
119
|
5 |
|
case "user_type": |
120
|
5 |
|
$this->userType = $value; |
121
|
5 |
|
break; |
122
|
5 |
|
case "redirect": |
123
|
5 |
|
$this->redirect = $value; |
124
|
5 |
|
break; |
125
|
5 |
|
case "action": |
126
|
5 |
|
$this->action = $value; |
127
|
5 |
|
break; |
128
|
5 |
|
case "controller": |
129
|
5 |
|
$this->controller = $value; |
130
|
5 |
|
if(!is_object($value)) { |
131
|
|
|
Log::write("warn", sprintf("controller is not an object (%s)", gettype($value))); |
132
|
|
|
} |
133
|
5 |
|
break; |
134
|
5 |
|
case "message": |
135
|
5 |
|
$this->message = $value; |
136
|
5 |
|
break; |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
140
|
5 |
|
foreach($rules['groups'] as $key => $value){ |
141
|
5 |
|
if($key == $this->userType){ |
142
|
5 |
|
foreach($value as $v){ |
143
|
5 |
|
array_push($this->actions, $v); |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
} |
147
|
5 |
|
} |
148
|
|
|
|
149
|
5 |
|
private function applyGroupsRules(array $rules) |
150
|
|
|
{ |
151
|
5 |
|
$existRulesForGroups = false; |
152
|
|
|
|
153
|
5 |
|
if(isset($rules['groups'])){ |
154
|
5 |
|
foreach($rules['groups'] as $key => $value){ |
155
|
5 |
|
$this->searchForApplyGroupRules($key, $value); |
|
|
|
|
156
|
|
|
} |
157
|
|
|
} |
158
|
|
|
|
159
|
5 |
|
return $existRulesForGroups; |
160
|
|
|
} |
161
|
|
|
|
162
|
5 |
|
private function searchForApplyGroupRules($key) |
163
|
|
|
{ |
164
|
5 |
|
if($key == $this->userType){ |
165
|
5 |
|
if ($this->notInArrayAction()) { |
166
|
2 |
|
$this->redirectIfIsSet(); |
167
|
|
|
|
168
|
2 |
|
$this->allow = false; |
169
|
|
|
} |
170
|
|
|
} |
171
|
5 |
|
} |
172
|
|
|
|
173
|
5 |
|
private function notInArrayAction() |
174
|
|
|
{ |
175
|
5 |
|
return ((!in_array('*', $this->actions)) && (!in_array($this->action, $this->actions))); |
176
|
|
|
} |
177
|
|
|
|
178
|
5 |
|
private function applyViewsRules(array $rules) |
179
|
|
|
{ |
180
|
5 |
|
if(isset($rules['views'])){ |
181
|
2 |
|
foreach($rules['views'] as $key => $value){ |
182
|
2 |
|
$this->searchForApplyViewRules($key, $value); |
183
|
|
|
} |
184
|
|
|
} |
185
|
5 |
|
} |
186
|
|
|
|
187
|
2 |
|
private function searchForApplyViewRules($key, $value) |
188
|
|
|
{ |
189
|
2 |
|
if($key == $this->action){ |
190
|
|
|
// about to call the view handler, so check first if it exists |
191
|
2 |
|
if(!method_exists($this->controller, $value)) { |
192
|
|
|
$msg = sprintf( |
193
|
|
|
"Controller %s (%s=%s) has no method called '%s'", |
194
|
|
|
$this->controller, |
195
|
|
|
is_object($this->controller) ? "class" : "type", |
196
|
|
|
is_object($this->controller) ? get_class($this->controller) : gettype($this->controller), |
197
|
|
|
$value |
198
|
|
|
); |
199
|
|
|
Log::write("debug", $msg); |
200
|
|
|
if($this->throwEx) { |
201
|
|
|
throw new MissingHandlerException($msg); |
202
|
|
|
} |
203
|
|
|
return; |
204
|
|
|
} |
205
|
|
|
|
206
|
2 |
|
if(!$this->controller->$value()){ |
|
|
|
|
207
|
1 |
|
$this->redirectIfIsSet(); |
208
|
|
|
|
209
|
1 |
|
$this->allow = false; |
210
|
|
|
} |
211
|
|
|
} |
212
|
2 |
|
} |
213
|
|
|
|
214
|
3 |
|
private function redirectIfIsSet() |
215
|
|
|
{ |
216
|
3 |
|
if($this->redirect != ''){ |
217
|
|
|
if($this->message != ''){ |
218
|
|
|
$this->Flash->set($this->message); |
|
|
|
|
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
header("Location: " . $this->redirect); |
222
|
|
|
exit; |
|
|
|
|
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
} |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.