Add support for nested wizards

The amount of vertical dimensions is not limited as well as the location a
nested wizard can occur in the main wizard's order. In case a custom
implementation is used as nested wizard, all core functionalities are
still being utilized.

refs #8191
This commit is contained in:
Johannes Meyer 2015-01-20 15:54:14 +01:00
parent 9cecc4d690
commit 2288e2a687
1 changed files with 119 additions and 6 deletions

View File

@ -39,6 +39,13 @@ class Wizard
*/ */
const BTN_PREV = 'btn_prev'; const BTN_PREV = 'btn_prev';
/**
* This wizard's parent
*
* @var Wizard
*/
protected $parent;
/** /**
* The name of the wizard's current page * The name of the wizard's current page
* *
@ -71,19 +78,55 @@ class Wizard
} }
/**
* Return this wizard's parent or null in case it has none
*
* @return Wizard|null
*/
public function getParent()
{
return $this->parent;
}
/**
* Set this wizard's parent
*
* @param Wizard $wizard The parent wizard
*
* @return self
*/
public function setParent(Wizard $wizard)
{
$this->parent = $wizard;
return $this;
}
/** /**
* Return the pages being part of this wizard * Return the pages being part of this wizard
* *
* In case this is a nested wizard a flattened array of all contained pages is returned.
*
* @return array * @return array
*/ */
public function getPages() public function getPages()
{ {
return $this->pages; $pages = array();
foreach ($this->pages as $page) {
if ($page instanceof self) {
$pages = array_merge($pages, $page->getPages());
} else {
$pages[] = $page;
}
}
return $pages;
} }
/** /**
* Return the page with the given name * Return the page with the given name
* *
* Note that it's also possible to retrieve a nested wizard's page by using this method.
*
* @param string $name The name of the page to return * @param string $name The name of the page to return
* *
* @return null|Form The page or null in case there is no page with the given name * @return null|Form The page or null in case there is no page with the given name
@ -98,22 +141,31 @@ class Wizard
} }
/** /**
* Add a new page to this wizard * Add a new page or wizard to this wizard
* *
* @param Form $page The page to add to the wizard * @param Form|Wizard $page The page or wizard to add to the wizard
* *
* @return self * @return self
*/ */
public function addPage(Form $page) public function addPage($page)
{ {
if (! $page instanceof Form && ! $page instanceof self) {
throw InvalidArgumentException(
'The $page argument must be an instance of Icinga\Web\Form '
. 'or Icinga\Web\Wizard but is of type: ' . get_class($page)
);
} elseif ($page instanceof self) {
$page->setParent($this);
}
$this->pages[] = $page; $this->pages[] = $page;
return $this; return $this;
} }
/** /**
* Add multiple pages to this wizard * Add multiple pages or wizards to this wizard
* *
* @param array $pages The pages to add to the wizard * @param array $pages The pages or wizards to add to the wizard
* *
* @return self * @return self
*/ */
@ -148,6 +200,10 @@ class Wizard
*/ */
public function getCurrentPage() public function getCurrentPage()
{ {
if ($this->parent) {
return $this->parent->getCurrentPage();
}
if ($this->currentPage === null) { if ($this->currentPage === null) {
$this->assertHasPages(); $this->assertHasPages();
$pages = $this->getPages(); $pages = $this->getPages();
@ -202,6 +258,10 @@ class Wizard
{ {
$page = $this->getCurrentPage(); $page = $this->getCurrentPage();
if (($wizard = $this->findWizard($page)) !== null) {
return $wizard->handleRequest($request);
}
if ($request === null) { if ($request === null) {
$request = $page->getRequest(); $request = $page->getRequest();
} }
@ -238,6 +298,39 @@ class Wizard
return $request; return $request;
} }
/**
* Return the wizard for the given page or null if its not part of a wizard
*
* @param Form $page The page to return its wizard for
*
* @return Wizard|null
*/
protected function findWizard(Form $page)
{
foreach ($this->getWizards() as $wizard) {
if ($wizard->getPage($page->getName()) === $page) {
return $wizard;
}
}
}
/**
* Return this wizard's child wizards
*
* @return array
*/
protected function getWizards()
{
$wizards = array();
foreach ($this->pages as $pageOrWizard) {
if ($pageOrWizard instanceof self) {
$wizards[] = $pageOrWizard;
}
}
return $wizards;
}
/** /**
* Return the request data based on given form's request method * Return the request data based on given form's request method
* *
@ -264,6 +357,10 @@ class Wizard
*/ */
protected function getRequestedPage(array $requestData) protected function getRequestedPage(array $requestData)
{ {
if ($this->parent) {
return $this->parent->getRequestedPage($requestData);
}
if (isset($requestData[static::BTN_NEXT])) { if (isset($requestData[static::BTN_NEXT])) {
return $requestData[static::BTN_NEXT]; return $requestData[static::BTN_NEXT];
} elseif (isset($requestData[static::BTN_PREV])) { } elseif (isset($requestData[static::BTN_PREV])) {
@ -280,6 +377,10 @@ class Wizard
*/ */
protected function getDirection(Request $request = null) protected function getDirection(Request $request = null)
{ {
if ($this->parent) {
return $this->parent->getDirection($request);
}
$currentPage = $this->getCurrentPage(); $currentPage = $this->getCurrentPage();
if ($request === null) { if ($request === null) {
@ -312,6 +413,10 @@ class Wizard
*/ */
protected function getNewPage($requestedPage, Form $originPage) protected function getNewPage($requestedPage, Form $originPage)
{ {
if ($this->parent) {
return $this->parent->getNewPage($requestedPage, $originPage);
}
if (($page = $this->getPage($requestedPage)) !== null) { if (($page = $this->getPage($requestedPage)) !== null) {
$permitted = true; $permitted = true;
@ -344,6 +449,10 @@ class Wizard
*/ */
protected function isLastPage(Form $page) protected function isLastPage(Form $page)
{ {
if ($this->parent) {
return $this->parent->isLastPage($page);
}
$pages = $this->getPages(); $pages = $this->getPages();
return $page->getName() === end($pages)->getName(); return $page->getName() === end($pages)->getName();
} }
@ -421,6 +530,10 @@ class Wizard
*/ */
public function getSession() public function getSession()
{ {
if ($this->parent) {
return $this->parent->getSession();
}
return Session::getSession()->getNamespace(get_class($this)); return Session::getSession()->getNamespace(get_class($this));
} }