Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Zend\Db\Resultset fix buffering #5308

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 68 additions & 51 deletions library/Zend/Db/ResultSet/AbstractResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
namespace Zend\Db\ResultSet;

use ArrayIterator;
use ArrayObject;
use Countable;
use Iterator;
use IteratorAggregate;
Expand Down Expand Up @@ -48,6 +47,11 @@ abstract class AbstractResultSet implements Iterator, ResultSetInterface
*/
protected $position = 0;

/**
* @var mixed
*/
protected $current = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= null is not needed


/**
* Set the data source for the result set
*
Expand All @@ -62,6 +66,10 @@ public function initialize($dataSource)
$this->buffer = array();
}

$this->count = null;
$this->fieldCount = null;
$this->current = null;

if ($dataSource instanceof ResultInterface) {
$this->count = $dataSource->count();
$this->fieldCount = $dataSource->getFieldCount();
Expand All @@ -73,9 +81,7 @@ public function initialize($dataSource)
$this->dataSource->rewind();
}
return $this;
}

if (is_array($dataSource)) {
} elseif (is_array($dataSource)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for this to be turned into elseif?

// its safe to get numbers from an array
$first = current($dataSource);
reset($dataSource);
Expand All @@ -91,10 +97,26 @@ public function initialize($dataSource)
throw new Exception\InvalidArgumentException('DataSource provided is not an array, nor does it implement Iterator or IteratorAggregate');
}

if ($this->count == null && $this->dataSource instanceof Countable) {
if ($this->count === null && $this->dataSource instanceof Countable) {
$this->count = $this->dataSource->count();
}

if ($this->fieldCount === null) {
if ($this->count == 0) {
$this->fieldCount = 0;
} else {
$dataSource->rewind();
$row = $dataSource->current();
if ($row instanceof Countable) {
$this->fieldCount = $row->count();
} else {
$this->fieldCount = count((array)$row);
}
}
} else {
$this->fieldCount = 0;
}

return $this;
}

Expand All @@ -113,10 +135,16 @@ public function buffer()

public function isBuffered()
{
if ($this->buffer === -1 || is_array($this->buffer)) {
return true;
return ($this->buffer === -1 || is_array($this->buffer));
}

protected function checkBuffered()
{
if ($this->buffer === null) {
// implicitly disable buffering from here on
$this->buffer = -2;
}
return false;
return $this;
}

/**
Expand All @@ -136,29 +164,6 @@ public function getDataSource()
*/
public function getFieldCount()
{
if (null !== $this->fieldCount) {
return $this->fieldCount;
}

$dataSource = $this->getDataSource();
if (null === $dataSource) {
return 0;
}

$dataSource->rewind();
if (!$dataSource->valid()) {
$this->fieldCount = 0;
return 0;
}

$row = $dataSource->current();
if (is_object($row) && $row instanceof Countable) {
$this->fieldCount = $row->count();
return $this->fieldCount;
}

$row = (array) $row;
$this->fieldCount = count($row);
return $this->fieldCount;
}

Expand All @@ -169,11 +174,10 @@ public function getFieldCount()
*/
public function next()
{
if ($this->buffer === null) {
$this->buffer = -2; // implicitly disable buffering from here on
}
$this->checkBuffered();
$this->dataSource->next();
$this->position++;
$this->current = null;
}

