These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /* |
||
4 | * soluble-flexstore library |
||
5 | * |
||
6 | * @author Vanvelthem Sébastien |
||
7 | * @link https://github.com/belgattitude/soluble-flexstore |
||
8 | * @copyright Copyright (c) 2016-2017 Vanvelthem Sébastien |
||
9 | * @license MIT License https://github.com/belgattitude/soluble-flexstore/blob/master/LICENSE.md |
||
10 | * |
||
11 | */ |
||
12 | |||
13 | namespace Soluble\FlexStore\Source\DbWrapper; |
||
14 | |||
15 | use Soluble\FlexStore\Source\AbstractSource; |
||
16 | use Soluble\FlexStore\Source\QueryableSourceInterface; |
||
17 | use Soluble\FlexStore\ResultSet\ResultSet; |
||
18 | use Soluble\FlexStore\Exception; |
||
19 | use Soluble\FlexStore\Options; |
||
20 | use ArrayObject; |
||
21 | use Soluble\DbWrapper\Adapter\AdapterInterface; |
||
22 | use Soluble\DbWrapper\Result\Resultset as DbWrapperResultset; |
||
23 | use Soluble\FlexStore\Column\ColumnModel; |
||
24 | use Soluble\FlexStore\Column\Type\MetadataMapper; |
||
25 | use Soluble\Metadata\Reader as MetadataReader; |
||
26 | |||
27 | class QuerySource extends AbstractSource implements QueryableSourceInterface |
||
28 | { |
||
29 | /** |
||
30 | * @var string |
||
31 | */ |
||
32 | protected $query; |
||
33 | |||
34 | /** |
||
35 | * @var AdapterInterface |
||
36 | */ |
||
37 | protected $adapter; |
||
38 | |||
39 | /** |
||
40 | * Initial params received in the constructor. |
||
41 | * |
||
42 | * @var ArrayObject |
||
43 | */ |
||
44 | protected $params; |
||
45 | |||
46 | /** |
||
47 | * The query string contains the query as it has been crafted (with options, limits...). |
||
48 | * |
||
49 | * @var string |
||
50 | */ |
||
51 | protected $query_string; |
||
52 | |||
53 | /** |
||
54 | * @var ColumnModel |
||
55 | */ |
||
56 | protected $columnModel; |
||
57 | |||
58 | /** |
||
59 | * @param AdapterInterface $adapter |
||
60 | * @param string $query |
||
61 | */ |
||
62 | 10 | public function __construct(AdapterInterface $adapter, $query = null) |
|
63 | { |
||
64 | 10 | $this->adapter = $adapter; |
|
65 | |||
66 | 10 | if ($query !== null) { |
|
67 | 7 | $this->setQuery($query); |
|
68 | } |
||
69 | 10 | } |
|
70 | |||
71 | /** |
||
72 | * @param string $query |
||
73 | */ |
||
74 | 10 | public function setQuery($query) |
|
75 | { |
||
76 | 10 | $this->query = $query; |
|
77 | 10 | } |
|
78 | |||
79 | /** |
||
80 | * @return string |
||
81 | */ |
||
82 | public function getQuery() |
||
83 | { |
||
84 | return $this->query; |
||
85 | } |
||
86 | |||
87 | /** |
||
88 | * @param string $query |
||
89 | * @param Options $options |
||
90 | * |
||
91 | * @return string query |
||
92 | */ |
||
93 | 6 | protected function assignOptions($query, Options $options) |
|
94 | { |
||
95 | 6 | if ($options->hasLimit()) { |
|
96 | /* |
||
97 | * For mysql queries, to allow counting rows we must prepend |
||
98 | * SQL_CALC_FOUND_ROWS to the select quantifiers |
||
99 | */ |
||
100 | 4 | if ($options->getLimit() > 0) { |
|
101 | 3 | $calc_found_rows = 'SQL_CALC_FOUND_ROWS'; |
|
102 | 3 | if (!preg_match("/$calc_found_rows/", $query)) { |
|
103 | 3 | $q = trim($query); |
|
104 | 3 | $query = preg_replace('/^select\b/i', "SELECT $calc_found_rows", $q); |
|
105 | } |
||
106 | } |
||
107 | |||
108 | // mysql only, @todo make it rule everything (use traits) |
||
109 | 4 | $replace_regexp = "LIMIT[\s]+[\d]+((\s*,\s*\d+)|(\s+OFFSET\s+\d+)){0,1}"; |
|
110 | |||
111 | 4 | $search_regexp = "$replace_regexp"; |
|
112 | 4 | if (!preg_match("/$search_regexp$/i", $query)) { |
|
113 | // Limit is not already present |
||
114 | 3 | $query .= ' LIMIT ' . $options->getLimit(); |
|
115 | } else { |
||
116 | 1 | $query = preg_replace("/($replace_regexp)/i", 'LIMIT ' . $options->getLimit(), $query); |
|
117 | } |
||
118 | |||
119 | 4 | if ($options->hasOffset()) { |
|
120 | 3 | $query .= ' OFFSET ' . $options->getOffset(); |
|
121 | } |
||
122 | } |
||
123 | |||
124 | 6 | return $query; |
|
125 | } |
||
126 | |||
127 | /** |
||
128 | * @param Options $options |
||
129 | * |
||
130 | * @throws Exception\EmptyQueryException |
||
131 | * @throws Exception\ErrorException |
||
132 | * |
||
133 | * @return ResultSet |
||
134 | */ |
||
135 | 6 | public function getData(Options $options = null) |
|
136 | { |
||
137 | 6 | if ($options === null) { |
|
138 | 2 | $options = $this->getOptions(); |
|
139 | } |
||
140 | |||
141 | 6 | $this->query_string = $this->assignOptions($this->query, $options); |
|
142 | |||
143 | try { |
||
144 | 6 | $results = $this->adapter->query($this->query_string, DbWrapperResultset::TYPE_ARRAYOBJECT); |
|
145 | |||
146 | 6 | $r = new ResultSet($results); |
|
0 ignored issues
–
show
|
|||
147 | 6 | $r->setSource($this); |
|
148 | 6 | $r->setHydrationOptions($options->getHydrationOptions()); |
|
149 | |||
150 | 6 | if ($options->hasLimit() && $options->getLimit() > 0) { |
|
151 | //$row = $this->adapter->query('select FOUND_ROWS() as total_count')->execute()->current(); |
||
152 | 3 | $row = $this->adapter->query('select FOUND_ROWS() as total_count')->current(); |
|
153 | 3 | $r->setTotalRows($row['total_count']); |
|
154 | } else { |
||
155 | 6 | $r->setTotalRows($r->count()); |
|
156 | } |
||
157 | } catch (\Exception $e) { |
||
158 | throw new Exception\ErrorException(__METHOD__ . ': Cannot retrieve data (' . $e->getMessage() . ')'); |
||
159 | } |
||
160 | |||
161 | 6 | return $r; |
|
162 | } |
||
163 | |||
164 | 2 | public function loadDefaultColumnModel() |
|
165 | { |
||
166 | 2 | $metadata_columns = $this->getMetadataReader()->getColumnsMetadata($this->query); |
|
167 | 2 | $this->setColumnModel(MetadataMapper::getColumnModelFromMetadata($metadata_columns)); |
|
168 | 2 | } |
|
169 | |||
170 | /** |
||
171 | * {@inheritdoc} |
||
172 | * |
||
173 | * @throws Exception\UnsupportedFeatureException |
||
174 | */ |
||
175 | 4 | public function getMetadataReader() |
|
176 | { |
||
177 | 4 | if ($this->metadataReader === null) { |
|
178 | 4 | $this->setMetadataReader($this->getDefaultMetadataReader()); |
|
179 | } |
||
180 | |||
181 | 4 | return $this->metadataReader; |
|
182 | } |
||
183 | |||
184 | /** |
||
185 | * @throws Exception\UnsupportedFeatureException |
||
186 | */ |
||
187 | 4 | protected function getDefaultMetadataReader() |
|
188 | { |
||
189 | 4 | $conn = $this->adapter->getConnection()->getResource(); |
|
190 | 4 | $class = strtolower(get_class($conn)); |
|
191 | switch ($class) { |
||
192 | 4 | case 'pdo': |
|
193 | return new MetadataReader\PdoMysqlMetadataReader($conn); |
||
194 | 4 | case 'mysqli': |
|
195 | 4 | return new MetadataReader\MysqliMetadataReader($conn); |
|
196 | default: |
||
197 | throw new Exception\UnsupportedFeatureException(__METHOD__ . " Does not support default metadata reader for driver '$class'"); |
||
198 | } |
||
199 | } |
||
200 | |||
201 | /** |
||
202 | * Return the query string that was executed with options etc. |
||
203 | * |
||
204 | * @throws Exception\InvalidUsageException |
||
205 | * |
||
206 | * @return string |
||
207 | */ |
||
208 | 2 | public function getQueryString() |
|
209 | { |
||
210 | 2 | if ($this->query_string == '') { |
|
211 | throw new Exception\InvalidUsageException(__METHOD__ . ': Invalid usage, getQueryString must be called after data has been loaded (performance reason).'); |
||
212 | } |
||
213 | |||
214 | 2 | return str_replace("\n", ' ', $this->query_string); |
|
215 | } |
||
216 | |||
217 | /** |
||
218 | * Return the query string. |
||
219 | * |
||
220 | * @throws Exception\InvalidUsageException |
||
221 | * |
||
222 | * @return string |
||
223 | */ |
||
224 | public function __toString() |
||
225 | { |
||
226 | if (trim($this->query) == '') { |
||
227 | throw new Exception\InvalidUsageException(__METHOD__ . ': Empty query given.'); |
||
228 | } |
||
229 | |||
230 | return $this->query; |
||
231 | } |
||
232 | } |
||
233 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: