From 107643f0be00e297cec7f9c13d996f004e540c5a Mon Sep 17 00:00:00 2001 From: Sebastian Lenz Date: Fri, 22 Nov 2019 11:14:41 +0100 Subject: [PATCH] Pass an option array to ForeignFieldQueryExtension instead of individual arguments --- src/foreignField/ForeignField.php | 35 ++++++++++- .../ForeignFieldQueryExtension.php | 60 +++++++++++++++---- 2 files changed, 79 insertions(+), 16 deletions(-) diff --git a/src/foreignField/ForeignField.php b/src/foreignField/ForeignField.php index d51515c..d20c9f1 100644 --- a/src/foreignField/ForeignField.php +++ b/src/foreignField/ForeignField.php @@ -112,7 +112,10 @@ public function isValueEmpty($value, ElementInterface $element): bool { * @throws Exception */ public function modifyElementsQuery(ElementQueryInterface $query, $value) { - static::queryExtensionClass()::attachTo($query, $this, $value); + static::queryExtensionClass()::attachTo($query, $this, [ + 'filter' => self::prepareQueryFilter($value), + ]); + return null; } @@ -121,7 +124,9 @@ public function modifyElementsQuery(ElementQueryInterface $query, $value) { * @throws Exception */ public function modifyElementIndexQuery(ElementQueryInterface $query) { - static::queryExtensionClass()::attachTo($query, $this, null, true); + static::queryExtensionClass()::attachTo($query, $this, [ + 'forceEagerLoad' => true, + ]); } /** @@ -271,6 +276,30 @@ protected function getHtml(ForeignFieldModel $value, ElementInterface $element = ]); } + /** + * @param mixed $value + * @return mixed + * @throws Exception + */ + protected function prepareQueryFilter($value) { + if (empty($value)) { + return null; + } + + if (!is_array($value)) { + throw new Exception("The query value for the field {$this->handle} must be an array."); + } + + $fields = self::recordModelAttributes(); + foreach ($value as $field => $condition) { + if (!in_array($field, $fields)) { + throw new Exception("The query for the field {$this->handle} refers to an unknown field '{$field}'."); + } + } + + return $value; + } + /** * @param string $template * @param array $variables @@ -358,7 +387,7 @@ abstract public static function modelClass(): string; /** * The query extension class used by this field. - * @return string + * @return string|ForeignFieldQueryExtension */ public static function queryExtensionClass(): string { return ForeignFieldQueryExtension::class; diff --git a/src/foreignField/ForeignFieldQueryExtension.php b/src/foreignField/ForeignFieldQueryExtension.php index 1f433ad..e03b120 100644 --- a/src/foreignField/ForeignFieldQueryExtension.php +++ b/src/foreignField/ForeignFieldQueryExtension.php @@ -52,12 +52,18 @@ class ForeignFieldQueryExtension */ private $_didAttachJoin = false; + /** + * @var ForeignFieldQueryExtension[] + */ + private static $INSTANCES = array(); + /** * ForeignFieldQueryExtension constructor. * @param array $config */ public function __construct(array $config) { + self::$INSTANCES[] = $this; Yii::configure($this, $config); $this->query->on( @@ -88,6 +94,23 @@ public function onAfterPrepare() { // Protected methods // ----------------- + /** + * @param array $options + * @return ForeignFieldQueryExtension + */ + protected function applyOptions(array $options) { + $this->enableEagerLoad = $this->enableEagerLoad || $options['enableEagerLoad']; + $this->enableJoin = $this->enableJoin || $options['enableJoin']; + + if (is_array($options['filters'])) { + $this->filters = is_array($this->filters) + ? array_merge($this->filters, $options['filters']) + : $options['filters']; + } + + return $this; + } + /** * @return void */ @@ -164,33 +187,41 @@ protected function getJsonExpression() { /** * @param ElementQueryInterface $query * @param ForeignField $field - * @param mixed $filters - * @param bool $forceEagerLoad + * @param array $options + * @return ForeignFieldQueryExtension|void|null * @throws Exception */ - static public function attachTo(ElementQueryInterface $query, ForeignField $field, $filters, $forceEagerLoad = false) { + static public function attachTo(ElementQueryInterface $query, ForeignField $field, array $options = []) { if (!($query instanceof ElementQuery)) { return; } - if (empty($filters)) { - $filters = null; - } elseif (!is_array($filters)) { - throw new Exception("The query value for the field {$field->handle} must be an array."); - } + $filters = ArrayHelper::getValue($options, 'filters', null); + $forceEagerLoad = !!ArrayHelper::getValue($options, 'forceEagerLoad', false); + $forceJoin = !!ArrayHelper::getValue($options, 'forceJoin', false); $enableEagerLoad = static::enableEagerLoad($query, $field) || $forceEagerLoad; - $enableJoin = static::enableJoin($query, $field) || $filters; + $enableJoin = static::enableJoin($query, $field) || $filters || $forceJoin; if ($enableEagerLoad || $enableJoin) { - new static([ + $options = [ 'enableEagerLoad' => $enableEagerLoad, 'enableJoin' => $enableJoin, 'field' => $field, 'filters' => $filters, 'query' => $query, - ]); + ]; + + foreach (self::$INSTANCES as $instance) { + if ($instance->query === $query) { + return $instance->applyOptions($options); + } + } + + return new static($options); } + + return null; } /** @@ -240,8 +271,11 @@ static protected function enableJoin(ElementQuery $query, ForeignField $field) { [Json::encode($query->where)] ); - foreach ($items as $item) { - if (strpos($item, $field->handle) !== false) { + foreach ($items as $key => $value) { + if ( + strpos($key, $field->handle) !== false || + strpos($value, $field->handle) !== false + ) { return true; } }