Skip to content

Commit 8b2e417

Browse files
committed
Conditions refactored
1 parent 98f7569 commit 8b2e417

File tree

9 files changed

+269
-6
lines changed

9 files changed

+269
-6
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace App\Discounts\Step;
5+
6+
use App\Discounts\Condition\IsAccountAnniversary;
7+
use Ibexa\Contracts\Discounts\Event\CreateFormDataEvent;
8+
use Ibexa\Contracts\Discounts\Event\MapDiscountToFormDataEvent;
9+
use Ibexa\Contracts\Discounts\Value\DiscountType;
10+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
11+
use Symfony\Contracts\EventDispatcher\Event;
12+
13+
final class AnniversaryConditionStepEventSubscriber implements EventSubscriberInterface
14+
{
15+
public static function getSubscribedEvents(): array
16+
{
17+
return [
18+
CreateFormDataEvent::class => 'addAnniversaryConditionStep',
19+
MapDiscountToFormDataEvent::class => 'addAnniversaryConditionStep',
20+
];
21+
}
22+
23+
/**
24+
* @param \Ibexa\Contracts\Discounts\Event\CreateFormDataEvent|\Ibexa\Contracts\Discounts\Event\MapDiscountToFormDataEvent $event
25+
*/
26+
public function addAnniversaryConditionStep(Event $event): void
27+
{
28+
$data = $event->getData();
29+
if ($data->getType() !== DiscountType::CART) {
30+
return;
31+
}
32+
33+
/** @var \App\Discounts\Condition\IsAccountAnniversary $discount */
34+
$discount = $event instanceof MapDiscountToFormDataEvent ?
35+
$event->getDiscount()->getConditionByIdentifier(IsAccountAnniversary::IDENTIFIER) :
36+
null;
37+
38+
$conditionStep = $discount !== null ?
39+
new AnniversaryConditionStep(true, $discount->getTolerance()) :
40+
new AnniversaryConditionStep();
41+
42+
$event->setData(
43+
$event->getData()->withStep(
44+
$conditionStep,
45+
AnniversaryConditionStep::IDENTIFIER,
46+
'Anniversary Condition',
47+
-45 // Priority
48+
)
49+
);
50+
}
51+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace App\Form\Data;
4+
5+
use Ibexa\Contracts\Discounts\Admin\Form\Data\AbstractDiscountValue;
6+
7+
final class PurchasingPowerParityValue extends AbstractDiscountValue
8+
{
9+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace App\Form\FormMapper;
4+
5+
use App\Form\Data\PurchasingPowerParityValue;
6+
use App\Form\Type\DiscountValue\PurchasingPowerParityValueType;
7+
use Ibexa\Contracts\Discounts\Admin\Form\Data\DiscountValueInterface;
8+
use Ibexa\Contracts\Discounts\Admin\Form\DiscountValueFormTypeMapperInterface;
9+
10+
final class PurchasingPowerParityDiscountValueFormTypeMapper implements DiscountValueFormTypeMapperInterface
11+
{
12+
public function hasFormTypeForData(DiscountValueInterface $data): bool
13+
{
14+
return $data instanceof PurchasingPowerParityValue;
15+
}
16+
17+
public function getFormTypeForData(DiscountValueInterface $data): ?string
18+
{
19+
return $data instanceof PurchasingPowerParityValue ? PurchasingPowerParityValueType::class : null;
20+
}
21+
22+
public function getFormTypeOptionsForData(DiscountValueInterface $data): array
23+
{
24+
return [];
25+
}
26+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace App\Form\FormMapper;
4+
5+
use App\Discounts\Rule\PurchasingPowerParityRule;
6+
use Ibexa\Bundle\Discounts\Form\FormMapper\AbstractFormMapper;
7+
use JMS\TranslationBundle\Model\Message;
8+
use JMS\TranslationBundle\Translation\TranslationContainerInterface;
9+
10+
final class PurchasingPowerParityFormMapper extends AbstractFormMapper implements TranslationContainerInterface
11+
{
12+
public function getDiscountRuleTypes(?string $type): array
13+
{
14+
return [PurchasingPowerParityRule::TYPE];
15+
}
16+
17+
public function supports(string $type, string $ruleType): bool
18+
{
19+
return $ruleType === PurchasingPowerParityRule::TYPE;
20+
}
21+
22+
public static function getTranslationMessages(): array
23+
{
24+
return [
25+
Message::create(
26+
sprintf('%s.%s', self::TRANSLATION_PREFIX, PurchasingPowerParityRule::TYPE),
27+
'ibexa_discounts',
28+
)->setDesc('Regional'),
29+
];
30+
}
31+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace App\Form\FormMapper;
4+
5+
use App\Discounts\Rule\PurchasingPowerParityRule;
6+
use App\Form\Data\PurchasingPowerParityValue;
7+
use Ibexa\Contracts\Discounts\Admin\Form\Data\DiscountValueInterface;
8+
use Ibexa\Contracts\Discounts\Admin\FormMapper\DiscountValueMapperInterface;
9+
use Ibexa\Contracts\Discounts\Value\DiscountInterface;
10+
use Ibexa\Contracts\Discounts\Value\Struct\DiscountCreateStruct;
11+
use Ibexa\Contracts\Discounts\Value\Struct\DiscountUpdateStruct;
12+
use LogicException;
13+
14+
final class PurchasingPowerParityValueMapper implements DiscountValueMapperInterface
15+
{
16+
public function createFormData(string $type, string $ruleType): DiscountValueInterface
17+
{
18+
if ($ruleType !== PurchasingPowerParityRule::TYPE) {
19+
throw new LogicException('Not implemented');
20+
}
21+
22+
return new PurchasingPowerParityValue();
23+
}
24+
25+
public function mapDiscountToFormData(DiscountInterface $discount): DiscountValueInterface
26+
{
27+
$discountRule = $discount->getRule();
28+
if (!$discountRule instanceof PurchasingPowerParityRule) {
29+
throw new LogicException('Not implemented');
30+
}
31+
32+
return new PurchasingPowerParityValue();
33+
}
34+
35+
public function mapCreateDataToStruct(
36+
DiscountValueInterface $data,
37+
DiscountCreateStruct $struct
38+
): void {
39+
$this->addRuleToStruct($data, $struct);
40+
}
41+
42+
public function mapUpdateDataToStruct(
43+
DiscountInterface $discount,
44+
DiscountValueInterface $data,
45+
DiscountUpdateStruct $struct
46+
): void {
47+
$this->addRuleToStruct($data, $struct);
48+
}
49+
50+
/**
51+
* @param \Ibexa\Contracts\Discounts\Value\Struct\DiscountCreateStruct|\Ibexa\Contracts\Discounts\Value\Struct\DiscountUpdateStruct $struct
52+
*/
53+
private function addRuleToStruct(DiscountValueInterface $data, $struct): void
54+
{
55+
if (!$data instanceof PurchasingPowerParityValue) {
56+
throw new LogicException('Not implemented');
57+
}
58+
59+
$rule = new PurchasingPowerParityRule();
60+
$struct->setRule($rule);
61+
}
62+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace App\Form\Type\DiscountValue;
5+
6+
use App\Form\Data\PurchasingPowerParityValue;
7+
use Ibexa\Bundle\Discounts\Form\Type\DiscountValueType;
8+
use Ibexa\Contracts\ProductCatalog\Values\RegionInterface;
9+
use Symfony\Component\Form\AbstractType;
10+
use Symfony\Component\Form\Event\PostSubmitEvent;
11+
use Symfony\Component\Form\Event\PreSetDataEvent;
12+
use Symfony\Component\Form\Extension\Core\Type\FormType;
13+
use Symfony\Component\Form\Extension\Core\Type\TextType;
14+
use Symfony\Component\Form\FormBuilderInterface;
15+
use Symfony\Component\Form\FormEvents;
16+
use Symfony\Component\Form\FormInterface;
17+
use Symfony\Component\OptionsResolver\OptionsResolver;
18+
19+
/**
20+
* @extends \Symfony\Component\Form\AbstractType<\App\Form\Data\PurchasingPowerParityValue>
21+
*/
22+
final class PurchasingPowerParityValueType extends AbstractType
23+
{
24+
public function buildForm(FormBuilderInterface $builder, array $options): void
25+
{
26+
$availableRegionHandler = static function (FormInterface $form, PurchasingPowerParityValue $data): void {
27+
$regions = $data->getDiscountData()->getGeneralProperties()->getRegions();
28+
$regionNames = implode(', ', array_map(static function (RegionInterface $region): string {
29+
return $region->getIdentifier();
30+
}, $regions));
31+
32+
$options = [
33+
'required' => false,
34+
'disabled' => true,
35+
'label' => 'This discount applies to the following regions',
36+
'data' => $regionNames,
37+
];
38+
39+
$form->add('value', TextType::class, $options);
40+
};
41+
42+
$builder->add('type', FormType::class, [
43+
'mapped' => false,
44+
'label' => false,
45+
]);
46+
47+
$builder->addEventListener(
48+
FormEvents::PRE_SET_DATA,
49+
static function (PreSetDataEvent $event) use ($availableRegionHandler): void {
50+
$form = $event->getForm();
51+
$availableRegionHandler($form, $event->getData());
52+
},
53+
);
54+
$builder->get('type')->addEventListener(
55+
FormEvents::POST_SUBMIT,
56+
static function (PostSubmitEvent $event) use ($availableRegionHandler): void {
57+
$form = $event->getForm()->getParent();
58+
assert($form !== null);
59+
$availableRegionHandler($form, $form->getData());
60+
},
61+
);
62+
}
63+
64+
public function getParent(): string
65+
{
66+
return DiscountValueType::class;
67+
}
68+
69+
public function configureOptions(OptionsResolver $resolver): void
70+
{
71+
$resolver->setDefaults([
72+
'data_class' => PurchasingPowerParityValue::class,
73+
]);
74+
}
75+
}

docs/discounts/extend_discounts.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Together with the existing [events](event_reference.md) and the [Discounts PHP A
1818
- Konrad Oboza: [Introduction to the Discounts system in Ibexa DXP](https://www.youtube.com/watch?v=kTgtxY38srw)
1919
- Paweł Niedzielski: [Extending new Discounts to suit your needs](https://www.youtube.com/watch?v=pDJxEKJLwPs)
2020

21-
## Create custom conditions
21+
## Create custom conditions and rules
2222

2323
With custom [conditions](discounts_api.md#conditions) you can create more advanced discounts that apply only in specific scenarios.
2424

@@ -122,7 +122,7 @@ You can now use the condition using the PHP API.
122122

123123
To learn how to integrate it into the back office, see [Extend Discounts wizard](extend_discounts_wizard.md).
124124

125-
## Create custom rules
125+
### Implement custom rules
126126

127127
The following example implements a [purchasing power parity](https://en.wikipedia.org/wiki/Purchasing_power_parity) discount, adjusting product's price in the cart based on buyer's region.
128128
You could use it, for example, in regions sharing the same currency and apply the rule only to them by using the [`IsInRegions` condition](discounts_api.md#conditions).

docs/discounts/extend_discounts_wizard.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ It contains the step identifier, properties for storing form data, and extends t
4949

5050
Then, create a new event listener listening to the [`CreateFormDataEvent` and `MapDiscountToFormDataEvent` events](discounts_events.md#form):
5151

52-
``` php hl_lines="21-22 31-55"
53-
[[= include_file('code_samples/discounts/src/Discounts/Step/AnniversaryConditionStepEventSubscriber.php') =]]
52+
``` php hl_lines="18-19 26-50"
53+
[[= include_file('code_samples/discounts/src/Discounts/Step/Step1/AnniversaryConditionStepEventSubscriber.php') =]]
5454
```
5555

5656
Attaching the `addAnniversaryConditionStep()` method to both these events adds the custom step both in discount creation and edit forms.
@@ -88,14 +88,23 @@ The new form step, including its form fields, are now part of the discounts wiza
8888

8989
The last task is making sure that the form data is correctly saved by attaching it to the discounts API structs.
9090

91-
The previously created `addStepDataToStruct()` method in `AnniversaryConditionStepEventSubscriber` is responsible for it:
91+
Expand the previously created `AnniversaryConditionStepEventSubscriber` to listen to two additional events:
92+
93+
- [`CreateDiscountCreateStructEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Discounts-Event-CreateDiscountCreateStructEvent.html)
94+
- [`CreateDiscountUpdateStructEvent`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Discounts-Event-CreateDiscountUpdateStructEvent.html)
95+
96+
and add the `addStepDataToStruct()` method:
9297

9398
``` php hl_lines="23-24 57-70"
94-
[[= include_file('code_samples/discounts/src/Discounts/Step/AnniversaryConditionStepEventSubscriber.php') =]]
99+
[[= include_file('code_samples/discounts/src/Discounts/Step/Step2/AnniversaryConditionStepEventSubscriber.php') =]]
95100
```
96101

97102
When the form is submitted, this method extracts information whether the store manager enabled the anniversary discount in the form and adds the condition to make sure this data is properly saved.
98103

99104
The custom condition is now integrated with the discounts wizard and can be used by store managers to attract new customers.
100105

101106
## Integrate custom rules
107+
108+
This example continues the [purchasing power parity rule example](extend_discounts.md#implement-custom-rules), integrating the rule with the wizard.
109+
110+

0 commit comments

Comments
 (0)