I have a HABTM relation like : Post <-> Tag
(a Post can have multiple Tag, and same the other way).
This work with the multiple checkbox selection generated by Cakephp. But I want to have at least one Tag for every Post and throw an error if someone try to insert an orphan.
I'm looking for the cleanest/most CakePHP alike way to do this.
This is more or less an update of this HABTM form validation in CakePHP question, as I get the same problem on my cakephp 2.7 (last cakephp 2.x for now with php 5.3 support at the date of 2016) and can't find a good way to do it.
Here are what I think is the best for now. It use the cakephp 3.x behaviour for HABTM validation.
I choose to only work in model, with the most generic code.
In your AppModel.php
, set this beforeValidate()
and afterValidate()
class AppModel extends Model {
/** @var array set the behaviour to `Containable` */
public $actsAs = array('Containable');
/**
* copy the HABTM post value in the data validation scope
* from data[distantModel][distantModel] to data[model][distantModel]
* @return bool true
*/
public function beforeValidate($options = array()){
foreach (array_keys($this->hasAndBelongsToMany) as $model){
if(isset($this->data[$model][$model]))
$this->data[$this->name][$model] = $this->data[$model][$model];
}
return true;
}
/**
* delete the HABTM value of the data validation scope (undo beforeValidate())
* and add the error returned by main model in the distant HABTM model scope
* @return bool true
*/
public function afterValidate($options = array()){
foreach (array_keys($this->hasAndBelongsToMany) as $model){
unset($this->data[$this->name][$model]);
if(isset($this->validationErrors[$model]))
$this->$model->validationErrors[$model] = $this->validationErrors[$model];
}
return true;
}
}
After this, you can use your validation in you model like this :
class Post extends AppModel {
public $validate = array(
// [...]
'Tag' => array(
// here we ask for min 1 tag
'rule' => array('multiple', array('min' => 1)),
'required' => true,
'message' => 'Please select at least one Tag for this Post.'
)
);
/** @var array many Post belong to many Tag */
public $hasAndBelongsToMany = array(
'Tag' => array(
// [...]
)
);
}
This answer use :
- Painless HABTM Validation in CakePHP by @jesal
- HABTM form validation in CakePHP
- CakePHP 2.x Saving and validating a HABTM relation example