Hmm, "you are too new to post comments" so a Forum post instead.
Referring to http://www.yiiframework.com/wiki/634/auto-update-denormalized-attributes-with-mongodb-and-yii2/ by @edoardo849
Thanks for the excellent article and code!
Minor nitpick: in Mongodb 2.6 timeout has been renamed to socketTimeout, so in mongoCommand use this:
'socketTimeoutMS' => $this->mongoTimeout
However… I couldn’t wrap my head around the way the errorOnDelete mechanism is supposed to work.
What I want is to block deletion of an item from the collection to which this behavior is attached as long as the specific item is referenced from any document in a related collection. With the current implementation this condition is not tested (only if any of the related documents would need the referenced value changed/updated).
The following method implements what I need. Maybe this can be done much more elegant, so please take this as a starting point. Or if I’m mistaken I would like to know as well.
- Modified method onBeforeDelete:
public function onBeforeDelete()
{
if ($this->errorOnDelete) {
$matches = $this->findDependencies();
if (!empty($matches)) {
throw new ErrorException('The following models have dependencies which prevent deletion: ' . Json::encode($matches), 500);
}
}
}
- New method findDependencies:
private function findDependencies()
{
$fields = $this->owner->attributes;
$matches = [];
foreach($fields as $key => $value) {
if (!isset($this->attributes[$key]))
continue;
$dependencies = $this->attributes[$key];
foreach ($dependencies as $dependency) {
/**
* @var \yii\mongodb\ActiveRecord $model
*/
$model = new $dependency['class'];
$targetAttribute = $dependency['targetAttribute'];
$collectionName = $model::collectionName();
if ($model instanceof MongoGridFsAR) {
$collectionName = $collectionName . '.files';
}
/**
* @var \MongoCollection $mongoCommand
*/
$mongoCommand = Yii::$app->mongodb->getCollection($collectionName);
$res = $mongoCommand->find(
[$targetAttribute => $value], [$targetAttribute])->count();
if (!empty($res)) {
$matches[$model->collectionName()] = "$targetAttribute ($res)";
}
}
}
return $matches;
}