Skip to content
This repository has been archived by the owner on Sep 20, 2021. It is now read-only.

Commit

Permalink
DAL: Introduce iterators over result sets!
Browse files Browse the repository at this point in the history
Now we can iterate over result sets with a `foreach` loop in a very
straightforward way. Simply do this:

    foreach ($statement as $result) {
        // …
    }

The iterator behavior is defined by the fetching style, i.e. the way
data are fetched by the database statement. By default, fetching style
is set to: `FROM_START`, `FORWARD` and `AS_MAP`, i.e. the expected
default behavior. Actually, the fetching style is defined by:

  * An offset: `FROM_START` or `FROM_END`,
  * A direction: `FORWARD` or `BACKWARD`,
  * And a result “type”/style: `AS_MAP`, `AS_SET`, `AS_OBJECT`,
    `AS_CLASS`, `AS_LAZY_OBJECT`,  `AS_REUSABLE_OBJECT` or
    `AS_DEBUG_MAP`.

Please, read the detailed API documentation to understand these
constants, but most of them are self-describing.

Why is this feature **very** important and cool? Because it can be
combined with the `Hoa\Iterator` library. Thus, it is possible to use
the `Hoa\Iterator\Lookahead` iterator with a database iterator to look
ahead of one result, or `Hoa\Iterator\Lookbehind` to have a “cache”/to
look behind of one result. This is also possible to use
`Hoa\Iterator\Buffer`, `Hoa\Iterator\Append` or
`Hoa\Iterator\Demultiplexer` to respectively bufferizing the
results, to have an union of results or to demuxe results.

Anyway… Possibilities are numerous and exciting!
  • Loading branch information
