Completed
Push — master ( 8146b2...061ea8 )
by Ryan
03:02
created

AbstractXmlMiddleware::generateQuery()   C

Complexity

Conditions 11
Paths 5

Size

Total Lines 65
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 45
nc 5
nop 2
dl 0
loc 65
rs 5.9999
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright (c) 2017–2018 Ryan Parman <http://ryanparman.com>.
4
 * Copyright (c) 2017–2018 Contributors.
5
 *
6
 * http://opensource.org/licenses/Apache2.0
7
 */
8
declare(strict_types=1);
9
10
namespace SimplePie\Middleware\Xml;
11
12
use SimplePie\Middleware\AbstractMiddleware;
13
use SimplePie\Type\Node;
14
15
/**
16
 * The base XML middleware class that all other XML middleware classes extend from. It handles low-level functionality
17
 * that is shared across all XML middleware classes.
18
 */
19
abstract class AbstractXmlMiddleware extends AbstractMiddleware
20
{
21
    /**
22
     * The status of case-sensitivity.
23
     *
24
     * @var bool
25
     */
26
    protected $caseSensitive = true;
27
28
    /**
29
     * By default, SimplePie NG is case-sensitive (as per the specification). If an invalid feed is parsed that does not
30
     * follow the specification with regard to casing of XML elements, this method allows you to trade some performance
31
     * in favor of case-insensitive parsing.
32
     *
33
     * @param bool $makeInsensitive Whether or not the handling should be made case-insensitive. A value of `true`
34
     *                              means that the handling should be case-insensitive. A value of `false` means that
35
     *                              the handling should be case-sensitive. The default value is `true`.
36
     *
37
     * @return self
38
     */
39
    public function setCaseInsensitive(bool $makeInsensitive = true): self
40
    {
41
        $this->caseSensitive = !$makeInsensitive;
42
43
        return $this;
44
    }
45
46
    /**
47
     * Replace all instances of `%s` with the `$namespaceAlias` parameter.
48
     *
49
     * This is similar to `sprintf()`, but the `$namespaceAlias` is applied to _all_ instances of `%s`.
50
     *
51
     * @param string $query          An XPath query where `%s` is used in-place of the XML namespace alias.
52
     * @param string $namespaceAlias The XML namespace alias to apply.
53
     *
54
     * @return string
55
     */
56
    public function applyNsToQuery(string $query, string $namespaceAlias): string
57
    {
58
        return \str_replace('%s', $namespaceAlias, $query);
59
    }
60
61
    /**
62
     * Produce an XPath 1.0 expression which is used to query XML document nodes.
63
     *
64
     * ```php
65
     * ['feed', 'entry', 5, 'id', '@xml:lang']
66
     * ```
67
     *
68
     * ```xpath
69
     * /feed/entry[5]/id/@xml:lang (simplified)
70
     * ```
71
     *
72
     * @param string $namespaceAlias The XML namespace alias to apply.
73
     * @param array  $path           An ordered array of nested elements, starting from the top-level XML node.
74
     *                               If an integer is added, then it is assumed that the element before it should be
75
     *                               handled as an array and the integer is its index. Expression is generated
76
     *                               left-to-right.
77
     *
78
     * @return string An XPath 1.0 expression.
79
     */
80
    public function generateQuery(string $namespaceAlias, array $path): string
81
    {
82
        $query = '';
83
84
        while (\count($path)) {
85
            $p    = \array_shift($path);
86
            $next = $path[0] ?? null;
87
88
            // Reduce to only the upper/lower of the active letters
89
            // ≈30-35% faster than the full alphabet
90
            $pLet  = \count_chars($p, 3);
91
            $pLow  = \mb_strtolower($pLet);
92
            $pUp   = \mb_strtoupper($pLet);
93
            $pAttr = ('@' === \mb_substr($p, 0, 1));
94
95
            if (\is_int($next)) {
96
                if ($this->caseSensitive || $pAttr) {
97
                    // case; next
98
                    $query .= \sprintf(
99
                        '/%s%s[position() = %d]',
100
                        (!$pAttr
101
                            ? $namespaceAlias . ':'
102
                            : ''),
103
                        $p,
104
                        \array_shift($path) + 1
105
                    );
106
                } else {
107
                    // icase; next
108
                    $query .= \sprintf(
109
                        '/%s*[translate(name(), \'%s\', \'%s\') = \'%s\'][position() = %d]',
110
                        (!$pAttr
111
                            ? $namespaceAlias . ':'
112
                            : ''),
113
                        $pUp,
114
                        $pLow,
115
                        $p,
116
                        \array_shift($path) + 1
117
                    );
118
                }
119
            } else {
120
                if ($this->caseSensitive || $pAttr) {
121
                    // case; no-next
122
                    $query .= \sprintf(
123
                        '/%s%s',
124
                        (!$pAttr
125
                            ? $namespaceAlias . ':'
126
                            : ''),
127
                        $p
128
                    );
129
                } else {
130
                    // icase; no-next
131
                    $query .= \sprintf(
132
                        '/%s*[translate(name(), \'%s\', \'%s\') = \'%s\']',
133
                        (!$pAttr
134
                            ? $namespaceAlias . ':'
135
                            : ''),
136
                        $pUp,
137
                        $pLow,
138
                        $p
139
                    );
140
                }
141
            }
142
        }
143
144
        return $query;
145
    }
146
}
147