added Table::with()
authorMichael Wallner <mike@php.net>
Sat, 13 Apr 2013 21:28:31 +0000 (23:28 +0200)
committerMichael Wallner <mike@php.net>
Sat, 13 Apr 2013 21:28:31 +0000 (23:28 +0200)
lib/autoload.php
lib/pq/Gateway/Row.php
lib/pq/Gateway/Table.php
lib/pq/Gateway/Table/LockInterface.php
lib/pq/Gateway/Table/OptimisticLock.php
lib/pq/Gateway/Table/PessimisticLock.php
lib/pq/Gateway/Table/Relations.php
tests/lib/pq/Gateway/RowTest.php
tests/lib/pq/Gateway/TableTest.php
tests/setup.inc

index d7b0cd8d4bf0ddc165af71a50e61d4e70cb5ee9a..cc5e906a728feaf3fa3e9fa836d2e375af63c2c2 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 spl_autoload_register(function($c) {
-       if (substr($c, 0, 10) === "pq\\Gateway" || susbtr($c, 0, 8) === "pq\\Query") {
+       if (substr($c, 0, 10) === "pq\\Gateway" || substr($c, 0, 8) === "pq\\Query") {
                return include __DIR__ . "/" . strtr($c, "\\", "/") . ".php";
        }
 });
index bba7c09c07642c90fe1d877f18c7462da40e7bfe..6d9c19e750b1b215da48b1b90959692f3f6c9fd8 100644 (file)
@@ -65,8 +65,8 @@ class Row implements \JsonSerializable
        }
        
        /**
-        * Export current state with security sensitive data removed. You should override that, just
-        * calls export() by default.
+        * Export current state with security sensitive data removed. You should override that.
+        * Just calls export() by default.
         * @return array
         */
        function exportPublic() {
@@ -167,10 +167,6 @@ class Row implements \JsonSerializable
                                $where["$col IS"] = new QueryExpr("NULL");
                        }
                }
-               
-               if (($lock = $this->getTable()->getLock())) {
-                       $lock->criteria($this, $where);
-               }
                return $where;
        }
        
@@ -262,7 +258,11 @@ class Row implements \JsonSerializable
         * @return \pq\Gateway\Row
         */
        function update() {
-               $rowset = $this->table->update($this->criteria(), $this->changes());
+               $criteria = $this->criteria();
+               if (($lock = $this->getTable()->getLock())) {
+                       $lock->onUpdate($this, $criteria);
+               }
+               $rowset = $this->table->update($criteria, $this->changes());
                if (!count($rowset)) {
                        throw new \UnexpectedValueException("No row updated");
                }
index fe5efbdd454309b2efa15fbdddb21d1f9a1a7a3e..a25b2ad3fd6e07008bf59f27caa56239293756ac 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace pq\Gateway;
 
+use \pq\Query\Expr as QueryExpr;
 use \pq\Query\Writer as QueryWriter;
 use \pq\Query\Executor as QueryExecutor;
 
@@ -88,8 +89,12 @@ class Table
         * @param \pq\Connection $conn
         * @param array $dependents
         */
-       function __construct($name, \pq\Connection $conn = null) {
-               $this->name = $name;
+       function __construct($name = null, \pq\Connection $conn = null) {
+               if (isset($name)) {
+                       $this->name = $name;
+               } elseif (!isset($this->name)) {
+                       throw new \InvalidArgumentException("Table must have a name");
+               }
                $this->conn = $conn ?: static::$defaultConnection ?: new \pq\Connection;
        }
        
@@ -374,6 +379,42 @@ class Table
                        $order, $limit, $offset
                );
        }
+       
+       /**
+        * Get rows dependent on other rows by foreign keys
+        * @param array $relations
+        * @param array $where
+        * @param string $order
+        * @param int $limit
+        * @param int $offset
+        * @return mixed
+        */
+       function with(array $relations, array $where = null, $order = null, $limit = 0, $offset = 0) {
+               $qthis = $this->conn->quoteName($this->getName());
+               $query = $this->getQueryWriter()->reset();
+               $query->write("SELECT", "$qthis.*", "FROM", $qthis);
+               foreach ($relations as $relation) {
+                       $query->write("JOIN", $relation->foreignTable)->write("ON")->criteria(
+                               array(
+                                       "{$relation->referencedTable}.{$relation->referencedColumn}=" => 
+                                               new QueryExpr("{$relation->foreignTable}.{$relation->foreignColumn}")
+                               )
+                       );
+               }
+               if ($where) {
+                       $query->write("WHERE")->criteria($where);
+               }
+               if ($order) {
+                       $query->write("ORDER BY", $order);
+               }
+               if ($limit) {
+                       $query->write("LIMIT", $limit);
+               }
+               if ($offset) {
+                       $query->write("OFFSET", $offset);
+               }
+               return $this->execute($query);
+       }
 
        /**
         * Insert a row into the table
index ff8e858fdafc81a3de135fd0bb6dcbc505457028..0cefb68adbc90ee56b700bab7c88ea2746e12d9a 100644 (file)
@@ -4,7 +4,10 @@ namespace pq\Gateway\Table;
 
 use \pq\Gateway\Row;
 
+/**
+ * Lazy row lock on update/delete
+ */
 interface LockInterface
 {
-       function criteria(Row $row, array &$where);
+       function onUpdate(Row $row, array &$where);
 }
