Acceder a los datos de un ManyToMany
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeObjetivo realmente sencillo: imprimir todos los droides asignados a un Starship
. Si te has sentido cómodo con la relación OneToMany
de Starship
a sus partes, ¡esto te va a encantar!
Abre la plantilla de la página de muestra Starship
:templates/starship/show.html.twig
. Robaré la etiqueta h4
y p
paraarrived at
, las pegaré a continuación, y cambiaré la h4
por Droids
. Borra arrived at
... y rompe esa línea:
// ... 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"> | |
Droids | |
</h4> | |
<p class="text-[22px] font-semibold"> | |
// ... lines 63 - 67 | |
</p> | |
// ... lines 69 - 84 | |
</div> | |
</div> | |
</div> | |
</div> | |
{% endblock %} |
Tenemos una variable ship
, que es un objeto Starship
. Y recuerda que tiene una propiedad droids
y un método getDroids()
. Así que, paradroid in ship.droids
. Esto llama al método getDroids()
, y eso devuelve una colección de objetos Droid
. Así que podemos decir {{ droid.name }}
.
El loop.last
Quiero comas, pero no una coma de más al final. Di : {% if not loop.last %}, {% endif %}
. Hay formas más elegantes de hacerlo, pero de momento hazlo sencillo.
Si no hay ningún droide, utiliza una etiqueta else
y diNo droids on board (clean up your own mess)
. ¡Grosero!
// ... 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"> | |
Droids | |
</h4> | |
<p class="text-[22px] font-semibold"> | |
{% for droid in ship.droids %} | |
{{ droid.name }}{% if not loop.last %}, {% endif %} | |
{% else %} | |
No droids on board (clean up your own mess) | |
{% endfor %} | |
</p> | |
// ... lines 69 - 84 | |
</div> | |
</div> | |
</div> | |
</div> | |
{% endblock %} |
Droides en la página de inicio
En la página de inicio, también queremos mostrar los droides. Abre la plantilla: templates/main/homepage.html.twig
. Justo después departs
, añade otro div con Droids: {{ ship.droidNames ?: 'none' }}
:
// ... lines 1 - 4 | |
{% block body %} | |
<main class="flex flex-col lg:flex-row"> | |
// ... lines 7 - 8 | |
<div class="px-12 pt-10 w-full"> | |
// ... lines 10 - 17 | |
<div class="space-y-5"> | |
{% for ship in ships %} | |
<div class="bg-[#16202A] rounded-2xl pl-5 py-5 pr-11 flex flex-col min-[1174px]:flex-row min-[1174px]:justify-between"> | |
<div class="flex justify-center min-[1174px]:justify-start"> | |
<img class="h-[83px] w-[84px]" src="{{ asset(ship.statusImageFilename) }}" alt="Status: {{ ship.statusString }}"> | |
<div class="ml-5"> | |
// ... lines 24 - 36 | |
<div> | |
Parts: {{ ship.parts|length }}</div> | |
<div> | |
Droids: {{ ship.droidNames ?: 'none' }} | |
</div> | |
</div> | |
</div> | |
// ... lines 44 - 54 | |
</div> | |
{% endfor %} | |
</div> | |
// ... lines 58 - 73 | |
</div> | |
</main> | |
{% endblock %} |
El método inteligente
Podríamos volver a utilizar nuestra coma de loop.last
, pero necesitamos los nombres de los droides en dos sitios, así que vamos a añadir un método inteligente para ello en la clase Starship
. Podría ir en cualquier sitio, pero lo pondré al final con los otros métodos de droides. Crea un public function getDroidNames(): string
. Para devolver una cadena de nombres de droides separados por comas, mira esto: returnimplode(',
', $this->droids->map(fn(Droid $droid) => $droid->getName())->toArray()):
// ... lines 1 - 15 | |
class Starship | |
{ | |
// ... lines 18 - 223 | |
public function getDroidNames(): string | |
{ | |
return implode(', ', $this->droids->map(fn(Droid $droid) => $droid->getName())->toArray()); | |
} | |
} |
Vaya, ¡qué bocado! Vamos a desglosarlo:
Primero, $this->droids
es nuestra colección de objetos Droid
. Segundo, map()
aplica una función a cada Droid
de la colección. Tercero, fn(Droid $droid) => $droid->getName()
es una forma hipster de decir:
Dame el nombre de cada droide
Cuarto, toArray()
convierte la colección en una matriz para poder utilizarla conimplode()
. Por último, implode(', ',
...) toma esa matriz de nombres y la convierte en una cadena separada por comas.
Ahora que tenemos un método getDroidNames()
, podemos decir{{ ship.droidNames ?: 'none'
}}.
¡Ya está! Actualiza... y disfruta de los nombres de los droides en la página de inicio.
A continuación: utilicemos Foundry para establecer la relación ManyToMany en los accesorios. ¡Otro lugar en el que brilla Foundry!