1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace ICanBoogie\ActiveRecord;
13
14 use ICanBoogie\PropertyNotDefined;
15
16 17 18 19 20 21 22
23 class Statement extends \PDOStatement
24 {
25 26 27 28 29
30 public $connection;
31
32 33 34 35 36 37 38 39
40 public function __invoke()
41 {
42 $args = func_get_args();
43
44 if ($args && is_array($args[0]))
45 {
46 $args = $args[0];
47 }
48
49 return $this->execute($args);
50 }
51
52 53 54
55 public function __get($property)
56 {
57 switch ($property)
58 {
59 case 'all': return $this->fetchAll();
60 case 'one': return $this->fetchAndClose();
61 case 'rc': return $this->fetchColumnAndClose();
62 }
63
64 throw new PropertyNotDefined([ $property, $this ]);
65 }
66
67 68 69 70 71 72 73
74 public function execute($args=[])
75 {
76 $start = microtime(true);
77
78 if (!empty($this->connection))
79 {
80 $this->connection->queries_count++;
81 }
82
83 try
84 {
85 $this->connection->profiling[] = [ $start, microtime(true), $this->queryString . ' ' . json_encode($args) ];
86
87 return parent::execute($args);
88 }
89 catch (\PDOException $e)
90 {
91 throw new StatementInvalid([ $this->queryString, $args ], 500, $e);
92 }
93 }
94
95 96 97 98 99 100 101 102 103 104 105
106 public function fetchAndClose($fetch_style=\PDO::FETCH_BOTH, $cursor_orientation=\PDO::FETCH_ORI_NEXT, $cursor_offset=0)
107 {
108 $args = func_get_args();
109 $rc = call_user_func_array([ $this, 'parent::fetch' ], $args);
110
111 $this->closeCursor();
112
113 return $rc;
114 }
115
116 117 118 119 120 121 122 123 124
125 public function fetchColumnAndClose($column_number=0)
126 {
127 $rc = parent::fetchColumn($column_number);
128
129 $this->closeCursor();
130
131 return $rc;
132 }
133
134 135 136 137 138 139 140 141 142
143 public function fetchGroups($fetch_style, $fetch_argument=null, array $ctor_args=[])
144 {
145 $args = func_get_args();
146 $rc = [];
147
148 if($fetch_style === \PDO::FETCH_LAZY)
149 {
150 call_user_func_array([ $this, 'setFetchMode' ], $args);
151
152 foreach($this as $row)
153 {
154 $rc[$row[0]][] = $row;
155 }
156
157 return $rc;
158 }
159
160 $args[0] = \PDO::FETCH_GROUP | $fetch_style;
161
162 $rc = call_user_func_array([ $this, 'parent::fetchAll' ], $args);
163
164 return $rc;
165 }
166
167 168 169 170 171 172 173 174 175 176 177
178 public function mode($mode)
179 {
180 $mode = func_get_args();
181
182 if (!call_user_func_array([ $this, 'setFetchMode' ], $mode))
183 {
184 throw new ActiveRecordException("Unable to set fetch mode.");
185 }
186
187 return $this;
188 }
189
190 191 192
193 public function all($fetch_style=null, $column_index=null, array $ctor_args=null)
194 {
195 return call_user_func_array([ $this, 'fetchAll' ], func_get_args());
196 }
197 }
198
199 200 201 202 203 204
205 class StatementInvalid extends ActiveRecordException
206 {
207 private $statement;
208 private $args;
209
210 public function __construct($statement, $code=500, \PDOException $previous)
211 {
212 $message = null;
213 $args = null;
214
215 if (is_array($statement))
216 {
217 list($statement, $args) = $statement;
218 }
219
220 if ($previous)
221 {
222 $er = array_pad($previous->errorInfo, 3, '');
223
224 $message = sprintf('%s(%s) <code>%s</code> — ', $er[0], $er[1], $er[2]);
225 }
226
227 $message .= sprintf('<code>%s</code>', htmlentities($statement));
228
229 if ($args)
230 {
231 $message .= sprintf(', arguments: <code>%s</code>', htmlentities(json_encode($args)));
232 }
233
234 parent::__construct($message, $code, $previous);
235 }
236
237 public function __get($property)
238 {
239 switch ($property)
240 {
241 case 'args': return $this->args;
242 case 'statement': return $this->statement;
243 }
244
245 throw new PropertyNotDefined([ $property, $this ]);
246 }
247 }