Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for passing a Twig template to relation condition rules #12679

Merged
merged 3 commits into from
Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
- The Asset Indexes utility no longer skips volumes if the root folder was completely empty. ([#12585](https://github.com/craftcms/cms/issues/12585), [#12604](https://github.com/craftcms/cms/pull/12604))
- The Asset Indexes utility now has a “List empty folders” setting, which determines whether empty folders sholud be listed for deletion from the index. ([#12604](https://github.com/craftcms/cms/pull/12604))
- The Asset Indexes utility now lists missing/empty folders and files separately in the review screen. ([#12604](https://github.com/craftcms/cms/pull/12604))
- Relational condition rules for conditions that are saved to the project config now accept a Twig template which outputs a related element ID dynamically. ([#12679](https://github.com/craftcms/cms/pull/12679), [#12676](https://github.com/craftcms/cms/discussions/12676))
- Improved the CLI output for `index-assets` commands. ([#12604](https://github.com/craftcms/cms/pull/12604))

### Development
Expand Down Expand Up @@ -88,6 +89,7 @@
- Added `craft\db\QueryBatcher`.
- Added `craft\debug\DumpPanel`.
- Added `craft\elements\conditions\assets\ViewableConditionRule`. ([#12266](https://github.com/craftcms/cms/pull/12266))
- Added `craft\elements\conditions\ElementCondition::$referenceElement`.
- Added `craft\elements\conditions\entries\ViewableConditionRule`. ([#12266](https://github.com/craftcms/cms/pull/12266))
- Added `craft\elements\Entry::EVENT_DEFINE_PARENT_SELECTION_CRITERIA`. ([#12475](https://github.com/craftcms/cms/discussions/12475))
- Added `craft\events\DefineInputOptionsEvent`. ([#12351](https://github.com/craftcms/cms/pull/12351))
Expand Down
11 changes: 10 additions & 1 deletion src/base/conditions/BaseElementSelectConditionRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

use Craft;
use craft\base\ElementInterface;
use craft\elements\conditions\ElementCondition;
use craft\elements\conditions\ElementConditionInterface;
use craft\helpers\App;
use craft\helpers\Cp;
use stdClass;

/**
* BaseElementSelectConditionRule provides a base implementation for element query condition rules that are composed of an element select input.
Expand Down Expand Up @@ -68,7 +70,13 @@ protected function criteria(): ?array
public function getElementId(bool $parse = true): int|string|null
{
if ($parse && is_string($this->_elementId)) {
return App::parseEnv($this->_elementId);
$elementId = App::parseEnv($this->_elementId);
if ($this->condition instanceof ElementCondition && isset($this->condition->referenceElement)) {
$referenceElement = $this->condition->referenceElement;
} else {
$referenceElement = new stdClass();
}
return Craft::$app->getView()->renderObjectTemplate($elementId, $referenceElement);
}
return $this->_elementId;
}
Expand Down Expand Up @@ -109,6 +117,7 @@ protected function inputHtml(): string
'id' => 'elementId',
'name' => 'elementId',
'value' => $this->getElementId(false),
'tip' => Craft::t('app', 'This can be set to an environment variable, or a Twig template that outputs an ID.'),
'placeholder' => Craft::t('app', '{type} ID', [
'type' => $this->elementType()::displayName(),
]),
Expand Down
4 changes: 4 additions & 0 deletions src/controllers/AssetsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use craft\assetpreviews\Image as ImagePreview;
use craft\base\Element;
use craft\elements\Asset;
use craft\elements\conditions\ElementCondition;
use craft\errors\AssetException;
use craft\errors\DeprecationException;
use craft\errors\ElementNotFoundException;
Expand Down Expand Up @@ -262,6 +263,9 @@ public function actionUpload(): Response
$folderId = $field->resolveDynamicPathToFolderId($element);

$selectionCondition = $field->getSelectionCondition();
if ($selectionCondition instanceof ElementCondition) {
$selectionCondition->referenceElement = $element;
}
} else {
$selectionCondition = null;
}
Expand Down
13 changes: 12 additions & 1 deletion src/controllers/ElementIndexesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use craft\base\ElementInterface;
use craft\elements\actions\DeleteActionInterface;
use craft\elements\actions\Restore;
use craft\elements\conditions\ElementCondition;
use craft\elements\conditions\ElementConditionInterface;
use craft\elements\conditions\ElementConditionRuleInterface;
use craft\elements\db\ElementQueryInterface;
Expand Down Expand Up @@ -492,7 +493,17 @@ protected function condition(): ?ElementConditionInterface
return null;
}

return Craft::$app->getConditions()->createCondition($conditionConfig);
$condition = Craft::$app->getConditions()->createCondition($conditionConfig);

if ($condition instanceof ElementCondition) {
$referenceElementId = $this->request->getBodyParam('referenceElementId');
if ($referenceElementId) {
$siteId = $this->request->getBodyParam('referenceElementSiteId');
$condition->referenceElement = Craft::$app->getElements()->getElementById((int)$referenceElementId, siteId: $siteId);
}
}

return $condition;
}

/**
Expand Down
7 changes: 7 additions & 0 deletions src/elements/conditions/ElementCondition.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ class ElementCondition extends BaseCondition implements ElementConditionInterfac
*/
public array $queryParams = [];

/**
* @var ElementInterface|null The element that this condition is being executed in reference to, if any.
*
* @since 4.4.0
*/
public ?ElementInterface $referenceElement = null;

/**
* Constructor.
*
Expand Down
9 changes: 8 additions & 1 deletion src/fields/BaseRelationField.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use craft\db\Query;
use craft\db\QueryAbortedException;
use craft\db\Table as DbTable;
use craft\elements\conditions\ElementCondition;
use craft\elements\conditions\ElementConditionInterface;
use craft\elements\db\ElementQuery;
use craft\elements\db\ElementQueryInterface;
Expand Down Expand Up @@ -1194,6 +1195,11 @@ protected function inputTemplateVariables(array|ElementQueryInterface $value = n
}
}

$selectionCondition = $this->getSelectionCondition();
if ($selectionCondition instanceof ElementCondition) {
$selectionCondition->referenceElement = $element;
}

return [
'jsClass' => $this->inputJsClass,
'elementType' => static::elementType(),
Expand All @@ -1204,7 +1210,8 @@ protected function inputTemplateVariables(array|ElementQueryInterface $value = n
'name' => $this->handle,
'elements' => $value,
'sources' => $this->getInputSources($element),
'condition' => $this->getSelectionCondition(),
'condition' => $selectionCondition,
'referenceElement' => $element,
'criteria' => $selectionCriteria,
'showSiteMenu' => ($this->targetSiteId || !$this->showSiteMenu) ? false : 'auto',
'allowSelfRelations' => (bool)$this->allowSelfRelations,
Expand Down
2 changes: 2 additions & 0 deletions src/templates/_components/fieldtypes/Assets/input.twig
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
elementType: elementType,
sources: sources,
condition: condition ? condition.getConfig() : null,
referenceElementId: referenceElement.id ?? null,
referenceElementSiteId: referenceElement.siteId ?? null,
criteria: criteria,
sourceElementId: sourceElementId,
viewMode: viewMode,
Expand Down
2 changes: 2 additions & 0 deletions src/templates/_includes/forms/elementSelect.twig
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
elementType: elementType,
sources: sources,
condition: condition ? condition.getConfig() : null,
referenceElementId: referenceElement.id ?? null,
referenceElementSiteId: referenceElement.siteId ?? null,
criteria: criteria,
allowSelfRelations: allowSelfRelations ?? false,
maintainHierarchy: maintainHierarchy,
Expand Down
1 change: 1 addition & 0 deletions src/translations/en/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,7 @@
'This can be set to an environment variable matching one of the option values.' => 'This can be set to an environment variable matching one of the option values.',
'This can be set to an environment variable with a boolean value ({examples}).' => 'This can be set to an environment variable with a boolean value ({examples}).',
'This can be set to an environment variable with a value of a [supported time zone]({url}).' => 'This can be set to an environment variable with a value of a [supported time zone]({url}).',
'This can be set to an environment variable, or a Twig template that outputs an ID.' => 'This can be set to an environment variable, or a Twig template that outputs an ID.',
'This can be set to an environment variable, or begin with an alias.' => 'This can be set to an environment variable, or begin with an alias.',
'This can be set to an environment variable.' => 'This can be set to an environment variable.',
'This element is conditional' => 'This element is conditional',
Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js.map

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/web/assets/cp/src/js/BaseElementIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,8 @@ Craft.BaseElementIndex = Garnish.Base.extend(
elementType: this.elementType,
source: this.instanceState.selectedSource,
condition: this.settings.condition,
referenceElementId: this.settings.referenceElementId,
referenceElementSiteId: this.settings.referenceElementSiteId,
criteria: criteria,
disabledElementIds: this.settings.disabledElementIds,
viewState: $.extend({}, this.getSelectedSourceState()),
Expand Down Expand Up @@ -3086,6 +3088,8 @@ Craft.BaseElementIndex = Garnish.Base.extend(
modal: null,
storageKey: null,
condition: null,
referenceElementId: null,
referenceElementSiteId: null,
criteria: null,
batchSize: 100,
disabledElementIds: [],
Expand Down
15 changes: 15 additions & 0 deletions src/web/assets/cp/src/js/BaseElementSelectInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ Craft.BaseElementSelectInput = Garnish.Base.extend(
storageKey: this.modalStorageKey,
sources: this.settings.sources,
condition: this.settings.condition,
referenceElementId: this.settings.referenceElementId,
referenceElementSiteId: this.settings.referenceElementSiteId,
criteria: this.settings.criteria,
multiSelect: this.settings.limit != 1,
hideOnSelect: !this.settings.maintainHierarchy,
Expand Down Expand Up @@ -547,6 +549,17 @@ Craft.BaseElementSelectInput = Garnish.Base.extend(
},

onModalHide: function () {
// If the modal has a condition and a reference element, recreate it each time it’s opened
// in case something about the edited element is going to affect the condition
if (
this.modal &&
this.settings.condition &&
this.settings.referenceElementId
) {
this.modal.destroy();
this.modal = null;
}

// If can add more elements, do default behavior of focus on "Add" button
if (this.canAddMoreElements()) return;

Expand Down Expand Up @@ -775,6 +788,8 @@ Craft.BaseElementSelectInput = Garnish.Base.extend(
elementType: null,
sources: null,
condition: null,
referenceElementId: null,
referenceElementSiteId: null,
criteria: {},
allowSelfRelations: false,
sourceElementId: null,
Expand Down
4 changes: 4 additions & 0 deletions src/web/assets/cp/src/js/BaseElementSelectorModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,8 @@ Craft.BaseElementSelectorModal = Garnish.Modal.extend(
modal: this,
storageKey: this.settings.storageKey,
condition: this.settings.condition,
referenceElementId: this.settings.referenceElementId,
referenceElementSiteId: this.settings.referenceElementSiteId,
criteria: this.settings.criteria,
disabledElementIds: this.settings.disabledElementIds,
selectable: true,
Expand All @@ -460,6 +462,8 @@ Craft.BaseElementSelectorModal = Garnish.Modal.extend(
storageKey: null,
sources: null,
condition: null,
referenceElementId: null,
referenceElementSiteId: null,
criteria: null,
multiSelect: false,
showSiteMenu: null,
Expand Down