Skip to content

Commit bf5491f

Browse files
authored
Merge pull request #331 from acquia/MAUT-11028
MAUT-11028 : fix segement filter issue in custom object
2 parents b0d76f2 + 065354e commit bf5491f

File tree

6 files changed

+193
-17
lines changed

6 files changed

+193
-17
lines changed

Config/config.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,12 @@
825825
'custom_object.config.provider',
826826
],
827827
],
828+
'custom_object.segments.filters_merge.subscriber' => [
829+
'class' => \MauticPlugin\CustomObjectsBundle\EventListener\SegmentFiltersMergeSubscriber::class,
830+
'arguments' => [
831+
'custom_object.config.provider',
832+
],
833+
],
828834
'custom_object.dynamic_content.subscriber' => [
829835
'class' => \MauticPlugin\CustomObjectsBundle\EventListener\DynamicContentSubscriber::class,
830836
'arguments' => [
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MauticPlugin\CustomObjectsBundle\EventListener;
6+
7+
use Mautic\LeadBundle\Event\LeadListMergeFiltersEvent;
8+
use Mautic\LeadBundle\LeadEvents;
9+
use Mautic\LeadBundle\Segment\ContactSegmentFilterFactory;
10+
use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider;
11+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
12+
13+
class SegmentFiltersMergeSubscriber implements EventSubscriberInterface
14+
{
15+
private ConfigProvider $configProvider;
16+
17+
public function __construct(ConfigProvider $configProvider)
18+
{
19+
$this->configProvider = $configProvider;
20+
}
21+
22+
/**
23+
* @return mixed[]
24+
*/
25+
public static function getSubscribedEvents(): array
26+
{
27+
return [LeadEvents::LIST_FILTERS_MERGE => 'mergeCustomObjectFilters'];
28+
}
29+
30+
public function mergeCustomObjectFilters(LeadListMergeFiltersEvent $event): void
31+
{
32+
if (!$this->configProvider->pluginIsEnabled()) {
33+
return;
34+
}
35+
36+
$filters = $event->getFilters();
37+
38+
$finalMergedFilters = [];
39+
$customFieldArr = [];
40+
$customObjectIndex = null;
41+
foreach ($filters as $index => $filter) {
42+
$glue = $filter['glue'];
43+
if ('or' === strtolower($glue)) {
44+
if (!empty($customFieldArr)) {
45+
$finalMergedFilters = array_merge($finalMergedFilters, $this->groupCustomObject($customFieldArr));
46+
$customObjectIndex = null;
47+
$customFieldArr = [];
48+
}
49+
}
50+
51+
if ('custom_object' !== $filter['object']) {
52+
$finalMergedFilters[] = $filter;
53+
continue;
54+
}
55+
if (!$customObjectIndex) {
56+
$customObjectIndex = $index;
57+
}
58+
$key = implode('_', [$filter['object'], $filter['field'], $filter['glue']]);
59+
$customFieldArr[$key][$index] = $filter;
60+
}
61+
if (!empty($customFieldArr)) {
62+
$finalMergedFilters = array_merge($finalMergedFilters, $this->groupCustomObject($customFieldArr));
63+
}
64+
$event->setFilters($finalMergedFilters);
65+
}
66+
67+
/**
68+
* @param array<mixed> $customObjectFilters
69+
*
70+
* @return array<mixed>
71+
*/
72+
private function groupCustomObject(array $customObjectFilters): array
73+
{
74+
$newGroupedArr = [];
75+
foreach ($customObjectFilters as $customObjects) {
76+
$key = key($customObjects);
77+
$newGroupedArr[$key] = $customObjects[$key];
78+
if (count($customObjects) > 1) {
79+
$newGroupedArr[$key]['operator'] = ContactSegmentFilterFactory::CUSTOM_OPERATOR;
80+
unset($newGroupedArr[$key]['filter']);
81+
$mergedProperty = [];
82+
foreach ($customObjects as $filter) {
83+
$mergedProperty[] = ['operator' => $filter['operator'], 'filter_value' => $filter['properties']['filter']];
84+
$newGroupedArr[$key]['properties'][] = $filter;
85+
}
86+
unset($newGroupedArr[$key]['properties']['filter']);
87+
$newGroupedArr[$key]['merged_property'] = $mergedProperty;
88+
}
89+
}
90+
91+
return $newGroupedArr;
92+
}
93+
}

Helper/QueryFilterHelper.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,24 +96,30 @@ public function addCustomFieldValueExpressionFromSegmentFilter(
9696
ContactSegmentFilter $filter
9797
): void {
9898
foreach ($unionQueryContainer as $segmentQueryBuilder) {
99-
$valueParameter = $this->randomParameterNameService->generateRandomParameterName();
100-
$expression = $this->getCustomValueValueExpression(
101-
$segmentQueryBuilder,
102-
$tableAlias,
103-
$filter->getOperator(),
104-
$valueParameter
105-
);
106-
107-
$this->addOperatorExpression(
108-
$segmentQueryBuilder,
109-
$expression,
110-
$filter->getOperator(),
111-
$filter->getParameterValue(),
112-
$valueParameter
113-
);
99+
if (!empty($filter->contactSegmentFilterCrate->getMergedProperty())) {
100+
foreach ($filter->contactSegmentFilterCrate->getMergedProperty() as $propertyFilter) {
101+
$this->addCustomObjectValueExpression($segmentQueryBuilder, $tableAlias, $propertyFilter['operator'], $propertyFilter['filter_value']);
102+
}
103+
} else {
104+
$this->addCustomObjectValueExpression($segmentQueryBuilder, $tableAlias, $filter->getOperator(), $filter->getParameterValue());
105+
}
114106
}
115107
}
116108

109+
/**
110+
* @param mixed[]|string|int|null $value
111+
*/
112+
public function addCustomObjectValueExpression(
113+
SegmentQueryBuilder $queryBuilder,
114+
string $tableAlias,
115+
string $operator,
116+
$value
117+
): void {
118+
$valueParameter = $this->randomParameterNameService->generateRandomParameterName();
119+
$expression = $this->getCustomValueValueExpression($queryBuilder, $tableAlias, $operator, $valueParameter);
120+
$this->addOperatorExpression($queryBuilder, $expression, $operator, $value, $valueParameter);
121+
}
122+
117123
public function addCustomObjectNameExpression(
118124
SegmentQueryBuilder $queryBuilder,
119125
string $tableAlias,
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MauticPlugin\CustomObjectsBundle\Tests\Functional\Command;
6+
7+
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
8+
use Mautic\LeadBundle\Entity\LeadList;
9+
use MauticPlugin\CustomObjectsBundle\Tests\Functional\DataFixtures\Traits\FixtureObjectsTrait;
10+
use PHPUnit\Framework\Assert;
11+
12+
class SegmentUpdateCommandFunctionalTest extends MauticMysqlTestCase
13+
{
14+
use FixtureObjectsTrait;
15+
16+
public function testMembershipAction(): void
17+
{
18+
$fixturesDirectory = $this->getFixturesDirectory();
19+
$objects = $this->loadFixtureFiles([
20+
$fixturesDirectory.'/leads.yml',
21+
$fixturesDirectory.'/custom_objects.yml',
22+
$fixturesDirectory.'/custom_fields.yml',
23+
$fixturesDirectory.'/custom_items.yml',
24+
$fixturesDirectory.'/custom_xref.yml',
25+
$fixturesDirectory.'/custom_values.yml',
26+
]);
27+
$this->setFixtureObjects($objects);
28+
29+
$custom_field = $this->getFixtureById('custom_field1')->getId();
30+
31+
$filters = [
32+
[
33+
'glue' => 'and',
34+
'object' => 'custom_object',
35+
'type' => 'text',
36+
'field' => 'cmf_'.$custom_field,
37+
'properties' => ['filter' => 'l'],
38+
'operator' => 'startsWith',
39+
],
40+
[
41+
'glue' => 'and',
42+
'object' => 'custom_object',
43+
'type' => 'text',
44+
'field' => 'cmf_'.$custom_field,
45+
'properties' => ['filter' => 'e'],
46+
'operator' => 'endsWith',
47+
],
48+
];
49+
$segment = $this->createSegment($filters);
50+
51+
$applicationTester = $this->testSymfonyCommand('mautic:segments:update', ['-i' => $segment->getId(), '--env' => 'test']);
52+
Assert::assertSame(0, $applicationTester->getStatusCode());
53+
Assert::assertStringContainsString('3 total contact(s) to be added in batches of 300', $applicationTester->getDisplay());
54+
}
55+
56+
/**
57+
* @param mixed[] $filters
58+
*/
59+
private function createSegment(array $filters): LeadList
60+
{
61+
$segment = new LeadList();
62+
$segment->setFilters($filters);
63+
$segment->setName('Segment A');
64+
$segment->setAlias('segment-a');
65+
$this->em->persist($segment);
66+
$this->em->flush();
67+
68+
return $segment;
69+
}
70+
}

Tests/Functional/DataFixtures/Traits/FixtureObjectsTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function getFixturesInUnloadableOrder(): array
9090
$entities = [];
9191

9292
$orderedKeys = $this->entityMap;
93-
array_reverse($orderedKeys, true);
93+
$orderedKeys = array_reverse($orderedKeys, true);
9494
foreach ($orderedKeys as $key => $type) {
9595
$entities[$key] = $this->objects[$type][$key];
9696
}

Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
88
use Mautic\LeadBundle\Segment\ContactSegmentFilter;
9+
use Mautic\LeadBundle\Segment\ContactSegmentFilterCrate;
910
use Mautic\LeadBundle\Segment\Query\QueryBuilder;
1011
use Mautic\LeadBundle\Segment\RandomParameterName;
1112
use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterFactory;
@@ -92,7 +93,7 @@ private function createSegmentFilterMock(
9293
$filterMock = $this->getMockBuilder(ContactSegmentFilter::class)
9394
->disableOriginalConstructor()
9495
->getMock();
95-
96+
$filterMock->contactSegmentFilterCrate = $this->createMock(ContactSegmentFilterCrate::class);
9697
$filterMock->method('getType')->willReturn($type);
9798
$filterMock->method('getOperator')->willReturn($operator);
9899
$filterMock->method('getField')->willReturn((string) $this->getFixtureById($fixtureField)->getId());

0 commit comments

Comments
 (0)