diff --git a/CHANGELOG.md b/CHANGELOG.md index c03594d7669..db8303c9340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,11 @@ - Fixed a PHP error that occurred when running PHP 8.2 or 8.3. - Fixed a bug where disabled entries became enabled when edited within Live Preview. ([#15670](https://github.com/craftcms/cms/issues/15670)) - Fixed a bug where new nested entries could get incremented slugs even if there were no elements with conflicting URIs. ([#15672](https://github.com/craftcms/cms/issues/15672)) +- Fixed a bug where users’ Addresses screens were displaying addresses that belonged to the user via a custom Addresses field. ([#15678](https://github.com/craftcms/cms/issues/15678)) - Fixed a bug where Addresses fields weren’t always returning data in GraphQL. +- Fixed a bug where partial addresses weren’t getting garbage collected. +- Fixed a bug where orphaned nested addresses weren’t getting garbage collected. ([#15678](https://github.com/craftcms/cms/issues/15678)) +- Fixed a bug where orphaned nested entries weren’t getting garbage collected after their field had been hard-deleted. ([#15678](https://github.com/craftcms/cms/issues/15678)) - Fixed an information disclosure vulnerability. ## 5.4.1 - 2024-09-04 diff --git a/src/elements/User.php b/src/elements/User.php index 2182f407912..a0839883f9c 100644 --- a/src/elements/User.php +++ b/src/elements/User.php @@ -1087,7 +1087,9 @@ public function getAddresses(): ElementCollection return ElementCollection::make(); } - $this->_addresses = $this->createAddressQuery()->collect(); + $this->_addresses = $this->createAddressQuery() + ->andWhere(['fieldId' => null]) + ->collect(); } return $this->_addresses; diff --git a/src/services/Gc.php b/src/services/Gc.php index dd3cca05f3c..de4671f497f 100644 --- a/src/services/Gc.php +++ b/src/services/Gc.php @@ -15,6 +15,7 @@ use craft\db\Connection; use craft\db\Query; use craft\db\Table; +use craft\elements\Address; use craft\elements\Asset; use craft\elements\Category; use craft\elements\Entry; @@ -111,10 +112,12 @@ public function run(bool $force = false): void $this->hardDelete([ Table::CATEGORYGROUPS, Table::ENTRYTYPES, + Table::FIELDS, Table::SECTIONS, Table::TAGGROUPS, ]); + $this->deletePartialElements(Address::class, Table::ADDRESSES, 'id'); $this->deletePartialElements(Asset::class, Table::ASSETS, 'id'); $this->deletePartialElements(Category::class, Table::CATEGORIES, 'id'); $this->deletePartialElements(Entry::class, Table::ENTRIES, 'id'); @@ -123,7 +126,8 @@ public function run(bool $force = false): void $this->deletePartialElements(User::class, Table::USERS, 'id'); $this->_deleteUnsupportedSiteEntries(); - $this->_deleteOrphanedNestedEntries(); + $this->deleteOrphanedNestedElements(Address::class, Table::ADDRESSES); + $this->deleteOrphanedNestedElements(Entry::class, Table::ENTRIES); // Fire a 'run' event // Note this should get fired *before* orphaned drafts & revisions are deleted @@ -141,7 +145,6 @@ public function run(bool $force = false): void $this->hardDelete([ Table::FIELDLAYOUTS, - Table::FIELDS, Table::SITES, ]); @@ -525,35 +528,56 @@ private function _deleteUnsupportedSiteEntries(): void } /** - * Deletes any orphaned nested entries. + * Deletes elements which have a `fieldId` value, but it’s set to an invalid field ID, + * or they're missing a row in the `elements_owners` table. + * + * @param string $elementType The element type + * @phpstan-param class-string $elementType + * @param string $table The extension table name + * @param string $fieldFk The column name that contains the foreign key to `fields.id` + * @since 5.4.2 */ - private function _deleteOrphanedNestedEntries(): void + public function deleteOrphanedNestedElements(string $elementType, string $table, string $fieldFk = 'fieldId'): void { - $this->_stdout(' > deleting orphaned nested entries ... '); + /** @var string|ElementInterface $elementType */ + $this->_stdout(sprintf(' > deleting orphaned nested %s ... ', $elementType::pluralLowerDisplayName())); - $now = Db::prepareDateForDb(new DateTime()); $elementsTable = Table::ELEMENTS; - $entriesTable = Table::ENTRIES; $elementsOwnersTable = Table::ELEMENTS_OWNERS; + $fieldsTable = Table::FIELDS; if ($this->db->getIsMysql()) { - $sql = <<db->createCommand($sql)->execute(); + $this->db->createCommand($sql1)->execute(); + $this->db->createCommand($sql2)->execute(); $this->_stdout("done\n", Console::FG_GREEN); }