I updated doctrine/orm and doctrine/dbal to dev-master some time ago to be able to use Criteria in Many-To-Many relations (with https://github.com/doctrine/doctrine2/pull/885). Suddenly today (now I'm not sure if it ever worked but I would say it did when using the same function in other places) I wasn't getting any objects in the collections of any of the sides. The only way it worked was If I added a bogus loop before the function with Criteria code was called (I suppose because the objects were being loaded beforehand and then they were available) or if I added fetch="EAGER" in the ManyToMany relation.
I'll try to resume my code bellow as best as I can. The function with the Criteria is getActiveServices inside the Resource class. It's used to get the Services from the Resource that are available depending on their start/end date (both can have a value or be null at the same time: no dates, only start date, only end date or both dates specified).
The action in the controller:
public function servicesLoadAction(Request $request, Business $business)
{
$params = $request->getMethod() === 'POST' ? $request->request->all() : $request->query->all();
$resource = array_key_exists('resource', $params) ? $params['resource'] : null;
if (!is_null($resource)) {
$resource = $this->getDoctrine()->getRepository('AppBundle:Resource')->find($resource);
}
/*
// The bogus loop that make this work without using fetch="EAGER"
foreach ($business->getResources() as $resource) {
$i = $resource->getServices()->count();
}
*/
$scheduleManager = $this->get('app.model.schedule');
if (!is_null($resource)) {
$services = $scheduleManager->getAvailableResourceServices($business, $resource);
} else {
$services = $scheduleManager->getAvailableServices($business);
}
return new JsonResponse($this->json_decode_group($services, 'service_minimum'));
}
The model:
public function getAvailableResourceServices(Business $business, \AppBundle\Entity\Resource $resource)
{
if ($business->getEnabledHumanResources()->contains($resource)) {
return $resource->getActiveServices(true); // THIS IS THE FUNCTION WITH Criteria
}
return array();
}
Resource class:
/**
* @ORM\Entity(repositoryClass="AppBundle\Entity\ResourceRepository")
* @ORM\Table(name="resources")
*/
class Resource
{
/**
* @ORM\ManyToMany(targetEntity="\AppBundle\Entity\Service", mappedBy="resources", cascade={"persist","remove"})
*/
protected $services;
/**
* Add service
*
* @param \AppBundle\Entity\Service $service
* @return Resource
*/
public function addService(Service $service)
{
$service->addResource($this);
if (!$this->services->contains($service)) {
$this->services[] = $service;
}
return $this;
}
/**
* Remove service
*
* @param \AppBundle\Entity\Service $service
*/
public function removeService(Service $service)
{
$service->getResources()->removeElement($this);
$this->services->removeElement($service);
}
/**
* Get services
*
* @return \Doctrine\Common\Collections\ArrayCollection
*/
public function getServices()
{
return $this->services;
}
/**
* Get active services
*
* @param boolean $onlyVisible
* @return \Doctrine\Common\Collections\ArrayCollection
*/
public function getActiveServices($onlyVisible = true)
{
$now = new DateTime();
$criteria = Criteria::create()
->where(Criteria::expr()->eq('status', Service::STATUS_ENABLED))
->andWhere(Criteria::expr()->orX(
Criteria::expr()->andX(
Criteria::expr()->isNull('dateStart'),
Criteria::expr()->isNull('dateEnd')
),
Criteria::expr()->andX(
Criteria::expr()->lt('dateStart', $now),
Criteria::expr()->isNull('dateEnd')
),
Criteria::expr()->andX(
Criteria::expr()->isNull('dateStart'),
Criteria::expr()->gt('dateEnd', $now)
),
Criteria::expr()->andX(
Criteria::expr()->lt('dateStart', $now),
Criteria::expr()->gt('dateEnd', $now)
)
))
;
if ($onlyVisible) {
$criteria->andWhere(Criteria::expr()->eq('visible', true));
}
return $this->getServices()->matching($criteria);
}
/**
* Set services
*
* @param array
* @return Resource
*/
public function setServices($services)
{
$this->services = new ArrayCollection();
if (!is_null($services)) {
/** @var \AppBundle\Entity\Service $service */
foreach ($services as $service) {
$this->addService($service);
}
}
return $this;
}
}
Service class:
/**
* @ORM\Entity(repositoryClass="AppBundle\Entity\ServiceRepository")
* @ORM\Table(name="services")
*/
class Service
{
/**
* @ORM\ManyToMany(targetEntity="\AppBundle\Entity\Resource", inversedBy="services", cascade={"persist","remove"})
* @ORM\JoinTable(name="resources_services")
*/
protected $resources;
/**
* Add resource
*
* @param \AppBundle\Entity\Resource $resource
* @return Service
*/
public function addResource(\AppBundle\Entity\Resource $resource)
{
$resource->addService($this);
if (!$this->resources->contains($resource)) {
$this->resources[] = $resource;
}
return $this;
}
/**
* Remove resource
*
* @param \AppBundle\Entity\Resource $resource
*/
public function removeResource(\AppBundle\Entity\Resource $resource)
{
$resource->getServices()->removeElement($this);
$this->resources->removeElement($resource);
}
/**
* Get resources
*
* @return \Doctrine\Common\Collections\ArrayCollection
*/
public function getResources()
{
return $this->resources;
}
/**
* Get enabled human resources
*
* @param boolean $onlyVisible
* @return \Doctrine\Common\Collections\ArrayCollection
*/
public function getEnabledHumanResources($onlyVisible = true)
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq('status', Resource::STATUS_ENABLED))
->andWhere(Criteria::expr()->eq('type', Resource::TYPE_HUMAN))
->orderBy(array('name' => Criteria::ASC))
;
if ($onlyVisible) {
$criteria->andWhere(Criteria::expr()->eq('visible', true));
}
return $this->getResources()->matching($criteria);
}
/**
* Get enabled resources
*
* @param boolean $onlyVisible
* @return \Doctrine\Common\Collections\ArrayCollection
*/
public function getEnabledResources($onlyVisible = true)
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq('status', Resource::STATUS_ENABLED))
->orderBy(array('name' => Criteria::ASC))
;
if ($onlyVisible) {
$criteria->andWhere(Criteria::expr()->eq('visible', true));
}
return $this->getResources()->matching($criteria);
}
/**
* Set resources
*
* @param array
* @return Service
*/
public function setResources($resources)
{
$this->resources = new ArrayCollection();
if (!is_null($resources)) {
/** @var \AppBundle\Entity\Resource $resource */
foreach ($resources as $resource) {
$resource->addService($this);
$this->addResource($resource);
}
}
return $this;
}
}
Criteria is broken in so many ways, I'm not sure why it's included in stable releases, it's totally unfinished.
Most helpful comment
Criteriais broken in so many ways, I'm not sure why it's included in stable releases, it's totally unfinished.