From eaf5680c878203ed45297d2f03f7a29350cc37ed Mon Sep 17 00:00:00 2001 From: ronlim Date: Fri, 26 Aug 2022 06:56:27 +0800 Subject: [PATCH] Add user condition for matching by user attributes --- CHANGELOG.md | 4 ++ composer.json | 2 +- src/Plugin.php | 2 +- src/behaviors/ProductBehavior.php | 8 +++- src/controllers/ProductLabelsController.php | 1 + src/elements/ProductLabel.php | 40 +++++++++++++++++++ src/elements/db/ProductLabelQuery.php | 1 + ...20825_081136_add_user_condition_column.php | 35 ++++++++++++++++ src/services/ProductLabels.php | 10 ++++- src/templates/productlabels/_edit.twig | 10 +++++ 10 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 src/migrations/m220825_081136_add_user_condition_column.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e225ec..6d0f30c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +## 4.0.5 - 2022-08-26 +### Added +- Add user condition for matching by user attributes + ## 4.0.4 - 2022-05-26 ### Added - Optimise querying product labels for products diff --git a/composer.json b/composer.json index 3d17176..6890ec5 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "thepixelage/craft-productlabels", "description": "Product Labels is a Craft Commerce plugin for creating labels for products", "type": "craft-plugin", - "version": "4.0.4", + "version": "4.0.5", "keywords": [ "craft", "cms", diff --git a/src/Plugin.php b/src/Plugin.php index 726d64e..9723655 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -41,7 +41,7 @@ class Plugin extends \craft\base\Plugin { public static Plugin $plugin; - public string $schemaVersion = '1.0.0'; + public string $schemaVersion = '1.0.1'; /** * @throws Exception diff --git a/src/behaviors/ProductBehavior.php b/src/behaviors/ProductBehavior.php index e56890f..1c95e35 100644 --- a/src/behaviors/ProductBehavior.php +++ b/src/behaviors/ProductBehavior.php @@ -2,6 +2,7 @@ namespace thepixelage\productlabels\behaviors; +use craft\commerce\elements\Product; use thepixelage\productlabels\elements\ProductLabel; use thepixelage\productlabels\Plugin; use yii\base\Behavior; @@ -10,10 +11,13 @@ class ProductBehavior extends Behavior { public function getProductLabels(): array { + /** @var Product $product */ + $product = $this->owner; $productLabels = Plugin::getInstance()->productLabels->getAllProductLabels(); - return array_filter($productLabels, function (ProductLabel $productLabel) { - return in_array($this->owner->id, $productLabel->getMatchedProductIds()); + return array_filter($productLabels, function (ProductLabel $productLabel) use ($product) { + return in_array($product->id, $productLabel->getMatchedProductIds()) && + $productLabel->getMatchCurrentUser(); }); } } diff --git a/src/controllers/ProductLabelsController.php b/src/controllers/ProductLabelsController.php index ef820fa..52ab95c 100644 --- a/src/controllers/ProductLabelsController.php +++ b/src/controllers/ProductLabelsController.php @@ -165,6 +165,7 @@ public function actionSave(): ?Response $productLabel->setFieldValuesFromRequest($this->request->getParam('fieldsLocation', 'fields')); $productLabel->setProductCondition($this->request->getBodyParam('productCondition')); + $productLabel->setUserCondition($this->request->getBodyParam('userCondition')); $dateFromParams = $this->request->getBodyParam('dateFrom'); $dateToParams = $this->request->getBodyParam('dateTo'); diff --git a/src/elements/ProductLabel.php b/src/elements/ProductLabel.php index 90d5cce..933f65d 100644 --- a/src/elements/ProductLabel.php +++ b/src/elements/ProductLabel.php @@ -11,6 +11,7 @@ use craft\elements\actions\Restore; use craft\elements\actions\SetStatus; use craft\elements\conditions\ElementConditionInterface; +use craft\elements\conditions\users\UserCondition; use craft\elements\db\ElementQuery; use craft\elements\db\ElementQueryInterface; use craft\elements\User; @@ -36,7 +37,9 @@ class ProductLabel extends Element public ?DateTime $dateFrom = null; public ?DateTime $dateTo = null; private ElementConditionInterface|null $_productCondition = null; + private ElementConditionInterface|null $_userCondition = null; private array $matchedProductIds = []; + private bool $matchCurrentUser = false; public function __construct($config = []) { @@ -100,6 +103,31 @@ public function setProductCondition(ElementConditionInterface|string|array|null $this->_productCondition = $condition; } + public function getUserCondition(): ElementConditionInterface + { + $condition = $this->_userCondition ?? new UserCondition(); + $condition->mainTag = 'div'; + $condition->name = 'userCondition'; + + return $condition; + } + + /** + * @throws InvalidConfigException + */ + public function setUserCondition(ElementConditionInterface|string|array|null $condition): void + { + if (is_string($condition)) { + $condition = Json::decodeIfJson($condition); + } + + $condition['class'] = UserCondition::class; + $condition = Craft::$app->getConditions()->createCondition($condition); + $condition->forProjectConfig = false; + + $this->_userCondition = $condition; + } + public function getMatchedProductIds(): array { return $this->matchedProductIds; @@ -110,6 +138,16 @@ public function setMatchedProductIds($ids) $this->matchedProductIds = $ids; } + public function getMatchCurrentUser(): bool + { + return $this->matchCurrentUser; + } + + public function setMatchCurrentUser($match) + { + $this->matchCurrentUser = $match; + } + public static function find(): ElementQueryInterface { return new ProductLabelQuery(static::class); @@ -287,6 +325,7 @@ public function afterSave(bool $isNew): void ->insert('{{%productlabels}}', [ 'id' => $this->id, 'productCondition' => Json::encode($this->getProductCondition()->getConfig()), + 'userCondition' => Json::encode($this->getUserCondition()->getConfig()), 'dateFrom' => $this->dateFrom ? $this->dateFrom->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s') : null, 'dateTo' => $this->dateTo ? $this->dateTo->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s') : null, ]) @@ -295,6 +334,7 @@ public function afterSave(bool $isNew): void Craft::$app->db->createCommand() ->update('{{%productlabels}}', [ 'productCondition' => Json::encode($this->getProductCondition()->getConfig()), + 'userCondition' => Json::encode($this->getUserCondition()->getConfig()), 'dateFrom' => $this->dateFrom ? $this->dateFrom->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s') : null, 'dateTo' => $this->dateTo ? $this->dateTo->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s') : null, ], ['id' => $this->id]) diff --git a/src/elements/db/ProductLabelQuery.php b/src/elements/db/ProductLabelQuery.php index d52609b..ef31fad 100644 --- a/src/elements/db/ProductLabelQuery.php +++ b/src/elements/db/ProductLabelQuery.php @@ -26,6 +26,7 @@ protected function beforePrepare(): bool $this->joinElementTable($productLabelsTableName); $this->query->select([ sprintf('%s.productCondition', $productLabelsTableName), + sprintf('%s.userCondition', $productLabelsTableName), sprintf('%s.dateFrom', $productLabelsTableName), sprintf('%s.dateTo', $productLabelsTableName), ]); diff --git a/src/migrations/m220825_081136_add_user_condition_column.php b/src/migrations/m220825_081136_add_user_condition_column.php new file mode 100644 index 0000000..b3aca56 --- /dev/null +++ b/src/migrations/m220825_081136_add_user_condition_column.php @@ -0,0 +1,35 @@ +addColumn(Table::PRODUCTLABELS, + 'userCondition', + $this->text()->after('productCondition')); + + return true; + } + + /** + * @inheritdoc + */ + public function safeDown(): bool + { + $this->dropColumn(Table::PRODUCTLABELS, 'userCondition'); + + return false; + } +} diff --git a/src/services/ProductLabels.php b/src/services/ProductLabels.php index d2176f8..75ceddc 100644 --- a/src/services/ProductLabels.php +++ b/src/services/ProductLabels.php @@ -6,6 +6,7 @@ use craft\base\Component; use craft\base\MemoizableArray; use craft\commerce\elements\Product; +use craft\elements\User; use craft\errors\BusyResourceException; use craft\errors\StaleResourceException; use craft\errors\StructureNotFoundException; @@ -180,6 +181,8 @@ private function _productLabels(): MemoizableArray { if (!isset($this->_productLabels)) { $productLabels = ProductLabel::find()->all(); + $currentUser = Craft::$app->user->id ? User::find()->id(Craft::$app->user->id)->one() : null; + /** @var ProductLabel $productLabel */ foreach ($productLabels as $productLabel) { $productCondition = $productLabel->getProductCondition(); @@ -187,10 +190,15 @@ private function _productLabels(): MemoizableArray foreach ($productCondition->getConditionRules() as $rule) { $query = Product::find(); $productCondition->modifyQuery($query); - $productLabel->setMatchedProductIds($query->ids()); } } + + $userCondition = $productLabel->getUserCondition(); + $productLabel->setMatchCurrentUser( + $userCondition->conditionRules == 0 || + ($currentUser && $userCondition->matchElement($currentUser)) + ); } $this->_productLabels = new MemoizableArray(array_values($productLabels)); diff --git a/src/templates/productlabels/_edit.twig b/src/templates/productlabels/_edit.twig index e3a2146..fe45a11 100644 --- a/src/templates/productlabels/_edit.twig +++ b/src/templates/productlabels/_edit.twig @@ -336,12 +336,22 @@ {{ productLabel.productCondition.getBuilderHtml()|raw }} {% endset %} + {% set userConditionInput %} + {{ productLabel.userCondition.getBuilderHtml()|raw }} + {% endset %} + {{ forms.field({ label: 'Match Product'|t('commerce'), instructions: 'Create rules that allow this product label to match the product. If no rules are added, this product label will match all products.'|t('productlabels'), errors: productLabel.getErrors('productCondition') }, productConditionInput) }} + {{ forms.field({ + label: 'Match User'|t('commerce'), + instructions: 'Create rules that allow this product label to match the user. If no rules are added, this product label will match all users.'|t('productlabels'), + errors: productLabel.getErrors('userCondition') + }, userConditionInput) }} + {% endblock %}