Test Failed
Branch master (206474)
by Fabio
18:24
created

TWizard::applyNavigationProperties()   F

Complexity

Conditions 30
Paths > 20000

Size

Total Lines 112
Code Lines 76

Duplication

Lines 49
Ratio 43.75 %

Importance

Changes 0
Metric Value
cc 30
eloc 76
nc 288002
nop 0
dl 49
loc 112
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * TWizard and the relevant class definitions.
4
 *
5
 * @author Qiang Xue <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @copyright Copyright &copy; 2005-2016 The PRADO Group
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 * @package Prado\Web\UI\WebControls
10
 */
11
12
namespace Prado\Web\UI\WebControls;
13
14
use Prado\Collections\TStack;
15
use Prado\Exceptions\TConfigurationException;
16
use Prado\Exceptions\TInvalidOperationException;
17
use Prado\TPropertyValue;
18
use Prado\Exceptions\TInvalidDataValueException;
19
20
/**
21
 * Class TWizard.
22
 *
23
 * TWizard splits a large form and presents the user with a series of smaller
24
 * forms to complete. TWizard is analogous to the installation wizard commonly
25
 * used to install software in Windows.
26
 *
27
 * The smaller forms are called wizard steps ({@link TWizardStep}, which can be accessed via
28
 * {@link getWizardSteps WizardSteps}. In template, wizard steps can be added
29
 * into a wizard using the following syntax,
30
 * <code>
31
 *   <com:TWizard>
32
 *      <com:TWizardStep Title="step 1">
33
 *          content in step 1, may contain other controls
34
 *      </com:TWizardStep>
35
 *      <com:TWizardStep Title="step 2">
36
 *          content in step 2, may contain other controls
37
 *      </com:TWizardStep>
38
 *   </com:TWizard>
39
 * </code>
40
 *
41
 * Each wizard step can be one of the following types:
42
 * - Start : the first step in the wizard.
43
 * - Step : the internal steps in the wizard.
44
 * - Finish : the last step that allows user interaction.
45
 * - Complete : the step that shows a summary to user (no interaction is allowed).
46
 * - Auto : the step type is determined by wizard automatically.
47
 * At any time, only one step is visible to end-users, which can be obtained
48
 * by {@link getActiveStep ActiveStep}. Its index in the step collection is given by
49
 * {@link getActiveStepIndex ActiveStepIndex}.
50
 *
51
 * Wizard content can be customized in many ways.
52
 *
53
 * The layout of a wizard consists of four parts: header, step content, navigation
54
 * and side bar. Their content are affected by the following properties, respectively,
55
 * - header: {@link setHeaderText HeaderText} and {@link setHeaderTemplate HeaderTemplate}.
56
 *   If both are present, the latter takes precedence.
57
 * - step: {@link getWizardSteps WizardSteps}.
58
 * - navigation: {@link setStartNavigationTemplate StartNavigationTemplate},
59
 *   {@link setStepNavigationTemplate StepNavigationTemplate},
60
 *   {@link setFinishNavigationTemplate FinishNavigationTemplate}.
61
 *   Default templates will be used if above templates are not set.
62
 * - side bar: {@link setSideBarTemplate SideBarTemplate}.
63
 *   A default template will be used if this template is not set.
64
 *   Its visibility is toggled by {@link setShowSideBar ShowSideBar}.
65
 *
66
 * The style of these wizard layout components can be customized via the following style properties,
67
 * - header: {@link getHeaderStyle HeaderStyle}.
68
 * - step: {@link getStepStyle StepStyle}.
69
 * - navigation: {@link getNavigationStyle NavigationStyle},
70
 *   {@link getStartNextButtonStyle StartNextButtonStyle},
71
 *   {@link getStepNextButtonStyle StepNextButtonStyle},
72
 *   {@link getStepPreviousButtonStyle StepPreviousButtonStyle},
73
 *   {@link getFinishPreviousButtonStyle FinishPreviousButtonStyle},
74
 *   {@link getFinishCompleteButtonStyle FinishCompleteButtonStyle},
75
 *   {@link getCancelButtonStyle CancelButtonStyle}.
76
 * - side bar: {@link getSideBarStyle SideBarStyle} and {@link getSideBarButtonStyle SideBarButtonStyle}.
77
 *
78
 * @author Qiang Xue <[email protected]>
79
 * @package Prado\Web\UI\WebControls
80
 * @since 3.0
81
 */
