From: Andrey Kutejko Date: Sun, 7 Sep 2014 20:36:04 +0000 (+0300) Subject: rework form errors. add set field and set table widget. X-Git-Tag: 0.6~146 X-Git-Url: https://git.andy128k.dev/?a=commitdiff_plain;h=6420ef5d3fbd100af9ba0a08e82e8579e9238628;p=ipf.git rework form errors. add set field and set table widget. --- diff --git a/ipf/admin/formlayout.php b/ipf/admin/formlayout.php index 47690e6..67dad33 100644 --- a/ipf/admin/formlayout.php +++ b/ipf/admin/formlayout.php @@ -19,7 +19,7 @@ class IPF_Admin_Form_Layout extends IPF_Form_LayoutAdapter return ''; } - public function field($boundField) + public function field($boundField, $errors) { if ($boundField->help_text) { $help_text = Tag::p(array('class' => 'help')) @@ -28,13 +28,20 @@ class IPF_Admin_Form_Layout extends IPF_Form_LayoutAdapter $help_text = ''; } - return $this->errors($boundField->errors) . - Tag::div(array('class' => 'form-row'), + if ($boundField->field instanceof IPF_Form_Field_Set) { + return $this->errors($errors) . Tag::div() - ->raw($boundField->renderLabel()) - ->raw(' ') ->raw($boundField->renderWidget()) - ->append($help_text)); + ->append($help_text); + } else { + return $this->errors($errors) . + Tag::div(array('class' => 'form-row'), + Tag::div() + ->raw($boundField->renderLabel()) + ->raw(' ') + ->raw($boundField->renderWidget()) + ->append($help_text)); + } } private function errors($errors) diff --git a/ipf/form/boundfield.php b/ipf/form/boundfield.php index ce18a79..f997d3d 100644 --- a/ipf/form/boundfield.php +++ b/ipf/form/boundfield.php @@ -51,9 +51,20 @@ class IPF_Form_BoundField $extra_attrs['id'] = $this->autoId(); } + if ($widget->embeds_errors) + $extra_attrs['errors'] = $this->errors; + return $widget->render($this->html_name, $this->value(), $extra_attrs); } + public function renderErrors() + { + if ($this->field->widget->embeds_errors) + return ''; + + return IPF_Form::renderErrorsAsHTML($this->errors); + } + public function renderLabel() { $label = Tag::label() @@ -70,7 +81,12 @@ class IPF_Form_BoundField return $label->html(); } - public function autoId() + public function __toString() + { + return (string)$this->renderWidget(); + } + + private function autoId() { $id_fields = $this->form->id_fields; if (false !== strpos($id_fields, '%s')) { @@ -80,39 +96,6 @@ class IPF_Form_BoundField } return ''; } - - - public function labelTag() - { - return $this->form->unescape($this->renderLabel()); - } - - public function render_w() - { - return $this->form->unescape($this->renderWidget()); - } - - public function fieldErrors($raw=false) - { - $errors = IPF_Form::renderErrorsAsHTML($this->errors); - if ($raw) - return $errors; - else - return $this->form->unescape($errors); - } - - public function __get($prop) - { - if (!in_array($prop, array('labelTag', 'fieldErrors', 'render_w'))) { - return $this->$prop; - } - return $this->$prop(); - } - - public function __toString() - { - return (string)$this->render_w(); - } } if (!function_exists('mb_ucfirst')) { diff --git a/ipf/form/error.php b/ipf/form/error.php new file mode 100644 index 0000000..85d4617 --- /dev/null +++ b/ipf/form/error.php @@ -0,0 +1,13 @@ +message = $message; + $this->meta = $meta; + } +} + diff --git a/ipf/form/exception.php b/ipf/form/exception.php index ab8a8ec..7e48727 100644 --- a/ipf/form/exception.php +++ b/ipf/form/exception.php @@ -1,3 +1,20 @@ meta = $meta; + } + + function getError() + { + return new IPF_Form_Error($this->getMessage(), $this->meta); + } +} + diff --git a/ipf/form/field/set.php b/ipf/form/field/set.php new file mode 100644 index 0000000..cbd9e7a --- /dev/null +++ b/ipf/form/field/set.php @@ -0,0 +1,53 @@ + $row) { + if (!array_filter(\PFF\Arr::flatten($row))) // recursively empty + continue; + + foreach ($this->fields as $name => $field) { + try { + $value = $field->clean(\PFF\Arr::get($row, $name)); + } catch (IPF_Exception_Form $ex) { + $errors->pushToKey(array($index, $name), $ex->getError()); + } + $row[$name] = $value; + } + $newValue[$index] = $row; + } + + if ($errors->count()) + throw new IPF_Exception_Form('', $errors); + + return $newValue; + } + + protected function createWidget($args) + { + $widgets = array(); + foreach ($this->fields as $name => $field) { + $widgets[] = array( + 'name' => $name, + 'widget' => $field->widget, + 'label' => $field->label ? $field->label : $name, + ); + } + $args['widgets'] = $widgets; + $args['addCount'] = $this->addCount; + return parent::createWidget($args); + } +} + diff --git a/ipf/form/form.php b/ipf/form/form.php index a79e6c5..3f6074f 100644 --- a/ipf/form/form.php +++ b/ipf/form/form.php @@ -62,13 +62,8 @@ abstract class IPF_Form implements Iterator $this->cleaned_data[$name] = $value; } } catch (IPF_Exception_Form $e) { - if (!isset($this->errors[$name])) - $this->errors[$name] = array(); - $this->errors[$name][] = $e->getMessage(); - - if (isset($this->cleaned_data[$name])) { - unset($this->cleaned_data[$name]); - } + $this->addError($name, $e->getError()); + unset($this->cleaned_data[$name]); } } @@ -76,8 +71,7 @@ abstract class IPF_Form implements Iterator try { $this->cleaned_data = $this->clean(); } catch (IPF_Exception_Form $e) { - if (!isset($this->errors['__all__'])) $this->errors['__all__'] = array(); - $this->errors['__all__'][] = $e->getMessage(); + $this->addError(null, $e->getError()); } } @@ -92,6 +86,13 @@ abstract class IPF_Form implements Iterator } } + public function addError($field, $error) + { + if (!$field) + $field = '__all__'; + \PFF\Arr::pushToKey($this->errors, $field, $error); + } + public function clean() { return $this->cleaned_data; @@ -111,18 +112,14 @@ abstract class IPF_Form implements Iterator return $hidden; } - public function render_top_errors($raw=false) + public function errors() { - $errors = IPF_Form::renderErrorsAsHTML($this->get_top_errors()); - if ($raw) - return $errors; - else - return $this->unescape($errors); + return \PFF\Arr::get($this->errors, '__all__', array()); } - public function get_top_errors() + public function renderErrors() { - return \PFF\Arr::get($this->errors, '__all__', array()); + IPF_Form::renderErrorsAsHTML($this->errors()); } public function renderLayout($layout, $raw=false) @@ -161,7 +158,10 @@ abstract class IPF_Form implements Iterator $bf = $this->field($name); - $output .= $layout->field($bf); + if ($field->widget->embeds_errors) + $output .= $layout->field($bf, array()); + else + $output .= $layout->field($bf, $bf->errors); } $output .= $layout->endGroup($groupLabel); } @@ -196,19 +196,6 @@ abstract class IPF_Form implements Iterator return $form->renderLayout(new IPF_Form_TableLayout, $raw); } - public function render_admin($raw=false) - { - return $form->renderLayout(new IPF_Admin_Form_Layout, $raw); - } - - function __get($prop) - { - if (!in_array($prop, array('render_p', 'render_ul', 'render_table', 'render_top_errors', 'get_top_errors'))) { - return $this->$prop; - } - return $this->$prop(); - } - public function field($key) { return new IPF_Form_BoundField($this, $this->fields[$key], $key); @@ -246,7 +233,7 @@ abstract class IPF_Form implements Iterator return ''; $ul = Tag::ul(array('class' => 'errorlist')); foreach ($errors as $err) - $ul->append(Tag::li(null, $err)); + $ul->append(Tag::li(null, $err->message)); return $ul->html(); } diff --git a/ipf/form/layout.php b/ipf/form/layout.php index 89a6eea..88e3f36 100644 --- a/ipf/form/layout.php +++ b/ipf/form/layout.php @@ -4,7 +4,7 @@ { public function startForm($form); public function startGroup($label); - public function field($boundField); + public function field($boundField, $errors); public function endGroup($label); public function endForm($form); }*/ @@ -14,13 +14,13 @@ abstract class IPF_Form_LayoutAdapter /*implements informal interface IPF_Form_L { public function startForm($form) { return ''; } public function startGroup($label) { return ''; } - public abstract function field($boundField); + public abstract function field($boundField, $errors); public function endGroup($label) { return ''; } public function endForm($form) { return ''; } protected function commonErrors($form) { - $commonErrors = $form->get_top_errors(); + $commonErrors = $form->errors(); foreach ($form->hiddenFields() as $field_name) foreach (\PFF\Arr::get($form->errors, $field_name, array()) as $error) $commonErrors[] = sprintf(__('(Hidden field %1$s) %2$s'), $field_name, $error); @@ -75,10 +75,10 @@ class IPF_Form_ParagraphLayout extends IPF_Form_LayoutAdapter return $o; } - public function field($boundField) + public function field($boundField, $errors) { return - $this->errorList($boundField->errors) . + $this->errorList($errors) . Tag::p() ->raw($boundField->renderLabel()) ->raw(' ') @@ -104,7 +104,7 @@ class IPF_Form_ListLayout extends IPF_Form_LayoutAdapter return ''; } - public function field($boundField) + public function field($boundField, $errors) { if ($boundField->help_text) $help_text = '
'.$boundField->help_text.''; @@ -113,7 +113,7 @@ class IPF_Form_ListLayout extends IPF_Form_LayoutAdapter return Tag::li() ->raw($this->takeDeferred()) - ->raw($this->errorList($boundField->errors)) + ->raw($this->errorList($errors)) ->raw($boundField->renderLabel()) ->raw(' ') ->raw($boundField->renderWidget()) @@ -147,7 +147,7 @@ class IPF_Form_TableLayout extends IPF_Form_LayoutAdapter return ''; } - public function field($boundField) + public function field($boundField, $errors) { if ($boundField->help_text) $help_text = '
'.$boundField->help_text.''; @@ -159,7 +159,7 @@ class IPF_Form_TableLayout extends IPF_Form_LayoutAdapter ->raw($boundField->renderLabel()), Tag::td() ->raw($this->takeDeferred()) - ->raw($this->errorList($boundField->errors)) + ->raw($this->errorList($errors)) ->raw($boundField->renderWidget()) ->raw($help_text)); } diff --git a/ipf/form/widget.php b/ipf/form/widget.php index e561d61..a2123b4 100644 --- a/ipf/form/widget.php +++ b/ipf/form/widget.php @@ -4,6 +4,7 @@ abstract class IPF_Form_Widget { public $is_hidden = false; // renders invisible public $needs_multipart_form = false; + public $embeds_errors = false; public $attrs = array(); public function __construct($attrs=array()) diff --git a/ipf/form/widget/settable.php b/ipf/form/widget/settable.php new file mode 100644 index 0000000..d5fb457 --- /dev/null +++ b/ipf/form/widget/settable.php @@ -0,0 +1,121 @@ +widgets = \PFF\Arr::pop($attrs, 'widgets', array()); + $this->addCount = \PFF\Arr::pop($attrs, 'addCount', 3); + parent::__construct($attrs); + } + + private function extraRows($value) + { + if (!$value) + $value = array(); + + $addRows = $this->addCount; + foreach ($value as $obj) + if (!array_key_exists('id', $obj)) + --$addRows; + + for (; $addRows > 0; --$addRows) + $value[] = array(); + + return $value; + } + + public function render($name, $value, $extra_attrs=array()) + { + $errors = new \PFF\MultidimensionalArray; + foreach (\PFF\Arr::pop($extra_attrs, 'errors', array()) as $e) + $errors = $e->meta; // TODO: merge + + $value = $this->extraRows($value); + + $table = Tag::table(array('class' => 'set-widget')) + ->attrs($this->attrs) + ->attrs($extra_attrs); + + $tr = Tag::tr(array('class' => 'nodrag nodrop')); + foreach ($this->widgets as $w) + $tr->append(Tag::th(null, $w['label'])); + $tr->append(Tag::th(null, __('Delete'))); + + $table->append($tr); + + $index = 0; + foreach ($value as $obj) { + $prefix = "{$name}[{$index}]"; + + $tr = $this->renderRow($prefix, $obj, $errors, $index); + $table->append($tr); + + ++$index; + } + + return $table->html(); + } + + protected function renderRow($prefix, $obj, $errors, $index) + { + $tr = Tag::tr(); + foreach ($this->widgets as $w) { + $cellErrors = $errors->get($index, $w['name']); + $e = IPF_Form::renderErrorsAsHTML($cellErrors); + + $val = \PFF\Arr::get($obj, $w['name']); + + $tr->append(Tag::td() + ->raw($e) + ->raw($w['widget']->render($prefix.'['.$w['name'].']', $val))); + } + + if (array_key_exists('id', $obj)) + $tr->append(Tag::td(null, + Tag::input(array('type' => 'checkbox', 'name' => "{$prefix}[is_remove]")), + Tag::input(array('type' => 'hidden', 'name' => "{$prefix}[id]", 'value' => $obj['id'])))); + else + $tr->append(Tag::td()); + + return $tr; + } + + public function extra_js() + { + $js = array(); + foreach ($this->widgets as $w) + $js = array_merge($js, $w['widget']->extra_js()); + return $js; + } + + public function valueFromFormData($name, $data) + { + if (!isset($data[$name])) + return null; + + $value = array(); + foreach ($data[$name] as $i => $rowData) { + $rowValue = array(); + + foreach ($this->widgets as $w) { + $rowValue[$w['name']] = $w['widget']->valueFromFormData($w['name'], $rowData); + } + if (array_key_exists('is_remove', $rowData)) + $rowValue['is_remove'] = $rowData['is_remove']; + if (array_key_exists('id', $rowData)) + $rowValue['id'] = $rowData['id']; + + $value[$i] = $rowValue; + } + + return $value; + } +} +