Passed
Push — master ( 3d13ab...202a73 )
by Fabio
05:43
created

TPage::getAutoGlobalListen()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
/**
3
 * TPage class file
4
 *
5
 * @author Qiang Xue <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
8
 * @package Prado\Web\UI
9
 */
10
11
namespace Prado\Web\UI;
12
13
use Prado\Collections\TList;
14
use Prado\Collections\TMap;
15
use Prado\Collections\TStack;
16
use Prado\Exceptions\TConfigurationException;
17
use Prado\Exceptions\THttpException;
18
use Prado\Exceptions\TInvalidDataValueException;
19
use Prado\Exceptions\TInvalidDataTypeException;
20
use Prado\Exceptions\TInvalidOperationException;
21
use Prado\Prado;
22
use Prado\TPropertyValue;
23
use Prado\Web\Javascripts\TJavaScript;
24
use Prado\Web\UI\ActiveControls\TActivePageAdapter;
25
use Prado\Web\UI\ActiveControls\TCallbackClientScript;
26
use Prado\Web\UI\WebControls\THead;
27
28
/**
29
 * TPage class
30
 *
31
 * @author Qiang Xue <[email protected]>
32
 * @package Prado\Web\UI
33
 * @since 3.0
34
 */
35
class TPage extends TTemplateControl
36
{
37
	/**
38
	 * system post fields
39
	 */
40
	const FIELD_POSTBACK_TARGET = 'PRADO_POSTBACK_TARGET';
41
	const FIELD_POSTBACK_PARAMETER = 'PRADO_POSTBACK_PARAMETER';
42
	const FIELD_LASTFOCUS = 'PRADO_LASTFOCUS';
43
	const FIELD_PAGESTATE = 'PRADO_PAGESTATE';
44
	const FIELD_CALLBACK_TARGET = 'PRADO_CALLBACK_TARGET';
45
	const FIELD_CALLBACK_PARAMETER = 'PRADO_CALLBACK_PARAMETER';
46
47
	/**
48
	 * @var array system post fields
49
	 */
50
	private static $_systemPostFields = [
51
		'PRADO_POSTBACK_TARGET' => true,
52
		'PRADO_POSTBACK_PARAMETER' => true,
53
		'PRADO_LASTFOCUS' => true,
54
		'PRADO_PAGESTATE' => true,
55
		'PRADO_CALLBACK_TARGET' => true,
56
		'PRADO_CALLBACK_PARAMETER' => true
57
	];
58
	/**
59
	 * @var TForm form instance
60
	 */
61
	private $_form;
62
	/**
63
	 * @var THead head instance
64
	 */
65
	private $_head;
66
	/**
67
	 * @var TList list of registered validators
68
	 */
69
	private $_validators;
70
	/**
71
	 * @var bool if validation has been performed
72
	 */
73
	private $_validated = false;
74
	/**
75
	 * @var TTheme page theme
76
	 */
77
	private $_theme;
78
	/**
79
	 * @var string page title set when Head is not in page yet
80
	 */
81
	private $_title;
82
	/**
83
	 * @var TTheme page stylesheet theme
84
	 */
85
	private $_styleSheet;
86
	/**
87
	 * @var TClientScriptManager client script manager
88
	 */
89
	private $_clientScript;
90
	/**
91
	 * @var TMap data post back by user
92
	 */
93
	protected $_postData;
94
	/**
95
	 * @var TMap postback data that is not handled during first invocation of LoadPostData.
96
	 */
97
	protected $_restPostData;
98
	/**
99
	 * @var array list of controls whose data have been changed due to the postback
100
	 */
101
	protected $_controlsPostDataChanged = [];
102
	/**
103
	 * @var array list of controls that need to load post data in the current request
104
	 */
105
	protected $_controlsRequiringPostData = [];
106
	/**
107
	 * @var array list of controls that need to load post data in the next postback
108
	 */
109
	protected $_controlsRegisteredForPostData = [];
110
	/**
111
	 * @var \Prado\Web\UI\TControl control that needs to raise postback event
112
	 */
113
	private $_postBackEventTarget;
114
	/**
115
	 * @var string postback event parameter
116
	 */
117
	private $_postBackEventParameter;
118
	/**
119
	 * @var bool whether the form has been rendered
120
	 */
121
	protected $_formRendered = false;
122
	/**
123
	 * @var bool whether the current rendering is within a form
124
	 */
125
	protected $_inFormRender = false;
126
	/**
127
	 * @var string|TControl the control or the ID of the element on the page to be focused when the page is sent back to user
128
	 */
129
	private $_focus;
130
	/**
131
	 * @var string page path to this page
132
	 */
133
	private $_pagePath = '';
134
	/**
135
	 * @var bool whether page state should be HMAC validated
136
	 */
137
	private $_enableStateValidation = true;
138
	/**
139
	 * @var bool whether page state should be encrypted
140
	 */
141
	private $_enableStateEncryption = false;
142
	/**
143
	 * @var bool whether page state should be compressed
144
	 * @since 3.1.6
145
	 */
146
	private $_enableStateCompression = true;
147
	/**
148
	 * @var bool whether to use the igbinary serializer if available
149
	 * @since 4.1
150
	 */
151
	private $_enableStateIGBinary = true;
152
	/**
153
	 * @var string page state persister class name
154
	 */
155
	private $_statePersisterClass = '\Prado\Web\UI\TPageStatePersister';
156
	/**
157
	 * @var mixed page state persister
158
	 */
159
	private $_statePersister;
160
	/**
161
	 * @var TStack stack used to store currently active caching controls
162
	 */
163
	private $_cachingStack;
164
	/**
165
	 * @var string state string to be stored on the client side
166
	 */
167
	private $_clientState = '';
168
	/**
169
	 * @var bool true if loading post data.
170
	 */
171
	protected $_isLoadingPostData = false;
172
	/**
173
	 * @var bool whether client supports javascript
174
	 */
175
	private $_enableJavaScript = true;
176
	/**
177
	 * @var THtmlWriter current html render writer
178
	 */
179
	private $_writer;
180
181
	/**
182
	 * Constructor.
183
	 * Sets the page object to itself.
184
	 * Derived classes must call parent implementation.
185
	 */
186
	public function __construct()
187
	{
188
		$this->setPage($this);
189
		parent::__construct();
190
	}
191
192
	/**
193
	 * TPage does autoGlobalListen and unlisten.  Developers
194
	 * may put fx events in the page that need to be picked up.
195
	 *
196
	 * @return bool returns true
197
	 */
198
	public function getAutoGlobalListen()
199
	{
200
		return true;
201
	}
202
203
	/**
204
	 * Runs through the page lifecycles.
205
	 * @param \Prado\Web\UI\THtmlWriter $writer the HTML writer
206
	 */
207
	public function run($writer)
208
	{
209
		Prado::trace("Running page life cycles", 'Prado\Web\UI\TPage');
210
		$this->_writer = $writer;
211
212
		$this->determinePostBackMode();
213
214
		if ($this->getIsPostBack()) {
215
			if ($this->getIsCallback()) {
216
				$this->processCallbackRequest($writer);
217
			} else {
218
				$this->processPostBackRequest($writer);
219
			}
220
		} else {
221
			$this->processNormalRequest($writer);
222
		}
223
224
		$this->_writer = null;
225
	}
226
227
	protected function processNormalRequest($writer)
228
	{
229
		Prado::trace("Page onPreInit()", 'Prado\Web\UI\TPage');
230
		$this->onPreInit(null);
231
232
		Prado::trace("Page initRecursive()", 'Prado\Web\UI\TPage');
233
		$this->initRecursive();
234
235
		Prado::trace("Page onInitComplete()", 'Prado\Web\UI\TPage');
236
		$this->onInitComplete(null);
237
238
		Prado::trace("Page onPreLoad()", 'Prado\Web\UI\TPage');
239
		$this->onPreLoad(null);
240
		Prado::trace("Page loadRecursive()", 'Prado\Web\UI\TPage');
241
		$this->loadRecursive();
242
		Prado::trace("Page onLoadComplete()", 'Prado\Web\UI\TPage');
243
		$this->onLoadComplete(null);
244
245
		Prado::trace("Page preRenderRecursive()", 'Prado\Web\UI\TPage');
246
		$this->preRenderRecursive();
247
		Prado::trace("Page onPreRenderComplete()", 'Prado\Web\UI\TPage');
248
		$this->onPreRenderComplete(null);
249
250
		Prado::trace("Page savePageState()", 'Prado\Web\UI\TPage');
251
		$this->savePageState();
252
		Prado::trace("Page onSaveStateComplete()", 'Prado\Web\UI\TPage');
253
		$this->onSaveStateComplete(null);
254
255
		Prado::trace("Page renderControl()", 'Prado\Web\UI\TPage');
256
		$this->renderControl($writer);
257
		Prado::trace("Page unloadRecursive()", 'Prado\Web\UI\TPage');
258
		$this->unloadRecursive();
259
	}
260
261
	protected function processPostBackRequest($writer)
262
	{
263
		Prado::trace("Page onPreInit()", 'Prado\Web\UI\TPage');
264
		$this->onPreInit(null);
265
266
		Prado::trace("Page initRecursive()", 'Prado\Web\UI\TPage');
267
		$this->initRecursive();
268
269
		Prado::trace("Page onInitComplete()", 'Prado\Web\UI\TPage');
270
		$this->onInitComplete(null);
271
272
		$this->_restPostData = new TMap;
273
		Prado::trace("Page loadPageState()", 'Prado\Web\UI\TPage');
274
		$this->loadPageState();
275
		Prado::trace("Page processPostData()", 'Prado\Web\UI\TPage');
276
		$this->processPostData($this->_postData, true);
277
		Prado::trace("Page onPreLoad()", 'Prado\Web\UI\TPage');
278
		$this->onPreLoad(null);
279
		Prado::trace("Page loadRecursive()", 'Prado\Web\UI\TPage');
280
		$this->loadRecursive();
281
		Prado::trace("Page processPostData()", 'Prado\Web\UI\TPage');
282
		$this->processPostData($this->_restPostData, false);
283
		Prado::trace("Page raiseChangedEvents()", 'Prado\Web\UI\TPage');
284
		$this->raiseChangedEvents();
285
		Prado::trace("Page raisePostBackEvent()", 'Prado\Web\UI\TPage');
286
		$this->raisePostBackEvent();
287
		Prado::trace("Page onLoadComplete()", 'Prado\Web\UI\TPage');
288
		$this->onLoadComplete(null);
289
290
		Prado::trace("Page preRenderRecursive()", 'Prado\Web\UI\TPage');
291
		$this->preRenderRecursive();
292
		Prado::trace("Page onPreRenderComplete()", 'Prado\Web\UI\TPage');
293
		$this->onPreRenderComplete(null);
294
295
		Prado::trace("Page savePageState()", 'Prado\Web\UI\TPage');
296
		$this->savePageState();
297
		Prado::trace("Page onSaveStateComplete()", 'Prado\Web\UI\TPage');
298
		$this->onSaveStateComplete(null);
299
300
		Prado::trace("Page renderControl()", 'Prado\Web\UI\TPage');
301
		$this->renderControl($writer);
302
		Prado::trace("Page unloadRecursive()", 'Prado\Web\UI\TPage');
303
		$this->unloadRecursive();
304
	}
305
306
	protected static function decodeUTF8($data, $enc)
307
	{
308
		if (is_array($data)) {
309
			foreach ($data as $k => $v) {
310
				$data[$k] = self::decodeUTF8($v, $enc);
311
			}
312
			return $data;
313
		} elseif (is_string($data)) {
314
			return iconv('UTF-8', $enc . '//IGNORE', $data);
315
		} else {
316
			return $data;
317
		}
318
	}
319
320
	/**
321
	 * Sets Adapter to TActivePageAdapter and calls apter to process the
322
	 * callback request.
323
	 * @param mixed $writer
324
	 */
325
	protected function processCallbackRequest($writer)
326
	{
327
		$this->setAdapter(new TActivePageAdapter($this));
328
329
		$callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
330
		if (strlen($callbackEventParameter) > 0) {
0 ignored issues
show
Bug introduced by
It seems like $callbackEventParameter can also be of type null; however, parameter $string of strlen() 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

330
		if (strlen(/** @scrutinizer ignore-type */ $callbackEventParameter) > 0) {
Loading history...
331
			$this->_postData[TPage::FIELD_CALLBACK_PARAMETER] = TJavaScript::jsonDecode((string) $callbackEventParameter);
332
		}
333
334
		// Decode Callback postData from UTF-8 to current Charset
335
		if (($g = $this->getApplication()->getGlobalization(false)) !== null &&
336
			strtoupper($enc = $g->getCharset()) != 'UTF-8') {
337
			foreach ($this->_postData as $k => $v) {
338
				$this->_postData[$k] = self::decodeUTF8($v, $enc);
339
			}
340
		}
341
342
		Prado::trace("Page onPreInit()", 'Prado\Web\UI\TPage');
343
		$this->onPreInit(null);
344
345
		Prado::trace("Page initRecursive()", 'Prado\Web\UI\TPage');
346
		$this->initRecursive();
347
348
		Prado::trace("Page onInitComplete()", 'Prado\Web\UI\TPage');
349
		$this->onInitComplete(null);
350
351
		$this->_restPostData = new TMap;
352
		Prado::trace("Page loadPageState()", 'Prado\Web\UI\TPage');
353
		$this->loadPageState();
354
		Prado::trace("Page processPostData()", 'Prado\Web\UI\TPage');
355
		$this->processPostData($this->_postData, true);
356
		Prado::trace("Page onPreLoad()", 'Prado\Web\UI\TPage');
357
		$this->onPreLoad(null);
358
		Prado::trace("Page loadRecursive()", 'Prado\Web\UI\TPage');
359
		$this->loadRecursive();
360
361
		Prado::trace("Page processPostData()", 'Prado\Web\UI\TPage');
362
		$this->processPostData($this->_restPostData, false);
363
364
		Prado::trace("Page raiseChangedEvents()", 'Prado\Web\UI\TPage');
365
		$this->raiseChangedEvents();
366
367
368
		$this->getAdapter()->processCallbackEvent($writer);
0 ignored issues
show
Bug introduced by
The method processCallbackEvent() does not exist on Prado\Web\UI\TControlAdapter. Since you implemented __call, 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

368
		$this->getAdapter()->/** @scrutinizer ignore-call */ processCallbackEvent($writer);
Loading history...
369
370
		/*
371
				Prado::trace("Page raisePostBackEvent()",'Prado\Web\UI\TPage');
372
				$this->raisePostBackEvent();
373
		*/
374
		Prado::trace("Page onLoadComplete()", 'Prado\Web\UI\TPage');
375
		$this->onLoadComplete(null);
376
377
		Prado::trace("Page preRenderRecursive()", 'Prado\Web\UI\TPage');
378
		$this->preRenderRecursive();
379
		Prado::trace("Page onPreRenderComplete()", 'Prado\Web\UI\TPage');
380
		$this->onPreRenderComplete(null);
381
382
		Prado::trace("Page savePageState()", 'Prado\Web\UI\TPage');
383
		$this->savePageState();
384
		Prado::trace("Page onSaveStateComplete()", 'Prado\Web\UI\TPage');
385
		$this->onSaveStateComplete(null);
386
387
		/*
388
				Prado::trace("Page renderControl()",'Prado\Web\UI\TPage');
389
				$this->renderControl($writer);
390
		*/
391
		$this->getAdapter()->renderCallbackResponse($writer);
0 ignored issues
show
Bug introduced by
The method renderCallbackResponse() does not exist on Prado\Web\UI\TControlAdapter. Since you implemented __call, 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

391
		$this->getAdapter()->/** @scrutinizer ignore-call */ renderCallbackResponse($writer);
Loading history...
392
393
		Prado::trace("Page unloadRecursive()", 'Prado\Web\UI\TPage');
394
		$this->unloadRecursive();
395
	}
396
397
	/**
398
	 * Gets the callback client script handler that allows javascript functions
399
	 * to be executed during the callback response.
400
	 * @return TCallbackClientScript interface to client-side javascript code.
401
	 */
402
	public function getCallbackClient()
403
	{
404
		if ($this->getAdapter() !== null) {
405
			return $this->getAdapter()->getCallbackClientHandler();
0 ignored issues
show
Bug introduced by
The method getCallbackClientHandler() does not exist on Prado\Web\UI\TControlAdapter. Since you implemented __call, 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

405
			return $this->getAdapter()->/** @scrutinizer ignore-call */ getCallbackClientHandler();
Loading history...
406
		} else {
407
			return new TCallbackClientScript();
408
		}
409
	}
410
411
	/**
412
	 * Set a new callback client handler.
413
	 * @param TCallbackClientScript $client new callback client script handler.
414
	 */
415
	public function setCallbackClient($client)
416
	{
417
		$this->getAdapter()->setCallbackClientHandler($client);
0 ignored issues
show
Bug introduced by
The method setCallbackClientHandler() does not exist on Prado\Web\UI\TControlAdapter. Since you implemented __call, 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

417
		$this->getAdapter()->/** @scrutinizer ignore-call */ setCallbackClientHandler($client);
Loading history...
418
	}
419
420
	/**
421
	 * @return \Prado\Web\UI\TControl the control responsible for the current callback event,
422
	 * null if nonexistent
423
	 */
424
	public function getCallbackEventTarget()
425
	{
426
		return $this->getAdapter()->getCallbackEventTarget();
0 ignored issues
show
Bug introduced by
The method getCallbackEventTarget() does not exist on Prado\Web\UI\TControlAdapter. Since you implemented __call, 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

426
		return $this->getAdapter()->/** @scrutinizer ignore-call */ getCallbackEventTarget();
Loading history...
427
	}
428
429
	/**
430
	 * Registers a control to raise callback event in the current request.
431
	 * @param \Prado\Web\UI\TControl $control control registered to raise callback event.
432
	 */
433
	public function setCallbackEventTarget(TControl $control)
434
	{
435
		$this->getAdapter()->setCallbackEventTarget($control);
0 ignored issues
show
Bug introduced by
The method setCallbackEventTarget() does not exist on Prado\Web\UI\TControlAdapter. Since you implemented __call, 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

435
		$this->getAdapter()->/** @scrutinizer ignore-call */ setCallbackEventTarget($control);
Loading history...
436
	}
437
438
	/**
439
	 * Callback parameter is decoded assuming JSON encoding.
440
	 * @return string callback event parameter
441
	 */
442
	public function getCallbackEventParameter()
443
	{
444
		return $this->getAdapter()->getCallbackEventParameter();
0 ignored issues
show
Bug introduced by
The method getCallbackEventParameter() does not exist on Prado\Web\UI\TControlAdapter. Since you implemented __call, 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

444
		return $this->getAdapter()->/** @scrutinizer ignore-call */ getCallbackEventParameter();
Loading history...
445
	}
446
447
	/**
448
	 * @param mixed $value callback event parameter
449
	 */
450
	public function setCallbackEventParameter($value)
451
	{
452
		$this->getAdapter()->setCallbackEventParameter($value);
0 ignored issues
show
Bug introduced by
The method setCallbackEventParameter() does not exist on Prado\Web\UI\TControlAdapter. Since you implemented __call, 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

452
		$this->getAdapter()->/** @scrutinizer ignore-call */ setCallbackEventParameter($value);
Loading history...
453
	}
454
455
	/**
456
	 * @return TForm the form on the page
457
	 */
458
	public function getForm()
459
	{
460
		return $this->_form;
461
	}
462
463
	/**
464
	 * Registers a TForm instance to the page.
465
	 * Note, a page can contain at most one TForm instance.
466
	 * @param TForm $form the form on the page
467
	 * @throws TInvalidOperationException if this method is invoked twice or more.
468
	 */
469
	public function setForm(TForm $form)
470
	{
471
		if ($this->_form === null) {
472
			$this->_form = $form;
473
		} else {
474
			throw new TInvalidOperationException('page_form_duplicated');
475
		}
476
	}
477
478
	/**
479
	 * Returns a list of registered validators.
480
	 * If validation group is specified, only the validators in that group will be returned.
481
	 * @param null|string $validationGroup validation group
482
	 * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
483
	 */
484
	public function getValidators($validationGroup = null)
485
	{
486
		if (!$this->_validators) {
487
			$this->_validators = new TList;
488
		}
489
		if (empty($validationGroup) === true) {
490
			return $this->_validators;
491
		} else {
492
			$list = new TList;
493
			foreach ($this->_validators as $validator) {
494
				if ($validator->getValidationGroup() === $validationGroup) {
495
					$list->add($validator);
496
				}
497
			}
498
			return $list;
499
		}
500
	}
501
502
	/**
503
	 * Performs input validation.
504
	 * This method will invoke the registered validators to perform the actual validation.
505
	 * If validation group is specified, only the validators in that group will be invoked.
506
	 * @param string $validationGroup validation group. If null, all validators will perform validation.
507
	 */
508
	public function validate($validationGroup = null)
509
	{
510
		Prado::trace("Page validate()", 'Prado\Web\UI\TPage');
511
		$this->_validated = true;
512
		if ($this->_validators && $this->_validators->getCount()) {
513
			if ($validationGroup === null) {
514
				foreach ($this->_validators as $validator) {
515
					$validator->validate();
516
				}
517
			} else {
518
				foreach ($this->_validators as $validator) {
519
					if ($validator->getValidationGroup() === $validationGroup) {
520
						$validator->validate();
521
					}
522
				}
523
			}
524
		}
525
	}
526
527
	/**
528
	 * Returns whether user input is valid or not.
529
	 * This method must be invoked after {@link validate} is called.
530
	 * @throws TInvalidOperationException if {@link validate} is not invoked yet.
531
	 * @return bool whether the user input is valid or not.
532
	 */
533
	public function getIsValid()
534
	{
535
		if ($this->_validated) {
536
			if ($this->_validators && $this->_validators->getCount()) {
537
				foreach ($this->_validators as $validator) {
538
					if (!$validator->getIsValid()) {
539
						return false;
540
					}
541
				}
542
			}
543
			return true;
544
		} else {
545
			throw new TInvalidOperationException('page_isvalid_unknown');
546
		}
547
	}
548
549
	/**
550
	 * @return TTheme the theme used for the page. Defaults to null.
551
	 */
552
	public function getTheme()
553
	{
554
		if (is_string($this->_theme)) {
0 ignored issues
show
introduced by
The condition is_string($this->_theme) is always false.
Loading history...
555
			$this->_theme = $this->getService()->getThemeManager()->getTheme($this->_theme);
556
		}
557
		return $this->_theme;
558
	}
559
560
	/**
561
	 * Sets the theme to be used for the page.
562
	 * @param string|TTheme $value the theme name or the theme object to be used for the page.
563
	 */
564
	public function setTheme($value)
565
	{
566
		$this->_theme = empty($value) ? null : $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like empty($value) ? null : $value can also be of type string. However, the property $_theme is declared as type Prado\Web\UI\TTheme. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
567
	}
568
569
570
	/**
571
	 * @return TTheme the stylesheet theme used for the page. Defaults to null.
572
	 */
573
	public function getStyleSheetTheme()
574
	{
575
		if (is_string($this->_styleSheet)) {
0 ignored issues
show
introduced by
The condition is_string($this->_styleSheet) is always false.
Loading history...
576
			$this->_styleSheet = $this->getService()->getThemeManager()->getTheme($this->_styleSheet);
577
		}
578
		return $this->_styleSheet;
579
	}
580
581
	/**
582
	 * Sets the stylesheet theme to be used for the page.
583
	 * @param string|TTheme $value the stylesheet theme name or the stylesheet theme object to be used for the page.
584
	 */
585
	public function setStyleSheetTheme($value)
586
	{
587
		$this->_styleSheet = empty($value) ? null : $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like empty($value) ? null : $value can also be of type string. However, the property $_styleSheet is declared as type Prado\Web\UI\TTheme. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
588
	}
589
590
	/**
591
	 * Applies a skin in the current theme to a control.
592
	 * This method should only be used by framework developers.
593
	 * @param \Prado\Web\UI\TControl $control a control to be applied skin with
594
	 */
595
	public function applyControlSkin($control)
596
	{
597
		if (($theme = $this->getTheme()) !== null) {
598
			$theme->applySkin($control);
599
		}
600
	}
601
602
	/**
603
	 * Applies a stylesheet skin in the current theme to a control.
604
	 * This method should only be used by framework developers.
605
	 * @param \Prado\Web\UI\TControl $control a control to be applied stylesheet skin with
606
	 */
607
	public function applyControlStyleSheet($control)
608
	{
609
		if (($theme = $this->getStyleSheetTheme()) !== null) {
610
			$theme->applySkin($control);
611
		}
612
	}
613
614
	/**
615
	 * @return TClientScriptManager client script manager
616
	 */
617
	public function getClientScript()
618
	{
619
		if (!$this->_clientScript) {
620
			$className = $classPath = $this->getService()->getClientScriptManagerClass();
0 ignored issues
show
Unused Code introduced by
The assignment to $classPath is dead and can be removed.
Loading history...
Bug introduced by
The method getClientScriptManagerClass() does not exist on Prado\IService. Since it exists in all sub-types, consider adding an abstract or default implementation to Prado\IService. ( Ignorable by Annotation )

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

620
			$className = $classPath = $this->getService()->/** @scrutinizer ignore-call */ getClientScriptManagerClass();
Loading history...
621
622
			if ($className !== '\Prado\Web\UI\TClientScriptManager' && !is_subclass_of($className, '\Prado\Web\UI\TClientScriptManager')) {
623
				throw new THttpException(404, 'page_csmanagerclass_invalid', $className);
624
			}
625
626
			$this->_clientScript = new $className($this);
627
		}
628
		return $this->_clientScript;
629
	}
630
631
	/**
632
	 * Raises OnPreInit event.
633
	 * This method is invoked right before {@link onInit OnInit} stage.
634
	 * You may override this method to provide additional initialization that
635
	 * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
636
	 * {@link setStyleSheetTheme StyleSheetTheme}).
637
	 * Remember to call the parent implementation to ensure OnPreInit event is raised.
638
	 * @param mixed $param event parameter
639
	 */
640
	public function onPreInit($param)
641
	{
642
		$this->raiseEvent('OnPreInit', $this, $param);
643
	}
644
645
	/**
646
	 * Raises OnInitComplete event.
647
	 * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
648
	 * You may override this method to provide additional initialization that
649
	 * should be done after {@link onInit OnInit}.
650
	 * Remember to call the parent implementation to ensure OnInitComplete event is raised.
651
	 * @param mixed $param event parameter
652
	 */
653
	public function onInitComplete($param)
654
	{
655
		$this->raiseEvent('OnInitComplete', $this, $param);
656
	}
657
658
	/**
659
	 * Raises OnPreLoad event.
660
	 * This method is invoked right before {@link onLoad OnLoad} stage.
661
	 * You may override this method to provide additional page loading logic that
662
	 * should be done before {@link onLoad OnLoad}.
663
	 * Remember to call the parent implementation to ensure OnPreLoad event is raised.
664
	 * @param mixed $param event parameter
665
	 */
666
	public function onPreLoad($param)
667
	{
668
		$this->raiseEvent('OnPreLoad', $this, $param);
669
	}
670
671
	/**
672
	 * Raises OnLoadComplete event.
673
	 * This method is invoked right after {@link onLoad OnLoad} stage.
674
	 * You may override this method to provide additional page loading logic that
675
	 * should be done after {@link onLoad OnLoad}.
676
	 * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
677
	 * @param mixed $param event parameter
678
	 */
679
	public function onLoadComplete($param)
680
	{
681
		$this->raiseEvent('OnLoadComplete', $this, $param);
682
	}
683
684
	/**
685
	 * Raises OnPreRenderComplete event.
686
	 * This method is invoked right after {@link onPreRender OnPreRender} stage.
687
	 * You may override this method to provide additional preparation for page rendering
688
	 * that should be done after {@link onPreRender OnPreRender}.
689
	 * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
690
	 * @param mixed $param event parameter
691
	 */
692
	public function onPreRenderComplete($param)
693
	{
694
		$this->raiseEvent('OnPreRenderComplete', $this, $param);
695
		$cs = $this->getClientScript();
696
		$theme = $this->getTheme();
697
		if ($theme instanceof ITheme) {
0 ignored issues
show
introduced by
$theme is always a sub-type of Prado\Web\UI\ITheme.
Loading history...
698
			foreach ($theme->getStyleSheetFiles() as $url) {
699
				$cs->registerStyleSheetFile($url, $url, $this->getCssMediaType($url));
700
			}
701
			foreach ($theme->getJavaScriptFiles() as $url) {
702
				$cs->registerHeadScriptFile($url, $url);
703
			}
704
		}
705
		$styleSheet = $this->getStyleSheetTheme();
706
		if ($styleSheet instanceof ITheme) {
0 ignored issues
show
introduced by
$styleSheet is always a sub-type of Prado\Web\UI\ITheme.
Loading history...
707
			foreach ($styleSheet->getStyleSheetFiles() as $url) {
708
				$cs->registerStyleSheetFile($url, $url, $this->getCssMediaType($url));
709
			}
710
			foreach ($styleSheet->getJavaScriptFiles() as $url) {
711
				$cs->registerHeadScriptFile($url, $url);
712
			}
713
		}
714
715
		if ($cs->getRequiresHead() && $this->getHead() === null) {
716
			throw new TConfigurationException('page_head_required');
717
		}
718
	}
719
720
	/**
721
	 * Determines the media type of the CSS file.
722
	 * The media type is determined according to the following file name pattern:
723
	 *        xxx.media-type.extension
724
	 * For example, 'mystyle.print.css' means its media type is 'print'.
725
	 * @param string $url CSS URL
726
	 * @return string media type of the CSS file
727
	 */
728
	private function getCssMediaType($url)
729
	{
730
		$segs = explode('.', basename($url));
731
		if (isset($segs[2])) {
732
			return $segs[count($segs) - 2];
733
		} else {
734
			return '';
735
		}
736
	}
737
738
	/**
739
	 * Raises OnSaveStateComplete event.
740
	 * This method is invoked right after {@link onSaveState OnSaveState} stage.
741
	 * You may override this method to provide additional logic after page state is saved.
742
	 * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
743
	 * @param mixed $param event parameter
744
	 */
745
	public function onSaveStateComplete($param)
746
	{
747
		$this->raiseEvent('OnSaveStateComplete', $this, $param);
748
	}
749
750
	/**
751
	 * Determines whether the current page request is a postback.
752
	 * Call {@link getIsPostBack} to get the result.
753
	 */
754
	private function determinePostBackMode()
755
	{
756
		$postData = $this->getRequest();
757
		if ($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET)) {
758
			$this->_postData = $postData;
0 ignored issues
show
Documentation Bug introduced by
It seems like $postData of type Prado\Web\THttpRequest is incompatible with the declared type Prado\Collections\TMap of property $_postData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
759
		}
760
	}
761
762
	/**
763
	 * @return bool whether the current page request is a postback
764
	 */
765
	public function getIsPostBack()
766
	{
767
		return $this->_postData !== null;
768
	}
769
770
	/**
771
	 * @return bool whether this is a callback request
772
	 */
773
	public function getIsCallback()
774
	{
775
		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
776
	}
777
778
	/**
779
	 * This method is invoked when control state is to be saved.
780
	 * You can override this method to do last step state saving.
781
	 * Parent implementation must be invoked.
782
	 */
783
	public function saveState()
784
	{
785
		parent::saveState();
786
		$this->setViewState('ControlsRequiringPostBack', $this->_controlsRegisteredForPostData, []);
787
	}
788
789
	/**
790
	 * This method is invoked right after the control has loaded its state.
791
	 * You can override this method to initialize data from the control state.
792
	 * Parent implementation must be invoked.
793
	 */
794
	public function loadState()
795
	{
796
		parent::loadState();
797
		$this->_controlsRequiringPostData = $this->getViewState('ControlsRequiringPostBack', []);
798
	}
799
800
	/**
801
	 * Loads page state from persistent storage.
802
	 */
803
	protected function loadPageState()
804
	{
805
		Prado::trace("Loading state", 'Prado\Web\UI\TPage');
806
		$state = $this->getStatePersister()->load();
807
		$this->loadStateRecursive($state, $this->getEnableViewState());
808
	}
809
810
	/**
811
	 * Saves page state from persistent storage.
812
	 */
813
	protected function savePageState()
814
	{
815
		Prado::trace("Saving state", 'Prado\Web\UI\TPage');
816
		$state = &$this->saveStateRecursive($this->getEnableViewState());
817
		$this->getStatePersister()->save($state);
818
	}
819
820
	/**
821
	 * @param string $field the field name
822
	 * @return bool whether the specified field is a system field in postback data
823
	 */
824
	protected function isSystemPostField($field)
825
	{
826
		return isset(self::$_systemPostFields[$field]);
827
	}
828
829
	/**
830
	 * Registers a control for loading post data in the next postback.
831
	 * This method needs to be invoked if the control to load post data
832
	 * may not have a post variable in some cases. For example, a checkbox,
833
	 * if not checked, will not have a post value.
834
	 * @param \Prado\Web\UI\TControl $control control registered for loading post data
835
	 */
836
	public function registerRequiresPostData($control)
837
	{
838
		$id = is_string($control) ? $control : $control->getUniqueID();
839
		$this->_controlsRegisteredForPostData[$id] = true;
840
		$params = func_get_args();
0 ignored issues
show
Unused Code introduced by
The assignment to $params is dead and can be removed.
Loading history...
841
		foreach ($this->getCachingStack() as $item) {
842
			$item->registerAction('Page', 'registerRequiresPostData', [$id]);
843
		}
844
	}
845
846
	/**
847
	 * @return \Prado\Web\UI\TControl the control responsible for the current postback event, null if nonexistent
848
	 */
849
	public function getPostBackEventTarget()
850
	{
851
		if ($this->_postBackEventTarget === null && $this->_postData !== null) {
852
			$eventTarget = $this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
853
			if (!empty($eventTarget)) {
854
				$this->_postBackEventTarget = $this->findControl($eventTarget);
855
			}
856
		}
857
		return $this->_postBackEventTarget;
858
	}
859
860
	/**
861
	 * Registers a control to raise postback event in the current request.
862
	 * @param \Prado\Web\UI\TControl $control control registered to raise postback event.
863
	 */
864
	public function setPostBackEventTarget(TControl $control)
865
	{
866
		$this->_postBackEventTarget = $control;
867
	}
868
869
	/**
870
	 * @return string postback event parameter
871
	 */
872
	public function getPostBackEventParameter()
873
	{
874
		if ($this->_postBackEventParameter === null && $this->_postData !== null) {
875
			if (($this->_postBackEventParameter = $this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER)) === null) {
876
				$this->_postBackEventParameter = '';
877
			}
878
		}
879
		return $this->_postBackEventParameter;
880
	}
