5 use \pq\Query\Expr
as QueryExpr
;
7 class Row
implements \JsonSerializable
10 * @var \pq\Gateway\Table
22 protected $cell = array();
25 * @param \pq\Gateway\Table $table
27 * @param bool $prime whether to mark all columns as modified
29 function __construct(Table
$table, array $data = null, $prime = false) {
30 $this->table
= $table;
31 $this->data
= (array) $data;
41 * @return \pq\Gateway\Row
43 function __invoke(array $data) {
46 return $that->prime();
50 * Export current state as an array
52 * @throws \UnexpectedValueException if a cell has been modified by an expression
55 $export = array_merge($this->data
, $this->cell
);
56 foreach ($export as &$val) {
57 if ($val instanceof Cell
) {
59 throw new \
UnexpectedValueException("Cannot export an SQL expression");
68 * Export current state with security sensitive data removed. You should override that.
69 * Just calls export() by default.
72 function exportPublic() {
73 return $this->export();
77 * @implements JsonSerializable
80 function jsonSerialize() {
81 return $this->exportPublic();
85 * @return \pq\Gateway\Table
99 * Get all column/value pairs to possibly uniquely identify this row
101 * @throws \OutOfBoundsException if any primary key column is not present in the row
103 function getIdentity() {
105 if (count($identity = $this->getTable()->getIdentity())) {
106 foreach ($identity as $col) {
107 if (!array_key_exists($col, $this->data
)) {
108 throw new \
OutOfBoundsException(
109 sprintf("Column '%s' does not exist in row of table '%s'",
110 $col, $this->getTable()->getName()
114 $cols[$col] = $this->data
[$col];
123 * Check whether the row contains modifications
127 foreach ($this->cell
as $cell) {
128 if ($cell->isDirty()) {
136 * Refresh the rows data
137 * @return \pq\Gateway\Row
140 $this->data
= $this->table
->find($this->criteria(), null, 1, 0)->current()->data
;
141 $this->cell
= array();
146 * Fill modified cells
147 * @return \pq\Gateway\Row
149 protected function prime() {
150 $this->cell
= array();
151 foreach ($this->data
as $key => $val) {
152 $this->cell
[$key] = new Cell($this, $key, $val, true);
158 * Transform the row's identity to where criteria
161 protected function criteria() {
163 foreach ($this->getIdentity() as $col => $val) {
165 $where["$col="] = $val;
167 $where["$col IS"] = new QueryExpr("NULL");
174 * Get an array of changed properties
177 protected function changes() {
179 foreach ($this->cell
as $name => $cell) {
180 if ($cell->isDirty()) {
181 $changes[$name] = $cell->get();
189 * @param string $p column name
190 * @return \pq\Gateway\Cell
192 protected function cell($p) {
193 if (!isset($this->cell
[$p])) {
194 $this->cell
[$p] = new Cell($this, $p, isset($this->data
[$p]) ?
$this->data
[$p] : null);
196 return $this->cell
[$p];
202 * @return \pq\Gateway\Cell
205 return $this->cell($p);
213 function __set($p, $v) {
214 $this->cell($p)->set($v);
221 function __unset($p) {
222 unset($this->data
[$p]);
223 unset($this->cell
[$p]);
227 * Check if a cell isset
231 function __isset($p) {
232 return isset($this->data
[$p]) ||
isset($this->cell
[$p]);
237 * @see \pq\Gateway\Table::by()
238 * @param mixed $foreign table (name)
240 * @return \pq\Gateway\Rowset
242 function ofWhich($foreign, $ref = null) {
243 if (!($foreign instanceof Table
)) {
244 $foreign = forward_static_call(
245 [get_class($this->getTable()), "resolve"],
249 return $foreign->by($this, $ref);
253 * Get child rows of this row by foreign key
254 * @see \pq\Gateway\Table::of()
255 * @param mixed $foreign table (name)
256 * @param string $order
259 * @return \pq\Gateway\Rowset
261 function allOf($foreign, $ref = null, $order = null, $limit = 0, $offset = 0) {
262 if (!($foreign instanceof Table
)) {
263 $foreign = forward_static_call(
264 [get_class($this->getTable()), "resolve"],
268 return $foreign->of($this, $ref, $order, $limit, $offset);
272 * Create this row in the database
273 * @return \pq\Gateway\Row
276 $this->table
->notify($this, "create");
277 $rowset = $this->table
->create($this->changes());
278 if (!count($rowset)) {
279 throw new \
UnexpectedValueException("No row created");
281 $this->data
= $rowset->current()->data
;
282 $this->cell
= array();
287 * Update this row in the database
288 * @return \pq\Gateway\Row
291 $where = $this->criteria();
292 $this->table
->notify($this, "update", $where);
293 $rowset = $this->table
->update($where, $this->changes());
294 if (!count($rowset)) {
295 throw new \
UnexpectedValueException("No row updated");
297 $this->data
= $rowset->current()->data
;
298 $this->cell
= array();
303 * Delete this row in the database
304 * @return \pq\Gateway\Row
307 $this->table
->notify($this, "delete");
308 $rowset = $this->table
->delete($this->criteria(), "*");
309 if (!count($rowset)) {
310 throw new \
UnexpectedValueException("No row deleted");
312 $this->data
= $rowset->current()->data
;
313 return $this->prime();