Hywan committed Feb 8, 2016
2 parents 6db1e87 + 91d1d6c commit eaa00b1
Show file tree
Hide file tree
Showing 7 changed files with 529 additions and 70 deletions.
195 changes: 176 additions & 19 deletions DalStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,142 @@
*/
class DalStatement
{
/**
* Start at the first offset.
*
* @var int
*/
const FROM_START = 0;

/**
* Start at the last offset.
*
* @var int
*/
const FROM_END = -1;

/**
* Fetch the next row in the result set.
*
* @var int
*/
const FORWARD = 0;

/**
* Fetch the previous row in the result set.
*
* @var int
*/
const BACKWARD = 1;

/**
* Specifies that the fetch method shall return each row as an object with
* variable names that correspond to the column names returned in the result
* set. `AS_LAZY_OBJECT` creates the object variable names as they are
* accessed.
*
* @var int
*/
const AS_LAZY_OBJECT = 1;

/**
* Specifies that the fetch method shall return each row as an array indexed
* by column name as returned in the corresponding result set. If the result
* set contains multiple columns with the same name, `AS_MAP` returns only a
* single value per column name.
*
* @var int
*/
const AS_MAP = 2;

/**
* Specifies that the fetch method shall return each row as an array indexed
* by column number as returned in the corresponding result set, starting at
* column 0.
*
* @var int
*/
const AS_SET = 3;

/**
* Specifies that the fetch method shall return each row as an object with
* property names that correspond to the column names returned in the result
* set.
*
* @var int
*/
const AS_OBJECT = 5;

/**
* Specifies that the fetch method shall return a new instance of the
* requested class, mapping the columns to named properties in the class.
* The magic `__set` method is called if the property doesn't exist in the
* requested class.
*
* @var int
*/
const AS_CLASS = 8;

/**
* Specifies that the fetch method shall update an existing instance of the
* requested class, mapping the columns to named properties in the class.
*
* @var int
*/
const AS_REUSABLE_OBJECT = 9;

/**
* Specifies that the fetch method shall return each row as an array indexed
* by column name as returned in the corresponding result set. If the result
* set contains multiple columns with the same name, `AS_DEBUG_MAP` returns
* an array of values per column name.
*
* @var int
*/
const AS_DEBUG_MAP = 11;

/**
* The start cursor offset.
*
* @var int
*/
const STYLE_OFFSET = 0;

/**
* The cursor orientation.
*
* @var int
*/
const STYLE_ORIENTATION = 1;

/**
* The fetching style.
*
* @var int
*/
const STYLE_MODE = 2;

/**
* The class name for `AS_CLASS`.
*
* @var int
*/
const STYLE_CLASS_NAME = 3;

/**
* The constructor arguments for `AS_CLASS`.
*
* @var int
*/
const STYLE_CONSTRUCTOR_ARGUMENTS = 4;

/**
* The reused object for `AS_REUSABLE_OBJECT`.
*
* @var int
*/
const STYLE_OBJECT = 5;

/**
* The statement instance.
*
Expand Down Expand Up @@ -161,47 +297,68 @@ public function fetchAll()
}

/**
* Fetch the first row in the result set.
* Set the iterator fetching style.
*
* @return mixed
* @throws \Hoa\Database\Exception
* @param int $offset This value must be one of the
* DalStatement::FROM_* constants or an
* arbitrary offset.
* @param int $orientation This value must be DalStatement::FORWARD
* or DalStatement::BACKWARD constant.
* @param int $style This value must be one of the
* DalStatement::AS_* constants.
* @param mixed $arg1 For AS_CLASS: The class name.
* For AS_REUSABLE_OBJECT: An object.
* @param array $arg2 For AS_CLASS: Constructor arguments.
* @return \Hoa\Database\DalStatement
*/
public function fetchFirst()
{
return $this->getStatement()->fetchFirst();
public function setFetchingStyle(
$offset = self::FROM_START,
$orientation = self::FORWARD,
$style = self::AS_MAP,
$arg1 = null,
$arg2 = null
) {
$this->getStatement()->setFetchingStyle(
$offset,
$orientation,
$style,
$arg1,
$arg2
);

return $this;
}

/**
* Fetch the last row in the result set.
* Get an Iterator.
*
* @return mixed
* @throws \Hoa\Database\Exception
* @return \Hoa\Database\IDal\WrapperIterator
*/
public function fetchLast()
public function getIterator()
{
return $this->getStatement()->fetchLast();
return $this->getStatement()->getIterator();
}

/**
* Fetch the next row in the result set.
* Fetch the first row in the result set.
*
* @param int $style Must be one of the DalStatement::AS_* constants.
* @return mixed
* @throws \Hoa\Database\Exception
*/
public function fetchNext()
public function fetchFirst($style = null)
{
return $this->getStatement()->fetchNext();
return $this->getStatement()->fetchFirst($style);
}

/**
* Fetch the previous row in the result set.
* Fetch the last row in the result set.
*
* @param int $style Must be one of the DalStatement::AS_* constants.
* @return mixed
* @throws \Hoa\Database\Exception
*/
public function fetchPrior()
public function fetchLast($style = null)
{
return $this->getStatement()->fetchPrior();
return $this->getStatement()->fetchLast($style);
}

/**
Expand Down
59 changes: 59 additions & 0 deletions IDal/WrapperIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/**
* Hoa
*
*
* @license
*
* New BSD License
*
* Copyright © 2007-2016, Hoa community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Hoa nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

namespace Hoa\Database\IDal;

use Hoa\Iterator;

/**
* Interface \Hoa\Database\IDal\WrapperIterator.
*
* Interface of a DAL iterator statement wrapper.
*
* @copyright Copyright © 2007-2016 Hoa community
* @license New BSD License
*/
interface WrapperIterator extends Iterator\Iterator
{
/**
* Create an iterator instance.
*
* @param object $statement The underlying statement instance.
* @param array $style An array of fetching style options.
* @return void
*/
public function __construct($statement, $style);
}
48 changes: 29 additions & 19 deletions IDal/WrapperStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@

namespace Hoa\Database\IDal;

use Hoa\Database;
use Hoa\Iterator;

/**
* Interface \Hoa\Database\IDal\WrapperStatement.
*
Expand All @@ -44,7 +47,7 @@
* @copyright Copyright © 2007-2016 Hoa community
* @license New BSD License
*/
interface WrapperStatement
interface WrapperStatement extends Iterator\Aggregate
{
/**
* Execute a prepared statement.
Expand Down Expand Up @@ -82,36 +85,43 @@ public function bindParameter(
public function fetchAll();

/**
* Fetch the first row in the result set.
*
* @return mixed
* @throws \Hoa\Database\Exception
*/
public function fetchFirst();

/**
* Fetch the last row in the result set.
* Set the Iterator fetching style.
*
* @return mixed
* @throws \Hoa\Database\Exception
* @param int $offset This value must be one of the
* DalStatement::FROM_* constants or an
* arbitrary offset.
* @param int $orientation This value must be DalStatement::FORWARD
* or DalStatement::BACKWARD constant.
* @param int $style This value must be one of the
* DalStatement::AS_* constants.
* @param mixed $arg1 For AS_CLASS: The Class name.
* For AS_REUSABLE_OBJECT: An object.
* @param array $arg2 For AS_CLASS: Constructor arguments.
* @return \Hoa\Database\IDal\WrapperStatement
*/
public function fetchLast();
public function setFetchingStyle(
$offset = Database\DalStatement::FROM_START,
$orientation = Database\DalStatement::FORWARD,
$style = Database\DalStatement::AS_MAP,
$arg1 = null,
$arg2 = null
);

/**
* Fetch the next row in the result set.
* Fetch the first row in the result set.
*
* @param int $style Must be one of the DalStatement::AS_* constants.
* @return mixed
* @throws \Hoa\Database\Exception
*/
public function fetchNext();
public function fetchFirst($style = null);

/**
* Fetch the previous row in the result set.
* Fetch the last row in the result set.
*
* @param int $style Must be one of the DalStatement::AS_* constants.
* @return mixed
* @throws \Hoa\Database\Exception
*/
public function fetchPrior();
public function fetchLast($style = null);

/**
* Return a single column from the next row of the result set or false if
Expand Down
Loading

0 comments on commit eaa00b1

Please sign in to comment.