Search code examples
phpdoctrine-ormsymfony-3.1

Symfony 3 Doctrine select with relationship


I have the following function:

 /**
     *
     * {@inheritDoc}
     * @see \AppBundle\Interfaces\CrudManagerInterface::search()
     *
     * @return Member[]
     */
    public function search(array $searchParams, array $order , $page, $limit)
    {
        /**
         * @var \Doctrine\Common\Persistence\ObjectRepository $queryBuilder
         */
        $queryBuilder=$this->entityManager->createQueryBuilder();
    
        $queryBuilder=$queryBuilder->select('m')->from('AppBundle:Member','m');
    
        if(!empty($searchParams['name']))
        {
            $queryBuilder->andWhere('m.name LIKE :name')->setParameter('name','%'.$searchParams['name'].'%');
        }
    
        if(!empty($searchParams['schools']))
        {
            if(!is_array($searchParams['schools']))
            {
                $searchParams['schools']=[$searchParams['schools']];
            }
    
            $queryBuilder->andWhere('m.schools IN ( Select s.id FROM AppBundle:Schools s WHERE s.id IN (:schools ) )')->setParameters(['schools'=>$searchParams['schools']]);
        }
    
        if(!empty($order))
        {
            if(isset($searchParams['name']))
            {
                $queryBuilder->addOrderBy('m.name',$order['name']);
            }
        }
    
        if((int)$limit>0)
        {
            $queryBuilder->setFirstResult((int)$page)->setMaxResults($limit);
        }
    
    
        /**
         * @var Doctrine\ORM\Query
         */
        $query=$queryBuilder->getQuery();
    
        $queryString=$query->getDql();
    
        $results=$query->getResult();
        return $results;
    }

And the following entities:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use AppBundle\Interfaces\ArrayAbleInterface;

/**
 * @ORM\Entity
 * @ORM\Table(name="members")
 */
class Member implements ArrayAbleInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $email;

    /**
     * @var string
     * @ORM\Column(type="string", length=100)
     */
    private $name;

    /**
     * @ORM\ManyToMany(targetEntity="School",mappedBy="members")
     * @ORM\JoinTable(name="members_have_schools")
     */
    private $schools;

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

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

    /**
     * Set email
     *
     * @param string $email
     *
     * @return Member
     */
    public function setEmail($email)
    {
        $this->email = $email;

        return $this;
    }

    /**
     * Get email
     *
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * Add school
     *
     * @param \AppBundle\Entity\School $school
     *
     * @return Member
     */
    public function addSchool(\AppBundle\Entity\School $school)
    {
        $school->addMember($this);
        $this->schools[] = $school;

        return $this;
    }

    /**
     * Remove school
     *
     * @param \AppBundle\Entity\School $school
     */
    public function removeSchool(\AppBundle\Entity\School $school)
    {
        $this->schools->removeElement($school);
    }

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

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Member
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * {@inheritDoc}
     * @see \AppBundle\Interfaces\ArrayAbleInterface::toArray()
     */
    public function toArray()
    {
        $array=['id'=>$this->getId(),'name'=>$this->getName(),'email'=>$this->getEmail(),'schools'=>array()];

        $schools=$this->getSchools()->getValues();

        foreach($schools as $school)
        {
            $array['schools'][]=$school->toArray();
        }

        return $array;
    }
}

And

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use AppBundle\Interfaces\ArrayAbleInterface;

/**
 * @ORM\Entity
 * @ORM\Table(name="schools")
 */
class School implements ArrayAbleInterface
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     * @ORM\Column(type="string", length=200)
     */
    private $name;

    /**
     *
     * @var unknown
     */
    private $school_id;

    /**
     * @var unknown
     * @ORM\ManyToMany(targetEntity="Member", inversedBy="schools")
     */
    private $members;

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

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

    /**
     * Set name
     *
     * @param string $name
     *
     * @return School
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Add member
     *
     * @param \AppBundle\Entity\Member $member
     *
     * @return School
     */
    public function addMember(\AppBundle\Entity\Member $member)
    {
        $this->members[] = $member;

        return $this;
    }

    /**
     * Remove member
     *
     * @param \AppBundle\Entity\Member $member
     */
    public function removeMember(\AppBundle\Entity\Member $member)
    {
        $this->members->removeElement($member);
    }

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

    /**
     *
     * {@inheritDoc}
     * @see \AppBundle\Interfaces\ArrayAbleInterface::toArray()
     */
    public function toArray()
    {
        $array=['id'=>$this->getId(),'name'=>$this->getName()];

        return $array;
    }
}

With the function Mentioned on the top I want to search for members with the name and some school id given as an array. All these are in the $searchParams Array. But I cannot find out a way to search with the schoool Ids.

An example parameter for $searchParams is:

[
  'name'=>'Sailor'
  'schools'=>[1,2,3]
]

Some example data that is into my Db is

Members:

> id|  name           | email              |
> 1 |  Sailor Mooon   | [email protected]    |
> 2 | Monk1ey D Luffy | [email protected] |

Schools

> id | name 
> 1  | Kokoro Daigaku
> 2  | Oumi Akademy
> 3  | Univercity of Pokemon Battle

In the function mentioned on the top I get the following error:

: [Semantical Error] line 0, col 71 near 'id IN ( Select': Error: Class AppBundle\Entity\Member has no field or association named schools.id [] []

How can I fix it?

Edit 1

I managed to solve it partially by changing the:

$queryBuilder->andWhere('m.schools IN ( Select s.id FROM AppBundle:Schools s WHERE s.id IN (:schools ) )')->setParameters(['schools'=>$searchParams['schools']]);

Into this:

$queryBuilder->join('AppBundle:School','s')->andWhere('s.id IN (:schools)')->setParameters(['schools'=>$searchParams['schools']]);

But I get members that do not have a relationship with any school.


Solution

  • In the end I changed the:

    $queryBuilder->join('AppBundle:School','s')->andWhere('s.id IN (:schools)')->setParameters(['schools'=>$searchParams['schools']]);
    

    Into this:

    $queryBuilder->join('m.schools','s')->andWhere('s.id IN (:schools)')->setParameters(['schools'=>$searchParams['schools']]);