Login to bookmark this video
Buy Access to Course
06.

Obtener los datos de una relación

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Navega hasta la página de inicio y haz clic en cualquiera de las naves estelares con estado "En curso".

Ya tenemos una lista de las piezas... más o menos... ¡todas están codificadas!

Ahora, ¿cómo obtenemos las piezas relacionadas con esta nave?

Abre el controlador de esta página: src/Controller/StarshipController.php

Consulta de piezas relacionadas como cualquier otra propiedad

Para consultar las piezas, lo normal sería autoconectar el StarshipPartRepository. Comienza de la misma manera aquí con un argumento StarshipPartRepository $partRepository:

28 lines | src/Controller/StarshipController.php
// ... lines 1 - 5
use App\Repository\StarshipPartRepository;
// ... lines 7 - 12
class StarshipController extends AbstractController
{
#[Route('/starships/{slug}', name: 'app_starship_show')]
public function show(
// ... lines 17 - 18
StarshipPartRepository $partRepository,
): Response {
// ... lines 21 - 25
}
}

A continuación, establece $parts, en $partRepository->findBy():

Esto es bastante estándar: si quieres consultar dónde una propiedad es igual a un valor, utiliza findBy() y pasa el nombre de la propiedad y el valor. Cuando se trata de relaciones, ¡es lo mismo!

$parts = $partRepository->findBy(['starship' => $ship]).

Y no, no vamos a hacer Starship ID ni nada por el estilo. ¡Mantén los identificadores fuera de esto! En su lugar, pasa el propio objeto Starship. Puedes pasarle id si te da pereza, pero en el espíritu de la Doctrine, las relaciones y el pensamiento sobre objetos, lo mejor es pasarle el objeto Starship entero.

Vamos a depurar y a ver qué tenemos: dd($parts):

28 lines | src/Controller/StarshipController.php
// ... lines 1 - 12
class StarshipController extends AbstractController
{
// ... line 15
public function show(
// ... lines 17 - 18
StarshipPartRepository $partRepository,
): Response {
$parts = $partRepository->findBy(['starship' => $ship]);
dd($parts);
// ... lines 23 - 25
}
}

Actualiza, y ¡voilá! Una matriz de 10 objetos StarshipPart, todos relacionados con este Starship. Impresionante, ¿verdad? Si piensas así, agárrate los pantalones.

Cómo coger las partes relacionadas fácilmente

Sustituye $parts por $ship->getParts():

28 lines | src/Controller/StarshipController.php
// ... lines 1 - 12
class StarshipController extends AbstractController
{
// ... line 15
public function show(
// ... lines 17 - 19
): Response {
// ... line 21
dd($ship->getParts());
// ... lines 23 - 25
}
}

¡Actualiza! En lugar de una matriz de objetos StarshipPart, obtenemos un objetoPersistentCollection que parece... vacío. ¿Recuerdas el ArrayCollection que make:entity añadió a nuestro constructorStarship? PersistentCollection y ArrayCollection forman parte de la misma familia de colecciones. Son objetos pero actúan como matrices. Genial... pero ¿por qué esta colección parece vacía? Es porque Doctrine es inteligente: no consulta las partes hasta que las necesitamos. Realiza un bucle sobre $ship->getParts() y vuelca $part:

32 lines | src/Controller/StarshipController.php
// ... lines 1 - 12
class StarshipController extends AbstractController
{
// ... line 15
public function show(
// ... lines 17 - 19
): Response {
// ... lines 21 - 22
foreach ($ship->getParts() as $part) {
dump($part);
}
// ... lines 26 - 29
}
}

De repente, esa colección de aspecto vacío está llena de los 10 objetos StarshipPart. ¡Mágico!

Consultas perezosas de relación

Aquí hay dos consultas en juego. La primera es para el Starship, y la segunda es para todos sus StarshipParts. La primera proviene de la consulta de Symfony para el Starship basada en el slug. La segunda es más interesante: ocurre en el momento en que foreach pasa por encima de parts. En ese preciso instante Doctrine dice:

Acabo de acordarme: En realidad no tengo los datos de StarshipParts para este Starship. Voy a buscarlos.

¿No es increíble? Me dan ganas de hacer una fiesta para Doctrine.

Ordenar y repasar partes

Deshazte por completo de la variable parts... y elimina StarshipPartRepository: era demasiado trabajo. En su lugar, establece una variable parts en $ship->getParts():

26 lines | src/Controller/StarshipController.php
// ... lines 1 - 12
class StarshipController extends AbstractController
{
#[Route('/starships/{slug}', name: 'app_starship_show')]
public function show(
#[MapEntity(mapping: ['slug' => 'slug'])]
Starship $ship,
): Response {
return $this->render('starship/show.html.twig', [
'ship' => $ship,
'parts' => $ship->getParts(),
]);
}
}

Ahora que tenemos nuestra nueva y brillante variable parts, haz un bucle sobre ella en la plantilla. Abre templates/starship/show.html.twig y sustituye la parte codificada por nuestro bucle: for part in parts, part.name, part.price,part.notes, endfor:

79 lines | templates/starship/show.html.twig
// ... lines 1 - 4
{% block body %}
// ... lines 6 - 19
<div class="md:flex justify-center space-x-3 mt-5 px-4 lg:px-8">
// ... lines 21 - 25
<div class="space-y-5">
<div class="mt-8 max-w-xl mx-auto">
<div class="px-8 pt-8">
// ... lines 29 - 61
<ul class="text-sm font-medium text-slate-400 tracking-wide">
{% for part in parts %}
<li class="border-b border-slate-600 py-2">
<span class="block text-white font-semibold">
{{ part.name }} (✦ {{ part.price }})
</span>
<span class="text-xs text-slate-500 italic">
{{ part.notes }}
</span>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
{% endblock %}

¿Sigue siendo demasiado trabajo?

¡Y lo hemos conseguido! Hemos conseguido mostrar las 10 partes relacionadas, sin hacer mucho trabajo gracias a $ship->getParts().

¿Pero sabes una cosa? Incluso esto es demasiado trabajo. Deshazte por completo de la variable parts:

25 lines | src/Controller/StarshipController.php
// ... lines 1 - 12
class StarshipController extends AbstractController
{
// ... line 15
public function show(
// ... lines 17 - 18
): Response {
return $this->render('starship/show.html.twig', [
'ship' => $ship,
]);
}
}

for part in ship.parts:

79 lines | templates/starship/show.html.twig
// ... lines 1 - 4
{% block body %}
// ... lines 6 - 19
<div class="md:flex justify-center space-x-3 mt-5 px-4 lg:px-8">
// ... lines 21 - 25
<div class="space-y-5">
<div class="mt-8 max-w-xl mx-auto">
<div class="px-8 pt-8">
// ... lines 29 - 61
<ul class="text-sm font-medium text-slate-400 tracking-wide">
{% for part in ship.parts %}
// ... lines 64 - 71
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
{% endblock %}

Y... ¡todavía no se ha roto! Para divertirnos, mostremos también el número de piezas de esta nave. ship.parts|length:

79 lines | templates/starship/show.html.twig
// ... lines 1 - 4
{% block body %}
// ... lines 6 - 19
<div class="md:flex justify-center space-x-3 mt-5 px-4 lg:px-8">
// ... lines 21 - 25
<div class="space-y-5">
<div class="mt-8 max-w-xl mx-auto">
<div class="px-8 pt-8">
// ... lines 29 - 58
<h4 class="text-xs text-slate-300 font-semibold mt-2 uppercase">
Parts ({{ ship.parts|length }})
</h4>
// ... lines 62 - 73
</div>
</div>
</div>
</div>
{% endblock %}

Seguimos teniendo dos consultas, pero Doctrine, una vez más, es inteligente. Sabe que ya hemos consultado todas las StarshipParts, así que cuando las contemos, en realidad no necesitamos hacer otra consulta de recuento.

A continuación hablaremos de un tema a menudo incomprendido en las relaciones Doctrine: el lado propio y el inverso de cada relación.