881
882
	/**
883
	 * @param string $value postback event parameter
884
	 */
885
	public function setPostBackEventParameter($value)
886
	{
887
		$this->_postBackEventParameter = $value;
888
	}
889
890
	/**
891
	 * Processes post data.
892
	 * @param TMap $postData post data to be processed
893
	 * @param bool $beforeLoad whether this method is invoked before {@link onLoad OnLoad}.
894
	 */
895
	protected function processPostData($postData, $beforeLoad)
896
	{
897
		$this->_isLoadingPostData = true;
898
		if ($beforeLoad) {
899
			$this->_restPostData = new TMap;
900
		}
901
		foreach ($postData as $key => $value) {
902
			if ($this->isSystemPostField($key)) {
903
				continue;
904
			} elseif ($control = $this->findControl($key)) {
905
				if ($control instanceof \Prado\Web\UI\IPostBackDataHandler) {
906
					if ($control->loadPostData($key, $postData)) {
0 ignored issues
show
Bug introduced by
$postData of type Prado\Collections\TMap is incompatible with the type array expected by parameter $values of Prado\Web\UI\IPostBackDataHandler::loadPostData(). ( Ignorable by Annotation )

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

906
					if ($control->loadPostData($key, /** @scrutinizer ignore-type */ $postData)) {
Loading history...
907
						$this->_controlsPostDataChanged[] = $control;
908
					}
909
				} elseif ($control instanceof IPostBackEventHandler &&
910
					empty($this->_postData[self::FIELD_POSTBACK_TARGET])) {
911
					// not calling setPostBackEventTarget() because the control may be removed later
912
					$this->_postData->add(self::FIELD_POSTBACK_TARGET, $key);
913
				}
914
				unset($this->_controlsRequiringPostData[$key]);
915
			} elseif ($beforeLoad) {
916
				$this->_restPostData->add($key, $value);
917
			}
918
		}
919
920
		foreach ($this->_controlsRequiringPostData as $key => $value) {
921
			if ($control = $this->findControl($key)) {
922
				if ($control instanceof \Prado\Web\UI\IPostBackDataHandler) {
923
					if ($control->loadPostData($key, $this->_postData)) {
924
						$this->_controlsPostDataChanged[] = $control;
925
					}
926
				} else {
927
					throw new TInvalidDataValueException('page_postbackcontrol_invalid', $key);
928
				}
929
				unset($this->_controlsRequiringPostData[$key]);
930
			}
931
		}
932
		$this->_isLoadingPostData = false;
933
	}
934
935
	/**
936
	 * @return bool true if loading post data.
937
	 */
938
	public function getIsLoadingPostData()
939
	{
940
		return $this->_isLoadingPostData;
941
	}
942
943
	/**
944
	 * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
945
	 */
946
	protected function raiseChangedEvents()
947
	{
948
		foreach ($this->_controlsPostDataChanged as $control) {
949
			$control->raisePostDataChangedEvent();
950
		}
951
	}
952
953
	/**
954
	 * Raises PostBack event.
955
	 */
956
	protected function raisePostBackEvent()
957
	{
958
		if (($postBackHandler = $this->getPostBackEventTarget()) === null) {
959
			$this->validate();
960
		} elseif ($postBackHandler instanceof IPostBackEventHandler) {
961
			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
0 ignored issues
show
Bug introduced by
The method raisePostBackEvent() does not exist on Prado\Web\UI\TControl. Since you implemented __call, 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

961
			$postBackHandler->/** @scrutinizer ignore-call */ 
962
                     raisePostBackEvent($this->getPostBackEventParameter());
Loading history...
962
		}
963
	}
964
965
	/**
966
	 * @return bool Whether form rendering is in progress
967
	 */
968
	public function getInFormRender()
969
	{
970
		return $this->_inFormRender;
971
	}
972
973
	/**
974
	 * Ensures the control is rendered within a form.
975
	 * @param \Prado\Web\UI\TControl $control the control to be rendered
976
	 * @throws TConfigurationException if the control is outside of the form
977
	 */
978
	public function ensureRenderInForm($control)
979
	{
980
		if (!$this->getIsCallback() && !$this->_inFormRender) {
981
			throw new TConfigurationException('page_control_outofform', get_class($control), $control ? $control->getUniqueID() : null);
0 ignored issues
show
introduced by
$control is of type Prado\Web\UI\TControl, thus it always evaluated to true.
Loading history...
982
		}
983
	}
984
985
	/**
986
	 * @internal This method is invoked by TForm at the beginning of its rendering
987
	 * @param mixed $writer
988
	 */
989
	public function beginFormRender($writer)
0 ignored issues
show
Unused Code introduced by
The parameter $writer is not used and could be removed. ( Ignorable by Annotation )

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

989
	public function beginFormRender(/** @scrutinizer ignore-unused */ $writer)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
990
	{
991
		if ($this->_formRendered) {
992
			throw new TConfigurationException('page_form_duplicated');
993
		}
994
		$this->_formRendered = true;
995
		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE, $this->getClientState());
996
		$this->_inFormRender = true;
997
	}
998
999
	/**
1000
	 * @internal This method is invoked by TForm  at the end of its rendering
1001
	 * @param mixed $writer
1002
	 */
1003
	public function endFormRender($writer)
0 ignored issues
show
Unused Code introduced by
The parameter $writer is not used and could be removed. ( Ignorable by Annotation )

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

1003
	public function endFormRender(/** @scrutinizer ignore-unused */ $writer)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1004
	{
1005
		if ($this->_focus) {
1006
			if (($this->_focus instanceof TControl) && $this->_focus->getVisible(true)) {
1007
				$focus = $this->_focus->getClientID();
1008
			} else {
1009
				$focus = $this->_focus;
1010
			}
1011
			$this->getClientScript()->registerFocusControl($focus);
1012
		} elseif ($this->_postData && ($lastFocus = $this->_postData->itemAt(self::FIELD_LASTFOCUS)) !== null) {
1013
			$this->getClientScript()->registerFocusControl($lastFocus);
1014
		}
1015
		$this->_inFormRender = false;
1016
	}
1017
1018
	/**
1019
	 * Sets input focus on a control after the page is rendered to users.
1020
	 * @param string|TControl $value control to receive focus, or the ID of the element on the page to receive focus
1021
	 */
1022
	public function setFocus($value)
1023
	{
1024
		$this->_focus = $value;
1025
	}
