data = $data; $this->is_bound = true; } if ($label_suffix !== null) $this->label_suffix = $label_suffix; $this->initFields($extra); $this->f = new Pluf_Form_FieldProxy($this); } function initFields($extra=array()) { throw new Exception('Definition of the fields not implemented.'); } /** * Add the prefix to the form names. * * @param string Field name. * @return string Field name or field name with form prefix. */ function addPrefix($field_name) { if ('' !== $this->prefix) { return $this->prefix.'-'.$field_name; } return $field_name; } /** * Check if the form is valid. * * It is also encoding the data in the form to be then saved. It * is very simple as it leaves the work to the field. It means * that you can easily extend this form class to have a more * complex validation procedure like checking if a field is equals * to another in the form (like for password confirmation) etc. * * @param array Associative array of the request * @return array Array of errors */ function isValid() { if ($this->is_valid !== null) { return $this->is_valid; } $this->cleaned_data = array(); $this->errors = array(); $form_methods = get_class_methods($this); $form_vars = get_object_vars($this); foreach ($this->fields as $name=>$field) { $value = $field->widget->valueFromFormData($this->addPrefix($name), $this->data); try { $value = $field->clean($value); $this->cleaned_data[$name] = $value; $method = 'clean_'.$name; if (in_array($method, $form_methods)) { $value = $this->$method(); $this->cleaned_data[$name] = $value; } else if (array_key_exists($method, $form_vars) && is_callable($this->$method)) { $value = call_user_func($this->$method, $this); $this->cleaned_data[$name] = $value; } } catch (Pluf_Form_Invalid $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]); } } } if (empty($this->errors)) { try { $this->cleaned_data = $this->clean(); } catch (Pluf_Form_Invalid $e) { if (!isset($this->errors['__all__'])) $this->errors['__all__'] = array(); $this->errors['__all__'][] = $e->getMessage(); } } if (empty($this->errors)) { $this->is_valid = true; return true; } // as some errors, we do not have cleaned data available. $this->failed(); $this->cleaned_data = array(); $this->is_valid = false; return false; } /** * Form wide cleaning function. That way you can check that if an * input is given, then another one somewhere is also given, * etc. If the cleaning is not ok, your method must throw a * Pluf_Form_Invalid exception. * * @return array Cleaned data. */ public function clean() { return $this->cleaned_data; } /** * Method just called after the validation if the validation * failed. This can be used to remove uploaded * files. $this->['cleaned_data'] will be available but of course * not fully populated and with possible garbage due to the error. * */ public function failed() { } /** * Get initial data for a given field. * * @param string Field name. * @return string Initial data or '' of not defined. */ public function initial($name) { if (isset($this->fields[$name])) { return $this->fields[$name]->initial; } return ''; } /** * Get the top errors. */ public function render_top_errors() { $top_errors = (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array(); array_walk($top_errors, 'Pluf_Form_htmlspecialcharsArray'); return new Pluf_Template_SafeString(Pluf_Form_renderErrorsAsHTML($top_errors), true); } /** * Get the top errors. */ public function get_top_errors() { return (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array(); } /** * Helper function to render the form. * * See render_p() for a usage example. * * @credit Django Project (http://www.djangoproject.com/) * @param string Normal row. * @param string Error row. * @param string Row ender. * @param string Help text HTML. * @param bool Should we display errors on a separate row. * @return string HTML of the form. */ protected function htmlOutput($normal_row, $error_row, $row_ender, $help_text_html, $errors_on_separate_row) { $top_errors = (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array(); array_walk($top_errors, 'Pluf_Form_htmlspecialcharsArray'); $output = array(); $hidden_fields = array(); foreach ($this->fields as $name=>$field) { $bf = new Pluf_Form_BoundField($this, $field, $name); $bf_errors = $bf->errors; array_walk($bf_errors, 'Pluf_Form_htmlspecialcharsArray'); if ($field->widget->is_hidden) { foreach ($bf_errors as $_e) { $top_errors[] = sprintf(__('(Hidden field %1$s) %2$s'), $name, $_e); } $hidden_fields[] = $bf; // Not rendered } else { if ($errors_on_separate_row and count($bf_errors)) { $output[] = sprintf($error_row, Pluf_Form_renderErrorsAsHTML($bf_errors)); } if (strlen($bf->label) > 0) { $label = htmlspecialchars($bf->label, ENT_COMPAT, 'UTF-8'); if ($this->label_suffix) { if (!in_array(mb_substr($label, -1, 1), array(':','?','.','!'))) { $label .= $this->label_suffix; } } $label = $bf->labelTag($label); } else { $label = ''; } if ($bf->help_text) { // $bf->help_text can contains HTML and is not // escaped. $help_text = sprintf($help_text_html, $bf->help_text); } else { $help_text = ''; } $errors = ''; if (!$errors_on_separate_row and count($bf_errors)) { $errors = Pluf_Form_renderErrorsAsHTML($bf_errors); } $output[] = sprintf($normal_row, $errors, $label, $bf->render_w(), $help_text); } } if (count($top_errors)) { $errors = sprintf($error_row, Pluf_Form_renderErrorsAsHTML($top_errors)); array_unshift($output, $errors); } if (count($hidden_fields)) { $_tmp = ''; foreach ($hidden_fields as $hd) { $_tmp .= $hd->render_w(); } if (count($output)) { $last_row = array_pop($output); $last_row = substr($last_row, 0, -strlen($row_ender)).$_tmp .$row_ender; $output[] = $last_row; } else { $output[] = $_tmp; } } return new Pluf_Template_SafeString(implode("\n", $output), true); } /** * Render the form as a list of paragraphs. */ public function render_p() { return $this->htmlOutput('
%1$s%2$s %3$s%4$s
', '%s', '', ' %s', true); } /** * Render the form as a list without the