Doctrine以嵌套形式获取DQL查询的结果

时间:2017-04-07 23:15:25

标签: php symfony doctrine-orm doctrine

我有以下问题:

我有以下方法来获取船只的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^"
    ],
    ....
  ],
  ....
]

你知道是否有一个允许我这样做的内部Doctrine机制,或者我应该实现自己的机制吗?

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;
    }
}

1 个答案:

答案 0 :(得分:2)

您想要转换数据的方式不是标准的,因此Doctrine中没有任何通用的方法可以这样做。但实现您想要的目标仍然非常简单。

然而,恕我直言,最简单的解决方案是使用闭包来转换结果:

$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并相应地调整格式化程序。

->select('v,m')

结果将是一个Vesel对象数组,其中已经加载了veselMoveStatuses关联(请参阅this doc - 部分“检索CmsUser并获取加入他所有的所有语音”)。

相关问题