SelectGenerator::generate()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
dl 9
loc 9
c 0
b 0
f 0
rs 9.6666
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
namespace Netdudes\DataSourceryBundle\DataSource\Driver\Doctrine\QueryBuilder;
3
4
use Doctrine\ORM\Query\Expr\Select;
5
use Netdudes\DataSourceryBundle\DataSource\Configuration\Field;
6
use Netdudes\DataSourceryBundle\Query\Query;
7
8
class SelectGenerator
9
{
10
    /**
11
     * @var JoinGenerator
12
     */
13
    private $joinsGenerator;
14
15
    /**
16
     * @var RequiredFieldsExtractor
17
     */
18
    private $requiredFieldsExtractor;
19
20
    /**
21
     * @var Field[]
22
     */
23
    private $queryBuilderDataSourceFields;
24
25
    /**
26
     * @var string
27
     */
28
    private $fromAlias;
29
30
    /**
31
     * @var Select[][]
32
     */
33
    private $selectFieldMapCache = [];
34
35
    /**
36
     * @var Select[]
37
     */
38
    private $selectCache = [];
39
40
    /**
41
     * @param array                   $queryBuilderDataSourceFields
42
     * @param                         $fromAlias
43
     * @param JoinGenerator           $joinsGenerator
44
     * @param RequiredFieldsExtractor $requiredFieldsExtractor
45
     */
46
    public function __construct(array $queryBuilderDataSourceFields, $fromAlias, JoinGenerator $joinsGenerator, RequiredFieldsExtractor $requiredFieldsExtractor)
47
    {
48
        $this->joinsGenerator = $joinsGenerator;
49
        $this->requiredFieldsExtractor = $requiredFieldsExtractor;
50
        $this->queryBuilderDataSourceFields = $queryBuilderDataSourceFields;
51
        $this->fromAlias = $fromAlias;
52
    }
53
54
    /**
55
     * Generates the SELECT part of the DQL (Select object) given a Query.
56
     *
57
     * @param Query $query
58
     *
59
     * @return Select|null
60
     */
61 View Code Duplication
    public function generate(Query $query)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
62
    {
63
        $uniqueId = spl_object_hash($query);
64
        if (!isset($this->selectCache[$uniqueId])) {
65
            $this->selectCache[$uniqueId] = $this->build($query);
66
        }
67
68
        return $this->selectCache[$uniqueId];
69
    }
70
71
    protected function build(Query $query)
72
    {
73
        $selectFieldMap = $this->getSelectFieldMap($query);
74
75
        $selectStatements = [];
76
        foreach ($selectFieldMap as $identifier => $selectField) {
77
            $selectStatements[] = $selectField . ' ' . $identifier;
78
        }
79
80
        if (empty($selectStatements)) {
81
            return new Select();
82
        }
83
84
        return new Select($selectStatements);
85
    }
86
87
    /**
88
     * @param Query $query
89
     *
90
     * @return string[]
91
     */
92 View Code Duplication
    public function getSelectFieldMap(Query $query)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
93
    {
94
        $uniqueId = spl_object_hash($query);
95
        if (!isset($this->selectFieldMapCache[$uniqueId])) {
96
            $this->selectFieldMapCache[$uniqueId] = $this->buildSelectFieldMap($query);
97
        }
98
99
        return $this->selectFieldMapCache[$uniqueId];
100
    }
101
102
    /**
103
     * @param Query $query
104
     *
105
     * @return array
106
     */
107
    public function getUniqueNameToSelectFieldMap(Query $query)
108
    {
109
        $selectFieldMap = $this->getSelectFieldMap($query);
110
        $uniqueNameToSelectFieldMap = [];
111
        foreach ($this->queryBuilderDataSourceFields as $field) {
112
            $alias = $field->getDatabaseSelectAlias();
113
            if (is_array($alias)) {
114
                $alias = str_replace('.', '_', $field->getDatabaseFilterQueryField());
115
            }
116
            if (array_key_exists($alias, $selectFieldMap)) {
117
                $uniqueNameToSelectFieldMap[$field->getUniqueName()] = $selectFieldMap[$alias];
118
            }
119
        }
120
121
        return $uniqueNameToSelectFieldMap;
122
    }
123
124
    /**
125
     * Builds a map relating the database field alias (the alias in the SELECT statement) and the
126
     * actual entity field (as in JOINED_ENTITY.field or FROM_ENTITY.field) in order to use them
127
     * within the WHERE statement.
128
     *
129
     * @param Query $query
130
     *
131
     * @return array
132
     */
133
    protected function buildSelectFieldMap(Query $query)
134
    {
135
        $selectFieldsMap = [];
136
        $requiredFields = $this->requiredFieldsExtractor->extractRequiredFields($query);
137
        $joins = $this->joinsGenerator->generate($query);
138
        foreach ($this->queryBuilderDataSourceFields as $element) {
139
            if (!in_array($element->getUniqueName(), $requiredFields, true)) {
140
                continue;
141
            }
142
            if (is_null($element->getDatabaseFilterQueryField())) {
143
                continue;
144
            }
145
            $fieldIdentifier = $element->getDatabaseSelectAlias();
146
            if (is_array($fieldIdentifier)) {
147
                $fieldIdentifier = str_replace('.', '_', $element->getDatabaseFilterQueryField());
148
            }
149
            $fieldParts = explode('.', $element->getDatabaseFilterQueryField());
150
            if (count($fieldParts) === 1) {
151
                $selectFieldsMap[$fieldIdentifier] = $this->fromAlias . '.' . array_slice($fieldParts, -1, 1)[0];
152
            } else {
153
                $joinField = implode('.', array_slice($fieldParts, 0, -1));
154
                foreach ($joins as $path => $join) {
155
                    if ($path == $joinField) {
156
                        $selectFieldsMap[$fieldIdentifier] = $join->getAlias() . '.' . array_slice($fieldParts, -1, 1)[0];
157
                        break;
158
                    }
159
                }
160
            }
161
        }
162
163
        return $selectFieldsMap;
164
    }
165
}
166