• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
basic but....

#11
[eluser]nmweb[/eluser]
Models represent data, if a field is no longer needed the model will misrepresent the data and therefore the model should be adapted, together with its rules. Having validation in your model will give consistency to your data since all data that passes must be validated meaning your database/text files whatever will have validated data. Validating in the model without having rules in the model seems a weird compromise.

Similar fieldnames is a convention, used in other frameworks as well. You can choose to abide it or not, it's not that important.

#12
[eluser]xwero[/eluser]
If you have a table with a lot of fields chances are there is going to be more than one form that alters another slice of the fields. So if i understand you well you would create a method for each view in which case you couple the model methods to a certain view file making the methods less reusable?
And what would you do with data that is required on one form but not on another or that has to match another field in on form and not on another?

I think there a several scenario's where it's beneficial for the model code not to have the validation in the model methods but in a separate layer, like the Akelos solution if i'm not mistaken or in the controller. This is why i made the compromise.

#13
[eluser]nmweb[/eluser]
Akelos
Code:
//controller
if($this->Post->save()){
      $this->redirectToAction("show", array('id' => $Post->getId()));
    }else{
      $this->Post->errors = $this->Post->getErrors();
    }
//Model
class Post extends ActiveRecord
{
    function validate(){
      $this->validatesPresenceOf( array('title', 'body'), "Missing required field");
      $this->get('title') > 10 ? $this->addError("title", "must be at most 10 characters") : null;
    }
}
Cakephp uses a similar approach. The save() method first tests the data for being valid before saving it into the database. Errors can then be retrieved. Validation and the rules are in a central place in the application and all data must pass.

When you have a table with a lot of fields and multiple forms to fill them, I don't see why the rules should therefore by stored in the controller. Each form field that is inserted into the db should be validated when an attempt to insertion is being made. The current CI_Validation falls short on that but that's no excuse to not do it. Sure you might have forms which are so complex that validation in the controller is easier, at this point you might want to retrieve the rules for the models concerned from the model.

No I don't have methods for each view, if I would need to do that, my model would be designed wrongly. If data is required in one form and not in another it'll lead to inconsistencies in your data. If you have properly designed your model and its validation you shouldn't run into any problems and you'll find that it is much easier.

You could always implement a save($validate=true) for exotic cases. I wrote a Form generation class which also does validation. I'm now writing something so I can pass my model (with rules) to that class and it'll generate a form of the fields I desire. The form generation class will also write my Javascript validation for usability purposes. To have this work properly I'll have to call the Form_generation->validate() method and may avoid calling the models validation methods. The validate() will check each form field against the rules retrieved from the model.

This way I have to write my rules once and it'll validate my forms everywhere with nice error messages and even javascript validation. All the way from the model through the controller to the view I have perfect validating forms with only a few lines of code. It's proper OOP so I can always for example add an extra javascript rule for usability purposes such as an ajax-username-exists rule or if my model doesn't exactly map to my form I can add or remove fields from the form. I can override rules, messages, anything.

Not validating in the model at all times, sure, you might want to do something like the above and forms don't always map to models. Not having rules in the model I find strange, try adding 300 characters to a varchar field and it'll trigger a crappy mysql error. Yet your controllers or views should have no knowledge of this limitation of varchar, it's the job of the model and using rules you can prevent 300chars from being added and trigger an error that is comprehensible for the user.

#14
[eluser]xwero[/eluser]
If you put this in CI model code a method would look like this (in a primitive state)
Code:
function update_user($where,$custom_fieldnames = array(),$custom_val_rules = array())
{
   $post['first_name'] = $_POST['first_name'];
   // ...
   $this->change_post_value($post,$custom_fieldnames)
   // array('given_name'=>array('first_name','Given name')) will change the $post['first_name'] value
   if(isset($post['first_name']))
   {
      $rules['first_name'] = $this->change_rule('first_name','alpha',$custom_val_rules);
      // array('first_name','required|alpha') would change the rule
      $fields['first_name'] = $this->change_error('first_name','First name',$custom_fieldnames);
      $this->db->set('first_name',$post['first_name']);
   }
   // ...
   $this->validation->set_rules($rules);
   $this->validation->set_fields($fields);
   if(!$this->validation->run())
   {
       return $this->validation->error_string;
   }
   else
   {
      $this->db->where($where);
      $this->db->update('users');
      return $this->affected_rows();
   }
}

