Helper::hydrate()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.0416

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 2
dl 0
loc 9
ccs 5
cts 6
cp 0.8333
crap 3.0416
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Api;
6
7
use Application\Acl\Acl;
8
use Application\Model\AbstractModel;
9
use Doctrine\ORM\QueryBuilder;
10
use Doctrine\ORM\Tools\Pagination\Paginator;
11
use Ecodev\Felix\Api\Exception;
12
use GraphQL\Doctrine\Definition\EntityID;
13
use RuntimeException;
14
15
abstract class Helper
16
{
17 31
    public static function throwIfDenied(AbstractModel $model, string $privilege): void
18
    {
19 31
        $acl = new Acl();
20 31
        if (!$acl->isCurrentUserAllowed($model, $privilege)) {
21 3
            throw new Exception($acl->getLastDenialMessage());
22
        }
23
    }
24
25 6
    public static function paginate(array $pagination, QueryBuilder $query): array
26
    {
27 6
        $offset = max(0, $pagination['offset']);
28 6
        $pageIndex = max(0, $pagination['pageIndex']);
29 6
        $pageSize = max(0, $pagination['pageSize']);
30
31 6
        $paginator = new Paginator($query);
32 6
        $paginator
33 6
            ->getQuery()
34 6
            ->setFirstResult($offset ?: $pageSize * $pageIndex)
35 6
            ->setMaxResults($pageSize);
36
37
        try {
38
            /*
39
             * We try to disable usage of Output Walkers because they leads to
40
             * suboptimal queries. But we can't disable them if the query
41
             * contains to-many(1) joins without disabling "fetchJoinCollection"
42
             * in Paginator too.
43
             *
44
             * Disable "fetchJoinCollection" in Paginator can lead to
45
             * inconsistent results and compromise the flexibility of this helper.
46
             *
47
             * So we try to disable the Output Walkers and if it fails we fallback
48
             * to the default behavior. It will fail at the Doctrine level and
49
             * no query will be executed by the database so it's safe to fallback.
50
             *
51
             * The solution implemented here may not be the cleanest but it's the
52
             * most flexible and evolutive one.
53
             *
54
             * This optimization is very useful when displaying a collection
55
             * because it allows to take advantage of the collection indexes and
56
             * avoid making a full table scan of the card table. Disyplaying an
57
             * empty collection now take ~130ms instead of ~900ms.
58
             *
59
             * (1) queries can contain to-many join when we try to sort cards by
60
             * artists for example.
61
             */
62 6
            $paginator->setUseOutputWalkers(false);
63 6
            $pagination['items'] = $paginator->getIterator();
64 1
        } catch (RuntimeException) {
65 1
            $paginator->setUseOutputWalkers(true);
66 1
            $pagination['items'] = $paginator->getIterator();
67
        }
68 6
        $pagination['length'] = fn () => $paginator->count();
69
70 6
        return $pagination;
71
    }
72
73 12
    public static function hydrate(AbstractModel $object, array $input): void
74
    {
75 12
        foreach ($input as $name => $value) {
76 12
            if ($value instanceof EntityID) {
77
                $value = $value->getEntity();
78
            }
79
80 12
            $setter = 'set' . ucfirst($name);
81 12
            $object->$setter($value);
82
        }
83
    }
84
}
85