ConditionFactory::create()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5.0073

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 14
c 1
b 0
f 0
nc 5
nop 3
dl 0
loc 26
ccs 14
cts 15
cp 0.9333
crap 5.0073
rs 9.4888
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Atlance\HttpDbalFilter\Query\Expression;
6
7
use Atlance\HttpDbalFilter\Utils\CacheKeyGenerator;
8
use Doctrine\DBAL\Query\QueryBuilder;
9
use Psr\SimpleCache\CacheInterface;
10
11
final class ConditionFactory implements Contract\ConditionFactoryInterface
12
{
13
    private const CACHE_KEY = 'http_dbal_filter_condition';
14
15 75
    public function __construct(private readonly ?CacheInterface $cache = null)
16
    {
17 75
    }
18
19 73
    public function create(QueryBuilder $qb, string $tableAliasAndColumnName, string $expr): Condition
20
    {
21 73
        [$cacheKey,] = CacheKeyGenerator::generate(self::CACHE_KEY, $tableAliasAndColumnName, ['expr' => $expr]);
22
        /** @var Condition|null $condition */
23 73
        $condition = $this->cache?->get($cacheKey);
24
25 73
        if ($condition instanceof Condition) {
26
            return $condition;
27
        }
28
29 73
        foreach ($this->getTableAliases($qb) as $tableName => $alias) {
30 73
            if (0 === strncasecmp($tableAliasAndColumnName, $alias . '_', mb_strlen($alias . '_'))) {
31 72
                $columnName = mb_substr($tableAliasAndColumnName, mb_strlen($alias . '_'));
32 72
                $columns = $this->getColumnsNamesByTable($qb, $tableName);
33 72
                if (!\in_array($columnName, $columns, true)) {
34 1
                    throw new \InvalidArgumentException(sprintf('%s not exist in %s.', $columnName, $tableName));
35
                }
36
37 71
                $condition = new Condition($expr, $alias, $columnName);
38 71
                $this->cache?->set($cacheKey, $condition);
39
40 71
                return $condition;
41
            }
42
        }
43
44 1
        throw new \InvalidArgumentException($tableAliasAndColumnName . ' not allowed');
45
    }
46
47
    /**
48
     * @return array<string,string>
49
     */
50 73
    private function getTableAliases(QueryBuilder $qb): array
51
    {
52 73
        $aliases = [];
53
54
        /** @var array<int,array{alias:string,table:string}> $from */
55 73
        $from = $qb->getQueryPart('from');
56 73
        foreach ($from as $item) {
57 73
            if (!\in_array($item['alias'], $aliases, true)) {
58 73
                $aliases[$item['table']] = $item['alias'];
59
            }
60
        }
61
62
        /** @var array<int,array<int,array{joinTable:string,joinAlias:string}>> $joins */
63 73
        $joins = $qb->getQueryPart('join');
64 73
        foreach ($joins as $items) {
65 73
            foreach ($items as $item) {
66 73
                $aliases[$item['joinTable']] = $item['joinAlias'];
67
            }
68
        }
69
70 73
        return $aliases;
71
    }
72
73 72
    private function getColumnsNamesByTable(QueryBuilder $qb, string $tableName): array
74
    {
75 72
        return array_keys($qb->getConnection()->getSchemaManager()->listTableColumns($tableName));
76
    }
77
}
78