1026
1027
	/**
1028
	 * @return bool whether client supports javascript. Defaults to true.
1029
	 */
1030
	public function getClientSupportsJavaScript()
1031
	{
1032
		return $this->_enableJavaScript;
1033
	}
1034
1035
	/**
1036
	 * @param bool $value whether client supports javascript. If false, javascript will not be generated for controls.
1037
	 */
1038
	public function setClientSupportsJavaScript($value)
1039
	{
1040
		$this->_enableJavaScript = TPropertyValue::ensureBoolean($value);
1041
	}
1042
1043
	/**
1044
	 * @return THead page head, null if not available
1045
	 */
1046
	public function getHead()
1047
	{
1048
		return $this->_head;
1049
	}
1050
1051
	/**
1052
	 * @param THead $value page head
1053
	 * @throws TInvalidOperationException if a head already exists
1054
	 */
1055
	public function setHead(THead $value)
1056
	{
1057
		if ($this->_head) {
1058
			throw new TInvalidOperationException('page_head_duplicated');
1059
		}
1060
		$this->_head = $value;
1061
		if ($this->_title !== null) {
1062
			$this->_head->setTitle($this->_title);
1063
			$this->_title = null;
1064
		}
1065
	}
1066
1067
	/**
1068
	 * @return string page title.
1069
	 */
1070
	public function getTitle()
1071
	{
1072
		if ($this->_head) {
1073
			return $this->_head->getTitle();
1074
		} else {
1075
			return $this->_title === null ? '' : $this->_title;
1076
		}
1077
	}
1078
1079
	/**
1080
	 * Sets the page title.
1081
	 * Note, a {@link THead} control needs to place on the page
1082
	 * in order that this title be rendered.
1083
	 * @param string $value page title. This will override the title set in {@link getHead Head}.
1084
	 */
1085
	public function setTitle($value)
1086
	{
1087
		if ($this->_head) {
1088
			$this->_head->setTitle($value);
1089
		} else {
1090
			$this->_title = $value;
1091
		}
1092
	}
1093
1094
	/**
1095
	 * Returns the state to be stored on the client side.
1096
	 * This method should only be used by framework and control developers.
1097
	 * @return string the state to be stored on the client side
1098
	 */
1099
	public function getClientState()
1100
	{
1101
		return $this->_clientState;
1102
	}
1103
1104
	/**
1105
	 * Sets the state to be stored on the client side.
1106
	 * This method should only be used by framework and control developers.
1107
	 * @param string $state the state to be stored on the client side
1108
	 */
1109
	public function setClientState($state)
1110
	{
1111
		$this->_clientState = $state;
1112
	}
