Skip to content

Commit 19890de

Browse files
Merge pull request #38 from Guiziweb/refactor/symmetric-registries-and-enabled-fields
refactor(schema): symmetric registry interface and tighten filter exposure to LLM
2 parents 46d1040 + ad8a343 commit 19890de

8 files changed

Lines changed: 69 additions & 28 deletions

src/Schema/Builder/FilterSchemaBuilderRegistry.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Guiziweb\SyliusGridAssistantPlugin\Schema\Builder;
66

7-
final class FilterSchemaBuilderRegistry
7+
final class FilterSchemaBuilderRegistry implements FilterSchemaBuilderRegistryInterface
88
{
99
/** @var array<string, FilterSchemaBuilderInterface> */
1010
private array $builders = [];
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Guiziweb\SyliusGridAssistantPlugin\Schema\Builder;
6+
7+
interface FilterSchemaBuilderRegistryInterface
8+
{
9+
public function register(FilterSchemaBuilderInterface $builder): void;
10+
11+
public function has(string $type): bool;
12+
13+
public function get(string $type): FilterSchemaBuilderInterface;
14+
}

src/Schema/GridSchemaBuilder.php

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44

55
namespace Guiziweb\SyliusGridAssistantPlugin\Schema;
66

7-
use Guiziweb\SyliusGridAssistantPlugin\Schema\Builder\FilterSchemaBuilderRegistry;
7+
use Guiziweb\SyliusGridAssistantPlugin\Schema\Builder\FilterSchemaBuilderRegistryInterface;
88
use Guiziweb\SyliusGridAssistantPlugin\Schema\Builder\TranslateLabelTrait;
9-
use Sylius\Component\Grid\Definition\Filter;
109
use Sylius\Component\Grid\Definition\Grid;
1110
use Sylius\Component\Grid\Provider\GridProviderInterface;
1211
use Symfony\Component\DependencyInjection\Attribute\Autowire;
@@ -23,7 +22,7 @@
2322
public function __construct(
2423
#[Autowire(service: 'sylius.grid.chain_provider')]
2524
private GridProviderInterface $gridProvider,
26-
private FilterSchemaBuilderRegistry $filterSchemaBuilderRegistry,
25+
private FilterSchemaBuilderRegistryInterface $filterSchemaBuilderRegistry,
2726
private TranslatorInterface $translator,
2827
) {
2928
}
@@ -64,24 +63,15 @@ private function buildFiltersSchema(Grid $grid): array
6463
continue;
6564
}
6665

67-
$filters[$name] = $this->buildFilterSchema($filter);
68-
}
69-
70-
return $filters;
71-
}
72-
73-
/**
74-
* @return array<string, mixed>
75-
*/
76-
private function buildFilterSchema(Filter $filter): array
77-
{
78-
$type = $filter->getType();
66+
$type = $filter->getType();
67+
if (!$this->filterSchemaBuilderRegistry->has($type)) {
68+
continue;
69+
}
7970

80-
if (!$this->filterSchemaBuilderRegistry->has($type)) {
81-
return [];
71+
$filters[$name] = $this->filterSchemaBuilderRegistry->get($type)->build($filter);
8272
}
8373

84-
return $this->filterSchemaBuilderRegistry->get($type)->build($filter);
74+
return $filters;
8575
}
8676

