Completed
Pull Request — 1.x (#7)
by Akihito
07:30
created

QueryLocator::getFileContents()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 0
cts 0
cp 0
rs 9.8666
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 12
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Koriym\QueryLocator;
6
7
use Koriym\QueryLocator\Exception\CountQueryException;
8
use Koriym\QueryLocator\Exception\QueryFileNotFoundException;
9
use Koriym\QueryLocator\Exception\ReadOnlyException;
10
use function is_string;
11
12
final class QueryLocator implements QueryLocatorInterface
13
{
14
    /**
15
     * @var string
16
     */
17
    private $sqlDir;
18
19
    public function __construct(string $sqlDir)
20
    {
21
        $this->sqlDir = $sqlDir;
22
    }
23 21
24
    /**
25 21
     * {@inheritdoc}
26 21
     */
27
    public function get($queryName)
28
    {
29
        $sqlFile = sprintf(
30
            '%s/%s.sql',
31 17
            $this->sqlDir,
32
            $queryName
33 17
        );
34 17
35 17
        return trim($this->getFileContents($sqlFile));
36 17
    }
37
38 17
    /**
39 2
     * {@inheritdoc}
40
     */
41 15
    public function getCountQuery($queryName)
42
    {
43 15
        return $this->rewriteCountQuery($this->get($queryName));
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 6
    public function offsetExists($offset)
50
    {
51 6
        return (bool) $this->get($offset);
52
    }
53 4
54
    /**
55
     * {@inheritdoc}
56
     */
57
    public function offsetGet($offset)
58
    {
59 1
        return $this->get($offset);
60
    }
61 1
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function offsetSet($offset, $value)
66
    {
67 2
        throw new ReadOnlyException('not supported');
68
    }
69 2
70
    /**
71
     * {@inheritdoc}
72
     */
73
    public function offsetUnset($offset)
74
    {
75 1
        throw new ReadOnlyException('not supported');
76
    }
77 1
78
    /**
79
     * Return count query
80
     *
81
     * @see https://github.com/pear/Pager/blob/master/examples/Pager_Wrapper.php
82
     * Taken from pear/pager and modified.
83 1
     * tested at https://github.com/pear/Pager/blob/80c0e31c8b94f913cfbdeccbe83b63822f42a2f8/tests/pager_wrapper_test.php#L19
84
     * @codeCoverageIgnore
85 1
     */
86
    private function rewriteCountQuery(string $sql) : string
87
    {
88
        if (preg_match('/^\s*SELECT\s+\bDISTINCT\b/is', $sql) || preg_match('/\s+GROUP\s+BY\s+/is', $sql)) {
89
            throw new CountQueryException($sql);
90
        }
91
        $openParenthesis = '(?:\()';
92
        $closeParenthesis = '(?:\))';
93
        $subQueryInSelect = $openParenthesis . '.*\bFROM\b.*' . $closeParenthesis;
94
        $pattern = '/(?:.*' . $subQueryInSelect . '.*)\bFROM\b\s+/Uims';
95
        if (preg_match($pattern, $sql)) {
96
            throw new CountQueryException($sql);
97
        }
98
        $subQueryWithLimitOrder = $openParenthesis . '.*\b(LIMIT|ORDER)\b.*' . $closeParenthesis;
99
        $pattern = '/.*\bFROM\b.*(?:.*' . $subQueryWithLimitOrder . '.*).*/Uims';
100
        if (preg_match($pattern, $sql)) {
101
            throw new CountQueryException($sql);
102
        }
103
        $queryCount = preg_replace('/(?:.*)\bFROM\b\s+/Uims', 'SELECT COUNT(*) FROM ', $sql, 1);
104
        if (! is_string($queryCount)) {
105
            throw new CountQueryException($sql);
106
        }
107
        list($queryCount) = preg_split('/\s+ORDER\s+BY\s+/is', $queryCount);
108
        if (! is_string($queryCount)) {
109
            throw new CountQueryException($sql);
110
        }
111
        list($queryCount) = preg_split('/\bLIMIT\b/is', $queryCount);
112
        if (! is_string($queryCount)) {
113
            throw new CountQueryException($sql);
114
        }
115
116
        return trim($queryCount);
117
    }
118
119
    private function getFileContents(string $file) : string
120
    {
121
        if (! file_exists($file)) {
122
            throw new QueryFileNotFoundException($file);
123
        }
124
        $contents = file_get_contents($file);
125
        if (! $contents) {
126
            throw new QueryFileNotFoundException($file);
127
        }
128
129
        return $contents;
130
    }
131
}
132