[eluser]lsemel[/eluser]
Hi Phil,
I was thinking about what the best way to integrate DataMapper model validation with regular CI form validation. I ended up writing an extension to the form validator in CI that lets you process forms involving DataMapper models in only a few lines of code. Assuming you have a DataMapper object Status that has its own validations, and your form's fields match the fields from Status, you can write this:
Code:
$status = new Status();
$status->get_by_id($status_id_to_update);
$this->form_validation->set_model($status);
# Add any additional form validation rules here
if ($this->form_validation->run($this)) {
$model->save();
}
Here's the full code:
Code:
<?php
/**
* This form validation class extends the one that comes with Code Igiter to solve
* a few problems:
* - The Code Igniter one does not work well with Modules. This gives the validation
* run() function an extra parameter to indicate what class contains any
* custom validation methods.
* - Form validation from Datamapper is completely separate from form validation
* Code Igniter, and this unites them. Call $this->form_validation->set_model($dm_object)
* to have the form validator include the data model's validations along with
* any rules you set up directly
* - This also copies data from the form into the model, so it doesn't have to be done
* manually. You can validate and save a model's 'text' field like this
*
* $status = new Status();
* $status->get_by_id($status_id_to_update);
* $this->form_validation->set_model($status,array('text'));
* if ($this->form_validation->run($this)) {
* $model->save();
* $this->form_validation->clear();
* $this->data->message = 'Your item was saved';
* }
*
* Any error messages from the model will appear using the regular form_error()
* helper. The fields used in the form must match the field names of the model
* - A clear() method is provided which will clear out any data submitted by the
* post, in cases where the form results are shown on the same page as the form
* itself
*/
class MY_Form_Validation extends CI_Form_Validation {
var $model;
var $model_fields = array();
/**
* Sets the error delimiters the way we want them on this site
*/
function __construct() {
parent::__construct();
$this->set_error_delimiters('<div class=\"error\">','</div>');
}
/**
* Call this to validate on the given model. The model's fields will be set from the
* contents of the post. Specify an array of fields to set, otherwise all the
* fields from the post will be set in the model. The model's validation rules
* will be called and added to the form validation object as if they had been
* set up using the usual Code Igniter way
*
* This can also be called with a dummy model (e.g. new Account()) if you want
* to ensure that the fields don't get saved
*/
function set_model(&$model,$fields = array()) {
$this->model =& $model;
if (is_string($fields)) $fields = preg_split('/\s*,\s*/',$fields);
$this->model_fields = $fields;
}
/**
* Modification needed to work with Modules
* See: http://ellislab.com/forums/viewthread/92212/P90/#578755
*/
function run($module = '', $group = '') {
(is_object($module)) AND $this->CI =& $module;
// CodeIgniter convention is to return false if nothing was posted
if (!$_POST) return false;
// Skip CI's validiton if nothing was posted, or if there are no validation rules
$result = ($_POST && (count($this->_config_rules) > 0 || count($this->_field_data) > 0)) ? parent::run($group) : true;
// Perform the model's own validation
$model_result = $this->model? $this->validate_model($this->model) : true;
return $result && $model_result;
}
/**
* Clears out all the posted data
*/
function clear() {
$this->_field_data = array();
}
/**
* Sets an error message on a particular field, which will be accessible
* via the form_error() helper
*
* @param <type> $field
* @param <type> $message
*/
function set_error($field,$message) {
$this->_field_data[$field]['error'] = $message;
$this->_error_array[$field] = $message;
}
/**
* Given a DataMapper object, run validations on it and add any additional error messages to the form
* This way we can use one validation mechanism. Returns true or false if the model is valid
* Form fields are pulled from the POST
*/
function validate_model(&$model) {
$ci =& get_instance();