/**
Expand All @@ -193,14 +197,36 @@ public function key()
*/
public function current()
{
if ($this->buffer === null) {
$this->buffer = -2; // implicitly disable buffering from here on
} elseif (is_array($this->buffer) && isset($this->buffer[$this->position])) {
return $this->buffer[$this->position];
if ($this->current !== null) {
return $this->current;
}
$data = $this->dataSource->current();
$this->checkBuffered();
if (is_array($this->buffer)) {
$this->buffer[$this->position] = $data;
if (!isset($this->buffer[$this->position])) {
return $this->current = $this->buffer[$this->position] = $this->hydrateCurrent();
}
return $this->current = $this->buffer[$this->position];
}
return $this->current = $this->hydrateCurrent();
}

protected function hydrateCurrent()
{
return $this->dataSource->current();
}

protected function extract($data)
{
if (is_array($data)) {
return $data;
} elseif (method_exists($data, 'toArray')) {
return $data->toArray();
} elseif (method_exists($data, 'getArrayCopy')) {
return $data->getArrayCopy();
} else {
throw new Exception\RuntimeException(
'Rows as part of this DataSource, with type ' . gettype($data) . ' cannot be cast to an array'
);
}
return $data;
}
Expand Down Expand Up @@ -238,6 +264,7 @@ public function rewind()
}
}
$this->position = 0;
$this->current = null;
}