1113
1114
	/**
1115
	 * @return string the state postback from client side
1116
	 */
1117
	public function getRequestClientState()
1118
	{
1119
		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
1120
	}
1121
1122
	/**
1123
	 * @return string class name of the page state persister. Defaults to TPageStatePersister.
1124
	 */
1125
	public function getStatePersisterClass()
1126
	{
1127
		return $this->_statePersisterClass;
1128
	}
1129
1130
	/**
1131
	 * @param string $value class name of the page state persister.
1132
	 */
1133
	public function setStatePersisterClass($value)
1134
	{
1135
		$this->_statePersisterClass = $value;
1136
	}
1137
1138
	/**
1139
	 * @return IPageStatePersister page state persister
1140
	 */
1141
	public function getStatePersister()
1142
	{
1143
		if ($this->_statePersister === null) {
1144
			$this->_statePersister = Prado::createComponent($this->_statePersisterClass);
1145
			if (!($this->_statePersister instanceof IPageStatePersister)) {
1146
				throw new TInvalidDataTypeException('page_statepersister_invalid');
1147
			}
1148
			$this->_statePersister->setPage($this);
1149
		}
1150
		return $this->_statePersister;
1151
	}
1152
1153
	/**
1154
	 * @return bool whether page state should be HMAC validated. Defaults to true.
1155
	 */
