Skip to content

Commit

Permalink
Merge pull request #14368 from craftcms/bugfix/13956-keep-relations-c…
Browse files Browse the repository at this point in the history
…lean

remove relations for fields that are not part of the layout anymore
  • Loading branch information
brandonkelly authored Feb 13, 2024
2 parents 3a75bd5 + bbac715 commit db97dd0
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@

### Development
- The `{% js %}` and `{% css %}` tags now support `.js.gz` and `.css.gz` URLs. ([#14243](https://github.com/craftcms/cms/issues/14243))

### Extensibility
- Added `craft\services\Relations::deleteLeftoverRelations()`. ([#13956](https://github.com/craftcms/cms/issues/13956))

### System
- Relations for fields that are no longer included in an element’s field layout are now deleted after element save. ([#13956](https://github.com/craftcms/cms/issues/13956))
5 changes: 5 additions & 0 deletions src/base/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -5182,6 +5182,11 @@ public function afterPropagate(bool $isNew): void
$field->afterElementPropagate($this, $isNew);
}

// Delete relations that don’t belong to a relational field on the element's field layout
if (!ElementHelper::isDraftOrRevision($this)) {
Craft::$app->getRelations()->deleteLeftoverRelations($this);
}

// Trigger an 'afterPropagate' event
if ($this->hasEventHandlers(self::EVENT_AFTER_PROPAGATE)) {
$this->trigger(self::EVENT_AFTER_PROPAGATE, new ModelEvent([
Expand Down
48 changes: 48 additions & 0 deletions src/services/Relations.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use craft\db\Command;
use craft\db\Query;
use craft\db\Table;
use craft\fieldlayoutelements\CustomField;
use craft\fields\BaseRelationField;
use craft\helpers\Db;
use Throwable;
Expand Down Expand Up @@ -125,4 +126,51 @@ public function saveRelations(BaseRelationField $field, ElementInterface $source
}
}
}

/**
* Deletes relations that don’t belong to a relational field on the given element’s field layout.
*
* @param ElementInterface $element
* @since 4.8.0
*/
public function deleteLeftoverRelations(ElementInterface $element): void
{
if (!$element->id) {
return;
}

$fieldLayout = $element->getFieldLayout();
if (!$fieldLayout) {
return;
}

$relationFieldIds = [];
foreach ($fieldLayout->getTabs() as $tab) {
foreach ($tab->getElements() as $layoutElement) {
if ($layoutElement instanceof CustomField) {
$field = $layoutElement->getField();
if ($field instanceof BaseRelationField) {
$relationFieldIds[] = $field->id;
}
}
}
}

// get those relations for the element that don't belong to any relational fields that are in the layout
$query = (new Query())
->select(['id'])
->from(Table::RELATIONS)
->where(['sourceId' => $element->id]);

if (!empty($relationFieldIds)) {
$query->andWhere(['not', ['fieldId' => $relationFieldIds]]);
}

$leftoverRelationIds = $query->column();

// if relations were returned - delete them
if (!empty($leftoverRelationIds)) {
Db::delete(Table::RELATIONS, ['id' => $leftoverRelationIds]);
}
}
}

0 comments on commit db97dd0

Please sign in to comment.