Skip to content

Commit 8fe1b3f

Browse files
[Recommendation] #1399868 - Add gally recommendation
1 parent e035ca3 commit 8fe1b3f

24 files changed

Lines changed: 773 additions & 10 deletions

File tree

src/Command/StructureSync.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class StructureSync extends Command
3535
'catalog' => 'syncAllLocalizedCatalogs',
3636
'sourceField' => 'syncAllSourceFields',
3737
'sourceFieldOption' => 'syncAllSourceFieldOptions',
38+
'recommenderType' => 'syncAllRecommenderTypes',
3839
];
3940

4041
/**

src/Form/Extension/ChannelTypeExtension.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,21 @@
1515
namespace Gally\SyliusPlugin\Form\Extension;
1616

1717
use Sylius\Bundle\ChannelBundle\Form\Type\ChannelType;
18+
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
19+
use Sylius\Component\Resource\Repository\RepositoryInterface;
1820
use Symfony\Component\Form\AbstractTypeExtension;
1921
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
22+
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
2023
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
2124
use Symfony\Component\Form\FormBuilderInterface;
2225

2326
final class ChannelTypeExtension extends AbstractTypeExtension
2427
{
28+
public function __construct(
29+
private RepositoryInterface $productAssociationTypeRepository,
30+
) {
31+
}
32+
2533
public function buildForm(FormBuilderInterface $builder, array $options): void
2634
{
2735
$builder
@@ -66,11 +74,43 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
6674
'attr' => [
6775
'min' => 0,
6876
],
77+
])
78+
->add('gallyProductRecommendationMaxSize', IntegerType::class, [
79+
'label' => 'gally_sylius.form.product_recommendation_max_size',
80+
'attr' => [
81+
'min' => 0,
82+
],
83+
])
84+
->add('gallyCartRecommendationTypeCode', ChoiceType::class, [
85+
'label' => 'gally_sylius.form.cart_recommendation_type',
86+
'choices' => $this->getProductAssociationTypeChoices(),
87+
'required' => false,
88+
'placeholder' => 'gally_sylius.form.cart_recommendation_type_none',
89+
])
90+
->add('gallyCartRecommendationMaxSize', IntegerType::class, [
91+
'label' => 'gally_sylius.form.cart_recommendation_max_size',
92+
'attr' => [
93+
'min' => 0,
94+
],
6995
]);
7096
}
7197

7298
public static function getExtendedTypes(): iterable
7399
{
74100
return [ChannelType::class];
75101
}
102+
103+
/**
104+
* @return array<string, string>
105+
*/
106+
private function getProductAssociationTypeChoices(): array
107+
{
108+
$choices = [];
109+
/** @var ProductAssociationTypeInterface $productAssociationType */
110+
foreach ($this->productAssociationTypeRepository->findAll() as $productAssociationType) {
111+
$choices[(string) $productAssociationType->getName()] = (string) $productAssociationType->getCode();
112+
}
113+
114+
return $choices;
115+
}
76116
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/**
3+
* DISCLAIMER
4+
*
5+
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
6+
*
7+
* @package Gally
8+
* @author Stephan Hochdörfer <S.Hochdoerfer@bitexpert.de>, Gally Team <elasticsuite@smile.fr>
9+
* @copyright 2022-present Smile
10+
* @license Open Software License v. 3.0 (OSL-3.0)
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Gally\SyliusPlugin\Indexer\Provider;
16+
17+
use Gally\Sdk\Entity\RecommenderType;
18+
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
19+
use Sylius\Component\Resource\Repository\RepositoryInterface;
20+
21+
/**
22+
* Gally recommender type data provider, built from Sylius product association types.
23+
*/
24+
class RecommenderTypeProvider implements ProviderInterface
25+
{
26+
public function __construct(
27+
private RepositoryInterface $productAssociationTypeRepository,
28+
) {
29+
}
30+
31+
/**
32+
* @return iterable<RecommenderType>
33+
*/
34+
public function provide(): iterable
35+
{
36+
/** @var ProductAssociationTypeInterface $productAssociationType */
37+
foreach ($this->productAssociationTypeRepository->findAll() as $productAssociationType) {
38+
yield $this->buildRecommenderType($productAssociationType);
39+
}
40+
}
41+
42+
public function buildRecommenderType(ProductAssociationTypeInterface $productAssociationType): RecommenderType
43+
{
44+
return new RecommenderType(
45+
(string) $productAssociationType->getName(),
46+
(string) $productAssociationType->getCode(),
47+
);
48+
}
49+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/**
3+
* DISCLAIMER
4+
*
5+
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
6+
*
7+
* @package Gally
8+
* @author Stephan Hochdörfer <S.Hochdoerfer@bitexpert.de>, Gally Team <elasticsuite@smile.fr>
9+
* @copyright 2022-present Smile
10+
* @license Open Software License v. 3.0 (OSL-3.0)
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Gally\SyliusPlugin\Indexer\Subscriber;
16+
17+
use Gally\Sdk\Service\StructureSynchonizer;
18+
use Gally\SyliusPlugin\Indexer\Provider\RecommenderTypeProvider;
19+
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
20+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
21+
use Symfony\Component\EventDispatcher\GenericEvent;
22+
23+
final class ProductAssociationTypeSubscriber implements EventSubscriberInterface
24+
{
25+
public function __construct(
26+
private RecommenderTypeProvider $recommenderTypeProvider,
27+
private StructureSynchonizer $structureSynchonizer,
28+
) {
29+
}
30+
31+
public static function getSubscribedEvents(): array
32+
{
33+
return [
34+
'sylius.product_association_type.post_create' => 'onProductAssociationTypeUpdate',
35+
'sylius.product_association_type.post_update' => 'onProductAssociationTypeUpdate',
36+
];
37+
}
38+
39+
public function onProductAssociationTypeUpdate(GenericEvent $event): void
40+
{
41+
$productAssociationType = $event->getSubject();
42+
if (!$productAssociationType instanceof ProductAssociationTypeInterface) {
43+
return;
44+
}
45+
46+
$recommenderType = $this->recommenderTypeProvider->buildRecommenderType($productAssociationType);
47+
$this->structureSynchonizer->syncRecommenderType($recommenderType);
48+
}
49+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
/**
3+
* DISCLAIMER
4+
*
5+
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
6+
*
7+
* @package Gally
8+
* @author Stephan Hochdörfer <S.Hochdoerfer@bitexpert.de>, Gally Team <elasticsuite@smile.fr>
9+
* @copyright 2022-present Smile
10+
* @license Open Software License v. 3.0 (OSL-3.0)
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Gally\SyliusPlugin\Migrations;
16+
17+
use Doctrine\DBAL\Schema\Schema;
18+
use Doctrine\Migrations\AbstractMigration;
19+
20+
final class Version20260709120000 extends AbstractMigration
21+
{
22+
public function getDescription(): string
23+
{
24+
return "Add recommendation configuration columns in 'sylius_channel' table.";
25+
}
26+
27+
public function up(Schema $schema): void
28+
{
29+
$this->addSql('ALTER TABLE sylius_channel ADD gally_product_recommendation_max_size INT DEFAULT 4 NOT NULL, ADD gally_cart_recommendation_type_code VARCHAR(255) DEFAULT NULL, ADD gally_cart_recommendation_max_size INT DEFAULT 4 NOT NULL');
30+
}
31+
32+
public function down(Schema $schema): void
33+
{
34+
$this->addSql('ALTER TABLE sylius_channel DROP gally_product_recommendation_max_size, DROP gally_cart_recommendation_type_code, DROP gally_cart_recommendation_max_size');
35+
}
36+
}

src/Model/GallyChannelInterface.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,16 @@ public function setGallyUidCookieLifetime(int $gallyUidCookieLifetime): void;
5757
public function getGallyVidCookieLifetime(): int;
5858

5959
public function setGallyVidCookieLifetime(int $gallyVidCookieLifetime): void;
60+
61+
public function getGallyProductRecommendationMaxSize(): int;
62+
63+
public function setGallyProductRecommendationMaxSize(int $gallyProductRecommendationMaxSize): void;
64+
65+
public function getGallyCartRecommendationTypeCode(): ?string;
66+
67+
public function setGallyCartRecommendationTypeCode(?string $gallyCartRecommendationTypeCode): void;
68+
69+
public function getGallyCartRecommendationMaxSize(): int;
70+
71+
public function setGallyCartRecommendationMaxSize(int $gallyCartRecommendationMaxSize): void;
6072
}

src/Model/GallyChannelTrait.php

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,43 @@
2020
trait GallyChannelTrait
2121
{
2222
#[ORM\Column(name: 'gally_active', type: 'boolean', options: ['default' => false])]
23-
protected $gallyActive = false;
23+
protected bool $gallyActive = false;
2424

2525
#[ORM\Column(name: 'gally_product_index_batch_size', type: 'integer', options: ['default' => 50])]
26-
protected $gallyProductIndexBatchSize = 50;
26+
protected int $gallyProductIndexBatchSize = 50;
2727

2828
#[ORM\Column(name: 'gally_category_index_batch_size', type: 'integer', options: ['default' => 50])]
29-
protected $gallyCategoryIndexBatchSize = 50;
29+
protected int $gallyCategoryIndexBatchSize = 50;
3030

3131
#[ORM\Column(name: 'gally_autocomplete_product_max_size', type: 'integer', options: ['default' => 6])]
32-
protected $gallyAutocompleteProductMaxSize = 6;
32+
protected int $gallyAutocompleteProductMaxSize = 6;
3333

3434
#[ORM\Column(name: 'gally_autocomplete_category_max_size', type: 'integer', options: ['default' => 6])]
35-
protected $gallyAutocompleteCategoryMaxSize = 6;
35+
protected int $gallyAutocompleteCategoryMaxSize = 6;
3636

3737
#[ORM\Column(name: 'gally_autocomplete_attribute_max_size', type: 'integer', options: ['default' => 6])]
38-
protected $gallyAutocompleteAttributeMaxSize = 6;
38+
protected int $gallyAutocompleteAttributeMaxSize = 6;
3939

4040
#[ORM\Column(name: 'gally_tracking_active', type: 'boolean', options: ['default' => true])]
41-
protected $gallyTrackingActive = true;
41+
protected bool $gallyTrackingActive = true;
4242

4343
#[ORM\Column(name: 'gally_use_sylius_endpoint_tracking', type: 'boolean', options: ['default' => true])]
44-
protected $gallyUseSyliusEndpointTracking = true;
44+
protected bool $gallyUseSyliusEndpointTracking = true;
4545

4646
#[ORM\Column(name: 'gally_uid_cookie_lifetime', type: 'integer', options: ['default' => 3600])]
47-
protected $gallyUidCookieLifetime = 3600;
47+
protected int $gallyUidCookieLifetime = 3600;
4848

4949
#[ORM\Column(name: 'gally_vid_cookie_lifetime', type: 'integer', options: ['default' => 31536000])]
50-
protected $gallyVidCookieLifetime = 31536000;
50+
protected int $gallyVidCookieLifetime = 31536000;
51+
52+
#[ORM\Column(name: 'gally_product_recommendation_max_size', type: 'integer', options: ['default' => 4])]
53+
protected int $gallyProductRecommendationMaxSize = 4;
54+
55+
#[ORM\Column(name: 'gally_cart_recommendation_type_code', type: 'string', nullable: true)]
56+
protected ?string $gallyCartRecommendationTypeCode = null;
57+
58+
#[ORM\Column(name: 'gally_cart_recommendation_max_size', type: 'integer', options: ['default' => 4])]
59+
protected int $gallyCartRecommendationMaxSize = 4;
5160

5261
public function getGallyActive(): bool
5362
{
@@ -148,4 +157,34 @@ public function setGallyVidCookieLifetime(int $gallyVidCookieLifetime): void
148157
{
149158
$this->gallyVidCookieLifetime = $gallyVidCookieLifetime;
150159
}
160+
161+
public function getGallyProductRecommendationMaxSize(): int
162+
{
163+
return $this->gallyProductRecommendationMaxSize;
164+
}
165+
166+
public function setGallyProductRecommendationMaxSize(int $gallyProductRecommendationMaxSize): void
167+
{
168+
$this->gallyProductRecommendationMaxSize = $gallyProductRecommendationMaxSize;
169+
}
170+
171+
public function getGallyCartRecommendationTypeCode(): ?string
172+
{
173+
return $this->gallyCartRecommendationTypeCode;
174+
}
175+
176+
public function setGallyCartRecommendationTypeCode(?string $gallyCartRecommendationTypeCode): void
177+
{
178+
$this->gallyCartRecommendationTypeCode = $gallyCartRecommendationTypeCode;
179+
}
180+
181+
public function getGallyCartRecommendationMaxSize(): int
182+
{
183+
return $this->gallyCartRecommendationMaxSize;
184+
}
185+
186+
public function setGallyCartRecommendationMaxSize(int $gallyCartRecommendationMaxSize): void
187+
{
188+
$this->gallyCartRecommendationMaxSize = $gallyCartRecommendationMaxSize;
189+
}
151190
}

0 commit comments

Comments
 (0)