Where To Perform Model Level Validation?

I need to perform validation by looking at all the related models.

Where to perform model level validation?

Would beforeSave() be a good place to do it?

If validation fails, where do I store the error since addError takes an attribute. http://www.yiiframework.com/doc/api/1.1/CModel#addError-detail

For example:

Let us say there is a model Person

It has OneToMany relation to PhoneNumber. Each PhoneNumber has a name.

I need to validate at the Person model level that each name is unique.

I need to validate only 1 cell phone or 1 land line number is given.


{Cell, Land, Work} => valid

{Cell, Cell, Land, Work} => invalid

{Cell, Land} => valid

use unique rule.

say if you want only 1 cell phone or land line number then do like this…

public function rules()




it may help you

What am I looking for is how to validate the model by looking at the data in related model. It has nothing to do with checking if the phone number is unique. It is more like a Person can only have 0…1 Cell phone, 0…1 Work phone and 0…1 Land line.

None of the books I have seen so far solves a problem like this, "Web Application Development with Yii and PHP", "Yii Application Development Cookbook - Second Edition" and "Yii Rapid Application Development Hotshot"

Found the solution by overloading

public function validate($attributes = null, $clearErrors = true)


public function save($runValidation = true, $attributes = null)

Person validate checks all associated records.

public function validate($attributes = null, $clearErrors = true) {

    $is_valid = parent::validate($attributes, $clearErrors);

    $phones = array();

    $phoneTypeOptions = getPhoneOptions();

    foreach ($this->phones as $phone {

        if ($phone->validate() == false) {

            $is_valid = false;



        if (isset($phones[$phone->type]) && $phones[$phone->type] != 2) {

            $phones[$phone->type] = 2;

            $is_valid = false;

            $this->addError('phones', 'Only one ' . $phone_options[$phone->type] . ' is allowed.');

        } else {

            $phones[$phone->type] = 1;



    return $is_valid;


public function save($runValidation = true, $attributes = null) {

    if ($runValidation) {

        if ($this->validate($attributes) == false)

            return false;


    foreach ($this->phones as $phone) {



    return parent::save(false, $attributes);