Skip to content

Commit

Permalink
Merge pull request #15685 from craftcms/bugfix/15678-user-addresses-a…
Browse files Browse the repository at this point in the history
…nd-fields

Bugfix/15678 user addresses and fields
  • Loading branch information
brandonkelly committed Sep 6, 2024
2 parents fadf48f + ac3ca1b commit b7bd7d6
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 15 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/elements/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
52 changes: 38 additions & 14 deletions src/services/Gc.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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');
Expand All @@ -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
Expand All @@ -141,7 +145,6 @@ public function run(bool $force = false): void

$this->hardDelete([
Table::FIELDLAYOUTS,
Table::FIELDS,
Table::SITES,
]);

Expand Down Expand Up @@ -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<ElementInterface> $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 = <<<SQL
$sql1 = <<<SQL
DELETE [[el]].* FROM $elementsTable [[el]]
INNER JOIN $entriesTable [[en]] ON [[en.id]] = [[el.id]]
INNER JOIN $table [[t]] ON [[t.id]] = [[el.id]]
LEFT JOIN $elementsOwnersTable [[eo]] ON [[eo.elementId]] = [[el.id]]
WHERE [[en.fieldId]] IS NOT NULL AND [[eo.elementId]] IS NULL
WHERE [[t.$fieldFk]] IS NOT NULL AND [[eo.elementId]] IS NULL
SQL;
$sql2 = <<<SQL
DELETE [[el]].* FROM $elementsTable [[el]]
INNER JOIN $table [[t]] ON [[t.id]] = [[el.id]]
LEFT JOIN $fieldsTable [[f]] ON [[f.id]] = [[t.$fieldFk]]
WHERE [[t.$fieldFk]] IS NOT NULL AND [[f.id]] IS NULL
SQL;
} else {
$sql = <<<SQL
$sql1 = <<<SQL
DELETE FROM $elementsTable
USING $elementsTable [[el]]
INNER JOIN $entriesTable [[en]] ON [[en.id]] = [[el.id]]
INNER JOIN $table [[t]] ON [[t.id]] = [[el.id]]
LEFT JOIN $elementsOwnersTable [[eo]] ON [[eo.elementId]] = [[el.id]]
WHERE [[en.fieldId]] IS NOT NULL AND [[eo.elementId]] IS NULL
WHERE [[t.$fieldFk]] IS NOT NULL AND [[eo.elementId]] IS NULL
SQL;
$sql2 = <<<SQL
DELETE FROM $elementsTable
USING $elementsTable [[el]]
INNER JOIN $table [[t]] ON [[t.id]] = [[el.id]]
LEFT JOIN $fieldsTable [[f]] ON [[f.id]] = [[t.$fieldFk]]
WHERE [[t.$fieldFk]] IS NOT NULL AND [[f.id]] IS NULL
SQL;
}

$this->db->createCommand($sql)->execute();
$this->db->createCommand($sql1)->execute();
$this->db->createCommand($sql2)->execute();

$this->_stdout("done\n", Console::FG_GREEN);
}
Expand Down

0 comments on commit b7bd7d6

Please sign in to comment.