diff --git a/src/base/NestedElementManagerProviderInterface.php b/src/base/NestedElementManagerProviderInterface.php new file mode 100644 index 00000000000..bd24a97c831 --- /dev/null +++ b/src/base/NestedElementManagerProviderInterface.php @@ -0,0 +1,31 @@ + + * @since 5.x + */ +interface NestedElementManagerProviderInterface extends ElementInterface +{ + /** + * Returns the nested element manager by the attribute name. + * + * @param string $attribute The attribute name + * @return ?NestedElementManager + */ + public function getNestedElementManager(string $attribute): ?NestedElementManager; +} diff --git a/src/controllers/NestedElementsController.php b/src/controllers/NestedElementsController.php index 2b5249bb1d0..ad143fca738 100644 --- a/src/controllers/NestedElementsController.php +++ b/src/controllers/NestedElementsController.php @@ -10,11 +10,13 @@ use Craft; use craft\base\ElementInterface; use craft\base\NestedElementInterface; +use craft\base\NestedElementManagerProviderInterface; use craft\db\Table; use craft\elements\db\ElementQueryInterface; use craft\elements\ElementCollection; use craft\helpers\Db; use craft\web\Controller; +use http\Exception\InvalidArgumentException; use yii\web\BadRequestHttpException; use yii\web\ForbiddenHttpException; use yii\web\Response; @@ -65,8 +67,16 @@ public function beforeAction($action): bool throw new ForbiddenHttpException('User is not authorized to perform this action'); } - // Set the nested elements for the action - $this->nestedElements = $this->owner->$attribute; + if ($this->owner instanceof NestedElementManagerProviderInterface) { + $manager = $this->owner->getNestedElementManager($attribute); + if (!$manager) { + throw new InvalidArgumentException('Owner does not provide a nested element manager for the given attribute'); + } + + $this->nestedElements = $manager->getValue($owner, true); + } else { + $this->nestedElements = $this->owner->$attribute; + } return true; } diff --git a/src/elements/NestedElementManager.php b/src/elements/NestedElementManager.php index a26861b4651..d32bffac547 100644 --- a/src/elements/NestedElementManager.php +++ b/src/elements/NestedElementManager.php @@ -172,7 +172,13 @@ private function nestedElementQuery(ElementInterface $owner): ElementQueryInterf return call_user_func($this->queryFactory, $owner); } - private function getValue(ElementInterface $owner, bool $fetchAll = false): ElementQueryInterface|ElementCollection + /** + * @param ElementInterface $owner + * @param bool $fetchAll + * @return ElementQueryInterface|ElementCollection + * @throws \craft\errors\InvalidFieldException + */ + public function getValue(ElementInterface $owner, bool $fetchAll = false): ElementQueryInterface|ElementCollection { if (isset($this->valueGetter)) { return call_user_func($this->valueGetter, $owner, $fetchAll); @@ -199,7 +205,12 @@ private function getValue(ElementInterface $owner, bool $fetchAll = false): Elem return $query; } - private function setValue(ElementInterface $owner, ElementQueryInterface|ElementCollection $value): void + /** + * @param ElementInterface $owner + * @param ElementQueryInterface|ElementCollection $value + * @return void + */ + public function setValue(ElementInterface $owner, ElementQueryInterface|ElementCollection $value): void { if ($this->valueSetter === false) { return; diff --git a/src/elements/User.php b/src/elements/User.php index 2caa43fd31f..b1ea557ffbb 100644 --- a/src/elements/User.php +++ b/src/elements/User.php @@ -11,6 +11,7 @@ use craft\base\Element; use craft\base\ElementInterface; use craft\base\NameTrait; +use craft\base\NestedElementManagerProviderInterface; use craft\db\Query; use craft\db\Table; use craft\elements\actions\DeleteUsers; @@ -85,7 +86,7 @@ * @author Pixel & Tonic, Inc. * @since 3.0.0 */ -class User extends Element implements IdentityInterface +class User extends Element implements IdentityInterface, NestedElementManagerProviderInterface { use NameTrait; @@ -2549,6 +2550,17 @@ public function beforeDelete(): bool return true; } + /** + * @inheritdoc + */ + public function getNestedElementManager(string $attribute): ?NestedElementManager + { + return match ($attribute) { + 'addresses' => $this->getAddressManager(), + default => null, + }; + } + /** * Validates a cookie's stored user agent against the current request's user agent string, * if the 'requireMatchingUserAgentForSession' config setting is enabled.