X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=lib%2Fpq%2FGateway%2FRow.php;h=bfda71b0575cfe73aa43d3f08051a2bed79c11d5;hb=HEAD;hp=e408430c736293fa3750ce810f31600500db1169;hpb=eb9591d498ac4a2a448d6021c804b3c41d1c7247;p=m6w6%2Fpq-gateway diff --git a/lib/pq/Gateway/Row.php b/lib/pq/Gateway/Row.php index e408430..bfda71b 100644 --- a/lib/pq/Gateway/Row.php +++ b/lib/pq/Gateway/Row.php @@ -2,6 +2,8 @@ namespace pq\Gateway; +use \pq\Query\Expr as QueryExpr; + class Row implements \JsonSerializable { /** @@ -43,13 +45,40 @@ class Row implements \JsonSerializable $that->data = $data; return $that->prime(); } + + /** + * Export current state as an array + * @return array + * @throws \UnexpectedValueException if a cell has been modified by an expression + */ + function export() { + $export = array_merge($this->data, $this->cell); + foreach ($export as &$val) { + if ($val instanceof Cell) { + if ($val->isExpr()) { + throw new \UnexpectedValueException("Cannot export an SQL expression"); + } + $val = $val->get(); + } + } + return $export; + } + /** + * Export current state with security sensitive data removed. You should override that. + * Just calls export() by default. + * @return array + */ + function exportPublic() { + return $this->export(); + } + /** * @implements JsonSerializable * @return array */ function jsonSerialize() { - return $this->data; + return $this->exportPublic(); } /** @@ -66,6 +95,30 @@ class Row implements \JsonSerializable return $this->data; } + /** + * Get all column/value pairs to possibly uniquely identify this row + * @return array + * @throws \OutOfBoundsException if any primary key column is not present in the row + */ + function getIdentity() { + $cols = array(); + if (count($identity = $this->getTable()->getIdentity())) { + foreach ($identity as $col) { + if (!array_key_exists($col, $this->data)) { + throw new \OutOfBoundsException( + sprintf("Column '%s' does not exist in row of table '%s'", + $col, $this->getTable()->getName() + ) + ); + } + $cols[$col] = $this->data[$col]; + } + } else { + $cols = $this->data; + } + return $cols; + } + /** * Check whether the row contains modifications * @return boolean @@ -79,6 +132,10 @@ class Row implements \JsonSerializable return false; } + /** + * Refresh the rows data + * @return \pq\Gateway\Row + */ function refresh() { $this->data = $this->table->find($this->criteria(), null, 1, 0)->current()->data; $this->cell = array(); @@ -98,13 +155,17 @@ class Row implements \JsonSerializable } /** - * Transform data array to where criteria + * Transform the row's identity to where criteria * @return array */ protected function criteria() { $where = array(); - foreach($this->data as $k => $v) { - $where["$k="] = $v; + foreach ($this->getIdentity() as $col => $val) { + if (isset($val)) { + $where["$col="] = $val; + } else { + $where["$col IS"] = new QueryExpr("NULL"); + } } return $where; } @@ -124,24 +185,87 @@ class Row implements \JsonSerializable } /** - * Get a cell - * @param string $p + * Cell accessor + * @param string $p column name * @return \pq\Gateway\Cell */ - function __get($p) { + protected function cell($p) { if (!isset($this->cell[$p])) { $this->cell[$p] = new Cell($this, $p, isset($this->data[$p]) ? $this->data[$p] : null); } return $this->cell[$p]; } + /** + * Get a cell + * @param string $p + * @return \pq\Gateway\Cell + */ + function __get($p) { + return $this->cell($p); + } + /** * Set a cell value * @param string $p * @param mixed $v */ function __set($p, $v) { - $this->__get($p)->set(($v instanceof Cell) ? $v->get() : $v); + $this->cell($p)->set($v); + } + + /** + * Unset a cell value + * @param string $p + */ + function __unset($p) { + unset($this->data[$p]); + unset($this->cell[$p]); + } + + /** + * Check if a cell isset + * @param string $p + * @return bool + */ + function __isset($p) { + return isset($this->data[$p]) || isset($this->cell[$p]); + } + + /** + * Get the parent row + * @see \pq\Gateway\Table::by() + * @param mixed $foreign table (name) + * @param string $ref + * @return \pq\Gateway\Rowset + */ + function ofWhich($foreign, $ref = null) { + if (!($foreign instanceof Table)) { + $foreign = forward_static_call( + [get_class($this->getTable()), "resolve"], + $foreign + ); + } + return $foreign->by($this, $ref); + } + + /** + * Get child rows of this row by foreign key + * @see \pq\Gateway\Table::of() + * @param mixed $foreign table (name) + * @param string $order + * @param int $limit + * @param int $offset + * @return \pq\Gateway\Rowset + */ + function allOf($foreign, $ref = null, $order = null, $limit = 0, $offset = 0) { + if (!($foreign instanceof Table)) { + $foreign = forward_static_call( + [get_class($this->getTable()), "resolve"], + $foreign + ); + } + return $foreign->of($this, $ref, $order, $limit, $offset); } /** @@ -149,7 +273,12 @@ class Row implements \JsonSerializable * @return \pq\Gateway\Row */ function create() { - $this->data = $this->table->create($this->changes())->current()->data; + $this->table->notify($this, "create"); + $rowset = $this->table->create($this->changes()); + if (!count($rowset)) { + throw new \UnexpectedValueException("No row created"); + } + $this->data = $rowset->current()->data; $this->cell = array(); return $this; } @@ -159,7 +288,13 @@ class Row implements \JsonSerializable * @return \pq\Gateway\Row */ function update() { - $this->data = $this->table->update($this->criteria(), $this->changes())->current()->data; + $where = $this->criteria(); + $this->table->notify($this, "update", $where); + $rowset = $this->table->update($where, $this->changes()); + if (!count($rowset)) { + throw new \UnexpectedValueException("No row updated"); + } + $this->data = $rowset->current()->data; $this->cell = array(); return $this; } @@ -169,7 +304,12 @@ class Row implements \JsonSerializable * @return \pq\Gateway\Row */ function delete() { - $this->data = $this->table->delete($this->criteria(), "*")->current()->data; + $this->table->notify($this, "delete"); + $rowset = $this->table->delete($this->criteria(), "*"); + if (!count($rowset)) { + throw new \UnexpectedValueException("No row deleted"); + } + $this->data = $rowset->current()->data; return $this->prime(); } }