diff --git a/src/applications/uiexample/examples/PhabricatorPagedFormExample.php b/src/applications/uiexample/examples/PhabricatorPagedFormExample.php index e34e4cf23e..64846f48db 100644 --- a/src/applications/uiexample/examples/PhabricatorPagedFormExample.php +++ b/src/applications/uiexample/examples/PhabricatorPagedFormExample.php @@ -1,67 +1,71 @@ PHUIPagedFormView')); } public function renderExample() { $request = $this->getRequest(); $user = $request->getUser(); $page1 = id(new PHUIFormPageView()) + ->setPageName(pht('Page 1')) ->addControl( id(new AphrontFormTextControl()) ->setName('page1') ->setLabel('Page 1')); $page2 = id(new PHUIFormPageView()) + ->setPageName(pht('Page 2')) ->addControl( id(new AphrontFormTextControl()) ->setName('page2') ->setLabel('Page 2')); $page3 = id(new PHUIFormPageView()) + ->setPageName(pht('Page 3')) ->addControl( id(new AphrontFormTextControl()) ->setName('page3') ->setLabel('Page 3')); $page4 = id(new PHUIFormPageView()) + ->setPageName(pht('Page 4')) ->addControl( id(new AphrontFormTextControl()) ->setName('page4') ->setLabel('Page 4')); $form = new PHUIPagedFormView(); $form->setUser($user); $form->addPage('page1', $page1); $form->addPage('page2', $page2); $form->addPage('page3', $page3); $form->addPage('page4', $page4); if ($request->isFormPost()) { $form->readFromRequest($request); if ($form->isComplete()) { return id(new AphrontDialogView()) ->setUser($user) ->setTitle(pht('Form Complete')) ->appendChild(pht('You submitted the form. Well done!')) ->addCancelButton($request->getRequestURI(), pht('Again!')); } } else { $form->readFromObject(null); } return $form; } } diff --git a/src/view/form/PHUIFormPageView.php b/src/view/form/PHUIFormPageView.php index ae17e08bd8..06eb8bcf8a 100644 --- a/src/view/form/PHUIFormPageView.php +++ b/src/view/form/PHUIFormPageView.php @@ -1,222 +1,224 @@ pageName = $page_name; return $this; } public function getPageName() { return $this->pageName; } public function addPageError($page_error) { $this->pageErrors[] = $page_error; return $this; } public function getPageErrors() { return $this->pageErrors; } public function setAdjustFormPageCallback($adjust_form_page_callback) { $this->adjustFormPageCallback = $adjust_form_page_callback; return $this; } public function setValidateFormPageCallback($validate_form_page_callback) { $this->validateFormPageCallback = $validate_form_page_callback; return $this; } public function addInstructions($text, $before = null) { $tag = phutil_tag( 'div', array( 'class' => 'aphront-form-instructions', ), $text); $append = true; if ($before !== null) { for ($ii = 0; $ii < count($this->content); $ii++) { if ($this->content[$ii] instanceof AphrontFormControl) { if ($this->content[$ii]->getName() == $before) { array_splice($this->content, $ii, 0, array($tag)); $append = false; break; } } } } if ($append) { $this->content[] = $tag; } return $this; } public function addRemarkupInstructions($remarkup, $before = null) { return $this->addInstructions( PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff())->setContent($remarkup), 'default', $this->getUser()), $before); } public function addControl(AphrontFormControl $control) { $name = $control->getName(); if (!strlen($name)) { throw new Exception("Form control has no name!"); } if (isset($this->controls[$name])) { throw new Exception( "Form page contains duplicate control with name '{$name}'!"); } $this->controls[$name] = $control; $this->content[] = $control; $control->setFormPage($this); return $this; } public function getControls() { return $this->controls; } public function getControl($name) { if (empty($this->controls[$name])) { throw new Exception("No page control '{$name}'!"); } return $this->controls[$name]; } protected function canAppendChild() { return false; } public function setPagedFormView(PHUIPagedFormView $view, $key) { if ($this->key) { throw new Exception("This page is already part of a form!"); } $this->form = $view; $this->key = $key; return $this; } public function adjustFormPage() { if ($this->adjustFormPageCallback) { call_user_func($this->adjustFormPageCallback, $this); } return $this; } protected function validateFormPage() { if ($this->validateFormPageCallback) { return call_user_func($this->validateFormPageCallback, $this); } return true; } public function getKey() { return $this->key; } public function render() { return $this->content; } public function getForm() { return $this->form; } public function getRequestKey($key) { return $this->getForm()->getRequestKey('p:'.$this->key.':'.$key); } public function validateObjectType($object) { return true; } public function validateResponseType($response) { return true; } protected function validateControls() { $result = true; foreach ($this->getControls() as $name => $control) { if (!$control->isValid()) { $result = false; break; } } return $result; } public function isValid() { if ($this->isValid === null) { $this->isValid = $this->validateControls() && $this->validateFormPage(); } return $this->isValid; } public function readFromRequest(AphrontRequest $request) { foreach ($this->getControls() as $name => $control) { $control->readValueFromRequest($request); } return $this; } public function readFromObject($object) { foreach ($this->getControls() as $name => $control) { - $control->readValueFromDictionary($object); + if (is_array($object)) { + $control->readValueFromDictionary($object); + } } return $this; } public function writeToResponse($response) { return $this; } public function readSerializedValues(AphrontRequest $request) { foreach ($this->getControls() as $name => $control) { $key = $this->getRequestKey($name); $control->readSerializedValue($request->getStr($key)); } return $this; } public function getSerializedValues() { $dict = array(); foreach ($this->getControls() as $name => $control) { $key = $this->getRequestKey($name); $dict[$key] = $control->getSerializedValue(); } return $dict; } } diff --git a/src/view/form/PHUIPagedFormView.php b/src/view/form/PHUIPagedFormView.php index a088980275..d68c5bbe2c 100644 --- a/src/view/form/PHUIPagedFormView.php +++ b/src/view/form/PHUIPagedFormView.php @@ -1,281 +1,282 @@ pages[$key])) { throw new Exception("Duplicate page with key '{$key}'!"); } $this->pages[$key] = $page; $page->setPagedFormView($this, $key); $this->selectedPage = null; $this->complete = null; return $this; } /** * @task page */ public function getPage($key) { if (!$this->pageExists($key)) { throw new Exception("No page '{$key}' exists!"); } return $this->pages[$key]; } /** * @task page */ public function pageExists($key) { return isset($this->pages[$key]); } /** * @task page */ protected function getPageIndex($key) { $page = $this->getPage($key); $index = 0; foreach ($this->pages as $target_page) { if ($page === $target_page) { break; } $index++; } return $index; } /** * @task page */ protected function getPageByIndex($index) { foreach ($this->pages as $page) { if (!$index) { return $page; } $index--; } throw new Exception("Requesting out-of-bounds page '{$index}'."); } protected function getLastIndex() { return count($this->pages) - 1; } protected function isFirstPage(PHUIFormPageView $page) { return ($this->getPageIndex($page->getKey()) === 0); } protected function isLastPage(PHUIFormPageView $page) { return ($this->getPageIndex($page->getKey()) === (count($this->pages) - 1)); } public function getSelectedPage() { return $this->selectedPage; } public function readFromObject($object) { return $this->processForm($is_request = false, $object); } public function writeToResponse($response) { foreach ($this->pages as $page) { $page->validateResponseType($response); $response = $page->writeToResponse($page); } return $response; } public function readFromRequest(AphrontRequest $request) { $this->choosePage = $request->getStr($this->getRequestKey('page')); $this->nextPage = $request->getStr('__submit__'); $this->prevPage = $request->getStr('__back__'); return $this->processForm($is_request = true, $request); } public function setName($name) { $this->name = $name; return $this; } public function getValue($page, $key, $default = null) { return $this->getPage($page)->getValue($key, $default); } public function setValue($page, $key, $value) { $this->getPage($page)->setValue($key, $value); return $this; } private function processForm($is_request, $source) { if ($this->pageExists($this->choosePage)) { $selected = $this->getPage($this->choosePage); } else { $selected = $this->getPageByIndex(0); } $is_attempt_complete = false; if ($this->prevPage) { $prev_index = $this->getPageIndex($selected->getKey()) - 1;; $index = max(0, $prev_index); $selected = $this->getPageByIndex($index); } else if ($this->nextPage) { $next_index = $this->getPageIndex($selected->getKey()) + 1; if ($next_index > $this->getLastIndex()) { $is_attempt_complete = true; } $index = min($this->getLastIndex(), $next_index); $selected = $this->getPageByIndex($index); } $validation_error = false; $found_selected = false; foreach ($this->pages as $key => $page) { if ($is_request) { if ($key === $this->choosePage) { $page->readFromRequest($source); } else { $page->readSerializedValues($source); } } else { $page->readFromObject($source); } if (!$found_selected) { $page->adjustFormPage(); } if ($page === $selected) { $found_selected = true; } if (!$found_selected || $is_attempt_complete) { if (!$page->isValid()) { $selected = $page; $validation_error = true; break; } } } if ($is_attempt_complete && !$validation_error) { $this->complete = true; } else { $this->selectedPage = $selected; } return $this; } public function isComplete() { return $this->complete; } public function getRequestKey($key) { return $this->name.':'.$key; } public function setCancelURI($cancel_uri) { $this->cancelURI = $cancel_uri; return $this; } public function getCancelURI() { return $this->cancelURI; } public function getTagContent() { $form = id(new AphrontFormView()) ->setUser($this->getUser()); $selected_page = $this->getSelectedPage(); if (!$selected_page) { throw new Exception("No selected page!"); } $form->addHiddenInput( $this->getRequestKey('page'), $selected_page->getKey()); $errors = array(); foreach ($this->pages as $page) { if ($page == $selected_page) { $errors = $page->getPageErrors(); continue; } foreach ($page->getSerializedValues() as $key => $value) { $form->addHiddenInput($key, $value); } } $submit = id(new PHUIFormMultiSubmitControl()); if (!$this->isFirstPage($selected_page)) { $submit->addBackButton(); } else if ($this->getCancelURI()) { $submit->addCancelButton($this->getCancelURI()); } if ($this->isLastPage($selected_page)) { $submit->addSubmitButton(pht("Save")); } else { $submit->addSubmitButton(pht("Continue \xC2\xBB")); } $form->appendChild($selected_page); $form->appendChild($submit); if ($errors) { $errors = id(new AphrontErrorView())->setErrors($errors); } - $header = null; + $box = id(new PHUIObjectBoxView()) + ->setFormError($errors) + ->setForm($form); + if ($selected_page->getPageName()) { $header = id(new PHUIHeaderView()) ->setHeader($selected_page->getPageName()); + $box->setHeader($header); } - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setFormError($errors) - ->setForm($form); + return $box; } }