82
class TWizard extends \Prado\Web\UI\WebControls\TWebControl implements \Prado\Web\UI\INamingContainer
83
{
84
	/**
85
	 * Navigation commands.
86
	 */
87
	const CMD_PREVIOUS = 'PreviousStep';
88
	const CMD_NEXT = 'NextStep';
89
	const CMD_CANCEL = 'Cancel';
90
	const CMD_COMPLETE = 'Complete';
91
	const CMD_MOVETO = 'MoveTo';
92
	/**
93
	 * Side bar button ID
94
	 */
95
	const ID_SIDEBAR_BUTTON = 'SideBarButton';
96
	/**
97
	 * Side bar data list
98
	 */
99
	const ID_SIDEBAR_LIST = 'SideBarList';
100
101
	/**
102
	 * @var TMultiView multiview that contains the wizard steps
103
	 */
104
	private $_multiView;
105
	/**
106
	 * @var mixed navigation template for the start step.
107
	 */
108
	private $_startNavigationTemplate;
109
	/**
110
	 * @var mixed navigation template for internal steps.
111
	 */
112
	private $_stepNavigationTemplate;
113
	/**
114
	 * @var mixed navigation template for the finish step.
115
	 */
116
	private $_finishNavigationTemplate;
117
	/**
118
	 * @var mixed template for wizard header.
119
	 */
120
	private $_headerTemplate;
121
	/**
122
	 * @var mixed template for the side bar.
123
	 */
124
	private $_sideBarTemplate;
125
	/**
126
	 * @var TWizardStepCollection
127
	 */
128
	private $_wizardSteps;
129
	/**
130
	 * @var TPanel container of the wizard header
131
	 */
132
	private $_header;
133
	/**
134
	 * @var TPanel container of the wizard step content
135
	 */
136
	private $_stepContent;
137
	/**
138
	 * @var TPanel container of the wizard side bar
139
	 */
140
	private $_sideBar;
141
	/**
142
	 * @var TPanel navigation panel
143
	 */
144
	private $_navigation;
145
	/**
146
	 * @var TWizardNavigationContainer container of the start navigation
147
	 */
148
	private $_startNavigation;
149
	/**
150
	 * @var TWizardNavigationContainer container of the step navigation
151
	 */
152
	private $_stepNavigation;
153
	/**
154
	 * @var TWizardNavigationContainer container of the finish navigation
155
	 */
156
	private $_finishNavigation;
157
	/**
158
	 * @var bool whether ActiveStepIndex was already set
159
	 */
160
	private $_activeStepIndexSet = false;
161
	/**
162
	 * @var TDataList side bar data list.
163
	 */
164
	private $_sideBarDataList;
165
	/**
166
	 * @var bool whether navigation should be cancelled (a status set in OnSideBarButtonClick)
167
	 */
168
	private $_cancelNavigation = false;
169
170
	/**
171
	 * @return string tag name for the wizard
172
	 */
173
	protected function getTagName()
174
	{
175
		return 'div';
176
	}
177
178
	/**
179
	 * Adds {@link TWizardStep} objects into step collection.
180
	 * This method overrides the parent implementation and is
181
	 * invoked when template is being instantiated.
182
	 * @param mixed $object object instantiated in template
183
	 */
184
	public function addParsedObject($object)
185
	{
186
		if ($object instanceof TWizardStep) {
187
			$this->getWizardSteps()->add($object);
188
		}
189
	}
190
191
	/**
192
	 * @return TWizardStep the currently active wizard step
193
	 */
194
	public function getActiveStep()
195
	{
196
		return $this->getMultiView()->getActiveView();
197
	}
198
199
	/**
200
	 * @param TWizardStep $step step to be activated
201
	 * @throws TInvalidOperationException if the step is not in the wizard step collection
202
	 */
203
	public function setActiveStep($step)
204
	{
205
		if (($index = $this->getWizardSteps()->indexOf($step)) < 0) {
206
			throw new TInvalidOperationException('wizard_step_invalid');
207
		}
208
		$this->setActiveStepIndex($index);
209
	}
210
211
	/**
212
	 * @return int the zero-based index of the active wizard step
213
	 */
214
	public function getActiveStepIndex()
215
	{
216
		return $this->getMultiView()->getActiveViewIndex();
217
	}
218
219
	/**
220
	 * @param int $value the zero-based index of the wizard step to be activated
221
	 */
222
	public function setActiveStepIndex($value)
223
	{
224
		$value = TPropertyValue::ensureInteger($value);
225
		$multiView = $this->getMultiView();
226
		if ($multiView->getActiveViewIndex() !== $value) {
227
			$multiView->setActiveViewIndex($value);
228
			$this->_activeStepIndexSet = true;
229
			if ($this->_sideBarDataList !== null && $this->getSideBarTemplate() !== null) {
230
				$this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
231
				$this->_sideBarDataList->dataBind();
232
			}
233
		}
234
	}
235
236
	/**
237
	 * @return TWizardStepCollection collection of wizard steps
238
	 */
239
	public function getWizardSteps()
240
	{
241
		if ($this->_wizardSteps === null) {
242
			$this->_wizardSteps = new TWizardStepCollection($this);
243
		}
244
		return $this->_wizardSteps;
245
	}
246
247
	/**
248
	 * @return bool whether to display a cancel button in each wizard step. Defaults to false.
249
	 */
250
	public function getShowCancelButton()
251
	{
252
		return $this->getViewState('ShowCancelButton', false);
253
	}
254
255
	/**
256
	 * @param bool $value whether to display a cancel button in each wizard step.
257
	 */
258
	public function setShowCancelButton($value)
259
	{
260
		$this->setViewState('ShowCancelButton', TPropertyValue::ensureBoolean($value), false);
261
	}
262
263
	/**
264
	 * @return bool whether to display a side bar that contains links to wizard steps. Defaults to true.
265
	 */
266
	public function getShowSideBar()
267
	{
268
		return $this->getViewState('ShowSideBar', true);
269
	}
270
271
	/**
272
	 * @param bool $value whether to display a side bar that contains links to wizard steps.
273
	 */
274
	public function setShowSideBar($value)
275
	{
276
		$this->setViewState('ShowSideBar', TPropertyValue::ensureBoolean($value), true);
277
	}
278
279
	/**
280
	 * @return ITemplate navigation template for the start step. Defaults to null.
281
	 */
282
	public function getStartNavigationTemplate()
283
	{
284
		return $this->_startNavigationTemplate;
285
	}
286
287
	/**
288
	 * @param ITemplate $value navigation template for the start step.
289
	 */
290
	public function setStartNavigationTemplate($value)
291
	{
292
		$this->_startNavigationTemplate = $value;
293
		$this->requiresControlsRecreation();
294
	}
295
296
	/**
297
	 * @return ITemplate navigation template for internal steps. Defaults to null.
298
	 */
299
	public function getStepNavigationTemplate()
300
	{
301
		return $this->_stepNavigationTemplate;
302
	}
303
304
	/**
305
	 * @param ITemplate $value navigation template for internal steps.
306
	 */
307
	public function setStepNavigationTemplate($value)
308
	{
309
		$this->_stepNavigationTemplate = $value;
310
		$this->requiresControlsRecreation();
311
	}
312
313
	/**
314
	 * @return ITemplate navigation template for the finish step. Defaults to null.
315
	 */
316
	public function getFinishNavigationTemplate()
317
	{
318
		return $this->_finishNavigationTemplate;
319
	}
320
321
	/**
322
	 * @param ITemplate $value navigation template for the finish step.
323
	 */
324
	public function setFinishNavigationTemplate($value)
325
	{
326
		$this->_finishNavigationTemplate = $value;
327
		$this->requiresControlsRecreation();
328
	}
329
330
	/**
331
	 * @return ITemplate template for wizard header. Defaults to null.
332
	 */
333
	public function getHeaderTemplate()
334
	{
335
		return $this->_headerTemplate;
336
	}
337
338
	/**
339
	 * @param ITemplate $value template for wizard header.
340
	 */
341
	public function setHeaderTemplate($value)
342
	{
343
		$this->_headerTemplate = $value;
344
		$this->requiresControlsRecreation();
345
	}
346
347
	/**
348
	 * @return ITemplate template for the side bar. Defaults to null.
349
	 */
350
	public function getSideBarTemplate()
351
	{
352
		return $this->_sideBarTemplate;
353
	}
354
355
	/**
356
	 * @param ITemplate $value template for the side bar.
357
	 */
358
	public function setSideBarTemplate($value)
359
	{
360
		$this->_sideBarTemplate = $value;
361
		$this->requiresControlsRecreation();
362
	}
363
364
	/**
365
	 * @return string header text. Defaults to ''.
366
	 */
367
	public function getHeaderText()
368
	{
369
		return $this->getViewState('HeaderText', '');
370
	}
371
372
	/**
373
	 * @param string $value header text.
374
	 */
375
	public function setHeaderText($value)
376
	{
377
		$this->setViewState('HeaderText', TPropertyValue::ensureString($value), '');
378
	}
379
380
	/**
381
	 * @return string the URL that the browser will be redirected to if the cancel button in the
382
	 * wizard is clicked. Defaults to ''.
383
	 */
384
	public function getCancelDestinationUrl()
385
	{
386
		return $this->getViewState('CancelDestinationUrl', '');
387
	}
388
389
	/**
390
	 * @param string $value the URL that the browser will be redirected to if the cancel button in the
391
	 * wizard is clicked.
392
	 */
393
	public function setCancelDestinationUrl($value)
394
	{
395
		$this->setViewState('CancelDestinationUrl', TPropertyValue::ensureString($value), '');
396
	}
397
398
	/**
399
	 * @return string the URL that the browser will be redirected to if the wizard finishes.
400
	 * Defaults to ''.
401
	 */
402
	public function getFinishDestinationUrl()
403
	{
404
		return $this->getViewState('FinishDestinationUrl', '');
405
	}
406
407
	/**
408
	 * @param string $value the URL that the browser will be redirected to if the wizard finishes.
409
	 */
410
	public function setFinishDestinationUrl($value)
411
	{
412
		$this->setViewState('FinishDestinationUrl', TPropertyValue::ensureString($value), '');
413
	}
414
415
	/**
416
	 * @return TStyle the style for the buttons displayed in the side bar.
417
	 */
418 View Code Duplication
	public function getSideBarButtonStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
419
	{
420
		if (($style = $this->getViewState('SideBarButtonStyle', null)) === null) {
421
			$style = new TStyle;
422
			$this->setViewState('SideBarButtonStyle', $style, null);
423
		}
424
		return $style;
425
	}
426
427
	/**
428
	 * @return TStyle the style common for all navigation buttons.
429
	 */
430 View Code Duplication
	public function getNavigationButtonStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
431
	{
432
		if (($style = $this->getViewState('NavigationButtonStyle', null)) === null) {
433
			$style = new TStyle;
434
			$this->setViewState('NavigationButtonStyle', $style, null);
435
		}
436
		return $style;
437
	}
438
439
	/**
440
	 * @return TWizardNavigationButtonStyle the style for the next button in the start wizard step.
441
	 */
442 View Code Duplication
	public function getStartNextButtonStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
443
	{
444
		if (($style = $this->getViewState('StartNextButtonStyle', null)) === null) {
445
			$style = new TWizardNavigationButtonStyle;
446
			$style->setButtonText('Next');
447
			$this->setViewState('StartNextButtonStyle', $style, null);
448
		}
449
		return $style;
450
	}
451
452
	/**
453
	 * @return TWizardNavigationButtonStyle the style for the next button in each internal wizard step.
454
	 */
455 View Code Duplication
	public function getStepNextButtonStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
456
	{
457
		if (($style = $this->getViewState('StepNextButtonStyle', null)) === null) {
458
			$style = new TWizardNavigationButtonStyle;
459
			$style->setButtonText('Next');
460
			$this->setViewState('StepNextButtonStyle', $style, null);
461
		}
462
		return $style;
463
	}
464
465
	/**
466
	 * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
467
	 */
468 View Code Duplication
	public function getStepPreviousButtonStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
469
	{
470
		if (($style = $this->getViewState('StepPreviousButtonStyle', null)) === null) {
471
			$style = new TWizardNavigationButtonStyle;
472
			$style->setButtonText('Previous');
473
			$this->setViewState('StepPreviousButtonStyle', $style, null);
474
		}
475
		return $style;
476
	}
477
478
	/**
479
	 * @return TWizardNavigationButtonStyle the style for the complete button in the finish wizard step.
480
	 */
481 View Code Duplication
	public function getFinishCompleteButtonStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
482
	{
483
		if (($style = $this->getViewState('FinishCompleteButtonStyle', null)) === null) {
484
			$style = new TWizardNavigationButtonStyle;
485
			$style->setButtonText('Complete');
486
			$this->setViewState('FinishCompleteButtonStyle', $style, null);
487
		}
488
		return $style;
489
	}
490
491
	/**
492
	 * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
493
	 */
494 View Code Duplication
	public function getFinishPreviousButtonStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
495
	{
496
		if (($style = $this->getViewState('FinishPreviousButtonStyle', null)) === null) {
497
			$style = new TWizardNavigationButtonStyle;
498
			$style->setButtonText('Previous');
499
			$this->setViewState('FinishPreviousButtonStyle', $style, null);
500
		}
501
		return $style;
502
	}
503
504
	/**
505
	 * @return TWizardNavigationButtonStyle the style for the cancel button
506
	 */
507 View Code Duplication
	public function getCancelButtonStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
508
	{
509
		if (($style = $this->getViewState('CancelButtonStyle', null)) === null) {
510
			$style = new TWizardNavigationButtonStyle;
511
			$style->setButtonText('Cancel');
512
			$this->setViewState('CancelButtonStyle', $style, null);
513
		}
514
		return $style;
515
	}
516
517
	/**
518
	 * @return TPanelStyle the style for the side bar.
519
	 */
520 View Code Duplication
	public function getSideBarStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
521
	{
522
		if (($style = $this->getViewState('SideBarStyle', null)) === null) {
523
			$style = new TPanelStyle;
524
			$this->setViewState('SideBarStyle', $style, null);
525
		}
526
		return $style;
527
	}
528
529
	/**
530
	 * @return TPanelStyle the style for the header.
531
	 */
532 View Code Duplication
	public function getHeaderStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
533
	{
534
		if (($style = $this->getViewState('HeaderStyle', null)) === null) {
535
			$style = new TPanelStyle;
536
			$this->setViewState('HeaderStyle', $style, null);
537
		}
538
		return $style;
539
	}
540
541
	/**
542
	 * @return TPanelStyle the style for each internal wizard step.
543
	 */
544 View Code Duplication
	public function getStepStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
545
	{
546
		if (($style = $this->getViewState('StepStyle', null)) === null) {
547
			$style = new TPanelStyle;
548
			$this->setViewState('StepStyle', $style, null);
549
		}
550
		return $style;
551
	}
552
553
	/**
554
	 * @return TPanelStyle the style for the navigation panel.
555
	 */
556 View Code Duplication
	public function getNavigationStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
557
	{
558
		if (($style = $this->getViewState('NavigationStyle', null)) === null) {
559
			$style = new TPanelStyle;
560
			$this->setViewState('NavigationStyle', $style, null);
561
		}
562
		return $style;
563
	}
564
565
	/**
566
	 * @return bool whether to use default layout to arrange side bar and the rest wizard components. Defaults to true.
567
	 */
568
	public function getUseDefaultLayout()
569
	{
570
		return $this->getViewState('UseDefaultLayout', true);
571
	}
572
573
	/**
574
	 * @param bool $value whether to use default layout to arrange side bar and the rest wizard components.
575
	 * If true, an HTML table will be used which places the side bar in the left cell
576
	 * while the rest components in the right cell.
577
	 */
578
	public function setUseDefaultLayout($value)
579
	{
580
		$this->setViewState('UseDefaultLayout', TPropertyValue::ensureBoolean($value), true);
581
	}
582
583
	/**
584
	 * @return TPanel container of the wizard header
585
	 */
586
	public function getHeader()
587
	{
588
		return $this->_header;
589
	}
590
591
	/**
592
	 * @return TPanel container of the wizard step content
593
	 */
594
	public function getStepContent()
595
	{
596
		return $this->_stepContent;
597
	}
598
599
	/**
600
	 * @return TPanel container of the wizard side bar
601
	 */
602
	public function getSideBar()
603
	{
604
		return $this->_sideBar;
605
	}
606
607
	/**
608
	 * @return TWizardNavigationContainer container of the start navigation
609
	 */
610
	public function getStartNavigation()
611
	{
612
		return $this->_startNavigation;
613
	}
614
615
	/**
616
	 * @return TWizardNavigationContainer container of the step navigation
617
	 */
618
	public function getStepNavigation()
619
	{
620
		return $this->_stepNavigation;
621
	}
622
623
	/**
624
	 * @return TWizardNavigationContainer container of the finish navigation
625
	 */
626
	public function getFinishNavigation()
627
	{
628
		return $this->_finishNavigation;
629
	}
630
631
	/**
632
	 * Raises <b>OnActiveStepChanged</b> event.
633
	 * This event is raised when the current visible step is changed in the
634
	 * wizard.
635
	 * @param TEventParameter $param event parameter
636
	 */
637
	public function onActiveStepChanged($param)
638
	{
639
		$this->raiseEvent('OnActiveStepChanged', $this, $param);
640
	}
641
642
	/**
643
	 * Raises <b>OnCancelButtonClick</b> event.
644
	 * This event is raised when a cancel navigation button is clicked in the
645
	 * current active step.
646
	 * @param TEventParameter $param event parameter
647
	 */
648
	public function onCancelButtonClick($param)
649
	{
650
		$this->raiseEvent('OnCancelButtonClick', $this, $param);
651
		if (($url = $this->getCancelDestinationUrl()) !== '') {
652
			$this->getResponse()->redirect($url);
653
		}
654
	}
655
656
	/**
657
	 * Raises <b>OnCompleteButtonClick</b> event.
658
	 * This event is raised when a finish navigation button is clicked in the
659
	 * current active step.
660
	 * @param TWizardNavigationEventParameter $param event parameter
661
	 */
662
	public function onCompleteButtonClick($param)
663
	{
664
		$this->raiseEvent('OnCompleteButtonClick', $this, $param);
665
		if (($url = $this->getFinishDestinationUrl()) !== '') {
666
			$this->getResponse()->redirect($url);
667
		}
668
	}
669
670
	/**
671
	 * Raises <b>OnNextButtonClick</b> event.
672
	 * This event is raised when a next navigation button is clicked in the
673
	 * current active step.
674
	 * @param TWizardNavigationEventParameter $param event parameter
675
	 */
676
	public function onNextButtonClick($param)
677
	{
678
		$this->raiseEvent('OnNextButtonClick', $this, $param);
679
	}
680
681
	/**
682
	 * Raises <b>OnPreviousButtonClick</b> event.
683
	 * This event is raised when a previous navigation button is clicked in the
684
	 * current active step.
685
	 * @param TWizardNavigationEventParameter $param event parameter
686
	 */
687
	public function onPreviousButtonClick($param)
688
	{
689
		$this->raiseEvent('OnPreviousButtonClick', $this, $param);
690
	}
691
692
	/**
693
	 * Raises <b>OnSideBarButtonClick</b> event.
694
	 * This event is raised when a link button in the side bar is clicked.
695
	 * @param TWizardNavigationEventParameter $param event parameter
696
	 */
697
	public function onSideBarButtonClick($param)
698
	{
699
		$this->raiseEvent('OnSideBarButtonClick', $this, $param);
700
	}
701
702
	/**
703
	 * Returns the multiview that holds the wizard steps.
704
	 * This method should only be used by control developers.
705
	 * @return TMultiView the multiview holding wizard steps
706
	 */
707
	public function getMultiView()
708
	{
709
		if ($this->_multiView === null) {
710
			$this->_multiView = new TMultiView;
711
			$this->_multiView->setID('WizardMultiView');
712
			$this->_multiView->attachEventHandler('OnActiveViewChanged', [$this, 'onActiveStepChanged']);
713
			$this->_multiView->ignoreBubbleEvents();
714
		}
715
		return $this->_multiView;
716
	}
717
718
	/**
719
	 * Adds a wizard step to the multiview.
720
	 * This method should only be used by control developers.
721
	 * It is invoked when a step is added into the step collection of the wizard.
722
	 * @param TWizardStep $step wizard step to be added into multiview.
723
	 */
724
	public function addedWizardStep($step)
725
	{
726
		if (($wizard = $step->getWizard()) !== null) {
727
			$wizard->getWizardSteps()->remove($step);
728
		}
729
		$step->setWizard($this);
730
		$this->wizardStepsChanged();
731
	}
732
733
	/**
734
	 * Removes a wizard step from the multiview.
735
	 * This method should only be used by control developers.
736
	 * It is invoked when a step is removed from the step collection of the wizard.
737
	 * @param TWizardStep $step wizard step to be removed from multiview.
738
	 */
739
	public function removedWizardStep($step)
740
	{
741
		$step->setWizard(null);
742
		$this->wizardStepsChanged();
743
	}
744
745
	/**
746
	 * Creates the child controls of the wizard.
747
	 * This method overrides the parent implementation.
748
	 * @param TEventParameter $param event parameter
749
	 */
750
	public function onInit($param)
751
	{
752
		parent::onInit($param);
753
		$this->ensureChildControls();
754
		$this->setEnsureId(true);
755
		if ($this->getActiveStepIndex() < 0 && $this->getWizardSteps()->getCount() > 0) {
756
			$this->setActiveStepIndex(0);
757
		}
758
	}
759
760
	/**
761
	 * Saves the current active step index into history.
762
	 * This method is invoked by the framework when the control state is being saved.
763
	 */
764
	public function saveState()
765
	{
766
		$index = $this->getActiveStepIndex();
767
		$history = $this->getHistory();
768
		if (!$history->getCount() || $history->peek() !== $index) {
769
			$history->push($index);
770
		}
771
	}
772
773
	/**
774
	 * Indicates the wizard needs to recreate all child controls.
775
	 */
776
	protected function requiresControlsRecreation()
777
	{
778
		if ($this->getChildControlsCreated()) {
779
			$this->setChildControlsCreated(false);
780
		}
781
	}
782
783
	/**
784
	 * Renders the wizard.
785
	 * @param THtmlWriter $writer
786
	 */
787
	public function render($writer)
788
	{
789
		$this->ensureChildControls();
790
		if ($this->getHasControls()) {
791
			if ($this->getUseDefaultLayout()) {
792
				$this->applyControlProperties();
793
				$this->renderBeginTag($writer);
794
				$writer->write("\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" height=\"100%\" width=\"100%\">\n<tr><td width=\"1\" valign=\"top\">\n");
795
				$this->_sideBar->renderControl($writer);
796
				$writer->write("\n</td><td valign=\"top\">\n");
797
				$this->_header->renderControl($writer);
798
				$this->_stepContent->renderControl($writer);
799
				$this->_navigation->renderControl($writer);
800
				$writer->write("\n</td></tr></table>\n");
801
				$this->renderEndTag($writer);
802
			} else {
803
				$this->applyControlProperties();
804
				$this->renderBeginTag($writer);
805
				$this->_sideBar->renderControl($writer);
806
				$this->_header->renderControl($writer);
807
				$this->_stepContent->renderControl($writer);
808
				$this->_navigation->renderControl($writer);
809
				$this->renderEndTag($writer);
810
			}
811
		}
812
	}
813
814
	/**
815
	 * Applies various properties to the components of wizard
816
	 */
817
	protected function applyControlProperties()
818
	{
819
		$this->applyHeaderProperties();
820
		$this->applySideBarProperties();
821
		$this->applyStepContentProperties();
822
		$this->applyNavigationProperties();
823
	}
824
825
	/**
826
	 * Applies properties to the wizard header
827
	 */
828
	protected function applyHeaderProperties()
829
	{
830
		if (($style = $this->getViewState('HeaderStyle', null)) !== null) {
831
			$this->_header->getStyle()->mergeWith($style);
832
		}
833 View Code Duplication
		if ($this->getHeaderTemplate() === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
834
			$this->_header->getControls()->clear();
835
			$this->_header->getControls()->add($this->getHeaderText());
836
		}
837
	}
838
839
	/**
840
	 * Applies properties to the wizard sidebar
841
	 */
842
	protected function applySideBarProperties()
843
	{
844
		$this->_sideBar->setVisible($this->getShowSideBar());
845
		if ($this->_sideBarDataList !== null && $this->getShowSideBar()) {
846
			$this->_sideBarDataList->setDataSource($this->getWizardSteps());
847
			$this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
848
			$this->_sideBarDataList->dataBind();
849
			if (($style = $this->getViewState('SideBarButtonStyle', null)) !== null) {
850
				foreach ($this->_sideBarDataList->getItems() as $item) {
851
					if (($button = $item->findControl('SideBarButton')) !== null) {
852
						$button->getStyle()->mergeWith($style);
853
					}
854
				}
855
			}
856
		}
857
		if (($style = $this->getViewState('SideBarStyle', null)) !== null) {
858
			$this->_sideBar->getStyle()->mergeWith($style);
859
		}
860
	}
861
862
	/**
863
	 * Applies properties to the wizard step content
864
	 */
865
	protected function applyStepContentProperties()
866
	{
867
		if (($style = $this->getViewState('StepStyle', null)) !== null) {
868
			$this->_stepContent->getStyle()->mergeWith($style);
869
		}
870
	}
871
872
	/**
873
	 * Apply properties to various navigation panels.
874
	 */
875
	protected function applyNavigationProperties()
876
	{
877
		$wizardSteps = $this->getWizardSteps();
878
		$activeStep = $this->getActiveStep();
879
		$activeStepIndex = $this->getActiveStepIndex();
880
881
		if (!$this->_navigation) {
882
			return;
883
		} elseif ($activeStepIndex < 0 || $activeStepIndex >= $wizardSteps->getCount()) {
884
			$this->_navigation->setVisible(false);
885
			return;
886
		}
887
888
		// set visibility of different types of navigation panel
889
		$showStandard = true;
890
		foreach ($wizardSteps as $step) {
891
			if (($step instanceof TTemplatedWizardStep) && ($container = $step->getNavigationContainer()) !== null) {
892
				if ($activeStep === $step) {
893
					$container->setVisible(true);
894
					$showStandard = false;
895
				} else {
896
					$container->setVisible(false);
897
				}
898
			}
899
		}
900
		$activeStepType = $this->getStepType($activeStep);
901
		if ($activeStepType === TWizardStepType::Complete) {
902
			$this->_sideBar->setVisible(false);
903
			$this->_header->setVisible(false);
904
		}
905
		$this->_startNavigation->setVisible($showStandard && $activeStepType === TWizardStepType::Start);
906
		$this->_stepNavigation->setVisible($showStandard && $activeStepType === TWizardStepType::Step);
907
		$this->_finishNavigation->setVisible($showStandard && $activeStepType === TWizardStepType::Finish);
908
909
		if (($navigationStyle = $this->getViewState('NavigationStyle', null)) !== null) {
910
			$this->_navigation->getStyle()->mergeWith($navigationStyle);
911
		}
912
913
		$displayCancelButton = $this->getShowCancelButton();
914
		$cancelButtonStyle = $this->getCancelButtonStyle();
915
		$buttonStyle = $this->getViewState('NavigationButtonStyle', null);
916
		if ($buttonStyle !== null) {
917
			$cancelButtonStyle->mergeWith($buttonStyle);
918
		}
919
920
		// apply styles to start navigation buttons
921
		if (($cancelButton = $this->_startNavigation->getCancelButton()) !== null) {
922
			$cancelButton->setVisible($displayCancelButton);
923
			$cancelButtonStyle->apply($cancelButton);
924
		}
925 View Code Duplication
		if (($button = $this->_startNavigation->getNextButton()) !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
926
			$button->setVisible(true);
927
			$style = $this->getStartNextButtonStyle();
928
			if ($buttonStyle !== null) {
929
				$style->mergeWith($buttonStyle);
930
			}
931
			$style->apply($button);
932
			if ($activeStepType === TWizardStepType::Start) {
933
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
934
			}
935
		}
936
937
		// apply styles to finish navigation buttons
938
		if (($cancelButton = $this->_finishNavigation->getCancelButton()) !== null) {
939
			$cancelButton->setVisible($displayCancelButton);
940
			$cancelButtonStyle->apply($cancelButton);
941
		}
942 View Code Duplication
		if (($button = $this->_finishNavigation->getPreviousButton()) !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
943
			$button->setVisible($this->allowNavigationToPreviousStep());
944
			$style = $this->getFinishPreviousButtonStyle();
945
			if ($buttonStyle !== null) {
946
				$style->mergeWith($buttonStyle);
947
			}
948
			$style->apply($button);
949
		}
950 View Code Duplication
		if (($button = $this->_finishNavigation->getCompleteButton()) !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
951
			$button->setVisible(true);
952
			$style = $this->getFinishCompleteButtonStyle();
953
			if ($buttonStyle !== null) {
954
				$style->mergeWith($buttonStyle);
955
			}
956
			$style->apply($button);
957
			if ($activeStepType === TWizardStepType::Finish) {
958
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
959
			}
960
		}
961
962
		// apply styles to step navigation buttons
963
		if (($cancelButton = $this->_stepNavigation->getCancelButton()) !== null) {
964
			$cancelButton->setVisible($displayCancelButton);
965
			$cancelButtonStyle->apply($cancelButton);
966
		}
967 View Code Duplication
		if (($button = $this->_stepNavigation->getPreviousButton()) !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
968
			$button->setVisible($this->allowNavigationToPreviousStep());
969
			$style = $this->getStepPreviousButtonStyle();
970
			if ($buttonStyle !== null) {
971
				$style->mergeWith($buttonStyle);
972
			}
973
			$style->apply($button);
974
		}
975 View Code Duplication
		if (($button = $this->_stepNavigation->getNextButton()) !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
976
			$button->setVisible(true);
977
			$style = $this->getStepNextButtonStyle();
978
			if ($buttonStyle !== null) {
979
				$style->mergeWith($buttonStyle);
980
			}
981
			$style->apply($button);
982
			if ($activeStepType === TWizardStepType::Step) {
983
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
984
			}
985
		}
986
	}
987
988
	/**
989
	 * @return TStack history containing step indexes that were navigated before
990
	 */
991
	protected function getHistory()
992
	{
993
		if (($history = $this->getControlState('History', null)) === null) {
994
			$history = new TStack;
995
			$this->setControlState('History', $history);
996
		}
997
		return $history;
998
	}
999
1000
	/**
1001
	 * Determines the type of the specified wizard step.
1002
	 * @param TWizardStep $wizardStep * @return TWizardStepType type of the step
1003
	 */
1004
	protected function getStepType($wizardStep)
1005
	{
1006
		if (($type = $wizardStep->getStepType()) === TWizardStepType::Auto) {
1007
			$steps = $this->getWizardSteps();
1008
			if (($index = $steps->indexOf($wizardStep)) >= 0) {
1009
				$stepCount = $steps->getCount();
1010
				if ($stepCount === 1 || ($index < $stepCount - 1 && $steps->itemAt($index + 1)->getStepType() === TWizardStepType::Complete)) {
1011
					return TWizardStepType::Finish;
1012
				} elseif ($index === 0) {
1013
					return TWizardStepType::Start;
1014
				} elseif ($index === $stepCount - 1) {
1015
					return TWizardStepType::Finish;
1016
				} else {
1017
					return TWizardStepType::Step;
1018
				}
1019
			} else {
1020
				return $type;
1021
			}
1022
		} else {
1023
			return $type;
1024
		}
1025
	}
1026
1027
	/**
1028
	 * Clears up everything within the wizard.
1029
	 */
1030
	protected function reset()
1031
	{
1032
		$this->getControls()->clear();
1033
		$this->_header = null;
1034
		$this->_stepContent = null;
1035
		$this->_sideBar = null;
1036
		$this->_sideBarDataList = null;
1037
		$this->_navigation = null;
1038
		$this->_startNavigation = null;
1039
		$this->_stepNavigation = null;
1040
		$this->_finishNavigation = null;
1041
	}
1042
1043
	/**
1044
	 * Creates child controls within the wizard
1045
	 */
1046
	public function createChildControls()
1047
	{
1048
		$this->reset();
1049
		$this->createSideBar();
1050
		$this->createHeader();
1051
		$this->createStepContent();
1052
		$this->createNavigation();
1053
//		$this->clearChildState();
1054
	}
1055
1056
	/**
1057
	 * Creates the wizard header.
1058
	 */
1059
	protected function createHeader()
1060
	{
1061
		$this->_header = new TPanel;
1062 View Code Duplication
		if (($template = $this->getHeaderTemplate()) !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1063
			$template->instantiateIn($this->_header);
1064
		} else {
1065
			$this->_header->getControls()->add($this->getHeaderText());
1066
		}
1067
		$this->getControls()->add($this->_header);
1068
	}
1069
1070
	/**
1071
	 * Creates the wizard side bar
1072
	 */
1073
	protected function createSideBar()
1074
	{
1075
		if ($this->getShowSideBar()) {
1076
			if (($template = $this->getSideBarTemplate()) === null) {
1077
				$template = new TWizardSideBarTemplate;
1078
			}
1079
			$this->_sideBar = new TPanel;
1080
			$template->instantiateIn($this->_sideBar);
1081
			$this->getControls()->add($this->_sideBar);
1082
1083
			if (($this->_sideBarDataList = $this->_sideBar->findControl(self::ID_SIDEBAR_LIST)) !== null) {
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->_sideBar->findCon...(self::ID_SIDEBAR_LIST) can also be of type object<Prado\Web\UI\TControl>. However, the property $_sideBarDataList is declared as type object<Prado\Web\UI\WebControls\TDataList>. 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...
1084
				$this->_sideBarDataList->attachEventHandler('OnItemCommand', [$this, 'dataListItemCommand']);
1085
				$this->_sideBarDataList->attachEventHandler('OnItemDataBound', [$this, 'dataListItemDataBound']);
1086
				$this->_sideBarDataList->setDataSource($this->getWizardSteps());
1087
				$this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
1088
				$this->_sideBarDataList->dataBind();
1089
			}
1090
		} else {
1091
			$this->_sideBar = new TPanel;
1092
			$this->getControls()->add($this->_sideBar);
1093
		}
1094
	}
1095
1096
	/**
1097
	 * Event handler for sidebar datalist's OnItemCommand event.
1098
	 * This method is used internally by wizard. It mainly
1099
	 * sets the active step index according to the button clicked in the sidebar.
1100
	 * @param mixed $sender sender of the event
1101
	 * @param TDataListCommandEventParameter $param
1102
	 */
1103
	public function dataListItemCommand($sender, $param)
1104
	{
1105
		$item = $param->getItem();
0 ignored issues
show
Unused Code introduced by
$item is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1106
		if ($param->getCommandName() === self::CMD_MOVETO) {
1107
			$stepIndex = $this->getActiveStepIndex();
1108
			$newStepIndex = TPropertyValue::ensureInteger($param->getCommandParameter());
1109
			$navParam = new TWizardNavigationEventParameter($stepIndex);
1110
			$navParam->setNextStepIndex($newStepIndex);
1111
1112
			// if the button clicked causes validation which fails,
1113
			// by default we will cancel navigation to the new step
1114
			$button = $param->getCommandSource();
1115 View Code Duplication
			if (($button instanceof \Prado\Web\UI\IButtonControl) && $button->getCausesValidation() && ($page = $this->getPage()) !== null && !$page->getIsValid()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1116
				$navParam->setCancelNavigation(true);
1117
			}
1118
1119
			$this->_activeStepIndexSet = false;
1120
			$this->onSideBarButtonClick($navParam);
1121
			$this->_cancelNavigation = $navParam->getCancelNavigation();
1122
			if (!$this->_cancelNavigation) {
1123
				if (!$this->_activeStepIndexSet && $this->allowNavigationToStep($newStepIndex)) {
1124
					$this->setActiveStepIndex($newStepIndex);
1125
				}
1126
			} else {
1127
				$this->setActiveStepIndex($stepIndex);
1128
			}
1129
		}
1130
	}
1131
1132
	/**
1133
	 * Event handler for sidebar datalist's OnItemDataBound event.
1134
	 * This method is used internally by wizard. It mainly configures
1135
	 * the buttons in the sidebar datalist.
1136
	 * @param mixed $sender sender of the event
1137
	 * @param TDataListItemEventParameter $param
1138
	 */
1139
	public function dataListItemDataBound($sender, $param)
1140
	{
1141
		$item = $param->getItem();
1142
		$itemType = $item->getItemType();
1143
		if ($itemType === 'Item' || $itemType === 'AlternatingItem' || $itemType === 'SelectedItem' || $itemType === 'EditItem') {
1144
			if (($button = $item->findControl(self::ID_SIDEBAR_BUTTON)) !== null) {
1145
				$step = $item->getData();
1146
				if (($this->getStepType($step) === TWizardStepType::Complete)) {
1147
					$button->setEnabled(false);
1148
				}
1149
				if (($title = $step->getTitle()) !== '') {
1150
					$button->setText($title);
1151
				} else {
1152
					$button->setText($step->getID(false));
1153
				}
1154
				$index = $this->getWizardSteps()->indexOf($step);
1155
				$button->setCommandName(self::CMD_MOVETO);
1156
				$button->setCommandParameter("$index");
1157
			}
1158
		}
1159
	}
1160
1161
	/**
1162
	 * Creates wizard step content.
1163
	 */
1164
	protected function createStepContent()
1165
	{
1166
		foreach ($this->getWizardSteps() as $step) {
1167
			if ($step instanceof TTemplatedWizardStep) {
1168
				$step->ensureChildControls();
1169
			}
1170
		}
1171
		$multiView = $this->getMultiView();
1172
		$this->_stepContent = new TPanel;
1173
		$this->_stepContent->getControls()->add($multiView);
1174
		$this->getControls()->add($this->_stepContent);
1175
		if ($multiView->getViews()->getCount()) {
1176
			$multiView->setActiveViewIndex(0);
1177
		}
1178
	}
1179
1180
	/**
1181
	 * Creates navigation panel.
1182
	 */
1183
	protected function createNavigation()
1184
	{
1185
		$this->_navigation = new TPanel;
1186
		$this->getControls()->add($this->_navigation);
1187
		$controls = $this->_navigation->getControls();
1188
		foreach ($this->getWizardSteps() as $step) {
1189
			if ($step instanceof TTemplatedWizardStep) {
1190
				$step->instantiateNavigationTemplate();
1191
				if (($panel = $step->getNavigationContainer()) !== null) {
1192
					$controls->add($panel);
1193
				}
1194
			}
1195
		}
1196
		$this->_startNavigation = $this->createStartNavigation();
1197
		$controls->add($this->_startNavigation);
1198
		$this->_stepNavigation = $this->createStepNavigation();
1199
		$controls->add($this->_stepNavigation);
1200
		$this->_finishNavigation = $this->createFinishNavigation();
1201
		$controls->add($this->_finishNavigation);
1202
	}
1203
1204
	/**
1205
	 * Creates start navigation panel.
1206
	 */
1207 View Code Duplication
	protected function createStartNavigation()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1208
	{
1209
		if (($template = $this->getStartNavigationTemplate()) === null) {
1210
			$template = new TWizardStartNavigationTemplate($this);
1211
		}
1212
		$navigation = new TWizardNavigationContainer;
1213
		$template->instantiateIn($navigation);
1214
		return $navigation;
1215
	}
1216
1217
	/**
1218
	 * Creates step navigation panel.
1219
	 */
1220 View Code Duplication
	protected function createStepNavigation()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1221
	{
1222
		if (($template = $this->getStepNavigationTemplate()) === null) {
1223
			$template = new TWizardStepNavigationTemplate($this);
1224
		}
1225
		$navigation = new TWizardNavigationContainer;
1226
		$template->instantiateIn($navigation);
1227
		return $navigation;
1228
	}
1229
1230
	/**
1231
	 * Creates finish navigation panel.
1232
	 */
1233 View Code Duplication
	protected function createFinishNavigation()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1234
	{
1235
		if (($template = $this->getFinishNavigationTemplate()) === null) {
1236
			$template = new TWizardFinishNavigationTemplate($this);
1237
		}
1238
		$navigation = new TWizardNavigationContainer;
1239
		$template->instantiateIn($navigation);
1240
		return $navigation;
1241
	}
1242
1243
	/**
1244
	 * Updates the sidebar datalist if any.
1245
	 * This method is invoked when any wizard step is changed.
1246
	 */
1247
	public function wizardStepsChanged()
1248
	{
1249
		if ($this->_sideBarDataList !== null) {
1250
			$this->_sideBarDataList->setDataSource($this->getWizardSteps());
1251
			$this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
1252
			$this->_sideBarDataList->dataBind();
1253
		}
1254
	}
1255
1256
	/**
1257
	 * Determines the index of the previous step based on history.
1258
	 * @param bool $popStack whether the first item in the history stack should be popped
1259
	 * up after calling this method.
1260
	 */
1261
	protected function getPreviousStepIndex($popStack)
1262
	{
1263
		$history = $this->getHistory();
1264
		if ($history->getCount() >= 0) {
1265
			$activeStepIndex = $this->getActiveStepIndex();
1266
			$previousStepIndex = -1;
0 ignored issues
show
Unused Code introduced by
$previousStepIndex is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1267
			if ($popStack) {
1268
				$previousStepIndex = $history->pop();
1269
				if ($activeStepIndex === $previousStepIndex && $history->getCount() > 0) {
1270
					$previousStepIndex = $history->pop();
1271
				}
1272
			} else {
1273
				$previousStepIndex = $history->peek();
1274
				if ($activeStepIndex === $previousStepIndex && $history->getCount() > 1) {
1275
					$saveIndex = $history->pop();
1276
					$previousStepIndex = $history->peek();
1277
					$history->push($saveIndex);
1278
				}
1279
			}
1280
			return $activeStepIndex === $previousStepIndex ? -1 : $previousStepIndex;
1281
		} else {
1282
			return -1;
1283
		}
1284
	}
1285
1286
	/**
1287
	 * @return bool whether navigation to the previous step is allowed
1288
	 */
1289
	protected function allowNavigationToPreviousStep()
1290
	{
1291
		if (($index = $this->getPreviousStepIndex(false)) !== -1) {
1292
			return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
1293
		} else {
1294
			return false;
1295
		}
1296
	}
1297
1298
	/**
1299
	 * @param int $index index of the step
1300
	 * @return bool whether navigation to the specified step is allowed
1301
	 */
1302
	protected function allowNavigationToStep($index)
1303
	{
1304
		if ($this->getHistory()->contains($index)) {
1305
			return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
1306
		} else {
1307
			return true;
1308
		}
1309
	}
1310
1311
	/**
1312
	 * Handles bubbled events.
1313
	 * This method mainly translate certain command events into
1314
	 * wizard-specific events.
1315
	 * @param mixed $sender sender of the original command event
1316
	 * @param TEventParameter $param event parameter
1317
	 * @throws TInvalidDataValueException if a navigation command is associated with an invalid parameter
1318
	 */
1319
	public function bubbleEvent($sender, $param)
1320
	{
1321
		if ($param instanceof \Prado\Web\UI\TCommandEventParameter) {
1322
			$command = $param->getCommandName();
1323
			if (strcasecmp($command, self::CMD_CANCEL) === 0) {
1324
				$this->onCancelButtonClick($param);
1325
				return true;
1326
			}
1327
1328
			$type = $this->getStepType($this->getActiveStep());
1329
			$index = $this->getActiveStepIndex();
1330
			$navParam = new TWizardNavigationEventParameter($index);
1331 View Code Duplication
			if (($sender instanceof \Prado\Web\UI\IButtonControl) && $sender->getCausesValidation() && ($page = $this->getPage()) !== null && !$page->getIsValid()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1332
				$navParam->setCancelNavigation(true);
1333
			}
1334
1335
			$handled = false;
1336
			$movePrev = false;
1337
			$this->_activeStepIndexSet = false;
1338
1339
			if (strcasecmp($command, self::CMD_NEXT) === 0) {
1340 View Code Duplication
				if ($type !== TWizardStepType::Start && $type !== TWizardStepType::Step) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1341
					throw new TInvalidDataValueException('wizard_command_invalid', self::CMD_NEXT);
1342
				}
1343
				if ($index < $this->getWizardSteps()->getCount() - 1) {
1344
					$navParam->setNextStepIndex($index + 1);
1345
				}
1346
				$this->onNextButtonClick($navParam);
1347
				$handled = true;
1348
			} elseif (strcasecmp($command, self::CMD_PREVIOUS) === 0) {
1349 View Code Duplication
				if ($type !== TWizardStepType::Finish && $type !== TWizardStepType::Step) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1350
					throw new TInvalidDataValueException('wizard_command_invalid', self::CMD_PREVIOUS);
1351
				}
1352
				$movePrev = true;
1353
				if (($prevIndex = $this->getPreviousStepIndex(false)) >= 0) {
1354
					$navParam->setNextStepIndex($prevIndex);
1355
				}
1356
				$this->onPreviousButtonClick($navParam);
1357
				$handled = true;
1358
			} elseif (strcasecmp($command, self::CMD_COMPLETE) === 0) {
1359
				if ($type !== TWizardStepType::Finish) {
1360
					throw new TInvalidDataValueException('wizard_command_invalid', self::CMD_COMPLETE);
1361
				}
1362
				if ($index < $this->getWizardSteps()->getCount() - 1) {
1363
					$navParam->setNextStepIndex($index + 1);
1364
				}
1365
				$this->onCompleteButtonClick($navParam);
1366
				$handled = true;
1367
			} elseif (strcasecmp($command, self::CMD_MOVETO) === 0) {
1368
				if ($this->_cancelNavigation) {  // may be set in onSideBarButtonClick
1369
					$navParam->setCancelNavigation(true);
1370
				}
1371
				$requestedStep = $param->getCommandParameter();
1372
				if (!is_numeric($requestedStep)) {
1373
					$requestedIndex = -1;
1374
					foreach ($this->getWizardSteps() as $index => $step) {
1375
						if ($step->getId() === $requestedStep) {
1376
							$requestedIndex = $index;
1377
							break;
1378
						}
1379
					}
1380
					if ($requestedIndex < 0) {
1381
						throw new TConfigurationException('wizard_step_invalid');
1382
					}
1383
				} else {
1384
					$requestedIndex = TPropertyValue::ensureInteger($requestedStep);
1385
				}
1386
				$navParam->setNextStepIndex($requestedIndex);
1387
				$handled = true;
1388
			}
1389
1390
			if ($handled) {
1391
				if (!$navParam->getCancelNavigation()) {
1392
					$nextStepIndex = $navParam->getNextStepIndex();
1393
					if (!$this->_activeStepIndexSet && $this->allowNavigationToStep($nextStepIndex)) {
1394
						if ($movePrev) {
1395
							$this->getPreviousStepIndex(true);
1396
						}  // pop out the previous move from history
1397
						$this->setActiveStepIndex($nextStepIndex);
1398
					}
1399
				} else {
1400
					$this->setActiveStepIndex($index);
1401
				}
1402
				return true;
1403
			}
1404
		}
1405
		return false;
1406
	}
1407
}
1408