Create a query to join two tables in symfony2
-
21-12-2019 - |
Question
how to listing two table join in symfony2
I have four table
- Country
- CountryTranslation
- State
- StateTranslation
following 4 table Entity
Table (1) Country
/**
*
*
* @ORM\Table(name="Country")
* @ORM\Entity(repositoryClass="Dashboard\CountryBundle\Entity\CountryRepository")
*/
class Country
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\OneToMany(
* targetEntity="CountryTranslation",
* mappedBy="object",
* cascade={"persist", "remove"}
* )
*/
private $translations;
}
Table (2) CountryTranslation
/**
*
*
* @ORM\Table(name="CountryTranslation")
* @ORM\Entity
*/
class CountryTranslation
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string $culture
*
* @ORM\Column(type="string", length=8)
*/
private $culture;
/**
* @ORM\Column(name="country_name", type="string", length=255)
*/
private $country_name;
/**
* @ORM\ManyToOne(targetEntity="Country", inversedBy="translations")
* @ORM\JoinColumn(name="country_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $object;
}
Table (3) State
/**
*
* @ORM\Table(name="State")
* @ORM\Entity(repositoryClass="Dashboard\CountryBundle\Entity\StateRepository")
*/
class State
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Country")
* @ORM\JoinColumn(name="country_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $countryId;
/**
* @ORM\OneToMany(
* targetEntity="StateTranslation",
* mappedBy="object",
* cascade={"persist", "remove"}
* )
*/
private $translations;
}
Table (4) StateTranslation
/**
* StateTranslation
*
* @ORM\Table(name="StateTranslation")
* @ORM\Entity
*/
class StateTranslation
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string $culture
*
* @ORM\Column(type="string", length=8)
*/
private $culture;
/**
* @ORM\Column(name="state_name", type="string", length=255)
*/
private $state_name;
/**
* @ORM\ManyToOne(targetEntity="State", inversedBy="translations")
* @ORM\JoinColumn(name="state_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $object;
}
I want to have the following type listing
**No Country name state name Action**
1 India Gujarat edit/delete
2 USA california edit/delete
I have following code in StateRepository file but how to display country name on list page now . I can see bellow table in listing page
**No Country name state name Action**
1 3(country id) Gujarat edit/delete
2 5(country id) california edit/delete
public function loadAllState($culture = 'en')
{
$em = $this->getEntityManager();
$q = $em->createQuery("SELECT c, t
FROM Dashboard\CountryBundle\Entity\State c
LEFT JOIN c.translations t
WHERE t.culture = :culture ")->setParameter('culture', $culture);
return $q->getResult();
}
my other question is
how to Language wise display in add / edit twig file
currently my code in StateType.php file
$builder->add('country', 'entity', array(
'class' => 'DashboardCountryBundle:Country',
'property' => 'translations[0].country_name',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('mc')
->select('mc','d')
->innerJoin('mc.translations', 'd')
->where('d.culture = :culture')
->setParameter('culture', 'en');
},
'label' => false,
'attr'=> array('class' => 'validate[required] form-control'),
'empty_value'=>'Please Select Category'
));
it is working fine but my question for how to reduce query which i have used in above statement ?
currently i am using this code but facing problem that i am getting country of all language
how to language wise getting country
**StateType.php file**
->add('country', 'entity', array('class' => 'DashboardCountryBundle:CountryTranslation','property' => 'name', 'label' => false,'attr'=> array('class' => 'validate[required] form-control')));
Solution
I think you're almost there, you just had to apply the same logic with the country entity to fetch the translations.
1 It's a good practice to change this in your State class:
protected $countryId;
to this:
protected $country
Why? Because it's a relationship between State
entity and Country
entity (and not between State
entity and CountryId
field. Entities and primary keys are different things. However, you use the primary key ($countryId
) of the Country
entity to create a relationship with the State
entity.
Note: Therefore, you'll have to change your getter and setter to getCountry()
and setCountry($country)
2 That would be your query:
public function loadAllState($culture = 'en')
{
$em = $this->getEntityManager();
$q = $em->createQuery("
SELECT s, st, c, ct
FROM Dashboard\CountryBundle\Entity\State s
INNER JOIN s.translations st
WHERE st.culture = :state_culture
INNER JOIN s.country c
INNER JOIN c.translations ct
WHERE ct.culture = :country_culture
")
->setParameter('state_culture', $culture)
->setParameter('country_culture', $culture);
return $q->getResult();
}
3 You will get a collection of Dashboard\CountryBundle\Entity\State
objects.
Extra for fun
Using the Query Builder instead:
public function loadAllState($culture = 'en')
{
// we create a query builder
$queryBuilder = $this->getEntityManager()
->createQueryBuilder();
// we select what we need
$queryBuilder
->select('s, st, c, ct')
// from the appropriate connection class
->from('Dashboard\CountryBundle\Entity\State', 's')
// join the state translations
->innerJoin('s.translations','st')
->andWhere('st.culture = :state_culture')
->setParameter('state_culture', $culture)
// join the country
->innerJoin('s.country','c')
// join the country translations
->innerJoin('c.translations','ct')
->andWhere('ct.culture = :country_culture')
->setParameter('country_culture', $culture);
return $queryBuilder
->getQuery()
->getResult();
}