简体   繁体   中英

Doctrine hydrated array result

I want to get Doctrine to return a hydrated array with the values being the id for the key, then all values inside an array of results (ie if there are multiple items with same ID, then return ID with multiple results in array).

This is the current function I do:

    public static function getMedia($em, $entity, $id = NULL)
    {
        $dql = 'SELECT m.id, m.url, m.nb, m.lang
            FROM iMT\Entity\Media m INDEX BY m.id JOIN iMT\Entity\\' . $entity . ' r WITH m.id = r.id';

        if($id) {
            $dql .= " WHERE r.id = ?1";
        }

        $q = $em->createQuery($dql);

        if($id) {
            $q->setParameter(1, $id);
        }

        return $q->getResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);
    }

Which returns:

array (size=44)
  479600 => 
    array (size=4)
      'id' => int 479600
      'url' => string 'pois/479600/Nonna.JPG' (length=48)
      'nb' => null
      'lang' => string 'fr' (length=2)
  479615 => 
    array (size=4)
      'id' => int 479615
      'url' => string 'pois/479615/Tramways.jpg' (length=51)
      'nb' => null
      'lang' => string 'fr' (length=2)
  479580 => 
    array (size=4)
      'id' => int 479580
      'url' => string 'pois/479580/ATLAS.jpg' (length=48)
      'nb' => null
      'lang' => string 'fr' (length=2)
  479581 => 
    array (size=4)
      'id' => int 479581
      'url' => string 'pois/479581/P'tit_sushi.jpg' (length=54)
      'nb' => null
      'lang' => string 'fr' (length=2)

However, I need the output to be:

array (size=44)
  479600 => 
    array (size=2)
        array (size=4)
          'id' => int 479600
          'url' => string 'pois/479600/Nonna.JPG' (length=48)
          'nb' => null
          'lang' => string 'fr' (length=2)
        array (size=4)
          'id' => int 479600
          'url' => string 'pois/479600/OtherPic.JPG' (length=48)
          'nb' => null
          'lang' => string 'fr' (length=2)

Would I need to create my own AbstractQuery::HYDRATE_ARRAY or is there something available that does what I need?

I'm using the result by checking if it contains a key that matches the ID of the current item (eg if(isset($data[$item])) // where $item = 479600 then output images), maybe there's a better way to check for the results?

EDIT
I've updated my function to return:

    $result = $q->getResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);

    $data = array();
    $count = count($result);
    for($i = 0; $i < $count; $i++) {
        if(!isset($data[$result[$i]['id']])) {
            $data[$result[$i]['id']] = array(
                    $result[$i]
                );
        } else {
            $data[$result[$i]['id']][] = $result[$i];
        }
    }

    return $data;

Which returns something more to what I want:

array (size=44)
  479600 => 
    array (size=1)
      0 => 
        array (size=4)
          'id' => int 479600
          'url' => string 'pois/479600/Nonna.JPG' (length=48)
          'nb' => null
          'lang' => string 'fr' (length=2)
  479577 => 
    array (size=2)
      0 => 
        array (size=4)
          'id' => int 479577
          'url' => string 'pois/479577/AOMC.JPG' (length=47)
          'nb' => null
          'lang' => string 'fr' (length=2)
      1 => 
        array (size=4)
          'id' => int 479577
          'url' => string 'pois/479577/Buffet AOMC.jpg' (length=54)
          'nb' => null
          'lang' => string 'fr' (length=2)

Can this be improved? Is there any Doctrine functions that can help, or should I leave my for() loop?

The problem with using INDEX BY together with a JOIN is that the result that doctrine gives you might not contain all data that's fetched from the database.

In your case the database might return multiple rows containing the same value for m.id (because of the JOIN ). But each subsequent row containing the same value for m.id will overwrite the previous one (because of the INDEX BY m.id ).

Doctrine does not come with a hydrator that can solve this problem out of the box. You shall indeed need to implement your own. Read more about creating custom hydration modes .

Alternative

Another solution would be to not use INDEX BY in this case.

You could write a repository method that translates the result given by Doctrine to the array you want to have. Other parts of your application can then call that repository method.

This is probably easier than creating a custom hydration mode.

Update

The translation can look like this:

$data = array();

foreach ($q->getArrayResult() as $row) {
    if (!isset($data[$row['id']])) {
        $data[$row['id']] = array();
    }

    $data[$row['id']][] = $row;
}

return $data;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM