• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

j-schumann / symfony-addons / 13832069333

13 Mar 2025 10:09AM UTC coverage: 71.761%. Remained the same
13832069333

push

github

j-schumann
upd: dev dependencies
upd: CS

15 of 27 new or added lines in 11 files covered. (55.56%)

432 of 602 relevant lines covered (71.76%)

4.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.68
/src/Filter/ContainsFilter.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Vrok\SymfonyAddons\Filter;
6

7
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
8
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
9
use ApiPlatform\Metadata\Exception\InvalidArgumentException;
10
use ApiPlatform\Metadata\Operation;
11
use Doctrine\ORM\Query\Expr\Join;
12
use Doctrine\ORM\QueryBuilder;
13

14
/**
15
 * @todo extensive tests
16
 *
17
 * Filters entities by their jsonb (Postgres-only) fields, if they contain
18
 * the search parameter, using the @> operator
19
 *
20
 * @see https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSONB-OP-TABLE
21
 */
22
class ContainsFilter extends AbstractFilter
23
{
24
    protected function filterProperty(
25
        string $property,
26
        $value,
27
        QueryBuilder $queryBuilder,
28
        QueryNameGeneratorInterface $queryNameGenerator,
29
        string $resourceClass,
30
        ?Operation $operation = null,
31
        array $context = [],
32
    ): void {
33
        if (
34
            !$this->isPropertyEnabled($property, $resourceClass)
2✔
35
            || !$this->isPropertyMapped($property, $resourceClass)
2✔
36
        ) {
37
            return;
×
38
        }
39

40
        $value = $this->normalizeValue($value, $property);
2✔
41
        if (null === $value) {
2✔
42
            return;
×
43
        }
44

45
        $alias = $queryBuilder->getRootAliases()[0];
2✔
46
        $field = $property;
2✔
47

48
        if ($this->isPropertyNested($property, $resourceClass)) {
2✔
49
            [$alias, $field] = $this->addJoinsForNestedProperty($property, $alias, $queryBuilder, $queryNameGenerator, $resourceClass, Join::LEFT_JOIN);
×
50
        }
51

52
        // @todo very primitive handling of multiple values, is there a better
53
        // way in Postgres, e.g. to give the array directly to the @> operator?
54
        // Also, is it possible to filter for Records that "contain one of" the
55
        // given values instead of "contains all the values"?
56
        foreach ((array) $value as $singleValue) {
2✔
57
            $valueParameter = $queryNameGenerator->generateParameterName($field);
2✔
58

59
            $queryBuilder
2✔
60
                ->andWhere(\sprintf('CONTAINS(%s.%s, :%s) = true', $alias, $field, $valueParameter))
2✔
61
                ->setParameter($valueParameter, $singleValue);
2✔
62
        }
63
    }
64

65
    protected function normalizeValue(mixed $value, string $property): mixed
66
    {
67
        if (null === $value) {
2✔
68
            $this->getLogger()->notice('Invalid filter ignored', [
×
NEW
69
                'exception' => new InvalidArgumentException(\sprintf('A value is required for %1$s', $property)),
×
70
            ]);
×
71

72
            return null;
×
73
        }
74

75
        return $value;
2✔
76
    }
77

78
    public function getDescription(string $resourceClass): array
79
    {
80
        $description = [];
1✔
81

82
        $properties = $this->getProperties();
1✔
83
        if (null === $properties) {
1✔
84
            $properties = array_fill_keys($this->getClassMetadata($resourceClass)->getFieldNames(), null);
×
85
        }
86

87
        foreach (array_keys($properties) as $property) {
1✔
88
            if (!$this->isPropertyMapped($property, $resourceClass)) {
1✔
89
                continue;
×
90
            }
91

92
            $propertyName = $this->normalizePropertyName($property);
1✔
93
            $filterParameterNames = [$propertyName, $propertyName.'[]'];
1✔
94
            foreach ($filterParameterNames as $filterParameterName) {
1✔
95
                $description[$filterParameterName] = [
1✔
96
                    'property' => $propertyName,
1✔
97
                    'type'     => 'mixed',
1✔
98
                    'required' => false,
1✔
99
                ];
1✔
100
            }
101
        }
102

103
        return $description;
1✔
104
    }
105
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc