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

Fixes #6812 : Zend\Paginator\Adapter\DbSelect::getItems should return array #6817

Conversation

samsonasik
Copy link
Contributor

Fixes #6812

$items[] = $result;
}

return $items;
}

Choose a reason for hiding this comment

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

Shouldn't you avoid to init the result set object at all, and use statement's result directly to fill the final array?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no

@Pittiplatsch
Copy link

Changing returned data from ResultSet to array is a BC.
Because old unit tests explicitly tested for ResultSet, it seems to have been a conscious decision rather than a bug to not return a plain array.
Note however that PHPDoc of old getItems() seems to be erroneous when stating @return array.

@samsonasik
Copy link
Contributor Author

should the changed place is in Zend\Paginator\Paginator::getItem() instead ?

@Martin-P
Copy link
Contributor

Martin-P commented Nov 2, 2014

There is no need for any BC break and changing of tests. Updating Zend\Paginator\Paginator::getItemsByPage() to detect AbstractResultset is enough to fix the issue. That method already has an if clause to detect if $items is not an instance of Traversable:

if (!$items instanceof Traversable) {
    $items = new ArrayIterator($items);
}

If you prepend an if clause to detect if $items is an instance of AbstractResultSet, the issue is fixed:

if ($items instanceof AbstractResultSet) {
    $temp = array();
    foreach ($items as $key => $value) {
        $temp[$key] = $value;
    }

    $items = $temp;
    unset($temp);
}

The complete code of Zend\Paginator\Paginator::getItemsByPage() would be as follows:

/**
 * Returns the items for a given page.
 *
 * @param int $pageNumber
 * @return mixed
 */
public function getItemsByPage($pageNumber)
{
    $pageNumber = $this->normalizePageNumber($pageNumber);

    if ($this->cacheEnabled()) {
        $data = static::$cache->getItem($this->_getCacheId($pageNumber));
        if ($data) {
            return $data;
        }
    }

    $offset = ($pageNumber - 1) * $this->getItemCountPerPage();

    $items = $this->adapter->getItems($offset, $this->getItemCountPerPage());

    $filter = $this->getFilter();

    if ($filter !== null) {
        $items = $filter->filter($items);
    }

    if ($items instanceof AbstractResultSet) {
        $temp = array();
        foreach ($items as $key => $value) {
            $temp[$key] = $value;
        }

        $items = $temp;
        unset($temp);
    }

    if (!$items instanceof Traversable) {
        $items = new ArrayIterator($items);
    }

    if ($this->cacheEnabled()) {
        $cacheId = $this->_getCacheId($pageNumber);
        static::$cache->setItem($cacheId, $items);
        static::$cache->setTags($cacheId, array($this->_getCacheInternalId()));
    }

    return $items;
}

@samsonasik samsonasik changed the title Fixes #6812 : Zend\Paginator\Adapter\DbSelect::getItems should return array Fixes #6812 : change Paginator::getItemsByPage($pageNumber) handle AbstractResultSet Nov 2, 2014
@samsonasik
Copy link
Contributor Author

@Martin-P done ;). updated.

samsonasik added a commit to samsonasik/zf2 that referenced this pull request Nov 16, 2014
@samsonasik
Copy link
Contributor Author

I've added unit test for it.