#15
[eluser]nmweb[/eluser]
You pass values to your model, your model should have no knowledge of $_POST nor should it do something with it. Your controller should give the model the values.

(primitive state)
Code:
class Some_Model{
protected $fields=array('email');

protected $validate=array(
'field_name'=>array('rules'=>array('required','email'))
);

public function save()
{
   if($this->validate())
   {
      //db insert here with values from $this->field array
return true;
   }
return false;
}
public function validate()
{ $validate=true;
    foreach($this->fields as $field)
    {
    //iterate over rules and what not
      if(!$this->is_valid($field)
      {
       $validate=false;
      }
    }
   return $validate;
}
public function is_valid($field)
{
//get rules for field and validate it
}
public function get_errors(){}
}
In the model above you can handle form field/db field differences with some property of the object.

Now, what does the controller look like:
Code:
//controller
$model=new Some_Model;
$model->email='some wrong email';
if($model->save())
{
echo 'correct mail';
}
else
{
$model->get_errors();
}

To show how Django handles it and how I plan to handle it:
Code:
//bit of pseudo code
class Email_Form extends Form_generation_class{
   protected $form_fields=array('email);
}

$form=new Email_Form(new Some_Model);
echo $form->render();
That's it. It will generate a form based on the model with proper validation including nice error messages and javascript validation. Say you want to edit an existing record.
Code:
$form=new Email_Form(new Some_Model(10); //record number 10
echo $form->render();
if($form->save()) //validates then tries to save the model
{
}
That's it in a nutshell.

#16
[eluser]xwero[/eluser]
Nice nice. If i read it right you think there are 2 problems with the CI validation class
- The $_POST[$field] should be replace with the actual string
- and you shouldn't be able to do trim, xss_clean, ...
I already noticed that from your validation library where you have a method to prepare the data.

Another question how would you handle uploads? Also in the model or in the controller?

#17
[eluser]nmweb[/eluser]
The CI validation class has several issues most of which can be solved by being more OO but it would involve a rewrite. For one think that a validation class should do what I expect it to do, namely validate and not assume that the page contains $_POST data or something. We should pass the data it should validate, for all I care I want to validate the data coming from the database once again. This means a simple
Code:
$validate=new Validation($_POST); //or $_GET or any array
$validate->add_rule('field','rule'); //or something
if($validate->validate())
{}
This is a more intuitive approach to validation, I think. It gives you more freedom as to where you can use it, the current library can only really be used in the controller. This is an historical issue I assume since CodeIgniter for a while didn't have models.

I think uploads should be handled by the model in that sense that you pass the $_FILES to a model and it should handle its storage. Ideally I would have an object representing the file
Code:
class Image_Model extends File_Model{}
class Textfile_Model extends File_Model{}

$image=new Image_Model('image001.gif');
$image->rename('image002.gif'); //rename inherited from file_model
echo $image->get_location; // from file_model

$image->resize(array(50,100)); //method in Image_Model
$image->save(); //method in Image_Model, overridden from File_Model

$file=new Textfile_Model('some_text.txt');
$file->rename('something.txt');
$file->append_text('some extra text at the end of the file');
$file->save(); //method in Textfile_Model, overridden from File_Model

This would be my approach. I love OOP Smile

#18
[eluser]nmweb[/eluser]
To come back to the Form generation from the model: http://h1368840.stratoserver.net/2008/03...eneration/ It works neat as it is but needs some polishing.

I hope to release something soon.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2020 MyBB Group.