5

In my Mapper class I'm extending AbstractDbMapper from ZfcBase to fetch rows from the database. A simple example would be code like this:

class MyMapper extends AbstractDbMapper
{

    //...

    public function fetchAll() {
        $select = $this->getSelect();
        return $this->select($select); // returns HydratingResultSet
    }
}

The problem is that $this->select() returns a Zend\Db\ResultSet\HydratingResultSet (containing the needed and hydrated objects). But I would like to return an array of these objects instead of a HydratingResultSet containing the objects.

The first thing to look at would be HydratingResultSet::toArray() but this returns a multidimensional array instead of an array of objects.

So I chose to do it by hand:

public function fetchAll() {
        $select = $this->getSelect();

        $results = array();
        foreach ($this->select($select) as $object) {
            $results[] = $object;
        }
        return $results; // returns array of needed objects
}

This works but looks ugly in every fetch method. Do I have to modify the code from select() to get the wanted behavior or is there an easier way?

Btw: Is it even recommended to return an array or convert it like this? Thanks for your help!

7
  • Is there a reason you need an array? The Resultset will work as an iterator just fine and can be used in most cases.. There's no built in method to get the array without doing what you are doing now, you could add the method into your Mapper or a just Hydrator as a shortcut. Commented May 16, 2013 at 16:23
  • I'm using these results in my Controller and think it would be cleaner to work with arrays instead of some Zend\Db objects. I don't understand why they chose to do it this way... Commented May 16, 2013 at 17:18
  • 1
    they chose to do it this way because you get extra functionality, such as buffering the result set etc. Think about if you have a collection of 9million objects, you array will become HUGE and consume RAM, with this collection the items are made on demand one at a time, it's much more efficient. Commented May 16, 2013 at 21:14
  • Okay, that sounds reasonable. Thanks a lot, I didn't think of that. It would at least be nice if there was a built in function to retrieve the whole array since that would fit the need of most cases imho. I will add this by hand now. Commented May 19, 2013 at 17:27
  • 1
    It is a Zend internal inconsistency indeed. See this issue: github.com/zendframework/zf2/issues/4635 Commented Jun 12, 2013 at 8:51

2 Answers 2

5

Update:

There is a cleaner possibility to do it (by limos from https://stackoverflow.com/a/19266650/1275778). Adapted to my example from above it works like this:

public function fetchAll() {
    $select = $this->getSelect();
    $results = $this->select($select);
    return \Zend\Stdlib\ArrayUtils::iteratorToArray($results); // returns desired array of objects
}

If limos posts his answer here, I will happily accept it.

Old answer:

Since no one could answer my question I tried to implement the cleanest option (to me): extending AbstractDbMapper to add the mentioned functionality. I document it here for anyone looking for a solution:

MyAbstractDbMapper extends AbstractDbMapper
{
    /**
     * @param Select $select
     * @param object|null $entityPrototype
     * @param HydratorInterface|null $hydrator
     * @return array
     */
    protected function select(Select $select, $entityPrototype = null, 
        HydratorInterface $hydrator = null)
    {
        $resultSet = parent::select($select, $entityPrototype, $hydrator);
        $results = array(); // Array of result objects
        foreach ($resultSet as $object) {
            $results[] = $object;
        }
        return $results;
    }
}

select() in MyAbstractDbMapper now returns an array of objects instead of HydratingResultSet.

As this is getting downvoted, could someone please explain why?

Sign up to request clarification or add additional context in comments.

1 Comment

Better explanation and code example here: stackoverflow.com/questions/18940759/…
1

usually you've already got the object class anyway so just popupate instances of your object (class):

public function fetchById($id) {

    [...]

    $resultSet = $this->getDbTable()->fetchAll($select);
    $entries   = array();

    foreach ($resultSet as $row) {
        $entries[] = $this->populate($row);
    }

    return $entries;
}

and the populate function could look something like this:

private function populate($row)
{
    $entry = new Application_Model_YourModel();

    $entry->setId($row->id);

    [...] //set other object values

    return $entry;
}

This will return an array of objects

3 Comments

The objects in my loop are already of the needed type as HydratedResultSet provides an iterator to loop over the hydrated objects. So these are NOT row objects and have already been hydrated in the AbstractDbMapper. Therefore there is no need for a populate function and no need to use fetchAll as $this->select() is fetching the results.
Okay. which version of zend are you using? Does toArray() fulfill your needs? tgaconnect.com/dox/zend/html/…
I'm using ZF 2.2. No, toArray() returns a multidimensional array and thus contains no objects at all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.