• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

longitude-one / doctrine-spatial / 9995813265

16 Jul 2024 07:44PM UTC coverage: 95.352%. Remained the same
9995813265

push

github

web-flow
Fix broken link (#101)

1272 of 1334 relevant lines covered (95.35%)

34.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.1
/lib/LongitudeOne/Spatial/ORM/Query/AST/Functions/AbstractSpatialDQLFunction.php
1
<?php
2
/**
3
 * This file is part of the doctrine spatial extension.
4
 *
5
 * PHP 8.1 | 8.2 | 8.3
6
 * Doctrine ORM 2.19 | 3.1
7
 *
8
 * Copyright Alexandre Tranchant <alexandre.tranchant@gmail.com> 2017-2024
9
 * Copyright Longitude One 2020-2024
10
 * Copyright 2015 Derek J. Lambert
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 *
15
 */
16

17
declare(strict_types=1);
18

19
namespace LongitudeOne\Spatial\ORM\Query\AST\Functions;
20

21
use Doctrine\DBAL\Exception;
22
use Doctrine\DBAL\Platforms\AbstractPlatform;
23
use Doctrine\ORM\Query\AST\ASTException;
24
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
25
use Doctrine\ORM\Query\AST\Node;
26
use Doctrine\ORM\Query\Parser;
27
use Doctrine\ORM\Query\QueryException;
28
use Doctrine\ORM\Query\SqlWalker;
29
use Doctrine\ORM\Query\TokenType;
30
use LongitudeOne\Spatial\Exception\InvalidValueException;
31
use LongitudeOne\Spatial\Exception\UnsupportedPlatformException;
32

33
/**
34
 * Abstract spatial DQL function.
35
 *
36
 * @author  Derek J. Lambert <dlambert@dereklambert.com>
37
 * @author  Alexandre Tranchant <alexandre.tranchant@gmail.com>
38
 * @license https://dlambert.mit-license.org MIT
39
 *
40
 * This spatial class is updated to avoid non-covered code. A lot of PostgreSQL functions were not tested,
41
 * but that was not displayed by coverage rapport. Some MySQL methods generate bug since MySQL 8.0 because their name
42
 * was updated.
43
 *
44
 * It is not possible to evaluate which function is tested or not with a children containing only protected methods.
45
 * The new pattern consists of create an abstract method for each removed property.
46
 * Then, if tests don't check function, the code coverage tools will report this information.
47
 *
48
 * Thus, if we analyze a platform version, we can implement the getFunctionName method to return geomfromtext for
49
 * MySQL Version 5.7 and return st_geomfromtext for version 8.0
50
 *
51
 * @see https://stackoverflow.com/questions/60377271/why-some-spatial-functions-does-not-exists-on-my-mysql-server
52
 */
53
abstract class AbstractSpatialDQLFunction extends FunctionNode
54
{
55
    /**
56
     * @var Node[]
57
     */
58
    private array $geometryExpression = [];
59

60
    /**
61
     * Get the SQL.
62
     *
63
     * @param SqlWalker $sqlWalker the SQL Walker
64
     *
65
     * @throws UnsupportedPlatformException when platform is unsupported
66
     * @throws Exception                    when an invalid platform was specified for this connection
67
     * @throws ASTException                 when node cannot dispatch SqlWalker
68
     */
69
    public function getSql(SqlWalker $sqlWalker): string
149✔
70
    {
71
        $this->validatePlatform($sqlWalker->getConnection()->getDatabasePlatform());
149✔
72

73
        $arguments = [];
149✔
74
        foreach ($this->getGeometryExpressions() as $expression) {
149✔
75
            $arguments[] = $expression->dispatch($sqlWalker);
149✔
76
        }
77

78
        return sprintf('%s(%s)', $this->getFunctionName(), implode(', ', $arguments));
149✔
79
    }
80

81
    /**
82
     * Parse SQL.
83
     *
84
     * @param Parser $parser parser
85
     *
86
     * @throws QueryException Query exception
87
     */
88
    public function parse(Parser $parser): void
149✔
89
    {
90
        $lexer = $parser->getLexer();
149✔
91

92
        $parser->match(TokenType::T_IDENTIFIER);
149✔
93
        $parser->match(TokenType::T_OPEN_PARENTHESIS);
149✔
94

95
        $this->addGeometryExpression($parser->ArithmeticPrimary());
149✔
96

97
        while (count($this->geometryExpression) < $this->getMinParameter()
149✔
98
            || ((count($this->geometryExpression) < $this->getMaxParameter())
149✔
99
                && TokenType::T_CLOSE_PARENTHESIS != $lexer->lookahead?->type)
149✔
100
        ) {
101
            $parser->match(TokenType::T_COMMA);
89✔
102

103
            $this->addGeometryExpression($parser->ArithmeticPrimary());
89✔
104
        }
105

106
        $parser->match(TokenType::T_CLOSE_PARENTHESIS);
149✔
107
    }
108

109
    /**
110
     * Geometry expressions fluent adder.
111
     *
112
     * @param Node|string $expression the node expression to add to the array of geometry expression
113
     *
114
     * @since 2.0 This function replace the protected property geomExpr which is now private.
115
     *
116
     * @throws InvalidValueException when expression is a string
117
     */
118
    protected function addGeometryExpression(Node|string $expression): self
149✔
119
    {
120
        if (is_string($expression)) {
149✔
121
            throw new InvalidValueException('Expression must be a node.');
×
122
        }
123

124
        $this->geometryExpression[] = $expression;
149✔
125

126
        return $this;
149✔
127
    }
128

129
    /**
130
     * Geometry expressions getter.
131
     *
132
     * @since 2.0 This function replace the protected property geomExpr which is now private.
133
     *
134
     * @return Node[]
135
     */
136
    final protected function getGeometryExpressions(): array
149✔
137
    {
138
        return $this->geometryExpression;
149✔
139
    }
140

141
    /**
142
     * Check that the current platform supports current spatial function.
143
     *
144
     * TODO when support for 8.1 will be dropped, this method will only return true.
145
     *
146
     * @param AbstractPlatform $platform database spatial
147
     *
148
     * @return true if the current platform is supported
149
     *
150
     * @throws UnsupportedPlatformException when platform is unsupported
151
     */
152
    protected function validatePlatform(AbstractPlatform $platform): bool
149✔
153
    {
154
        foreach ($this->getPlatforms() as $acceptedPlatform) {
149✔
155
            if ($platform instanceof $acceptedPlatform) {
149✔
156
                return true;
149✔
157
            }
158
        }
159

160
        throw new UnsupportedPlatformException(
×
161
            sprintf('DBAL platform "%s" is not currently supported.', $platform::class)
×
162
        );
×
163
    }
164

165
    /**
166
     * Function SQL name getter.
167
     *
168
     * @since 2.0 This function replace the protected property functionName.
169
     */
170
    abstract protected function getFunctionName(): string;
171

172
    /**
173
     * Maximum number of parameters for the spatial function.
174
     *
175
     * @since 2.0 This function replace the protected property maxGeomExpr.
176
     *
177
     * @return int the inherited methods shall NOT return a null, but 0 when the function has no parameter
178
     */
179
    abstract protected function getMaxParameter(): int;
180

181
    /**
182
     * Minimum number of parameters for the spatial function.
183
     *
184
     * @since 2.0 This function replace the protected property minGeomExpr.
185
     *
186
     * @return int the inherited methods shall NOT return a null, but 0 when the function has no parameter
187
     */
188
    abstract protected function getMinParameter(): int;
189

190
    /**
191
     * Get the platforms accepted.
192
     *
193
     * The AbstractPlatform::getName() method is now deprecated in the doctrine/dbal component.
194
     * We now use the class name to identify the platform.
195
     *
196
     * @see https://github.com/doctrine/dbal/issues/4749
197
     * @see https://github.com/longitude-one/doctrine-spatial/issues/40
198
     *
199
     * @return class-string<AbstractPlatform>[] a non-empty array of accepted platforms
200
     */
201
    abstract protected function getPlatforms(): array;
202
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc