2017-04-07 118 views
1

我有以下问题:学说得到一个DQL查询结果以嵌套形式

我有下面的方法获取船舶的GPS点:

/** 
    * @param array $mmsids 
    * @param unknown $longituteMin 
    * @param unknown $longtitudeMax 
    * @param unknown $latitudeMin 
    * @param unknown $latitudeMax 
    * @param \Datetime $timeInterval 
    * 
    * @throws EmptyParamGivenException 
    * @throws Exception 
    * 
    * @return Vesel[] with their routes 
    */ 
    public function getRoutes(array $mmsids=[], 
            $longituteMin=null, 
            $longtitudeMax=null, 
            $latitudeMin=null, 
            $latitudeMax=null, 
            \DateTime $fromDate=null, 
            \DateTime $toDate=null 
    ) { 
     $em=$this->getEntityManager(); 

     $query=$em->createQueryBuilder('v') 
       ->from('AppBundle:Vesel', 'v') 
       ->innerJoin('v.veselMoveStatuses','m') 
       ->select('v.mmsi,m.logtitude,m.latitude,m.timestamp') 
       ->addOrderBy('v.mmsi','ASC') 
       ->addOrderBy('m.timestamp','DESC'); 

     if(!empty($longituteMin)){ 
      $query->andWhere('m.logtitude >= :long_min')->setParameter(':long_min',$longituteMin); 
     } 

     if(!empty($longtitudeMax)) { 
      $query->andWhere('m.logtitude <= :long_max')->setParameter(':long_max',$longituteMax); 
     } 

     if(!empty($latitudeMin)){ 
         $query->andWhere('m.latitude >= :lat_min')->setParameter(':lat_min',$latitudeMin); 
     } 

     if(!empty($latitudeMax)){ 
         $query->andWhere('m.latitude <= :lat_max')->setParameter(':lat_max',$latitudeMin); 
     } 

     if(!empty($mmsids)){ 
      $query->andWhere('v.mmsi IN (:mmsids)')->setParameter('mmsids', $mmsids,\Doctrine\DBAL\Connection::PARAM_STR_ARRAY); 
     } 

     $paramsToValidate=[RouteInputParameter::PARAM_DATE_FROM=>$fromDate,RouteInputParameter::PARAM_DATE_TO=>$toDate]; 
     if($fromDate!==null && $toDate!==null){ 
      InputValidator::dateRangeValidation($paramsToValidate,RouteInputParameter::PARAM_DATE_FROM,RouteInputParameter::PARAM_DATE_TO); 
      $query->andWhere('m.timestamp BETWEEN :date_min AND :date_max') 
       ->setParameters(['date_min'=>$fromDate,'date_max'=>$toDate]); 
     } else if($fromDate!==null) { 
      $query->andWhere('m.timestamp <= :date_min') 
       ->setParameters(['date_min'=>$fromDate]); 
     } else if($toDate!==null) { 
      $query->where('m.timestamp >= :date_max') 
       ->setParameters(['date_max'=>$toDate]); 
     } 

     $query = $query->getQuery(); 
     return $query->getResult(); 
    } 

我想什么实现这一目标,我想在这样的一个嵌套的方式产生结果:

[ 
    [ 
    "mmsi"=>"^somevalue^" 
    points=>[ 
     "longtitude":"^longtitude_value^", 
     "latitude":"^latitude_value^", 
     "time":"^time_value^" 
    ], 
    .... 
    ], 
    .... 
] 

你有什么想法,如果有一个内部主义机制,允许我这样做,或者我应该实现自己的?

Vessel实体是:

namespace AppBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
* @ORM\Entity 
* @ORM\Table(name="vessel",indexes={ 
* @ORM\Index(name="mmsi",columns={"mmsi"}) 
* }) 
*/ 
class Vesel 
{ 
    /** 
    * @ORM\Column(type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    * @var integer 
    */ 
    private $id; 

    /** 
    * @ORM\Column(type="integer",name="mmsi") 
    * @var integer 
    */ 
    private $mmsi; 

    /** 
    * @ORM\OneToMany(targetEntity="VesselMoveStatus",mappedBy="vesel") 
    * @var \Doctrine\Common\Collections\Collection 
    */ 
    private $veselMoveStatuses; 

    /** 
    * Constructor 
    */ 
    public function __construct($mmsi) 
    { 
     $this->veselMoveStatuses = new \Doctrine\Common\Collections\ArrayCollection(); 
     $this->setMmsi($mmsi); 
    } 

    /** 
    * Get id 
    * 
    * @return integer 
    */ 
    public function getId() 
    { 
     return $this->id; 
    } 

