af84e7f5eb59ed5c0e59c054a48c86bcb6f52620
[m6w6/pq-gateway] / lib / pq / Gateway / Table.php
1 <?php
2
3 namespace pq\Gateway;
4
5 use \pq\Query\Writer as QueryWriter;
6 use \pq\Query\Executor as QueryExecutor;
7
8 class Table
9 {
10 /**
11 * @var \pq\Connection
12 */
13 public static $defaultConnection;
14
15 /**
16 * @var callable
17 */
18 public static $defaultResolver;
19
20 /**
21 * @var \pq\Connection
22 */
23 protected $conn;
24
25 /**
26 * @var string
27 */
28 protected $name;
29
30 /**
31 * @var string
32 */
33 protected $rowset = "\\pq\\Gateway\\Rowset";
34
35 /**
36 * @var \pq\Query\WriterIterface
37 */
38 protected $query;
39
40 /**
41 * @var \pq\Query\ExecutorInterface
42 */
43 protected $exec;
44
45 /**
46 * @var \pq\Gateway\Table\Relations
47 */
48 protected $relations;
49
50 /**
51 * @param string $table
52 * @return \pq\Gateway\Table
53 */
54 public static function resolve($table) {
55 if ($table instanceof Table) {
56 return $table;
57 }
58 if (is_callable(static::$defaultResolver)) {
59 if (($resolved = call_user_func(static::$defaultResolver, $table))) {
60 return $resolved;
61 }
62 }
63 return new Table($table);
64 }
65
66 /**
67 * @param string $name
68 * @param \pq\Connection $conn
69 * @param array $dependents
70 */
71 function __construct($name, \pq\Connection $conn = null) {
72 $this->name = $name;
73 $this->conn = $conn ?: static::$defaultConnection ?: new \pq\Connection;
74 }
75
76 /**
77 * Set the rowset prototype
78 * @param mixed $rowset
79 * @return \pq\Gateway\Table
80 */
81 function setRowsetPrototype($rowset) {
82 $this->rowset = $rowset;
83 return $this;
84 }
85
86 /**
87 * Get the rowset prototype
88 * @return mixed
89 */
90 function getRowsetPrototype() {
91 return $this->rowset;
92 }
93
94 /**
95 * Set the query writer
96 * @param \pq\Query\WriterInterface $query
97 * @return \pq\Gateway\Table
98 */
99 function setQueryWriter(\pq\Query\WriterInterface $query) {
100 $this->query = $query;
101 return $this;
102 }
103
104 /**
105 * Get the query writer
106 * @return \pq\Query\WriterInterface
107 */
108 function getQueryWriter() {
109 if (!$this->query) {
110 $this->query = new QueryWriter;
111 }
112 return $this->query;
113 }
114
115 /**
116 * Set the query executor
117 * @param \pq\Query\ExecutorInterface $exec
118 * @return \pq\Gateway\Table
119 */
120 function setQueryExecutor(\pq\Query\ExecutorInterface $exec) {
121 $this->exec = $exec;
122 return $this;
123 }
124
125 /**
126 * Get the query executor
127 * @return \pq\Query\ExecutorInterface
128 */
129 function getQueryExecutor() {
130 if (!$this->exec) {
131 $this->exec = new QueryExecutor($this->conn);
132 }
133 return $this->exec;
134 }
135
136 /**
137 * Get foreign key relations
138 * @param string $to fkey
139 * @return \pq\Gateway\Table\Relations|stdClass
140 */
141 function getRelations($to = null) {
142 if (!isset($this->relations)) {
143 $this->relations = new Table\Relations($this);
144 }
145 if (isset($to)) {
146 if (!isset($this->relations->$to)) {
147 return null;
148 }
149 return $this->relations->$to;
150 }
151 return $this->relations;
152 }
153
154 /**
155 * Check whether a certain relation exists
156 * @param string $name
157 * @param string $table
158 * @return bool
159 */
160 function hasRelation($name, $table = null) {
161 if (!($rel = $this->getRelations($name))) {
162 return false;
163 }
164 if (!isset($table)) {
165 return true;
166 }
167 return isset($rel->$table);
168 }
169
170 /**
171 * @return \pq\Connection
172 */
173 function getConnection() {
174 return $this->conn;
175 }
176
177 /**
178 * @return string
179 */
180 function getName() {
181 return $this->name;
182 }
183
184 /**
185 * Execute the query
186 * @param \pq\Query\WriterInterface $query
187 * @return mixed
188 */
189 protected function execute(QueryWriter $query) {
190 echo $query,"\n",json_encode($query->getParams()),"\n";
191 return $this->getQueryExecutor()->execute($query, array($this, "onResult"));
192 }
193
194 /**
195 * Retreives the result of an executed query
196 * @param \pq\Result $result
197 * @return mixed
198 */
199 public function onResult(\pq\Result $result = null) {
200 if ($result && $result->status != \pq\Result::TUPLES_OK) {
201 return $result;
202 }
203
204 $rowset = $this->getRowsetPrototype();
205 if (is_callable($rowset)) {
206 return $rowset($result);
207 } elseif ($rowset) {
208 return new $rowset($this, $result);
209 }
210
211 return $result;
212 }
213
214 /**
215 * Find rows in the table
216 * @param array $where
217 * @param array|string $order
218 * @param int $limit
219 * @param int $offset
220 * @return mixed
221 */
222 function find(array $where = null, $order = null, $limit = 0, $offset = 0) {
223 $query = $this->getQueryWriter()->reset();
224 $query->write("SELECT * FROM", $this->conn->quoteName($this->name));
225 if ($where) {
226 $query->write("WHERE")->criteria($where);
227 }
228 if ($order) {
229 $query->write("ORDER BY", $order);
230 }
231 if ($limit) {
232 $query->write("LIMIT", $limit);
233 }
234 $query->write("OFFSET", $offset);
235 return $this->execute($query);
236 }
237
238 /**
239 * Get the child rows of a row by foreign key
240 * @param \pq\Gateway\Row $foreign
241 * @param string $name optional fkey name
242 * @param string $order
243 * @param int $limit
244 * @param int $offset
245 * @return mixed
246 */
247 function of(Row $foreign, $name = null, $order = null, $limit = 0, $offset = 0) {
248 // select * from $this where $this->$foreignColumn = $foreign->$referencedColumn
249
250 if (!isset($name)) {
251 $name = $this->getName();
252 }
253
254 if (!$foreign->getTable()->hasRelation($name, $this->getName())) {
255 return $this->onResult(null);
256 }
257 $rel = $foreign->getTable()->getRelations($name)->{$this->getName()};
258
259 return $this->find(
260 array($rel->foreignColumn . "=" => $foreign->{$rel->referencedColumn}),
261 $order, $limit, $offset
262 );
263 }
264
265 /**
266 * Get the parent rows of a row by foreign key
267 * @param \pq\Gateway\Row $me
268 * @param string $foreign
269 * @param string $order
270 * @param int $limit
271 * @param int $offset
272 * @return mixed
273 */
274 function by(Row $me, $foreign, $order = null, $limit = 0, $offset = 0) {
275 // select * from $foreign where $foreign->$referencedColumn = $me->$foreignColumn
276
277 if (!$this->hasRelation($foreign, $this->getName())) {
278 return $this->onResult(null);
279 }
280 $rel = $this->getRelations($foreign)->{$this->getName()};
281
282 return static::resolve($rel->referencedTable)->find(
283 array($rel->referencedColumn . "=" => $me->{$rel->foreignColumn}),
284 $order, $limit, $offset
285 );
286 }
287
288 /**
289 * Insert a row into the table
290 * @param array $data
291 * @param string $returning
292 * @return mixed
293 */
294 function create(array $data = null, $returning = "*") {
295 $query = $this->getQueryWriter()->reset();
296 $query->write("INSERT INTO", $this->conn->quoteName($this->name));
297 if ($data) {
298 $first = true;
299 $params = array();
300 foreach ($data as $key => $val) {
301 $query->write($first ? "(" : ",", $key);
302 $params[] = $query->param($val);
303 $first and $first = false;
304 }
305 $query->write(") VALUES (", $params, ")");
306 } else {
307 $query->write("DEFAULT VALUES");
308 }
309
310 if (strlen($returning)) {
311 $query->write("RETURNING", $returning);
312 }
313 return $this->execute($query);
314 }
315
316 /**
317 * Update rows in the table
318 * @param array $where
319 * @param array $data
320 * @param string $returning
321 * @retunr mixed
322 */
323 function update(array $where, array $data, $returning = "*") {
324 $query = $this->getQueryWriter()->reset();
325 $query->write("UPDATE", $this->conn->quoteName($this->name));
326 $first = true;
327 foreach ($data as $key => $val) {
328 $query->write($first ? "SET" : ",", $key, "=", $query->param($val));
329 $first and $first = false;
330 }
331 $query->write("WHERE")->criteria($where);
332 if (strlen($returning)) {
333 $query->write("RETURNING", $returning);
334 }
335 return $this->execute($query);
336 }
337
338 /**
339 * Delete rows from the table
340 * @param array $where
341 * @param string $returning
342 * @return mixed
343 */
344 function delete(array $where, $returning = null) {
345 $query = $this->getQueryWriter()->reset();
346 $query->write("DELETE FROM", $this->conn->quoteName($this->name));
347 $query->write("WHERE")->criteria($where);
348 if (strlen($returning)) {
349 $query->write("RETURNING", $returning);
350 }
351 return $this->execute($query);
352 }
353 }