@@ -74,7 +74,7 @@ public function __construct(Select $select, $adapterOrSqlObject, ResultSetInterf
*
* @param int $offset Page offset
* @param int $itemCountPerPage Number of items per page
* @return array
* @return ResultSetInterface
Copy link
Member

Choose a reason for hiding this comment

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

The AdapterInterface#getItems() defined return type is array, and it cannot be changed here.

Copy link
Contributor

Choose a reason for hiding this comment

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

DbSelect::getItems() never returned an array but always returned a ResultSet. The docs were wrong from the beginning.

See the current master: Zend\Paginator\Adapter\DbSelect line 90

Copy link
Member

Choose a reason for hiding this comment

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

I'd say it is a bug in DbSelect then, since it does not respect the interface specification.

@samsonasik
Copy link
Contributor Author

@Ocramius Ok, I've updated back to @return array and DbSelect::getItems() logic instead to get return array.


$items = array();
foreach($resultSet as $key => $value) {
$items[$key] = $value;
Copy link
Contributor

Choose a reason for hiding this comment

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

Urk, this would be a perfect use-case of generators

@samsonasik samsonasik changed the title Fixes #6812 : change Paginator::getItemsByPage($pageNumber) handle AbstractResultSet Fixes #6812 : Zend\Paginator\Adapter\DbSelect::getItems should return array Nov 24, 2014
@samsonasik samsonasik force-pushed the hotfix/paginator-adapter-getitems branch from 5402f21 to 8a3721b Compare November 29, 2014 00:57
samsonasik added a commit to samsonasik/zf2 that referenced this pull request Nov 29, 2014
@samsonasik
Copy link
Contributor Author

updated loop resultset with ArrayUtils::iteratorToArray($resultSet);

@@ -86,8 +87,8 @@ public function getItems($offset, $itemCountPerPage)

$resultSet = clone $this->resultSetPrototype;
$resultSet->initialize($result);

return $resultSet;

Copy link
Member

Choose a reason for hiding this comment

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

Trailing whitespace here

@samsonasik
Copy link
Contributor Author

@Ocramius done, trailing_spaces should be fixed and @group added.

@samsonasik
Copy link
Contributor Author

if it is accepted, then zf2-documentation need to be updated for Album tutorial on loop as $album as object to $album as array.
before

 <?php foreach ($this->paginator as $album) : ?>
         <tr>
             <td><?php echo $this->escapeHtml($album->title);?></td>
              <!-- // ... 
        </tr>    
<?php endforeach; ?>

After

 <?php foreach ($this->paginator as $album) : ?>
         <tr>
             <td><?php echo $this->escapeHtml($album['title']);?></td>
              <!-- // ... 
        </tr>    
<?php endforeach; ?>

@Ocramius should I ?

@Ocramius
Copy link
Member

Ocramius commented Dec 4, 2014

@samsonasik I think ArrayUtils::iteratorToArray() is recursive, while iterator_to_array() is not. We may want to use iterator_to_array() only here.

@samsonasik samsonasik force-pushed the hotfix/paginator-adapter-getitems branch from eb17223 to 1cbd255 Compare December 4, 2014 10:48
@samsonasik
Copy link
Contributor Author

@Ocramius done, I have changed to iterator_to_array()

@Ocramius
Copy link
Member

Ocramius commented Dec 4, 2014

@samsonasik the last change needs a test along the lines of (pseudo-code):

$resultset = new Resultset([new ArrayObject(['foo' => 'bar']), new ArrayObject(['foo' => 'bar'])]);

// ... 

foreach ($paginator as $item) {
    $this->assertInstanceOf('ArrayObject', $item);
}

This should prevent a regression, as it will fail with the previous ArrayUtils::iteratorToArray() approach

@Ocramius Ocramius self-assigned this Dec 4, 2014
@Ocramius Ocramius modified the milestones: 2.3.4, 2.4.0 Dec 4, 2014
@samsonasik
Copy link
Contributor Author

@Ocramius I can't reproduce it directly, but I've updated so it looks like :

$paginator = new Paginator\Paginator($dbSelect);
$this->assertInstanceOf('ArrayIterator', $paginator->getItemsByPage(1));

and to proof that the paginator items instanceof ArrayObject, I did pass $resultSet->getDatasource() to Iterator adapter:

$paginator = new Paginator\Paginator(new Paginator\Adapter\Iterator($resultSet->getDataSource()));
foreach($paginator as $item) {
     $this->assertInstanceOf('ArrayObject', $item);
 }

please let me know I need to do something, thanks ;)

@Ocramius
Copy link
Member

Ocramius commented Dec 4, 2014

@samsonasik that seems to work

Ocramius pushed a commit that referenced this pull request Dec 5, 2014
Ocramius added a commit that referenced this pull request Dec 5, 2014
Ocramius added a commit that referenced this pull request Dec 5, 2014
Ocramius added a commit that referenced this pull request Dec 5, 2014
Ocramius added a commit that referenced this pull request Dec 5, 2014
Ocramius added a commit that referenced this pull request Dec 5, 2014
Ocramius added a commit that referenced this pull request Dec 5, 2014
@Ocramius
Copy link
Member

Ocramius commented Dec 5, 2014

@samsonasik merged, thanks!

develop: 9f1aeb9

@Ocramius Ocramius closed this Dec 5, 2014
gianarb pushed a commit to zendframework/zend-paginator that referenced this pull request May 15, 2015
gianarb pushed a commit to zendframework/zend-paginator that referenced this pull request May 15, 2015
gianarb pushed a commit to zendframework/zend-paginator that referenced this pull request May 15, 2015
gianarb pushed a commit to zendframework/zend-paginator that referenced this pull request May 15, 2015
gianarb pushed a commit to zendframework/zend-paginator that referenced this pull request May 15, 2015
…DbSelect#getItems()` should return `array` types
gianarb pushed a commit to zendframework/zend-paginator that referenced this pull request May 15, 2015
…ixed `@group` annotations to comply with `DbSelectTest` ones
gianarb pushed a commit to zendframework/zend-paginator that referenced this pull request May 15, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Zend\Paginator\Paginator's getItem() trigger an "Fatal error: ..."
5 participants