diff --git a/CHANGELOG-WIP.md b/CHANGELOG-WIP.md index e39a4ba7a24..3d39f002aea 100644 --- a/CHANGELOG-WIP.md +++ b/CHANGELOG-WIP.md @@ -12,6 +12,7 @@ - Entries can now have multiple authors. ([#12380](https://github.com/craftcms/cms/pull/12380)) - The “Save as a new entry” action is now available to all users with the “Create entries” permission, and will create a new unpublished draft rather than a fully-saved entry. ([#9577](https://github.com/craftcms/cms/issues/9577), [#10244](https://github.com/craftcms/cms/discussions/10244)) - Entry conditions can now have a “Matrix field” rule. ([#13794](https://github.com/craftcms/cms/discussions/13794)) +- Money field condition rules now use money inputs. ([#14148](https://github.com/craftcms/cms/pull/14148)) - Selected elements within relational fields now include a context menu with “View in a new tab”, “Edit”, and “Remove” options. - Selected elements within relational fields now include a dedicated drag handle. - Selected assets within Assets fields no longer open the file preview modal when their thumbnail is clicked on. The “Preview file” quick action, or the Shift + Spacebar keyboard shortcut, can be used instead. @@ -211,8 +212,14 @@ - Added `craft\fields\Matrix::getSupportedSitesForElement()`. - Added `craft\fields\Matrix::setEntryTypes()`. - Added `craft\fields\Matrix::supportedSiteIds()`. +- Added `craft\fields\Money::currencyLabel()`. +- Added `craft\fields\Money::currencyLabel()`. +- Added `craft\fields\Money::subunits()`. +- Added `craft\fields\Money::subunits()`. - Added `craft\fields\conditions\FieldConditionRuleTrait::fieldInstances()`. - Added `craft\fields\conditions\FieldConditionRuleTrait::setLayoutElementUid()`. +- Added `craft\fields\conditions\MoneyFieldConditionRule`. +- Added `craft\fields\conditions\MoneyFieldConditionRule`. - Added `craft\helpers\App::isWindows()`. - Added `craft\helpers\App::silence()`. - Added `craft\helpers\ArrayHelper::lastValue()`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f648f64aee..12273e1361b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ ## Unreleased +- Money field condition rules now use money inputs. ([#14148](https://github.com/craftcms/cms/pull/14148)) - Improved the accessibility of element indexes. ([#14120](https://github.com/craftcms/cms/pull/14120)) +- Added `craft\fields\Money::currencyLabel()`. +- Added `craft\fields\Money::subunits()`. +- Added `craft\fields\conditions\MoneyFieldConditionRule`. - `craft\base\BaseFsInterface::renameFile()` and `copyFile()` now have a `$config` argument. ([#14147](https://github.com/craftcms/cms/pull/14147)) - Fixed a bug where `craft\helpers\Db::prepareValueForDb()` wasn’t converting objects to arrays for JSON columns. - Fixed a bug where Checkboxes, Multi-select, Dropdown, and Radio Buttons fields weren’t displaying `0` option labels within element indexes. ([#14127](https://github.com/craftcms/cms/issues/14127)) diff --git a/src/fields/Money.php b/src/fields/Money.php index ca36ac63207..ab257b34b8f 100644 --- a/src/fields/Money.php +++ b/src/fields/Money.php @@ -12,7 +12,7 @@ use craft\base\Field; use craft\base\InlineEditableFieldInterface; use craft\base\SortableFieldInterface; -use craft\fields\conditions\NumberFieldConditionRule; +use craft\fields\conditions\MoneyFieldConditionRule; use craft\gql\types\Money as MoneyType; use craft\helpers\Cp; use craft\helpers\Db; @@ -144,7 +144,7 @@ public function getSettingsHtml(): ?string return Craft::$app->getView()->renderTemplate('_components/fieldtypes/Money/settings.twig', [ 'field' => $this, 'currencies' => $this->_isoCurrencies, - 'subUnits' => $this->_isoCurrencies->subunitFor(new Currency($this->currency)), + 'subUnits' => $this->subunits(), ]); } @@ -257,30 +257,23 @@ protected function inputHtml(mixed $value, ?ElementInterface $element, bool $inl $decimals = null; if ($value instanceof MoneyLibrary) { - $decimals = $this->_isoCurrencies->subunitFor($value->getCurrency()); + $decimals = $this->subunits($value->getCurrency()); $value = MoneyHelper::toNumber($value); } - if ($decimals === null) { - $decimals = $this->_isoCurrencies->subunitFor(new Currency($this->currency)); - } + $decimals = $decimals ?? $this->subunits(); $defaultValue = null; if (isset($this->defaultValue)) { $defaultValue = MoneyHelper::toNumber(new MoneyLibrary($this->defaultValue, new Currency($this->currency))); } - $currencyLabel = Craft::t('app', '({currencyCode}) {currencySymbol}', [ - 'currencyCode' => $this->currency, - 'currencySymbol' => Craft::$app->getFormattingLocale()->getCurrencySymbol($this->currency), - ]); - return Cp::moneyInputHtml([ 'id' => $this->getInputId(), 'name' => $this->handle, 'size' => $this->size, 'currency' => $this->currency, - 'currencyLabel' => $currencyLabel, + 'currencyLabel' => $this->currencyLabel(), 'showCurrency' => $this->showCurrency, 'decimals' => $decimals, 'defaultValue' => $defaultValue, @@ -290,6 +283,29 @@ protected function inputHtml(mixed $value, ?ElementInterface $element, bool $inl ]); } + /** + * @return string + * @since 5.0.0 + */ + public function currencyLabel(): string + { + return Craft::t('app', '({currencyCode}) {currencySymbol}', [ + 'currencyCode' => $this->currency, + 'currencySymbol' => Craft::$app->getFormattingLocale()->getCurrencySymbol($this->currency), + ]); + } + + /** + * @param Currency|null $currency + * @return int + * @since 5.0.0 + */ + public function subunits(?Currency $currency = null): int + { + $currency = $currency ?? new Currency($this->currency); + return $this->_isoCurrencies->subunitFor($currency); + } + /** * @inheritdoc */ @@ -305,7 +321,7 @@ public function getElementValidationRules(): array */ public function getElementConditionRuleType(): array|string|null { - return NumberFieldConditionRule::class; + return MoneyFieldConditionRule::class; } /** diff --git a/src/fields/conditions/MoneyFieldConditionRule.php b/src/fields/conditions/MoneyFieldConditionRule.php new file mode 100644 index 00000000000..976afc5f3c8 --- /dev/null +++ b/src/fields/conditions/MoneyFieldConditionRule.php @@ -0,0 +1,136 @@ + + * @since 5.0.0 + */ +class MoneyFieldConditionRule extends BaseNumberConditionRule implements FieldConditionRuleInterface +{ + use FieldConditionRuleTrait; + + /** + * @inheritdoc + */ + public function setAttributes($values, $safeOnly = true): void + { + // Hold setting of the value attribute until we have all the info we need + if (isset($values['value']) && is_array($values['value'])) { + /** @var array $value */ + $value = ArrayHelper::remove($values, 'value'); + } + + if (isset($values['maxValue']) && is_array($values['maxValue'])) { + /** @var array $maxValue */ + $maxValue = ArrayHelper::remove($values, 'maxValue'); + } + + parent::setAttributes($values, $safeOnly); + + /** @var Money $field */ + $field = $this->field(); + + if (isset($value) && isset($this->_fieldUid)) { + if (!isset($value['currency'])) { + $value['currency'] = $field->currency; + } + $this->value = MoneyHelper::toDecimal(MoneyHelper::toMoney($value)); + } + + if (isset($maxValue) && isset($this->_fieldUid)) { + if (!isset($maxValue['currency'])) { + $maxValue['currency'] = $field->currency; + } + $this->maxValue = MoneyHelper::toDecimal(MoneyHelper::toMoney($maxValue)); + } + } + + /** + * @inheritdoc + */ + protected function inputHtml(): string + { + // don't show the value input if the condition checks for empty/notempty + if ($this->operator === self::OPERATOR_EMPTY || $this->operator === self::OPERATOR_NOT_EMPTY) { + return ''; + } + + if ($this->operator === self::OPERATOR_BETWEEN) { + return Html::tag('div', + Html::hiddenLabel(Craft::t('app', 'Min Value'), 'min') . + // Min value (value) input + Cp::moneyInputHtml($this->inputOptions()) . + Html::tag('span', Craft::t('app', 'and')) . + Html::hiddenLabel(Craft::t('app', 'Max Value'), 'max') . + // Max value input + Cp::moneyInputHtml(array_merge( + $this->inputOptions(), + ['id' => 'maxValue', 'name' => 'maxValue', 'value' => $this->maxValue] + )) . + Html::tag('span', Craft::t('app', 'The values are matched inclusively.'), ['class' => 'info']), + ['class' => 'flex flex-center'] + ); + } + + return Cp::moneyInputHtml($this->inputOptions()); + } + + /** + * @inheritdoc + */ + protected function inputOptions(): array + { + /** @var Money $field */ + $field = $this->field(); + $defaultValue = null; + if ($field->defaultValue !== null) { + $defaultValue = MoneyHelper::toNumber(new MoneyLibrary($field->defaultValue, new Currency($field->currency))); + } + + return [ + 'type' => 'text', + 'id' => 'value', + 'name' => 'value', + 'value' => $this->value, + 'autocomplete' => false, + 'currency' => $field->currency, + 'currencyLabel' => $field->currencyLabel(), + 'showCurrency' => $field->showCurrency, + 'decimals' => $field->subunits(), + 'defaultValue' => $defaultValue, + 'describedBy' => $field->describedBy, + 'field' => $field, + 'showClear' => false, + ]; + } + + /** + * @inheritdoc + */ + protected function elementQueryParam(): ?string + { + return $this->paramValue(); + } + + /** + * @inheritdoc + */ + protected function matchFieldValue($value): bool + { + /** @var int|float|null $value */ + return $this->matchValue($value); + } +}