验证嵌套关系中没有重复 - CakePHP 2

I need to make sure that there are no duplicates in a nested relationship. For instance, say I have a purchase that can have many purchase items. I want to make sure that there can't be more than 1 of the same purchase item.

The post data looks like this:

enter image description here

I can't figure out how to validate that purchase items are unique.

The "isUnique" rule only checks that it is not already in the database, but does not check if there are two within the same post.

Note that I have Purchase, PurchaseItem, and Item models. I am not sure which one the validation should really be in...

Something I've tried, but doesn't work:

// PurchaseItem model
public $validate = array(
    'item_id' => array(
        'unique' => array(
            'rule' => array('isUnique', array('purchase_id', 'item_id'), false),
            'message' => 'You may only use the same item once!'
        )
    )
);

Q What is the best way to validate in this situation?

You won't (as far as I am aware) be able to validate the hasMany data like this using Cake's validator. Validation is called for each individual record being saved rather than for all the data as a whole. So you won't be able to just write a custom validation rule for your model.

When Cake saves hasMany data what it does is call $this->Model->save() for each record; this is where validation gets called along with the beforeSave and beforeValidate callbacks. They can only see the data for the individual record getting saved.

Instead you will need to take a more manual approach to validating just before saving. You could do this by extending saveMany() for your model:-

public function saveMany($data = null, $options = array()) {
    // 1. Do some additional cross record validation here 
    //    (return false if duplicates found)
    // 2. Continue to save
    return parent::saveMany($data, $options);
}

You could perhaps add a new callback for beforeSaveMany and add your extra validation rules in the new callback.

If you find that the data contains duplicates you can use Cake's Validator to flag the relevant field as an issue should you want:-

$this->Model->invalidate('field_name', 'error message');

To test the data (which I assume you only want to test is unique in the submitted data and not in the database) you could utilise Cake's Hash utility. It should be simple to extract the data you want and check for duplicates.