[英]Symfony Doctrine query builder find entity with many to one relation
I'm building a website with Symfony for a project which will act like "booking.com" websites but much simplier and with some variations.我正在使用 Symfony 为一个项目构建一个网站,该网站的行为类似于“booking.com”网站,但要简单得多,并且有一些变化。
Some errors on the database fields but not really important for my issue.数据库字段上的一些错误,但对我的问题并不重要。
As you can see, these tables concern two entities : apartment and visit.如您所见,这些表涉及两个实体:公寓和访问。 A customer can ask for a visit of an apartment.
客户可以要求参观公寓。 It is a many to one relationship.
这是多对一的关系。
I have a search form to search for apartments with criterias.我有一个搜索表格来搜索符合条件的公寓。 I want to only show apartments that don't have any visits between the arrival and departure dates that the user provided.
我只想显示在用户提供的到达和离开日期之间没有任何访问的公寓。 So I ended up making a function in apartmentRepository to manage that and other cases.
因此,我最终在 apartmentRepository 中创建了一个函数来管理该情况和其他情况。
Problem is: how can I get these apartments ?问题是:我怎样才能得到这些公寓?
Here is a draft of this function which is of course not finished neither perfect (if you have some comments to improve it, it would be great !).这是这个功能的草稿,当然还没有完成,也不完美(如果你有一些评论来改进它,那就太好了!)。
public function findByCustom($parameters): ?array
{
$query = $this->createQueryBuilder('a');
foreach ($parameters as $key=> $parameter){
if($key != 'keywords' and $key!= 'priceMin' & $key!='priceMax' and $key!="typeAp" and $key!="searchVisitDate") $query->orWhere('a.'.$key." = '".$parameter."'");
if($key == "typeAp")
{
$typeApQuery = "";
foreach ($parameters[$key] as $index => $type)
{
if($index !== count($parameters[$key])-1)
{
$typeApQuery.=" a.typeAp = '".$type."' or";
}
else
{
$typeApQuery.= " a.typeAp = '".$type."'";
}
}
$query->andWhere($typeApQuery);
}
}
$query->andWhere('a.rentPrice >='.$parameters['priceMin']." and a.rentPrice <= ".$parameters['priceMax']);
$withoutInner = $query;
$query
->join('App\Entity\Visit', 'v', Join::ON, 'a = v.apartment')
->where("v.date between '2020-03-15' and '2020-03-19'");
$query->getQuery()->getResult();
$sorted = $withoutInner->andWhere($this->createQueryBuilder('a')->expr()->notIn('a.id', $query));
return array($sorted);
Of course apartment has a collection of visits and visit as a field named "apartment" which is related to the apartment object.当然,公寓有一个访问和访问的集合,作为一个名为“公寓”的字段,与公寓对象相关。
I really didn't find a proprer way to do it and I want to avoid doing SQL, to improve my understanding of Doctrine.我真的没有找到合适的方法来做到这一点,我想避免使用 SQL,以提高我对 Doctrine 的理解。
Thank you for your help because I'm stuck right now :/感谢您的帮助,因为我现在被困住了:/
EDIT 1: forgot to mention that I want to get apartments that don't have visits between required dates or that don't have any visits at all编辑 1:忘了提到我想要在规定的日期之间没有访问或根本没有访问的公寓
EDIT 2 :编辑 2:
public function findByCustom($parameters): ?array
{
$query = $this->createQueryBuilder('a');
$withoutInner = $this->createQueryBuilder("a");
foreach ($parameters as $key=> $parameter){
if($key != 'keywords' and $key!= 'priceMin' & $key!='priceMax' and $key!="typeAp" and $key!="searchVisitDate")
{
$withoutInner->orWhere('a.'.$key." = '".$parameter."'");
$query->orWhere('a.'.$key." = '".$parameter."'");
}
if($key == "typeAp")
{
$typeApQuery = "";
foreach ($parameters[$key] as $index => $type)
{
if($index !== count($parameters[$key])-1)
{
$typeApQuery.=" a.typeAp = '".$type."' or";
}
else
{
$typeApQuery.= " a.typeAp = '".$type."'";
}
}
$withoutInner->andWhere($typeApQuery);
$query->andWhere($typeApQuery);
}
}
$query->andWhere('a.rentPrice >='.$parameters['priceMin']." and a.rentPrice <= ".$parameters['priceMax']);
$withoutInner->andWhere('a.rentPrice >='.$parameters['priceMin']." and a.rentPrice <= ".$parameters['priceMax']);
$query
->join('App\Entity\Visit', 'v', Join::WITH, 'a.id = v.apartment')
->where("v.date between '2020-03-15' and '2020-03-19'");
$query->getQuery()->getResult();
$sorted = $withoutInner->andWhere($this->createQueryBuilder('a')->expr()->notIn('a.id', $query));
With this function I get doctrine error :有了这个功能,我得到了学说错误:
Error: Method Doctrine\Common\Collections\ArrayCollection::__toString() must not throw an exception, caught ErrorException: Catchable Fatal Error: Object of class Doctrine\ORM\EntityManager could not be converted to string
I haven't tested this myself, but something like this should work:我自己还没有测试过,但是这样的事情应该可行:
$query
->leftJoin('App\Entity\Visit', 'v', Join::WITH, 'a = v.apartment AND v.date between "2020-03-15" and "2020-03-19"')
->where('a.visits IS EMPTY');
The idea here is to use leftJoin
and select only those result that do not have a corresponding entry in the visit
table.这里的想法是使用
leftJoin
并仅选择那些在visit
表中没有相应条目的结果。
I found a solution to get all apartments that have no rents (where the join is null).我找到了一个解决方案来获取所有没有租金的公寓(连接为空)。 Yes I changed visits for rents because that was a mistake in my main question.
是的,我改变了租金的访问,因为这是我的主要问题中的一个错误。
$query->leftJoin('a.rents', 'r',Join::WITH,'a = r.apartment')
->where(
$query->expr()->andX($query->expr()->isNull('r')))
->orWhere($query->expr()-> **);
I have an attribute in my apartment entity which has all rents of the current apartment.我的公寓实体中有一个属性,其中包含当前公寓的所有租金。 So I use it to make the join.
所以我用它来进行连接。 With the expression isNull I get it to work for the apartments with no visits.
使用表达式 isNull 我让它在没有访问的情况下为公寓工作。
** : I want to be able to get the apartments that have no locations where user entered required arrival date is not between r.arrival and r.departure. ** :我希望能够获得没有用户输入所需到达日期不在 r.arrival 和 r.departure 之间的位置的公寓。 This would give me all apartments without any rents and those which are free to book.
这将给我所有没有租金的公寓和那些可以免费预订的公寓。
I thought about doing another query and do a notIn but I don't know how to do it neither.我想过做另一个查询并做一个 notIn 但我也不知道该怎么做。
Thank you.谢谢你。
EDIT and solution :编辑和解决方案:
I found out by myself how to do it.我自己发现了如何做到这一点。 This is absolutly not the best approach neither the best solution but I'm out of time for my projet so I needed to get this done.
这绝对不是最好的方法,也不是最好的解决方案,但我的项目没时间了,所以我需要完成这项工作。
$rents = $this->getEntityManager()->createQueryBuilder()
->select("a.id")->from('App:Rent', 'r')
->andWhere('r.arrival between :arrival and :departure')
->leftJoin('r.apartment', 'a')
->setParameters(array("arrival"=>\DateTime::createFromFormat('Y-m-d', "2020-04-20")->setTime(00,00,00), "departure"=>\DateTime::createFromFormat('Y-m-d',"2020-04-31")->setTime(00,00,00)))
->getQuery()->getArrayResult();
$rentsSorted = array();
foreach ($rents as $rent)
{
if(!in_array( $rent['id'],$rentsSorted))
{
$rentsSorted[] = $rent['id'];
}
}
if(count($rentsSorted)>0)
{
$withRentsNotBetweenDates->andWhere('a1.rentPrice >=' . $parameters['priceMin'] . " and a1.rentPrice <= " . $parameters['priceMax'])
->andWhere($withRentsNotBetweenDates->expr()->notIn('a1.id', $rentsSorted));
}
else
{
$withRentsNotBetweenDates->andWhere('a1.rentPrice >=' . $parameters['priceMin'] . " and a1.rentPrice <= " . $parameters['priceMax']);
}
Of course I'm going to change the parameters to the required dates given by my form.当然,我要将参数更改为我的表单给出的所需日期。
This code allows me to get all rents that exists within these required dates.此代码允许我获得这些所需日期内存在的所有租金。 I then store each apartment id in an array that I will pass in the not in to exclude these apartments because they have a rent at this period.
然后我将每个公寓 id 存储在一个数组中,我将传入 not in 以排除这些公寓,因为它们在此期间有租金。
If you have any improvents or a better way to do this don't be shy xD.如果您有任何改进或更好的方法来做到这一点,请不要害羞 xD。
Have a good day.祝你有美好的一天。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.