/**
Expand All @@ -264,17 +291,7 @@ public function toArray()
{
$return = array();
foreach ($this as $row) {
if (is_array($row)) {
$return[] = $row;
} elseif (method_exists($row, 'toArray')) {
$return[] = $row->toArray();
} elseif (method_exists($row, 'getArrayCopy')) {
$return[] = $row->getArrayCopy();
} else {
throw new Exception\RuntimeException(
'Rows as part of this DataSource, with type ' . gettype($row) . ' cannot be cast to an array'
);
}
$return[] = $this->extract($row);
}
return $return;
}
Expand Down
54 changes: 21 additions & 33 deletions library/Zend/Db/ResultSet/HydratingResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class HydratingResultSet extends AbstractResultSet
public function __construct(HydratorInterface $hydrator = null, $objectPrototype = null)
{
$this->setHydrator(($hydrator) ?: new ArraySerializable);
$this->setObjectPrototype(($objectPrototype) ?: new ArrayObject);
$this->setObjectPrototype($objectPrototype);
}

/**
Expand All @@ -46,7 +46,9 @@ public function __construct(HydratorInterface $hydrator = null, $objectPrototype
*/
public function setObjectPrototype($objectPrototype)
{
if (!is_object($objectPrototype)) {
if (!$objectPrototype) {
$objectPrototype = new ArrayObject;
} elseif (!is_object($objectPrototype)) {
throw new Exception\InvalidArgumentException(
'An object must be set as the object prototype, a ' . gettype($objectPrototype) . ' was provided.'
);
Expand All @@ -55,6 +57,16 @@ public function setObjectPrototype($objectPrototype)
return $this;
}

/**
* Get the row object prototype
*
* @return stdClass
*/
public function getObjectPrototype()
{
return $this->objectPrototype;
}

/**
* Set the hydrator to use for each row object
*
Expand All @@ -77,40 +89,16 @@ public function getHydrator()
return $this->hydrator;
}

/**
* Iterator: get current item
*
* @return object
*/
public function current()
protected function hydrateCurrent()
{
if ($this->buffer === null) {
$this->buffer = -2; // implicitly disable buffering from here on
} elseif (is_array($this->buffer) && isset($this->buffer[$this->position])) {
return $this->buffer[$this->position];
}
$data = $this->dataSource->current();
$object = is_array($data) ? $this->hydrator->hydrate($data, clone $this->objectPrototype) : false;

if (is_array($this->buffer)) {
$this->buffer[$this->position] = $object;
}

return $object;
$current = parent::hydrateCurrent();
return is_array($current)
? $this->hydrator->hydrate($current, clone $this->getObjectPrototype())
: false;
}

/**
* Cast result set to array of arrays
*
* @return array
* @throws Exception\RuntimeException if any row is not castable to an array
*/
public function toArray()
protected function extract($data)
{
$return = array();
foreach ($this as $row) {
$return[] = $this->getHydrator()->extract($row);
}
return $return;
return $this->getHydrator()->extract($data);
}
}
66 changes: 31 additions & 35 deletions library/Zend/Db/ResultSet/ResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,7 @@
class ResultSet extends AbstractResultSet
{
const TYPE_ARRAYOBJECT = 'arrayobject';
const TYPE_ARRAY = 'array';

/**
* Allowed return types
*
* @var array
*/
protected $allowedReturnTypes = array(
self::TYPE_ARRAYOBJECT,
self::TYPE_ARRAY,
);
const TYPE_ARRAY = 'array';

/**
* @var ArrayObject
Expand All @@ -38,17 +28,21 @@ class ResultSet extends AbstractResultSet
*/
protected $returnType = self::TYPE_ARRAYOBJECT;

protected $defaultReturnType = self::TYPE_ARRAYOBJECT;

/**
* Constructor
*
* @param string $returnType
* @param null|ArrayObject $arrayObjectPrototype
* @param null|ArrayObject $arrayObjectPrototype - this parameter id deprecated
*/
public function __construct($returnType = self::TYPE_ARRAYOBJECT, $arrayObjectPrototype = null)
public function __construct($returnType = self::TYPE_ARRAYOBJECT)
{
$this->returnType = (in_array($returnType, array(self::TYPE_ARRAY, self::TYPE_ARRAYOBJECT))) ? $returnType : self::TYPE_ARRAYOBJECT;
if ($this->returnType === self::TYPE_ARRAYOBJECT) {
$this->setArrayObjectPrototype(($arrayObjectPrototype) ?: new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS));
if (func_num_args() == 2 && func_get_arg(1) != null) {
//backward compatibility
$this->setArrayObjectPrototype(func_get_arg(1));
} else {
$this->setArrayObjectPrototype($returnType);
}
}

Expand All @@ -61,13 +55,23 @@ public function __construct($returnType = self::TYPE_ARRAYOBJECT, $arrayObjectPr
*/
public function setArrayObjectPrototype($arrayObjectPrototype)
{
if (!is_object($arrayObjectPrototype)
|| (!$arrayObjectPrototype instanceof ArrayObject && !method_exists($arrayObjectPrototype, 'exchangeArray'))

) {
throw new Exception\InvalidArgumentException('Object must be of type ArrayObject, or at least implement exchangeArray');
if (in_array($arrayObjectPrototype, array(null, self::TYPE_ARRAY, self::TYPE_ARRAYOBJECT), true)) {
$this->returnType = $arrayObjectPrototype ?:$this->defaultReturnType;
if ($this->returnType == self::TYPE_ARRAYOBJECT) {
$this->arrayObjectPrototype = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS);
} else {
$this->arrayObjectPrototype = null;
}
} elseif (is_object($arrayObjectPrototype) && method_exists($arrayObjectPrototype, 'exchangeArray')) {
$this->returnType = self::TYPE_ARRAYOBJECT;
$this->arrayObjectPrototype = $arrayObjectPrototype;
} else {
throw new Exception\InvalidArgumentException(sprintf(
'Object must be of type ArrayObject, or at least implement exchangeArray, or must be %s or $s',
self::TYPE_ARRAYOBJECT,
self::TYPE_ARRAY
));
}
$this->arrayObjectPrototype = $arrayObjectPrototype;
return $this;
}

Expand All @@ -91,22 +95,14 @@ public function getReturnType()
return $this->returnType;
}

/**
* @return array|\ArrayObject|null
*/
public function current()
protected function hydrateCurrent()
{
$data = parent::current();

if ($this->returnType === self::TYPE_ARRAYOBJECT && is_array($data)) {
/** @var $ao ArrayObject */
$current = parent::hydrateCurrent();
if (is_object($this->arrayObjectPrototype) && is_array($current)) {
$ao = clone $this->arrayObjectPrototype;
if ($ao instanceof ArrayObject || method_exists($ao, 'exchangeArray')) {
$ao->exchangeArray($data);
}
$ao->exchangeArray($current);
return $ao;
}

return $data;
return $current;
}
}
Loading