QueryPartBuilder::buildQueryParts()   A
last analyzed

Complexity

Conditions 6
Paths 9

Size

Total Lines 27
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 9
nop 2
dl 0
loc 27
ccs 14
cts 14
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright 2021 Aleksandar Panic
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
namespace ArekX\PQL\Drivers\Pdo\MySql\Builders;
19
20
use ArekX\PQL\Contracts\QueryBuilder;
21
use ArekX\PQL\Contracts\QueryBuilderState;
22
use ArekX\PQL\Contracts\RawQuery;
23
use ArekX\PQL\Contracts\StructuredQuery;
24
use ArekX\PQL\Drivers\Pdo\MySql\MySqlQueryBuilderState;
25
use ArekX\PQL\RawQueryResult;
26
use Exception;
27
28
/**
29
 * Represents a base builder for query parts.
30
 */
31
abstract class QueryPartBuilder implements QueryBuilder
32
{
33
    /**
34
     * @inheritDoc
35
     * @throws Exception
36
     */
37 91
    public function build(StructuredQuery $query, QueryBuilderState $state = null): RawQuery
38
    {
39
        /** @var MySqlQueryBuilderState $state */
40
41 91
        if ($state === null) {
42 1
            throw new \InvalidArgumentException('Passed state cannot be null.');
43
        }
44
45 90
        $input = $query->toArray();
46
47
48 90
        return RawQueryResult::create(
49 90
            $this->joinParts($state->getQueryPartGlue(), $this->buildQueryParts($input, $state)),
50 90
            $state->getParamsBuilder()->build(),
51 90
            $query->get('config') ?? null
52 90
        );
53
    }
54
55
    /**
56
     * Join built parts into one complete string.
57
     *
58
     * Part can be a string, in which case it will be joined with other by
59
     * using a string in $stringGlue
60
     *
61
     * If a part is an array it is used as a tuple [glue, partString] and
62
     * it will use its own glue string to join.
63
     *
64
     * @param string $stringGlue Default string glue to use if part is string
65
     * @param array $builtParts List of parts to join.
66
     *
67
     * @return string
68
     */
69 86
    protected function joinParts(string $stringGlue, array $builtParts): string
70
    {
71 86
        $result = '';
72
73 86
        foreach ($builtParts as $index => $part) {
74 86
            if (is_string($part)) {
75 86
                $result .= $index > 0 ? $stringGlue . $part : $part;
76 86
                continue;
77
            }
78
79 2
            [$partGlue, $partString] = $part;
80 2
            $result .= $partGlue . $partString;
81
        }
82
83 86
        return $result;
84
    }
85
86
    /**
87
     * Build each part from the structured query
88
     *
89
     * @param array $parts Parts from the structured query
90
     * @param MySqlQueryBuilderState $state Builder state
91
     * @return array Resulting array for each built part.
92
     * @throws Exception
93
     */
94 90
    protected function buildQueryParts(array $parts, MySqlQueryBuilderState $state): array
95
    {
96 90
        $results = $this->getInitialParts();
97 90
        $requiredParts = $this->getRequiredParts();
98
99 90
        foreach ($this->getPartBuilders() as $partName => $buildPart) {
100 89
            if (empty($parts[$partName])) {
101
102 78
                if (in_array($partName, $requiredParts)) {
103 7
                    throw new \UnexpectedValueException("Part '${partName}' is required.");
104
                }
105
106 76
                continue;
107
            }
108
109 88
            $result = $buildPart($parts[$partName], $state);
110
111 88
            if ($result !== null) {
112 88
                $results[] = $result;
113
            }
114
        }
115
116 86
        foreach ($this->getLastParts() as $part) {
117 2
            $results[] = $part;
118
        }
119
120 86
        return $results;
121
    }
122
123
    /**
124
     * Return initial parts for the query
125
     *
126
     * @return array
127
     */
128
    abstract protected function getInitialParts(): array;
129
130
    /**
131
     * Return parts which must be set in the query in order to be built.
132
     * @return array
133
     */
134
    abstract protected function getRequiredParts(): array;
135
136
    /**
137
     * Return part builders for resolving the query parts to string.
138
     *
139
     * @return array
140
     */
141
    abstract protected function getPartBuilders(): array;
142
143
    /**
144
     * Return last parts to be applied at the end of the query.
145
     *
146
     * @return array
147
     */
148
    abstract protected function getLastParts(): array;
149
}
150