    /** 
    * Set mmsi 
    * 
    * @param integer $mmsi 
    * 
    * @return Vesel 
    */ 
    public function setMmsi($mmsi) 
    { 
     $this->mmsi = $mmsi; 

     return $this; 
    } 

    /** 
    * Get mmsi 
    * 
    * @return integer 
    */ 
    public function getMmsi() 
    { 
     return $this->mmsi; 
    } 

    /** 
    * Add veselMoveStatus 
    * 
    * @param \AppBundle\Entity\VesselMoveStatus $veselMoveStatus 
    * 
    * @return Vesel 
    */ 
    public function addVeselMoveStatus(\AppBundle\Entity\VesselMoveStatus $veselMoveStatus) 
    { 
     $this->veselMoveStatuses[] = $veselMoveStatus; 

     return $this; 
    } 

    /** 
    * Remove veselMoveStatus 
    * 
    * @param \AppBundle\Entity\VesselMoveStatus $veselMoveStatus 
    */ 
    public function removeVeselMoveStatus(\AppBundle\Entity\VesselMoveStatus $veselMoveStatus) 
    { 
     $this->veselMoveStatuses->removeElement($veselMoveStatus); 
    } 

    /** 
    * Get veselMoveStatuses 
    * 
    * @return \Doctrine\Common\Collections\Collection 
    */ 
    public function getVeselMoveStatuses() 
    { 
     return $this->veselMoveStatuses; 
    } 
} 

并涉及到VesselMoveStatus实体:

namespace AppBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use AppBundle\Entity\Vesel; 

/** 
* @ORM\Entity(repositoryClass="AppBundle\Repository\VeselRouteRepository") 
* @ORM\Table(name="vessel_position_status",indexes={ 
* @ORM\Index(name="position",columns={"long","lat"}) 
* }) 
*/ 
class VesselMoveStatus 
{ 
    /** 
    * @ORM\Column(type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id=null; 

    /** 
    * @ORM\ManyToOne(targetEntity="Vesel",inversedBy="veselMoveStatuses") 
    * @ORM\JoinColumn(name="vesel_id", referencedColumnName="id") 
    * @var Vesel 
    */ 
    private $vesel=null; 

    /** 
    * @ORM\Column(name="status",type="integer") 
    * @var integer|null 
    */ 
    private $status=null; 

    /** 
    * @ORM\Column(name="speed",type="integer") 
    * @var integer|null 
    */ 
    private $speed=null; 

    /** 
    * @ORM\Column(name="long",type="float") 
    * @var float|null 
    */ 
    private $logtitude=null; 

    /** 
    * @ORM\Column(name="lat",type="float") 
    * @var float|null 
    */ 
    private $latitude=null; 

    /** 
    * @ORM\Column(name="course",type="integer") 
    * @var integer|null 
    */ 
    private $course=null; 

    /** 
    * @ORM\Column(name="heading",type="integer") 
    * @var integer|null 
    */ 
    private $heading=null; 

    /** 
    * @ORM\Column(name="rotation",type="integer") 
    * @var integer|null 
    */ 
    private $rotation=null; 

    /** 
    * @ORM\Column(name="timestamp",type="datetime") 
    * @var Datetime|null 
    */ 
    private $timestamp=null; 

    public function __construct(
      Vesel $vesel=null, 
      $status=null, 
      $speed=null, 
      $long=null, 
      $lat=null, 
      $course=null, 
      $heading=null, 
      $rotation=null, 
      $timestamp=null 
    ){ 
     $this->setVesel($vesel) 
      ->setStatus($status) 
      ->setSpeed($speed) 
      ->setLogtitude($long) 
      ->setLatitude($lat) 
      ->setCourse($course) 
      ->setHeading($heading) 
      ->setRotation($rotation) 
      ->setTimestamp($timestamp); 
    } 

    /** 
    * Get id 
    * 
    * @return integer 
    */ 
    public function getId() 
    { 
     return $this->id; 
    } 

    /** 
    * Set mmsi 
    * 
    * @param integer $mmsi 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setMmsi($mmsi) 
    { 
     $this->mmsi = $mmsi; 

     return $this; 
    } 

    /** 
    * Get mmsi 
    * 
    * @return integer 
    */ 
    public function getMmsi() 
    { 
     return $this->mmsi; 
    } 

    /** 
    * 
    * @param integer $status 
    * @return \AppBundle\Entity\VesselMoveStatus 
    */ 
    public function setStatus($status) 
    { 
     $this->status=$status; 
     return $this; 
    } 

    /** 
    * 
    * @return \AppBundle\Entity\integer|NULL 
    */ 
    public function getStatus() 
    { 
     return $this->status; 
    } 

    /** 
    * Set speed 
    * 
    * @param integer $speed 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setSpeed($speed) 
    { 
     $this->speed = $speed; 

     return $this; 
    } 

    /** 
    * Get speed 
    * 
    * @return float 
    */ 
    public function getSpeed() 
    { 
     return $this->speed/10; 
    } 

    /** 
    * Set logtitude 
    * 
    * @param integer $logtitude 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setLogtitude($logtitude) 
    { 
     $this->logtitude = $this->sanitizeGpsCoordinate($logtitude); 

     return $this; 
    } 

    /** 
    * Get logtitude 
    * 
    * @return float 
    */ 
    public function getLogtitude() 
    { 
     return $this->logtitude; 
    } 

    /** 
    * Set latitude 
    * 
    * @param integer $latitude 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setLatitude($latitude) 
    { 
     $this->latitude = $this->sanitizeGpsCoordinate($latitude); 

     return $this; 
    } 

    /** 
    * Get latitude 
    * 
    * @return float 
    */ 
    public function getLatitude() 
    { 
     $latitude=$this->latitude; 
     return $latitude; 
    } 

    /** 
    * Set course 
    * 
    * @param integer $course 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setCourse($course) 
    { 
     $this->course = $course; 

     return $this; 
    } 

    /** 
    * Get course 
    * 
    * @return integer 
    */ 
    public function getCourse() 
    { 
     return $this->course; 
    } 

    /** 
    * Set heading 
    * 
    * @param integer $heading 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setHeading($heading) 
    { 
     $this->heading = $heading; 

     return $this; 
    } 

    /** 
    * Get heading 
    * 
    * @return integer 
    */ 
    public function getHeading() 
    { 
     return $this->heading; 
    } 

    /** 
    * Set rotation 
    * 
    * @param integer $rotation 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setRotation($rotation) 
    { 
     $this->rotation = $rotation; 

     return $this; 
    } 

    /** 
    * Get rotation 
    * 
    * @return integer 
    */ 
    public function getRotation() 
    { 
     return $this->rotation; 
    } 

    /** 
    * Set timesptamp 
    * 
    * @param string $timesptamp 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setTimestamp($timesptamp) 
    { 
     $this->timestamp = date_create_from_format("Y-m-d H:i:s.u",$timesptamp); 
     return $this; 
    } 

    /** 
    * Get timesptamp 
    * 
    * @return \DateTime 
    */ 
    public function getTimestamp() 
    { 
     return $this->timestamp; 
    } 

    /** 
    * Set vesel 
    * 
    * @param \AppBundle\Entity\Vesel $vesel 
    * 
    * @return VesselMoveStatus 
    */ 
    public function setVesel(\AppBundle\Entity\Vesel $vesel = null) 
    { 
     $this->vesel = $vesel; 

     return $this; 
    } 

    /** 
    * Get vesel 
    * 
    * @return \AppBundle\Entity\Vesel 
    */ 
    public function getVesel() 
    { 
     return $this->vesel; 
    } 

    /** 
    * Sometimes a GPS Coordinate may have the following format: 
    * 1,234532 if inserted as is then itn WONT be retreived correctly. 
    * Please use this method to sanitize the gps coordinate on setter method. 
    * 
    * @param string | float $coordinate 
    * @return number 
    */ 
    private function sanitizeGpsCoordinate($coordinate) 
    { 
     if(is_string($coordinate)) 
     { 
      $coordinate=str_replace(',','.',$coordinate); 
     } 

     return (float)$coordinate; 
    } 
} 

回答

2

要转换数据的方式不标准因此没有什么学说一般做所以。但实现你想要的目标仍然非常简单。

然而,IMHO最简单的解决方案是使用一个封闭件来转换结果:

$result = $query->getResult(); 
$formatter = function($row) { 
    return [ 
     "mmsi" => $row['mmsi'] 
     "points" => [ 
     "longtitude" => $row['logtitude'], 
     "latitude" => $row['latitude'], 
     "time" => $row['timestamp'] 
     ] 
    ]; 
}; 
return array_map($formatter, $result); 

最终阵列将具有每点一个元素(veselMoveStatuses)。如果你真正想要的是每个vesel有一个元素,考虑改变SELECT并相应地调整formatter。

->select('v,m') 

结果将是Vesel的阵列已加载veselMoveStatuses关联对象(见this doc - 部分“检索CmsUser并获取加入他的全部PHONENUMBERS”)。