index 08e5ae364f687f2e019cc633d83dc7c72542c897..8c2ec7b9741cb52b57e4c6bee3fdf9294726a81b 100644 (file)
@@ -23,11 +23,11 @@ class OptimisticLock implements LockInterface
        }
        
        /**
-        * @implements LockInterface
+        * @inheritdoc
         * @param \pq\Gateway\Row $row
         * @param array $where reference to the criteria
         */
-       function criteria(Row $row, array &$where) {
+       function onUpdate(Row $row, array &$where) {
                $where["{$this->column}="] = $row->getData()[$this->column];
                $row->{$this->column}->mod(+1);
        }
index e711b461226544b8c3c258aa26e2beacab0e85dd..2076dbd2b7dc05aa06b7124a7088de4d0eb843b0 100644 (file)
@@ -15,7 +15,7 @@ class PessimisticLock implements LockInterface
         * @param array $ignore
         * @throws \UnexpectedValueException if the row has already been modified
         */
-       function criteria(Row $row, array &$ignore) {
+       function onUpdate(Row $row, array &$ignore) {
                $where = array();
                foreach ($row->getIdentity() as $col => $val) {
                        if (isset($val)) {
index ab74d4060b23bdd49b7d795aa8b29101b2486cb7..7ad5326a84931c84f7fe1c8e40bcc747ad48c913 100644 (file)
@@ -46,7 +46,7 @@ class Relations
                        $table->getQueryExecutor()->execute(
                                new \pq\Query\Writer(RELATION_SQL, array($table->getName())),
                                function($result) use($table, $cache) {
-                                       $this->references = $result->map(array(0,1), array(2,3,4), \pq\Result::FETCH_OBJECT);
+                                       $this->references = $result->map(array(0,1), array(1,2,3,4), \pq\Result::FETCH_OBJECT);
                                        $cache->set("$table#relations", $this->references);
                                }
                        );
index 00dbbbb6c9c2eb806a877e3177adb1036d05ed54..6a738d3b4e54dae0f58be6d3f8141c57809e101b 100644 (file)
@@ -90,7 +90,6 @@ class RowTest extends \PHPUnit_Framework_TestCase {
        function testOptimisticLockFail() {
                $this->table->setLock(new Table\OptimisticLock("counter"));
                $row = $this->table->find(null, null, 1)->current();
-               $cnt = $row->counter->get();
                $row->data = "foo";
                executeInConcurrentTransaction(
                        $this->table->getQueryExecutor(), 
@@ -103,7 +102,7 @@ class RowTest extends \PHPUnit_Framework_TestCase {
        function testRef() {
                foreach ($this->table->find() as $row) {
                        foreach ($row->reftest() as $ref) {
-                               $this->assertEquals($row->id->get(), $ref->test->id->get());
+                               $this->assertEquals($row->id->get(), $ref->test->current()->id->get());
                        }
                }
        }
index e1b66870c706fe1e9f7518e1bef1ed8722c2435e..f3d955819c4e25ba6eeecf35c6e3064aa3431cf7 100644 (file)
@@ -84,4 +84,17 @@ class TableTest extends \PHPUnit_Framework_TestCase {
                $this->table->delete(array("id!=" => 0));
                $this->assertCount(0, $this->table->find());
        }
+       
+       public function testWith() {
+               $relation = $this->table->getRelations("test")->reftest;
+               $rowset = $this->table->with([$relation], array("another_test_id=" => 2));
+               $this->assertCount(1, $rowset);
+               $this->assertEquals(array(
+                       "id" => 2,
+                       "created" => date_create("today")->format("Y-m-d H:i:s"),
+                       "counter" => 0,
+                       "number" => 0,
+                       "data" => "today"
+               ), $rowset->current()->getData());
+       }
 }
index bec6c718515da035756d829d47f00b548e065a2b..38dff5a3202f8000bab1758803696d6c235127b4 100644 (file)
@@ -74,12 +74,7 @@ class QueryLogger implements \SplObserver
                if (isset($result)) {
                        fprintf($this->fp, "[%s] R %s\n", 
                                date_create()->format("Y-m-d H:i:s"),
-                               json_encode([
-                                       "S" => $result->statusMessage, 
-                                       "N" => $result->numRows, 
-                                       "C" => $result->numCols,
-                                       "A" => $result->affectedRows
-                               ]));
+                               json_encode($result));
                } elseif (($query = $executor->getQuery())) {
                        fprintf($this->fp, "[%s] Q %s %% %s\n", 
                                date_create()->format("Y-m-d H:i:s"),