public function save()
{
$collectionName = $this->intermediateCollection;
$firstClassName = $this->extractClassName($this->getParentEntity());
$secondClassName = $this->extractClassName($this->getEntity());
// Make sure indexes exist
$indexOrder = [$firstClassName, $secondClassName];
list($indexKey1, $indexKey2) = $this->arr($indexOrder)->sort()->val();
$index = new CompoundIndex($collectionName, [$indexKey1 => 1, $indexKey2 => 1], false, true);
Entity::getInstance()->getDatabase()->createIndex($collectionName, $index, ['background' => true]);
/**
* Insert values
*/
$existingIds = [];
$firstEntityId = $this->getParentEntity()->id;
foreach ($this->getValue() as $item) {
if ($item instanceof AbstractEntity && !$item->exists()) {
$item->save();
}
if ($item instanceof AbstractEntity) {
$secondEntityId = $item->id;
} else {
$secondEntityId = $item;
}
$existingIds[] = $secondEntityId;
$data = [$firstClassName => $firstEntityId, $secondClassName => $secondEntityId];
try {
Entity::getInstance()->getDatabase()->insertOne($collectionName, $this->arr($data)->sortKey()->val());
} catch (BulkWriteException $e) {
// Unique index was hit and an exception is thrown - that's ok, means the values are already inserted
continue;
}
}
/**
* Remove old links
*/
$removeQuery = [$firstClassName => $firstEntityId, $secondClassName => ['$nin' => $existingIds]];
Entity::getInstance()->getDatabase()->delete($collectionName, $removeQuery);
/**
* The value of many2many attribute must be set to 'null' to trigger data reload on next access.
* If this is not done, we may not have proper links between the 2 entities and it may seem as if data was missing.
*/
$this->setValue(null);
}