The Model::validates() trap

Published on and tagged with cakephp  model  validation

One mistake I make from time to time is to try to validate my data in the following way:

public function example() {
    $data = array('Project' => array('name' => 'Testproject'));
    if ($this->Project->validates($data)) {
        echo 'valid';
    } else {
        echo 'invalid';
    }
}

If you look at this snippet, it probably looks fine to you. And it is fine if you are using CakePHP 1.1. Unfortunately, in CakePHP 1.2 the behavior of this method has changed, and so the example above doesn’t work as you would expect (depending on the validation rules). For a while the parameter of Model::validates() was deprecated (see Parameter for Model::validates() is now deprecated) and caused a warning if you used it. In the meantime the parameter is back with a new meaning…

Compare the API docs for the validates() methods. First the CakePHP 1.1 docs:

/**
 * Returns true if all fields pass validation, otherwise false.
 *
 * @param array $data POST data
 * @return boolean True if there are no errors
 * @access public
 */

And now the docs for CakePHP 1.2:

/**
 * Returns true if all fields pass validation.
 *
 * @param string $options An optional array of custom options to be made available in the beforeValidate callback
 * @return boolean True if there are no errors
 * @access public
 * @link http://book.cakephp.org/view/410/Validating-Data-from-the-Controller
 */

The parameter of the method is no longer for the data you want to validate but for options for the beforeValidate() callback method. So the example from the beginning has to be changed in the following way to make it work as expected:

public function example() {
    $data = array('Project' => array('name' => 'Testproject'));
    $this->Project->create($data);
    if ($this->Project->validates()) {
        echo 'valid';
    } else {
        echo 'invalid';
    }
}

Happy baking :)

5 comments baked

  • joe siao

    Hi,

    I also make mistakes like you when using that function. Can’t get it used to my system yet.

  • Phally

    You can also use set() for that. Like this:

    public function example() {
        $data = array('Project' => array('name' => 'Testproject'));
        $this->Project->set($data);
        if ($this->Project->validates()) {
            echo 'valid';
        } else {
            echo 'invalid';
        }
    }
  • rafaelbandeira3

    On thing one should be aware when dealing with models is that the Model class represents almost the whole Model layer in cake’s MVC – the (Active)Record and the Finder – so every method that is not related to the finder scope is applied directly to the current record that the model is representing, if any, or the data and state of a incoming record.
    So Model::validate() is supposed to validate the current record/state data, and that’s why it should receive only $options as parameters, and no data.
    And that’s why the idea of keeping find methods on Model::find() and so on… to make a little separation, between the Finder and the Record.
    In my implementations, every custom public method is only appliable to the Record concept or to the class itself – defining params and options.
    That’s why I’m a “http://cakebaker.42dh.com/2008/09/23/an-alternative-way-to-define-custom-find-types/” Evangelist.

  • cakebaker

    @all: Thanks for your comments!

    @joe: Yes, somehow it feels just natural to pass the data directly to the validates() method.

    @Phally: Yes, that’s an alternative to create(), thanks for mentioning it.

    @Rafael: Yes, you can see it in that way. Unfortunately, the implementation doesn’t follow this principle strictly. Compare the methods validates() and save(): validates() doesn’t have a $data parameter whereas save() has such a parameter…

  • rafaelbandeira3

    @cakebaker: yes, but actually, save is not part of the ActiveRecord pattern, it belongs to the Mapper – wich is another role in the Model layer that is played by the Model class on cake – as update, and delete. The last one is the cranky one, that on cake acts on the record, that, although doesn’t feet the “pattern”, is much more logical.
    But as you say “you can see it in that way”. It’s not a rule.

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License