diff --git a/doc/menu.texy b/doc/menu.texy index e73d54df..d3dfd780 100644 --- a/doc/menu.texy +++ b/doc/menu.texy @@ -1,5 +1,6 @@ - [Connection | default] - [Param Placeholders | param-placeholders] +- [Result | result] - [Query Builder | query-builder] - [DateTime TimeZones | datetime] diff --git a/doc/result.texy b/doc/result.texy new file mode 100644 index 00000000..94c485d6 --- /dev/null +++ b/doc/result.texy @@ -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 +\-- diff --git a/src/Result/Result.php b/src/Result/Result.php index c284fe54..b41ce7d4 100644 --- a/src/Result/Result.php +++ b/src/Result/Result.php @@ -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; diff --git a/src/Result/Row.php b/src/Result/Row.php index d844f3f3..8170ffad 100644 --- a/src/Result/Row.php +++ b/src/Result/Row.php @@ -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 @@ -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.'); + } } diff --git a/tests/cases/unit/ResultTest.phpt b/tests/cases/unit/ResultTest.phpt index 22628aab..0fd032f5 100644 --- a/tests/cases/unit/ResultTest.phpt +++ b/tests/cases/unit/ResultTest.phpt @@ -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); diff --git a/tests/cases/unit/RowTest.phpt b/tests/cases/unit/RowTest.phpt index 6a9d4d3d..d7c66b66 100644 --- a/tests/cases/unit/RowTest.phpt +++ b/tests/cases/unit/RowTest.phpt @@ -5,6 +5,7 @@ namespace NextrasTests\Dbal; use Nextras\Dbal\InvalidArgumentException; +use Nextras\Dbal\NotSupportedException; use Nextras\Dbal\Result\Row; use Tester\Assert; @@ -13,7 +14,6 @@ require_once __DIR__ . '/../../bootstrap.php'; class RowTest extends TestCase { - public function testPropertyAccess() { $row = new Row(['name' => 'Jon', 'surname' => 'Snow']); @@ -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()); } - }