Skip to content

Commit

Permalink
Fixed deleting reverse relations
Browse files Browse the repository at this point in the history
  • Loading branch information
boboldehampsink committed Dec 10, 2018
1 parent 3b1859f commit c484bfc
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## 1.0.4 - 2018-12-10
### Fixed
- Fixed saving new reverse relations
- Fixed deleting reverse relations
- Fixed bug when importing with Schematic when the target field didn't yet exist
- Fixed bug where targets where validated

Expand Down
104 changes: 100 additions & 4 deletions src/fields/ReverseEntries.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Craft;
use craft\base\Field;
use craft\base\Element;
use craft\db\Query;
use craft\elements\Entry;
use craft\fields\Matrix;
use craft\fields\Entries;
Expand Down Expand Up @@ -43,6 +44,11 @@ class ReverseEntries extends Entries
*/
protected $sortable = false;

/**
* @var array
*/
private $oldSources = [];

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -112,6 +118,25 @@ public function normalizeValue($value, ElementInterface $element = null)
return $query;
}

/**
* Get original relations so we can diff those
* with the new value and find out which ones need to be deleted.
*
* {@inheritdoc}
*/
public function beforeElementSave(ElementInterface $element, bool $isNew): bool
{
if (!$isNew) {
// Get cached element
$entry = Craft::$app->getEntries()->getEntryById($element->id);

// Get old sources
$this->oldSources = $entry->{$this->handle}->all();
}

return parent::beforeElementSave($element, $isNew);
}

/**
* Save relations on the other side.
*
Expand All @@ -128,22 +153,30 @@ public function afterElementSave(ElementInterface $element, bool $isNew)
return;
}

// Get targets
$value = $element->getFieldValue($this->handle);
// Get sources
$sources = $element->getFieldValue($this->handle)->all();

// Find out which ones to delete
$delete = array_diff($this->oldSources, $sources);

// Loop through sources
/** @var ElementInterface $source */
foreach ($value->all() as $source) {
foreach ($sources as $source) {
$target = $source->getFieldValue($field->handle);

// Set this element on that entry
Craft::$app->getRelations()->saveRelations(
$this->saveRelations(
$field,
$source,
array_merge($target->ids(), [$element->id])
);
}

// Loop through deleted sources
foreach ($delete as $source) {
$this->deleteRelations($field, $source, [$element->id]);
}

Field::afterElementSave($element, $isNew);
}

Expand Down Expand Up @@ -215,4 +248,67 @@ private function canSaveReverseRelation(FieldInterface $field): bool

return true;
}

/**
* Saves some relations for a field.
*
* @param Entries $field
* @param Entry $source
* @param array $targetIds
*/
private function saveRelations(Entries $field, Entry $source, array $targetIds)
{
if ($field->localizeRelations) {
$sourceSiteId = $source->siteId;
} else {
$sourceSiteId = null;
}

foreach ($targetIds as $sortOrder => $targetId) {
$criteria = [
'fieldId' => $field->id,
'sourceId' => $source->id,
'sourceSiteId' => $sourceSiteId,
'targetId' => $targetId,
];

if (!(new Query())->select('id')->from('{{%relations}}')->where($criteria)->exists()) {
Craft::$app->getDb()->createCommand()
->insert('{{%relations}}', array_merge($criteria, ['sortOrder' => 1]))
->execute();
}
}
}

/**
* Deletes some relations for a field.
*
* @param Entries $field
* @param Entry $source
* @param array $targetIds
*/
private function deleteRelations(Entries $field, Entry $source, array $targetIds)
{
// Delete the existing relations
$oldRelationConditions = [
'and',
[
'fieldId' => $field->id,
'sourceId' => $source->id,
'targetId' => $targetIds,
],
];

if ($field->localizeRelations) {
$oldRelationConditions[] = [
'or',
['sourceSiteId' => null],
['sourceSiteId' => $source->siteId],
];
}

Craft::$app->getDb()->createCommand()
->delete('{{%relations}}', $oldRelationConditions)
->execute();
}
}

0 comments on commit c484bfc

Please sign in to comment.