Completed
Push — master ( e30e5f...00a259 )
by Adam
02:09
created

ConfirmerAttributes::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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