8777
/**

src/Validator/GridCriteriaValidator.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ public function validate(array $rawCriteria, Grid $grid): array
3434
$filter = $grid->getFilter($filterName);
3535
$filterType = $filter->getType();
3636

37-
if ($this->formatterRegistry->has($filterType)) {
38-
$formatted = $this->formatterRegistry->get($filterType)->format($value, $filter)->value;
39-
} else {
40-
$formatted = $value;
37+
if (!$this->formatterRegistry->has($filterType)) {
38+
$this->aiLogger->warning('[GridAssistant] No formatter registered for filter type, skipping', ['filter' => $filterName, 'type' => $filterType]);
39+
40+
continue;
4141
}
4242

43+
$formatted = $this->formatterRegistry->get($filterType)->format($value, $filter)->value;
44+
4345
if (null !== $formatted) {
4446
$valid[$filterName] = $formatted;
4547
}

src/Validator/GridSortingValidator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function __construct(
1717
public function validate(array $rawSorting, Grid $grid): array
1818
{
1919
$sortableFields = [];
20-
foreach ($grid->getFields() as $field) {
20+
foreach ($grid->getEnabledFields() as $field) {
2121
if ($field->isSortable()) {
2222
$sortableFields[] = $field->getName();
2323
}

tests/Unit/Schema/GridSchemaBuilderTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ public function testFiltersWithAiSearchableFalseAreExcluded(): void
3030
self::assertArrayNotHasKey('internal_notes', $schema['filters']);
3131
}
3232

33+
public function testFiltersWithoutRegisteredSchemaBuilderAreExcluded(): void
34+
{
35+
$grid = $this->makeGrid();
36+
$grid->addFilter($this->makeFilter('date', 'date'));
37+
$grid->addFilter($this->makeFilter('legacy', 'custom_unknown'));
38+
39+
$schema = $this->makeBuilder($grid)->buildSchema('any');
40+
41+
self::assertArrayHasKey('date', $schema['filters']);
42+
self::assertArrayNotHasKey('legacy', $schema['filters']);
43+
}
44+
3345
public function testSortableFieldsWithAiSearchableFalseAreExcluded(): void
3446
{
3547
$grid = $this->makeGrid();

tests/Unit/Validator/GridCriteriaValidatorTest.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,19 @@ public function testSkipsUnknownFilterAndLogsWarning(): void
4040
self::assertSame([], $validator->validate(['unknown' => 'value'], $grid));
4141
}
4242

43-
public function testPassesValueThroughWhenNoFormatterRegistered(): void
43+
public function testSkipsValueWhenNoFormatterRegisteredAndLogsWarning(): void
4444
{
4545
$grid = $this->makeGrid();
46-
$grid->addFilter(Filter::fromNameAndType('state', 'select'));
46+
$grid->addFilter(Filter::fromNameAndType('state', 'custom_unknown'));
4747

48-
$validator = new GridCriteriaValidator($this->emptyRegistry(), $this->createMock(LoggerInterface::class));
48+
$logger = $this->createMock(LoggerInterface::class);
49+
$logger->expects(self::once())
50+
->method('warning')
51+
->with('[GridAssistant] No formatter registered for filter type, skipping', ['filter' => 'state', 'type' => 'custom_unknown']);
52+
53+
$validator = new GridCriteriaValidator($this->emptyRegistry(), $logger);
4954

50-
self::assertSame(['state' => 'new'], $validator->validate(['state' => 'new'], $grid));
55+
self::assertSame([], $validator->validate(['state' => 'attacker-controlled'], $grid));
5156
}
5257

5358
public function testAppliesFormatterWhenRegistered(): void

tests/Unit/Validator/GridSortingValidatorTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,24 @@ public function testInvalidDirectionIsSkippedAndLogged(): void
104104
);
105105
}
106106

107+
public function testIgnoresDisabledField(): void
108+
{
109+
$logger = $this->createMock(LoggerInterface::class);
110+
$logger->expects(self::once())
111+
->method('warning')
112+
->with('[GridAssistant] Unknown sortable field skipped', ['field' => 'total']);
113+
114+
$grid = Grid::fromCodeAndDriverConfiguration('test_grid', 'doctrine/orm', []);
115+
$field = Field::fromNameAndType('total', 'string');
116+
$field->setSortable('total');
117+
$field->setEnabled(false);
118+
$grid->addField($field);
119+
120+
$validator = new GridSortingValidator($logger);
121+
122+
self::assertSame([], $validator->validate(['total' => 'asc'], $grid));
123+
}
124+
107125
private function gridWithSortableField(string $name): Grid
108126
{
109127
$grid = Grid::fromCodeAndDriverConfiguration('test_grid', 'doctrine/orm', []);

0 commit comments

Comments
 (0)