Passed
Push — dev_2x ( 1e248d...fedccd )
by Adrian
01:40
created

Aggregate   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 17
eloc 43
c 2
b 0
f 1
dl 0
loc 118
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getQuery() 0 33 2
A attachLazyAggregateToEntity() 0 4 1
A entityMatchesRow() 0 14 5
A getForEntity() 0 9 3
A isEagerLoad() 0 4 2
A isLazyLoad() 0 4 2
A getName() 0 3 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Sirius\Orm\Relation;
5
6
use Sirius\Orm\Contract\EntityInterface;
7
use Sirius\Orm\Contract\HydratorInterface;
8
use Sirius\Orm\Entity\LazyAggregate;
9
use Sirius\Orm\Entity\Tracker;
10
use Sirius\Orm\Query;
11
12
class Aggregate
13
{
14
    /**
15
     * @var string
16
     */
17
    protected $name;
18
19
    /**
20
     * @var Relation
21
     */
22
    protected $relation;
23
24
    /**
25
     * @var array
26
     */
27
    protected $options;
28
29
    /**
30
     * @var HydratorInterface
31
     */
32
    protected $entityHydrator;
33
34
    /**
35
     * @var HydratorInterface
36
     */
37
    protected $foreignEntityHydrator;
38
39
    public function __construct(string $name, Relation $relation, array $options)
40
    {
41
        $this->name           = $name;
42
        $this->relation       = $relation;
43
        $this->options        = $options;
44
        $this->entityHydrator = $relation->getNativeMapper()->getHydrator();
45
    }
46
47
    public function getQuery(Tracker $tracker)
48
    {
49
        $keys = $this->relation->getKeyPairs();
50
51
        /** @var Query $query */
52
        $query = $this->relation->getQuery($tracker);
53
        $query->resetColumns();
54
        $query->columns(...array_values($keys));
55
        $query->columns(sprintf(
56
            '%s as %s',
57
            $this->options[RelationConfig::AGG_FUNCTION],
58
            $this->name
59
        ));
60
61
        $callback = $this->options[RelationConfig::AGG_CALLBACK] ?? null;
62
        if (is_callable($callback)) {
63
            $query = $callback($query);
64
        }
65
66
        $query->groupBy(...array_values($keys));
67
68
        /**
69
         * the query callback for the relation or for the aggregate might implement ORDER_BY
70
         * and that would cause issues with MySQL's sql_mode=ONLY_FULL_GROUP_BY
71
         */
72
        $query->resetOrderBy();
73
74
        /**
75
         * just in case a query callback is setting limits
76
         */
77
        $query->resetLimit();
78
79
        return $query;
80
    }
81
82
    public function attachLazyAggregateToEntity(EntityInterface $entity, Tracker $tracker)
83
    {
84
        $valueLoader = $tracker->getLazyAggregate($this);
85
        $this->entityHydrator->set($entity, $this->name, $valueLoader);
86
    }
87
88
    public function getForEntity(EntityInterface $entity, array $results)
89
    {
90
        foreach ($results as $row) {
91
            if ($this->entityMatchesRow($entity, $row)) {
92
                return $row[$this->name] ?? null;
93
            }
94
        }
95
96
        return null;
97
    }
98
99
    public function isLazyLoad()
100
    {
101
        return ! isset($this->options[RelationConfig::LOAD_STRATEGY]) ||
102
               $this->options[RelationConfig::LOAD_STRATEGY] == RelationConfig::LOAD_LAZY;
103
    }
104
105
    public function isEagerLoad()
106
    {
107
        return isset($this->options[RelationConfig::LOAD_STRATEGY]) &&
108
               $this->options[RelationConfig::LOAD_STRATEGY] == RelationConfig::LOAD_EAGER;
109
    }
110
111
    public function getName()
112
    {
113
        return $this->name;
114
    }
115
116
    private function entityMatchesRow(EntityInterface $entity, $row)
117
    {
118
        $keys = $this->relation->getKeyPairs();
119
        foreach ($keys as $nativeCol => $foreignCol) {
120
            $entityValue = $this->entityHydrator->get($entity, $nativeCol);
121
            $rowValue    = $row[$foreignCol];
122
            // if both native and foreign key values are present (not unlinked entities) they must be the same
123
            // otherwise we assume that the entities can be linked together
124
            if ($entityValue && $rowValue && $entityValue != $rowValue) {
125
                return false;
126
            }
127
        }
128
129
        return true;
130
    }
131
}
132