1156
	public function getEnableStateValidation()
1157
	{
1158
		return $this->_enableStateValidation;
1159
	}
1160
1161
	/**
1162
	 * @param bool $value whether page state should be HMAC validated.
1163
	 */
1164
	public function setEnableStateValidation($value)
1165
	{
1166
		$this->_enableStateValidation = TPropertyValue::ensureBoolean($value);
1167
	}
1168
1169
	/**
1170
	 * @return bool whether page state should be encrypted. Defaults to false.
1171
	 */
1172
	public function getEnableStateEncryption()
1173
	{
1174
		return $this->_enableStateEncryption;
1175
	}
1176
1177
	/**
1178
	 * @param bool $value whether page state should be encrypted.
1179
	 */
1180
	public function setEnableStateEncryption($value)
1181
	{
1182
		$this->_enableStateEncryption = TPropertyValue::ensureBoolean($value);
1183
	}
1184
1185
	/**
1186
	 * @return bool whether page state should be compressed. Defaults to true.
1187
	 * @since 3.1.6
1188
	 */
1189
	public function getEnableStateCompression()
1190
	{
1191
		return $this->_enableStateCompression;
1192
	}
1193
1194
	/**
1195
	 * @param bool $value whether page state should be compressed.
1196
	 * @since 3.1.6
1197
	 */
1198
	public function setEnableStateCompression($value)
1199
	{
1200
		$this->_enableStateCompression = TPropertyValue::ensureBoolean($value);
1201
	}
1202
1203
	/**
1204
	 * @return bool whether page state should be serialized using igbinary if available. Defaults to true.
1205
	 * @since 4.1
1206
	 */
1207
	public function getEnableStateIGBinary()
1208
	{
1209
		return $this->_enableStateIGBinary;
1210
	}
1211
1212
	/**
1213
	 * @param bool $value whether page state should be serialized using igbinary if available.
1214
	 * @since 4.1
1215
	 */
1216
	public function setEnableStateIGBinary($value)
1217
	{
1218
		$this->_enableStateIGBinary = TPropertyValue::ensureBoolean($value);
1219
	}
1220
1221
	/**
1222
	 * @return string the requested page path for this page
1223
	 */
1224
	public function getPagePath()
1225
	{
1226
		return $this->_pagePath;
1227
	}
1228
1229
	/**
1230
	 * @param string $value the requested page path for this page
1231
	 */
1232
	public function setPagePath($value)
1233
	{
1234
		$this->_pagePath = $value;
1235
	}
1236
1237
	/**
1238
	 * Registers an action associated with the content being cached.
1239
	 * The registered action will be replayed if the content stored
1240
	 * in the cache is served to end-users.
1241
	 * @param string $context context of the action method. This is a property-path
1242
	 * referring to the context object (e.g. Page, Page.ClientScript).
1243
	 * @param string $funcName method name of the context object
1244
	 * @param array $funcParams list of parameters to be passed to the action method
1245
	 */
1246
	public function registerCachingAction($context, $funcName, $funcParams)
1247
	{
1248
		if ($this->_cachingStack) {
1249
			foreach ($this->_cachingStack as $cache) {
1250
				$cache->registerAction($context, $funcName, $funcParams);
1251
			}
1252
		}
1253
	}
1254
1255
	/**
1256
	 * @return TStack stack of {@link TOutputCache} objects
1257
	 */
1258
	public function getCachingStack()
1259
	{
1260
		if (!$this->_cachingStack) {
1261
			$this->_cachingStack = new TStack;
1262
		}
1263
		return $this->_cachingStack;
1264
	}
1265
1266
	/**
1267
	 * Flushes output
1268
	 */
1269
	public function flushWriter()
1270
	{
1271
		if ($this->_writer) {
1272
			$this->getResponse()->write($this->_writer->flush());
1273
		}
1274
	}
1275
}
1276