"name": "m6w6/pq-gateway",
"type": "library",
"description": "Table/row gateway for ext-pq",
- "keywords": ["postgres", "orm", "gateway", "pq"],
- "homepage": "http://bitbucket.org/mike_php_net/pq-gateway",
+ "keywords": ["postgres", "postgresql", "orm", "gateway", "pq"],
+ "homepage": "http://bitbucket.org/m6w6/pq-gateway",
"license": "BSD-2-Clause",
"authors": [
{
* @return \pq\Gateway\Row
*/
function create() {
+ $this->table->notify($this, "create");
$rowset = $this->table->create($this->changes());
if (!count($rowset)) {
throw new \UnexpectedValueException("No row created");
* @return \pq\Gateway\Row
*/
function update() {
- $criteria = $this->criteria();
- if (($lock = $this->getTable()->getLock())) {
- $lock->onUpdate($this, $criteria);
- }
- $rowset = $this->table->update($criteria, $this->changes());
+ $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");
}
* @return \pq\Gateway\Row
*/
function delete() {
+ $this->table->notify($this, "delete");
$rowset = $this->table->delete($this->criteria(), "*");
if (!count($rowset)) {
throw new \UnexpectedValueException("No row deleted");
use \pq\Query\Writer as QueryWriter;
use \pq\Query\Executor as QueryExecutor;
-class Table
+class Table implements \SplSubject
{
/**
* @var \pq\Connection
protected $metadataCache;
/**
- * @var \pq\Gateway\Table\LockInterface
+ * @var \SplObjectStorage
*/
- protected $lock;
+ protected $observers;
/**
* @param string $table
throw new \InvalidArgumentException("Table must have a name");
}
$this->conn = $conn ?: static::$defaultConnection ?: new \pq\Connection;
+ $this->observers = new \SplObjectStorage;
}
/**
}
/**
- * Set a lock provider
- * @param \pq\Gateway\Table\LockInterface $lock
+ * Attach an observer
+ * @param \SplObserver
* @return \pq\Gateway\Table
*/
- function setLock(Table\LockInterface $lock) {
- $this->lock = $lock;
+ function attach(\SplObserver $observer) {
+ $this->observers->attach($observer);
return $this;
}
/**
- * Get any set lock provider
- * @return \pq\Gateway\Table\LockIntferace
+ * Detach an observer
+ * @param \SplObserver
+ * @return \pq\Gateway\Table
*/
- function getLock() {
- return $this->lock;
+ function detach(\SplObserver $observer) {
+ $this->observers->attach($observer);
+ return $this;
+ }
+
+ /**
+ * Implements \SplSubject
+ */
+ function notify(\pq\Gateway\Row $row = null, $event = null, array &$where = null) {
+ foreach ($this->observers as $observer) {
+ $observer->update($this, $row, $event, $where);
+ }
}
/**
+++ /dev/null
-<?php
-
-namespace pq\Gateway\Table;
-
-use \pq\Gateway\Row;
-
-/**
- * Lazy row lock on update
- */
-interface LockInterface
-{
- function onUpdate(Row $row, array &$where);
-}
/**
* An optimistic row lock implementation using a versioning column
*/
-class OptimisticLock implements LockInterface
+class OptimisticLock implements \SplObserver
{
/**
* The name of the versioning column
}
/**
- * @inheritdoc
+ * @param \pq\Gateway\Table $table
* @param \pq\Gateway\Row $row
+ * @param string $event create/update/delete
* @param array $where reference to the criteria
*/
- function onUpdate(Row $row, array &$where) {
- $where["{$this->column}="] = $row->getData()[$this->column];
- $row->{$this->column}->mod(+1);
+ function update(\SplSubject $table, Row $row = null, $event = null, array &$where = null) {
+ if ($event === "update") {
+ $where["{$this->column}="] = $row->getData()[$this->column];
+ $row->{$this->column}->mod(+1);
+ }
}
}
/**
* A pessimistic row lock implementation using an additional SELECT FOR UPDATE
*/
-class PessimisticLock implements LockInterface
+class PessimisticLock implements \SplObserver
{
/**
- * @inheritdoc
+ * @param \pq\Gateway\Table $table
* @param \pq\Gateway\Row $row
- * @param array $ignore
+ * @param string $event create/update/delete
+ * @param array $where reference to the criteria
* @throws \UnexpectedValueException if the row has already been modified
*/
- function onUpdate(Row $row, array &$ignore) {
- $where = array();
- foreach ($row->getIdentity() as $col => $val) {
- if (isset($val)) {
- $where["$col="] = $val;
- } else {
- $where["$col IS"] = new QueryExpr("NULL");
+ function update(\SplSubject $table, Row $row = null, $event = null, array &$where = null) {
+ if ($event === "update") {
+ if (1 != count($rowset = $table->find($where, null, 0, 0, "update nowait"))) {
+ throw new \UnexpectedValueException("Failed to select a single row");
+ }
+ if ($rowset->current()->getData() != $row->getData()) {
+ throw new \UnexpectedValueException("Row has already been modified");
}
- }
-
- if (1 != count($rowset = $row->getTable()->find($where, null, 0, 0, "update nowait"))) {
- throw new \UnexpectedValueException("Failed to select a single row");
- }
- if ($rowset->current()->getData() != $row->getData()) {
- throw new \UnexpectedValueException("Row has already been modified");
}
}
}
\ No newline at end of file
}
function testPessimisticLock() {
- $this->table->setLock(new Table\PessimisticLock);
+ $this->table->attach(new Table\PessimisticLock);
$txn = $this->table->getConnection()->startTransaction();
$row = $this->table->find(null, null, 1)->current();
$row->data = "foo";
}
function testPessimisticLockFail() {
- $this->table->setLock(new Table\PessimisticLock);
+ $this->table->attach(new Table\PessimisticLock);
$txn = $this->table->getConnection()->startTransaction();
$row = $this->table->find(null, null, 1)->current();
$row->data = "foo";
}
function testOptimisticLock() {
- $this->table->setLock(new Table\OptimisticLock("counter"));
+ $this->table->attach(new Table\OptimisticLock("counter"));
$row = $this->table->find(null, null, 1)->current();
$cnt = $row->counter->get();
$row->data = "foo";
}
function testOptimisticLockFail() {
- $this->table->setLock(new Table\OptimisticLock("counter"));
+ $this->table->attach(new Table\OptimisticLock("counter"));
$row = $this->table->find(null, null, 1)->current();
$row->data = "foo";
executeInConcurrentTransaction(