Skip to content

Commit

Permalink
row: added support for indexed array access [closes #33]
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Feb 13, 2016
1 parent 3a0cda6 commit 1eb2fee
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 8 deletions.
1 change: 1 addition & 0 deletions doc/menu.texy
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
- [Connection | default]
- [Param Placeholders | param-placeholders]
- [Result | result]
- [Query Builder | query-builder]
- [DateTime TimeZones | datetime]

Expand Down
54 changes: 54 additions & 0 deletions doc/result.texy
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Result
######

Connection::query() methods returns `Nextras\Dbal\Result\Result` instance. You can call fetching methods to get the fetched data.

- `Result::fetchAll()` returns array of `Nextras\Dbal\Result\Row` instances.
- `Result::fetch()` returns the next unfetched `Row` instance.
- `Result::fetchField($column)` returns nth column of the next unfetched `Row` instance.
- `Result::fetchPairs($key, $value)` allows to transform all fetcher `Row` instances into associative array.

/--php
$result = $connection->query('SELECT ...');
foreach ($result as $row) { // equals to $result->fetchAll() as $row
}


$result = $connection->query('SELECT ...');
$row = $result->fetch();


$result = $connection->query('SELECT name FROM ...');
$name = $result->fetchField();


$result = $connection->query('SELECT name, age FROM ...');
$assoc = $result->fetchPairs('name', 'age');
// ['peter' => 20, 'john' => 13]

$assoc = $result->fetchPairs(null, 'age');
// [20, 13]

$assoc = $result->fetchPairs('name', null);
// [
// 'peter' => ['name' => 'peter', 'age' => 20],
// 'john' => ['name' => 'john', 'age' => 13],
// ]
\--


Row
===

Row instances holds the data of specific fetched result-row. You can access data by property access and the column name. Optionally, you can use array access for the indexed read.

/--php
$row = $connection->query('SELECT name, age FROM ...')->fetch();

echo $row->name;
echo $row->age;

echo $row[0]; // prints name
isset($row[1]) // true
isset($row[2]) // false
\--
7 changes: 3 additions & 4 deletions src/Result/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,13 @@ public function fetch()


/**
* @param int $column
* @return mixed|NULL
*/
public function fetchField()
public function fetchField($column = 0)
{
if ($row = $this->fetch()) { // = intentionally
foreach ($row as $value) {
return $value;
}
return $row[$column];
}

return NULL;
Expand Down
40 changes: 39 additions & 1 deletion src/Result/Row.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@

namespace Nextras\Dbal\Result;

use ArrayAccess;
use Nextras\Dbal\InvalidArgumentException;
use Nextras\Dbal\NotSupportedException;
use Nextras\Dbal\Utils\Typos;


class Row
class Row implements ArrayAccess
{
/**
* @param array $data
Expand Down Expand Up @@ -43,4 +45,40 @@ public function __get($name)
$closest = Typos::getClosest($name, array_keys($this->toArray()), 3);
throw new InvalidArgumentException("Column '$name' does not exist" . ($closest ? ", did you mean '$closest'?" : "."));
}


public function offsetExists($offset)
{
if (!is_int($offset)) {
throw new NotSupportedException('Array access is suported only for indexed reading. Use property access.');
}

return $offset >= 0 && $offset < count((array) $this);
}


public function offsetGet($offset)
{
if (!is_int($offset)) {
throw new NotSupportedException('Array access is suported only for indexed reading. Use property access.');
}

$slice = array_slice((array) $this, $offset, 1);
if (!$slice) {
throw new InvalidArgumentException("Column '$offset' does not exist.");
}
return current($slice);
}


public function offsetSet($offset, $value)
{
throw new NotSupportedException('Array access is suported only for indexed reading. Use property access.');
}


public function offsetUnset($offset)
{
throw new NotSupportedException('Array access is suported only for indexed reading. Use property access.');
}
}
6 changes: 5 additions & 1 deletion tests/cases/unit/ResultTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,17 @@ class ResultTest extends TestCase
{
$adapter = Mockery::mock(IResultAdapter::class);
$adapter->shouldReceive('getTypes')->once()->andReturn([]);
$adapter->shouldReceive('fetch')->once()->andReturn(['name' => 'First', 'surname' => 'Two']);
$adapter->shouldReceive('fetch')->times(3)->andReturn(['name' => 'First', 'surname' => 'Two']);

$driver = Mockery::mock(IDriver::class);

$result = new Result($adapter, $driver, 0);
$result->setValueNormalization(FALSE);
Assert::same('First', $result->fetchField());
Assert::same('Two', $result->fetchField(1));
Assert::throws(function () use ($result) {
$result->fetchField(2);
}, InvalidArgumentException::class);


$adapter = Mockery::mock(IResultAdapter::class);
Expand Down
36 changes: 34 additions & 2 deletions tests/cases/unit/RowTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace NextrasTests\Dbal;

use Nextras\Dbal\InvalidArgumentException;
use Nextras\Dbal\NotSupportedException;
use Nextras\Dbal\Result\Row;
use Tester\Assert;

Expand All @@ -13,7 +14,6 @@ require_once __DIR__ . '/../../bootstrap.php';

class RowTest extends TestCase
{

public function testPropertyAccess()
{
$row = new Row(['name' => 'Jon', 'surname' => 'Snow']);
Expand All @@ -34,12 +34,44 @@ class RowTest extends TestCase
}


public function testArrayAccess()
{
$row = new Row(['name' => 'Jon', 'surname' => 'Snow']);
Assert::same('Jon', $row[0]);
Assert::same('Snow', $row[1]);
Assert::true(isset($row[0]));
Assert::true(isset($row[1]));

Assert::false(isset($row[2]));
Assert::false(isset($row[-1]));

Assert::throws(function () use ($row) {
$row[2];
}, InvalidArgumentException::class);

Assert::throws(function () use ($row) {
$row['name'];
}, NotSupportedException::class);

Assert::throws(function () use ($row) {
isset($row['name']);
}, NotSupportedException::class);

Assert::throws(function () use ($row) {
unset($row['name']);
}, NotSupportedException::class);

Assert::throws(function () use ($row) {
$row['name'] = 'bar';
}, NotSupportedException::class);
}


public function testToArray()
{
$row = new Row(['name' => 'Jon', 'surname' => 'Snow']);
Assert::same(['name' => 'Jon', 'surname' => 'Snow'], $row->toArray());
}

}


Expand Down

0 comments on commit 1eb2fee

Please # to comment.