Passed
Push — trunk ( 7ae7db...d8d8b1 )
by Christian
12:59 queued 14s
created

DoctrineExtension::prettifySql()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\Profiling\Twig;
4
5
use Doctrine\SqlFormatter\HtmlHighlighter;
6
use Doctrine\SqlFormatter\NullHighlighter;
7
use Doctrine\SqlFormatter\SqlFormatter;
8
use Shopware\Core\Framework\Log\Package;
9
use Symfony\Component\VarDumper\Cloner\Data;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\VarDumper\Cloner\Data was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Twig\Extension\AbstractExtension;
11
use Twig\TwigFilter;
12
13
#[Package('core
14
This class contains the needed functions in order to do the query highlighting')]
15
class DoctrineExtension extends AbstractExtension
16
{
17
    private SqlFormatter $sqlFormatter;
18
19
    /**
20
     * Define our functions
21
     *
22
     * @return list<TwigFilter>
0 ignored issues
show
Bug introduced by
The type Shopware\Core\Profiling\Twig\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
     */
24
    public function getFilters(): array
25
    {
26
        return [
0 ignored issues
show
Bug Best Practice introduced by
The expression return array(new Twig\Tw...eQueryParameters(...))) returns the type array<integer,Twig\TwigFilter> which is incompatible with the documented return type Shopware\Core\Profiling\Twig\list.
Loading history...
27
            new TwigFilter('doctrine_prettify_sql', $this->prettifySql(...), ['is_safe' => ['html']]),
28
            new TwigFilter('doctrine_format_sql', $this->formatSql(...), ['is_safe' => ['html']]),
29
            new TwigFilter('doctrine_replace_query_parameters', $this->replaceQueryParameters(...)),
30
        ];
31
    }
32
33
    /**
34
     * Escape parameters of a SQL query
35
     * DON'T USE THIS FUNCTION OUTSIDE ITS INTENDED SCOPE
36
     *
37
     * @internal
38
     */
39
    public static function escapeFunction(mixed $parameter): string
40
    {
41
        $result = $parameter;
42
43
        switch (true) {
44
            // Check if result is non-unicode string using PCRE_UTF8 modifier
45
            case \is_string($result) && !preg_match('//u', $result):
0 ignored issues
show
Bug introduced by
The function is_string was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

45
            case /** @scrutinizer ignore-call */ \is_string($result) && !preg_match('//u', $result):
Loading history...
46
                $result = '0x' . strtoupper(bin2hex($result));
47
48
                break;
49
50
            case \is_string($result):
51
                $result = '\'' . addslashes($result) . '\'';
52
53
                break;
54
55
            case \is_array($result):
0 ignored issues
show
Bug introduced by
The function is_array was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
            case /** @scrutinizer ignore-call */ \is_array($result):
Loading history...
56
                foreach ($result as &$value) {
57
                    $value = static::escapeFunction($value);
58
                }
59
60
                $result = implode(', ', $result) ?: 'NULL';
61
62
                break;
63
64
            case \is_object($result) && method_exists($result, '__toString'):
0 ignored issues
show
Bug introduced by
The function is_object was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

64
            case /** @scrutinizer ignore-call */ \is_object($result) && method_exists($result, '__toString'):
Loading history...
65
                $result = addslashes((string) $result->__toString());
66
67
                break;
68
69
            case $result === null:
70
                $result = 'NULL';
71
72
                break;
73
74
            case \is_bool($result):
0 ignored issues
show
Bug introduced by
The function is_bool was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

74
            case /** @scrutinizer ignore-call */ \is_bool($result):
Loading history...
75
                $result = $result ? '1' : '0';
76
77
                break;
78
        }
79
80
        return (string) $result;
81
    }
82
83
    /**
84
     * Return a query with the parameters replaced
85
     *
86
     * @param array<mixed>|Data $parameters
87
     */
88
    public function replaceQueryParameters(string $query, array|Data $parameters = []): string
89
    {
90
        if ($parameters instanceof Data) {
0 ignored issues
show
introduced by
$parameters is never a sub-type of Symfony\Component\VarDumper\Cloner\Data.
Loading history...
91
            $parameters = $parameters->getValue(true);
92
            /** @var array<mixed> $parameters */
93
        }
94
95
        $i = 0;
96
97
        if (!\array_key_exists(0, $parameters) && \array_key_exists(1, $parameters)) {
98
            $i = 1;
99
        }
100
101
        return (string) preg_replace_callback(
102
            '/\?|((?<!:):[a-z0-9_]+)/i',
103
            static function ($matches) use ($parameters, &$i) {
104
                $key = substr($matches[0], 1);
105
106
                if (!\array_key_exists($i, $parameters) && !\array_key_exists($key, $parameters)) {
107
                    return $matches[0];
108
                }
109
110
                $value = \array_key_exists($i, $parameters) ? $parameters[$i] : $parameters[$key];
111
                $result = DoctrineExtension::escapeFunction($value);
112
                ++$i;
113
114
                return $result;
115
            },
116
            $query
117
        );
118
    }
119
120
    public function prettifySql(string $sql): string
121
    {
122
        $this->setUpSqlFormatter();
123
124
        return $this->sqlFormatter->highlight($sql);
125
    }
126
127
    public function formatSql(string $sql, bool $highlight): string
128
    {
129
        $this->setUpSqlFormatter($highlight);
130
131
        return $this->sqlFormatter->format($sql);
132
    }
133
134
    /**
135
     * Get the name of the extension
136
     */
137
    public function getName(): string
138
    {
139
        return 'doctrine_extension';
140
    }
141
142
    private function setUpSqlFormatter(bool $highlight = true, bool $legacy = false): void
143
    {
144
        $this->sqlFormatter = new SqlFormatter($highlight ? new HtmlHighlighter([
145
            HtmlHighlighter::HIGHLIGHT_PRE => 'class="highlight highlight-sql"',
146
            HtmlHighlighter::HIGHLIGHT_QUOTE => 'class="string"',
147
            HtmlHighlighter::HIGHLIGHT_BACKTICK_QUOTE => 'class="string"',
148
            HtmlHighlighter::HIGHLIGHT_RESERVED => 'class="keyword"',
149
            HtmlHighlighter::HIGHLIGHT_BOUNDARY => 'class="symbol"',
150
            HtmlHighlighter::HIGHLIGHT_NUMBER => 'class="number"',
151
            HtmlHighlighter::HIGHLIGHT_WORD => 'class="word"',
152
            HtmlHighlighter::HIGHLIGHT_ERROR => 'class="error"',
153
            HtmlHighlighter::HIGHLIGHT_COMMENT => 'class="comment"',
154
            HtmlHighlighter::HIGHLIGHT_VARIABLE => 'class="variable"',
155
        ], !$legacy) : new NullHighlighter());
156
    }
157
}
158