1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Confirmer.php |
4
|
|
|
* |
5
|
|
|
* @copyright More in license.md |
6
|
|
|
* @license http://www.ipublikuj.eu |
7
|
|
|
* @author Adam Kadlec http://www.ipublikuj.eu |
8
|
|
|
* @package iPublikuj:ConfirmationDialog! |
9
|
|
|
* @subpackage Components |
10
|
|
|
* @since 1.0.0 |
11
|
|
|
* |
12
|
|
|
* @date 31.03.14 |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
declare(strict_types = 1); |
16
|
|
|
|
17
|
|
|
namespace IPub\ConfirmationDialog\Components; |
18
|
|
|
|
19
|
|
|
use Nette; |
20
|
|
|
use Nette\Application; |
21
|
|
|
|
22
|
|
|
use IPub; |
23
|
|
|
use IPub\ConfirmationDialog; |
24
|
|
|
use IPub\ConfirmationDialog\Exceptions; |
25
|
|
|
use IPub\ConfirmationDialog\Storage; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Confirmation dialog confirmer control |
29
|
|
|
* |
30
|
|
|
* @package iPublikuj:ConfirmationDialog! |
31
|
|
|
* @subpackage Components |
32
|
|
|
* |
33
|
1 |
|
* @property-read string $name |
34
|
|
|
*/ |
35
|
|
|
abstract class ConfirmerAttributes extends BaseControl |
36
|
|
|
{ |
37
|
|
|
/** |
38
|
|
|
* @var array localization strings |
39
|
|
|
*/ |
40
|
|
|
public static $strings = [ |
41
|
|
|
'yes' => 'Yes', |
42
|
|
|
'no' => 'No', |
43
|
|
|
'expired' => 'Confirmation token has expired. Please try action again.', |
44
|
|
|
]; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var string |
48
|
|
|
*/ |
49
|
|
|
protected $cssClass; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var string|callable heading |
53
|
|
|
*/ |
54
|
|
|
protected $heading; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @var string|callable question |
58
|
|
|
*/ |
59
|
|
|
protected $question; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @var string|callable icon |
63
|
1 |
|
*/ |
64
|
|
|
protected $icon; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @var callable |
68
|
|
|
*/ |
69
|
|
|
protected $handler; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @var bool |
73
|
|
|
*/ |
74
|
|
|
protected $useAjax = TRUE; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @var Storage\IStorage |
78
|
|
|
*/ |
79
|
|
|
protected $storage; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @param Storage\IStorage $storage |
83
|
|
|
*/ |
84
|
1 |
|
public function injectStorage(Storage\IStorage $storage) |
85
|
1 |
|
{ |
86
|
|
|
// Get data storage for confirmer |
87
|
|
|
$this->storage = $storage; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Set dialog heading |
92
|
|
|
* |
93
|
|
|
* @param string|callable $heading |
94
|
|
|
* |
95
|
|
|
* @return void |
96
|
|
|
* |
97
|
|
|
* @throws Exceptions\InvalidArgumentException |
98
|
|
|
*/ |
99
|
1 |
|
public function setHeading($heading) |
100
|
|
|
{ |
101
|
1 |
|
// Check variable type |
102
|
1 |
|
if ($this->checkCallableOrString($heading)) { |
103
|
|
|
// Update confirmation heading |
104
|
1 |
|
$this->heading = $heading; |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Get dialog heding |
110
|
|
|
* |
111
|
|
|
* @return string|NULL |
112
|
|
|
* |
113
|
|
|
* @throws Exceptions\InvalidStateException |
114
|
|
|
*/ |
115
|
|
View Code Duplication |
public function getHeading() : string |
|
|
|
|
116
|
|
|
{ |
117
|
1 |
|
// Check if attribute is callable |
118
|
|
|
if (is_callable($this->heading)) { |
119
|
|
|
return (string) $this->callCallableAttribute($this->heading); |
120
|
|
|
|
121
|
1 |
|
} elseif ($this->heading) { |
122
|
|
|
return (string) $this->heading; |
123
|
|
|
} |
124
|
1 |
|
|
125
|
|
|
return NULL; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Set dialog question |
130
|
|
|
* |
131
|
|
|
* @param string|callable $question |
132
|
|
|
* |
133
|
|
|
* @return void |
134
|
|
|
* |
135
|
|
|
* @throws Exceptions\InvalidArgumentException |
136
|
|
|
*/ |
137
|
|
|
public function setQuestion($question) |
138
|
|
|
{ |
139
|
1 |
|
// Check variable type |
140
|
|
|
if ($this->checkCallableOrString($question)) { |
141
|
1 |
|
// Update confirmation question |
142
|
1 |
|
$this->question = $question; |
143
|
|
|
} |
144
|
1 |
|
} |
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* @return string|bool |
148
|
|
|
* |
149
|
|
|
* @throws Exceptions\InvalidStateException |
150
|
|
|
*/ |
151
|
|
|
public function getQuestion() |
152
|
|
|
{ |
153
|
|
|
$question = FALSE; |
154
|
|
|
|
155
|
1 |
|
// Check if attribute is callable |
156
|
|
|
if (is_callable($this->question)) { |
157
|
|
|
$question = $this->callCallableAttribute($this->question); |
158
|
|
|
|
159
|
|
|
if (!is_bool($question)) { |
160
|
|
|
$question = (string) $question; |
161
|
|
|
} |
162
|
1 |
|
|
163
|
1 |
|
} elseif (!is_bool($this->question)) { |
164
|
1 |
|
$question = (string) $this->question; |
165
|
|
|
} |
166
|
1 |
|
|
167
|
|
|
return $question; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Set dialog icon |
172
|
|
|
* |
173
|
|
|
* @param string|callable $icon |
174
|
|
|
* |
175
|
|
|
* @return void |
176
|
|
|
* |
177
|
|
|
* @throws Exceptions\InvalidArgumentException |
178
|
|
|
*/ |
179
|
|
|
public function setIcon($icon) |
180
|
|
|
{ |
181
|
|
|
// Check variable type |
182
|
|
|
if ($this->checkCallableOrString($icon)) { |
183
|
|
|
// Update confirmation icon |
184
|
|
|
$this->icon = $icon; |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* @return string|NULL |
190
|
|
|
* |
191
|
|
|
* @throws Exceptions\InvalidStateException |
192
|
|
|
*/ |
193
|
|
View Code Duplication |
public function getIcon() : string |
|
|
|
|
194
|
|
|
{ |
195
|
|
|
// Check if attribute is callable |
196
|
|
|
if (is_callable($this->icon)) { |
197
|
1 |
|
return (string) $this->callCallableAttribute($this->icon); |
198
|
|
|
|
199
|
|
|
} elseif ($this->icon) { |
200
|
|
|
return (string) $this->icon; |
201
|
1 |
|
} |
202
|
|
|
|
203
|
|
|
return NULL; |
204
|
1 |
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Set dialog handler |
208
|
|
|
* |
209
|
|
|
* @param callable $handler |
210
|
|
|
* |
211
|
|
|
* @return void |
212
|
|
|
* |
213
|
|
|
* @throws Exceptions\InvalidArgumentException |
214
|
1 |
|
*/ |
215
|
|
|
public function setHandler($handler) |
216
|
|
|
{ |
217
|
|
|
if (!is_callable($handler)) { |
218
|
1 |
|
throw new Exceptions\InvalidArgumentException('$handler must be callable.'); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
// Update confirmation handler |
222
|
|
|
$this->handler = $handler; |
223
|
1 |
|
} |
224
|
|
|
|
225
|
1 |
|
/** |
226
|
|
|
* @return callable |
227
|
|
|
*/ |
228
|
|
|
public function getHandler() : callable |
229
|
|
|
{ |
230
|
|
|
return $this->handler; |
231
|
|
|
} |
232
|
|
|
|
233
|
1 |
|
/** |
234
|
|
|
* @param Nette\ComponentModel\IContainer $obj |
235
|
|
|
* @param array $params |
236
|
|
|
* |
237
|
|
|
* @return mixed |
238
|
|
|
* |
239
|
|
|
* @throws Exceptions\HandlerNotCallableException |
240
|
|
|
*/ |
241
|
|
|
public function callHandler(Nette\ComponentModel\IContainer $obj, array $params) |
242
|
|
|
{ |
243
|
|
|
$callback = $this->getHandler(); |
244
|
|
|
|
245
|
|
|
if ($callback instanceof \Closure) { |
246
|
1 |
|
$result = call_user_func_array($callback, $params); |
247
|
|
|
|
248
|
1 |
|
} elseif (method_exists($obj, 'tryCall')) { |
249
|
|
|
$result = call_user_func_array([$obj, 'tryCall'], ['method' => $callback[1], 'params' => $params]); |
250
|
|
|
|
251
|
1 |
|
} else { |
252
|
1 |
|
$result = call_user_func_array([$obj, $callback[1]], $params); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
if ($result === FALSE) { |
256
|
|
|
throw new Exceptions\HandlerNotCallableException('Confirm action callback was not successful.'); |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
return $result; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* @return void |
264
|
|
|
*/ |
265
|
|
|
public function enableAjax() |
266
|
|
|
{ |
267
|
|
|
$this->useAjax = TRUE; |
268
|
|
|
} |
269
|
|
|
|
270
|
1 |
|
/** |
271
|
|
|
* @return void |
272
|
1 |
|
*/ |
273
|
|
|
public function disableAjax() |
274
|
|
|
{ |
275
|
|
|
$this->useAjax = FALSE; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* @return Application\UI\Form |
280
|
|
|
*/ |
281
|
|
|
protected function createComponentForm() |
282
|
|
|
{ |
283
|
|
|
// Create confirmation form |
284
|
|
|
$form = new Application\UI\Form(); |
285
|
|
|
|
286
|
|
|
// Security field |
287
|
|
|
$form->addHidden('secureToken'); |
288
|
|
|
|
289
|
|
|
// Form protection |
290
|
|
|
$form->addProtection($this->translator ? $this->translator->translate('confirmationDialog.messages.tokenIsExpired') : self::$strings['expired']); |
291
|
1 |
|
|
292
|
|
|
// Confirm buttons |
293
|
|
|
$form->addSubmit('yes', $this->translator ? $this->translator->translate('confirmationDialog.buttons.bYes') : self::$strings['yes']) |
294
|
1 |
|
->onClick[] = [$this, 'confirmClicked']; |
295
|
|
|
|
296
|
|
|
$form->addSubmit('no', $this->translator ? $this->translator->translate('confirmationDialog.buttons.bNo') : self::$strings['no']) |
297
|
1 |
|
->onClick[] = [$this, 'cancelClicked']; |
298
|
|
|
|
299
|
|
|
return $form; |
300
|
1 |
|
} |
301
|
1 |
|
|
302
|
|
|
/** |
303
|
1 |
|
* @param callable|string $var |
304
|
1 |
|
* |
305
|
|
|
* @return bool |
306
|
1 |
|
* |
307
|
|
|
* @throws Exceptions\InvalidArgumentException |
308
|
|
|
*/ |
309
|
|
|
protected function checkCallableOrString($var) : bool |
310
|
|
|
{ |
311
|
|
|
if (!is_callable($var) && !is_string($var)) { |
312
|
|
|
throw new Exceptions\InvalidArgumentException(sprintf('%s must be callback or string.', $var)); |
313
|
1 |
|
} |
314
|
|
|
|
315
|
|
|
return TRUE; |
316
|
|
|
} |
317
|
|
|
|
318
|
1 |
|
/** |
319
|
|
|
* @param callable $attribute |
320
|
|
|
* |
321
|
|
|
* @return string |
322
|
1 |
|
* |
323
|
|
|
* @throws Exceptions\InvalidStateException |
324
|
|
|
*/ |
325
|
|
|
protected function callCallableAttribute($attribute) : string |
326
|
|
|
{ |
327
|
|
|
if ($this['form']['secureToken']->value === NULL) { |
328
|
|
|
throw new Exceptions\InvalidStateException('Token is not set!'); |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
// Get token from form |
332
|
|
|
$token = $this['form']['secureToken']->value; |
333
|
|
|
|
334
|
|
|
// Get values stored in confirmer storage |
335
|
|
|
$values = $this->getConfirmerValues($token); |
336
|
|
|
|
337
|
|
|
return call_user_func_array($attribute, [$this, $values['params']]); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* @param string $token |
342
|
|
|
* |
343
|
|
|
* @return array |
344
|
|
|
* |
345
|
|
|
* @throws Exceptions\InvalidStateException |
346
|
|
|
*/ |
347
|
|
|
protected function getConfirmerValues(string $token) : array |
348
|
|
|
{ |
349
|
|
|
// Get values stored in confirmer storage |
350
|
|
|
$values = $this->storage->get($token); |
351
|
|
|
|
352
|
|
|
// Check for correct values |
353
|
|
|
if (!is_array($values) || !isset($values['confirmer']) || !isset($values['params'])) { |
354
|
|
|
throw new Exceptions\InvalidStateException('Confirmer is not configured!'); |
355
|
1 |
|
} |
356
|
|
|
|
357
|
|
|
return $values; |
358
|
1 |
|
} |
359
|
|
|
} |
360
|
|
|
|
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.