17/05/2015 - DOCTRINE, SYMFONY
Eğer ne yaptığınızı bilmiyorsanız, doctrinenin lazy load özelliği kötü sonuçlara sebep olabilir. Bu özellik varsayılan olarak aktif haldedir, bu nedenle kendi sorgularımızı kendimiz kontrol altında tutmamız gerekir. Size vereceğim en iyi tavsiye, eğer sorgunuz içinde farklı tablo ilişkileri var ise, repository class yaratıp DQL sorgusunu kendiniz yazın. Örneğin; bir Country (Ülke) sıfır veya birden fazla League (Lig) barındırabileceği için, bu 1-N ilişkidir. Şimdi aşağıdaki örneğe bakalım.
# Country entity
/**
* @ORM\Entity
* @ORM\Table(name="country")
*/
class Country
{
protected $id;
protected $code;
protected $name;
protected $createdAt;
protected $updatedAt;
/**
* @ORM\OneToMany(
* targetEntity="League",
* mappedBy="country",
* cascade={"persist", "remove"},
* orphanRemoval=true
* )
*/
protected $league;
.......
}
# League entity
/**
* @ORM\Entity
* @ORM\Table(name="league")
*/
class League
{
protected $id;
protected $name;
protected $createdAt;
protected $updatedAt;
/**
* @ORM\ManyToOne(
* targetEntity="Country",
* inversedBy="league"
* )
* @ORM\JoinColumn(
* name="country_id",
* referencedColumnName="id",
* onDelete="CASCADE",
* nullable=false
* )
*/
protected $country;
.......
}
mysql> SELECT * FROM country;
+----+----------------+---------------------+------------+------+
| id | name | created_at | updated_at | code |
+----+----------------+---------------------+------------+------+
| 28 | Germany | 2015-05-16 19:59:00 | NULL | DE |
| 29 | Spain | 2015-05-16 19:59:00 | NULL | ES |
| 30 | Turkey | 2015-05-16 19:59:00 | NULL | TR |
| 31 | United Kingdom | 2015-05-16 21:39:25 | NULL | GB |
+----+----------------+---------------------+------------+------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM league;
+----+------------+-------------------+---------------------+------------+
| id | country_id | name | created_at | updated_at |
+----+------------+-------------------+---------------------+------------+
| 6 | 28 | Bundesliga | 2015-05-16 19:59:00 | NULL |
| 7 | 29 | Primera División | 2015-05-16 19:59:00 | NULL |
| 8 | 29 | Segunda División | 2015-05-16 19:59:00 | NULL |
| 9 | 30 | Süper Lig | 2015-05-16 19:59:00 | NULL |
| 10 | 30 | TFF 1. Lig | 2015-05-16 19:59:00 | NULL |
| 11 | 31 | Premier League | 2015-05-16 19:59:00 | NULL |
+----+------------+-------------------+---------------------+------------+
6 rows in set (0.00 sec)
Buna "kötü" dememizin nedeni, ana varlık ile birlikte lazy load ile alakalı varlığa da ulaşacağız. Mevcut olan findAll()
doctrine fonksiyonunu kullanacağız. İyi kontrol edilmeyen lazy load, $c->getLeague()->first()->getName()
ve {{ country.getLeague.first.name }}
satırları için extra sorgulama yapar. Bu işlem sonuç olarak toplam 5 tane sorgulama yapar. 1 tanesi ülkeleri seçmek için, 1'er tanede tüm ülkelerin ilk liglerini seçmek için.
# Country controller
class CountryController
{
public function listAction()
{
$repo = $this->getDoctrine()->getRepository('FootballFrontendBundle:Country');
$country = $repo->findAll();
// foreach ($country as $c) {
// $id = $c->getId();
// $code = $c->getCode();
// // ....
// $league = $c->getLeague()->first()->getName();
// }
return $this->render(
'FootballFrontendBundle:Country:list.html.twig', ['countryArray' => $country]
);
}
}
# FootballFrontendBundle:Country:list.html.twig
{% if countryArray is defined and countryArray|length != 0 %}
<table border="1px">
<tr>
<td>#</td>
<td>ID</td>
<td>CODE</td>
<td>NAME</td>
<td>CREATED</td>
<td>UPDATED</td>
<td>LEAGUE</td>
</tr>
{% for country in countryArray %}
<tr>
<td class="head">{{ loop.index }}</td>
<td>{{ country.id }}</td>
<td>{{ country.code }}</td>
<td>{{ country.name }}</td>
<td>{{ country.createdAt|date('d/m/Y H:i:s') }}</td>
<td>{{ country.updatedAt is not null ? country.updatedAt|date('d/m/Y H:i:s') : '' }}</td>
<td>{{ country.getLeague.first.name }}</td>
</tr>
{% endfor %}
</table>
{% else %}
No country found in database!
{% endif %}
Burada kendi repository classımızı yaratıp, ilgili ligleride seçebilmek için, kendi findAll()
fonksiyonumuzu yaratacağız. Bu yöntemle yukarıdaki işlem toplam 1 tane sorgulama yapacaktır. Aşağıdaki çıktı her iki yöntem için de geçerlidir.
# Country repository
class CountryRepository extends EntityRepository
{
public function findAll()
{
return
$this->createQueryBuilder('c')
->select('c, l')
->leftJoin('c.league', 'l')
->getQuery()
->getResult();
}
}
Yukarıdaki yorumlar bu bölüm için de geçerlidir. İyi kontrol edilmeyen lazy load, $l->getCountry()->getName()
ve {{ league.country.name }}
satırları için extra sorgulama yapar. Bu işlem sonuç olarak toplam 5 tane sorgulama yapar. 1 tanesi ligleri seçmek için, 1'er tanede tüm liglerin ülkelerini seçmek için.
# League controller
class LeagueController
{
public function listAction()
{
$repo = $this->getDoctrine()->getRepository('FootballFrontendBundle:League');
$league = $repo->findAll();
// foreach ($league as $l) {
// $id = $l->getId();
// $name = $l->getName();
// // ...
// $countryName = $l->getCountry()->getName();
// }
return $this->render(
'FootballFrontendBundle:League:list.html.twig', ['leagueArray' => $league]
);
}
}
# FootballFrontendBundle:League:list.html.twig
{% if leagueArray is defined and leagueArray|length != 0 %}
<table border="1px">
<tr>
<td>#</td>
<td>ID</td>
<td>NAME</td>
<td>CREATED</td>
<td>UPDATED</td>
<td>COUNTRY</td>
</tr>
{% for league in countryArray %}
<tr>
<td class="head">{{ loop.index }}</td>
<td>{{ league.id }}</td>
<td>{{ league.name }}</td>
<td>{{ league.createdAt|date('d/m/Y H:i:s') }}</td>
<td>{{ league.updatedAt is not null ? league.updatedAt|date('d/m/Y H:i:s') : '' }}</td>
<td>{{ league.country.name }}</td>
</tr>
{% endfor %}
</table>
{% else %}
No league found in database!
{% endif %}
Burada kendi repository classımızı yaratıp, ilgili ülkeleri seçebilmek için, kendi findAll()
fonksiyonumuzu yaratacağız. Bu yöntemle yukarıdaki işlem toplam 1 tane sorgulama yapacaktır. Aşağıdaki çıktı her iki yöntem için de geçerlidir.
# League repository
class LeagueRepository extends EntityRepository
{
public function findAll()
{
return
$this->createQueryBuilder('l')
->select('l, c')
->leftJoin('l.country', 'c')
->getQuery()
->getResult();
}
}