Search code examples
phpdoctrine-ormdoctrine-query

Doctrine Format result to a Array Of strings


Over my repository I have the following method:

  /**
  * List and Seatch for existing emails
  * @param Integer $page The pagination page
  * @param Integet $limit The page limit
  * @return String[]
  */
  public function getEmailListInOrderToSendEmail()
  {
    $em=$this->getEntityManager();

    $queryBuilder = $em->createQueryBuilder();
    $queryBuilder->select('c.email')->from(ContactEmail::class,'c');

    $value=$queryBuilder->getQuery()->getScalarResult();

    if(empty($value)){
      return [];
    }

    return $value;
  }

A custom example of the returned type that I want to get returned is the following:

["ddesyllas@gmail.com","contact@papaioannou.com"]

But Instead the following result is returned:

[['email'=>"ddesyllas@gmail.com"],["name"=>"contact@papaioannou.com"]]

So a Naive approach is to iterate over the results with a loop and unfold it:

$newResults=[];
foreach($results as $result){
 $newResults[]=$result['email'];
}

But seems way to inefficient to me. Is there a way to format the returned query data on the way that being fetched without the need to do the loop?

The reason I am asking is because the result set may become rather big and iterating over a big array seems a bit slow (for example in a batch process via cli using a symfony command).


Solution

  • You should create your own Hydrator as :

    namespace AppBundle\Hydrators;
    
    use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
    
    class ColumnHydrator extends AbstractHydrator
    {
        protected function hydrateAllData()
        {
            return $this->_stmt->fetchAll(\PDO::FETCH_COLUMN);
        }
    }
    

    And load it on entity Manager when you need to load the data as an array:

    //Namepsace Definitions etc etc
    use AppBundle\Hydrators\ColumnHydrator;
    
    //Class definition
    
     /**
      * List and Search for existing emails
      * @param Integer $page The pagination page
      * @param Integer $limit The page limit
      * @return String[]
      */
      public function getEmailListInOrderToSendEmail()
      {
        $em=$this->getEntityManager();
        $em->getConfiguration()->addCustomHydrationMode('ColumnHydrator', ColumnHydrator::class);
    
        $queryBuilder = $em->createQueryBuilder();
        $queryBuilder->select('c.email')->from(ContactEmail::class,'c');
    
        $value=$queryBuilder->getQuery()->getResult('ColumnHydrator');
    
        if(empty($value)){
          return [];
        }
    
        return $value;
      }
    

    As you can see:

    1. You load the hydrator via $em->getConfiguration()->addCustomHydrationMode('ColumnHydrator', ColumnHydrator::class);

    2. Instead of fetching the results with getScalarResult fetch it with a simple getResult and pass as parameter the custom Hydrator.