return '';
}
- public function field($boundField)
+ public function field($boundField, $errors)
{
if ($boundField->help_text) {
$help_text = Tag::p(array('class' => 'help'))
$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)
$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()
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')) {
}
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')) {
--- /dev/null
+<?php
+
+class IPF_Form_Error
+{
+ public $message, $meta;
+
+ public function __construct($message, $meta=null)
+ {
+ $this->message = $message;
+ $this->meta = $meta;
+ }
+}
+
<?php
-class IPF_Exception_Form extends IPF_Exception{}
+// Form validation exception
+
+class IPF_Exception_Form extends IPF_Exception
+{
+ private $meta;
+
+ function __construct($message, $meta=null)
+ {
+ parent::__construct($message);
+ $this->meta = $meta;
+ }
+
+ function getError()
+ {
+ return new IPF_Form_Error($this->getMessage(), $this->meta);
+ }
+}
+
--- /dev/null
+<?php
+
+class IPF_Form_Field_Set extends IPF_Form_Field
+{
+ public $widget = 'IPF_Form_Widget_SetTable';
+ public $fields = array();
+ public $addCount = 3;
+
+ public function clean($value)
+ {
+ if (!$value)
+ return $value;
+
+ $errors = new \PFF\MultidimensionalArray;
+
+ $newValue = array();
+ foreach ($value as $index => $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);
+ }
+}
+
$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]);
}
}
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());
}
}
}
}
+ public function addError($field, $error)
+ {
+ if (!$field)
+ $field = '__all__';
+ \PFF\Arr::pushToKey($this->errors, $field, $error);
+ }
+
public function clean()
{
return $this->cleaned_data;
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)
$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);
}
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);
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();
}
{
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);
}*/
{
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);
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(' ')
return '';
}
- public function field($boundField)
+ public function field($boundField, $errors)
{
if ($boundField->help_text)
$help_text = '<br /><span class="helptext">'.$boundField->help_text.'</span>';
return Tag::li()
->raw($this->takeDeferred())
- ->raw($this->errorList($boundField->errors))
+ ->raw($this->errorList($errors))
->raw($boundField->renderLabel())
->raw(' ')
->raw($boundField->renderWidget())
return '';
}
- public function field($boundField)
+ public function field($boundField, $errors)
{
if ($boundField->help_text)
$help_text = '<br /><span class="helptext">'.$boundField->help_text.'</span>';
->raw($boundField->renderLabel()),
Tag::td()
->raw($this->takeDeferred())
- ->raw($this->errorList($boundField->errors))
+ ->raw($this->errorList($errors))
->raw($boundField->renderWidget())
->raw($help_text));
}
{
public $is_hidden = false; // renders invisible
public $needs_multipart_form = false;
+ public $embeds_errors = false;
public $attrs = array();
public function __construct($attrs=array())
--- /dev/null
+<?php
+
+use \PFF\HtmlBuilder\Tag as Tag;
+
+class IPF_Form_Widget_SetTable extends IPF_Form_Widget
+{
+ public $embeds_errors = true;
+
+ public $widgets, $addCount;
+
+ public function __construct($attrs=array())
+ {
+ $this->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;
+ }
+}
+