Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Actualización de una entidad

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.

Start your All-Access Pass
Buy just this tutorial for $12.00

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

Login Subscribe

Hemos conseguido cambiar el valor de la propiedad votes. Ahora tenemos que hacer una consulta de actualización para guardarlo en la base de datos.

Para insertar un VinylMix, utilizamos el servicio EntityManagerInterface, y luego llamamos apersist() y flush(). Para actualizar, utilizaremos exactamente el mismo servicio.

Actualizar una entidad con el Gestor de Entidades

Añade un nuevo argumento al método vote(), indicado con EntityManagerInterface. Lo llamaré $entityManager. Luego, muy sencillamente, después de haber establecido la propiedad votes con el nuevo valor, llama a $entityManager->flush().

... lines 1 - 12
class MixController extends AbstractController
{
... lines 15 - 44
public function vote(VinylMix $mix, Request $request, EntityManagerInterface $entityManager): Response
{
... lines 47 - 53
$entityManager->flush();
... line 55
}
}

¡Eso es todo, gente! Antes de explicar esto, vamos a asegurarnos de que funciona. Actualiza. Ahora mismo tenemos 49 votos. Voy a pulsar arriba. Dice 50. Pero la verdadera prueba es que cuando refrescamos... ¡sigue mostrando 50! ¡Se ha guardado!

Persistir y descargar: los detalles

Vale, cuando antes creamos un nuevo VinylMix, tuvimos que llamar a persist() -pasando el objeto VinylMix - y luego a flush(). Pero ahora, lo único que necesitamos es flush(). ¿Por qué?

Esta es la historia completa. Cuando llamas a flush(), Doctrine hace un bucle sobre todos los objetos de entidad que "conoce" y los "guarda". Y ese "guardado" es inteligente. Si Doctrine determina que una entidad no se ha guardado todavía, ejecutará una consulta INSERT, pero si se trata de un objeto que ya existe en la base de datos, Doctrine averiguará qué ha cambiado en el objeto -si es que ha cambiado algo- y ejecutará una consulta UPDATE. ¡Sí! Sólo tenemos que llamar a flush() y Doctrine averiguará qué hacer. Es... lo mejor desde las gominolas Starburst.

Pero... ¿por qué no tenemos que llamar a persist() cuando estamos actualizando? Bueno, puedes decir $entityManager->persist($mix) si quieres. Es que es... ¡totalmente redundante!

Cuando llamas a persist(), le dice a Doctrine:

Quiero que conozcas este objeto para que, la próxima vez que llame a flush(), sepas que debes guardarlo.

Cuando creas un nuevo objeto entidad, Doctrine no conoce realmente ese objeto hasta que llamas a persist(). Pero cuando actualizas una entidad, significa que ya has pedido a Doctrine que consulte por ese objeto. Así que Doctrine ya lo conoce... y cuando llamemos a flush(), Doctrine comprobará -de forma automática- ese objeto para ver si se ha realizado algún cambio en él.

Redirigir a otra página

Así que... ¡hemos guardado con éxito el nuevo recuento de votos en la base de datos! ¿Y ahora qué? Porque... No creo que esta declaración die vaya a quedar bien en producción.

Bueno, cada vez que se envía un formulario con éxito, siempre se hace lo mismo: redirigir a otra página. ¿Cómo redirigimos en Symfony? Conreturn $this->redirect() pasando la URL a la que quieras redirigir. Aunque, por lo general, estamos redirigiendo a otra página de nuestro sitio... así que utilizamos un atajo similar llamado redirectToRoute() y luego pasamos un nombre de ruta.

Vamos a redirigir a la página del programa. Copia el nombre de la ruta app_mix_show, pégalo... y al igual que con la función Twig path(), ésta acepta un segundo argumento: una matriz de los comodines de la ruta que debemos rellenar. En este caso, tenemos un comodín{id}... así que pasa id ajustado a $mix->getId().

... lines 1 - 44
public function vote(VinylMix $mix, Request $request, EntityManagerInterface $entityManager): Response
{
... lines 47 - 55
return $this->redirectToRoute('app_mix_show', [
'id' => $mix->getId(),
]);
}
... lines 60 - 61

Ahora, recuerda: los controladores siempre devuelven un objeto Response. Y resulta que una redirección es una respuesta. Es una respuesta que, en lugar de contener HTML, básicamente dice

Por favor, envía al usuario a esta otra URL

El método redirectToRoute() es un atajo que devuelve este objeto de respuesta especial, llamado RedirectResponse.

De todos modos, ¡probemos todo el flujo! Refresca, y... ¡lo tienes! Después de votar, acabamos de nuevo en esta página. Y, gracias a Turbo, todo esto sucede a través de llamadas Ajax... lo cual es un buen plus.

El único problema es que... es tan suave que no es súper obvio que mi voto se haya guardado realmente, aparte de ver cómo cambia el número de voto. Sería mejor si mostráramos un mensaje de éxito. Vamos a hacer eso a continuación, aprendiendo sobre los mensajes flash. También vamos a hacer más moderna nuestra entidad VinylMix explorando el concepto de modelos inteligentes frente a los anémicos.

Leave a comment!

2
Login or Register to join the conversation
thephilosoft Avatar
thephilosoft Avatar thephilosoft | posted hace 10 meses

In a challenge after this video. Shouldn't 1 be the answer? Or at least there should be a call for setPrice with a different value...

1 Reply

Hey Thephilosoft,

Yes, you're totally correct, the price should be changed to make the 2nd query, otherwise the Doctrine is smart enough to ignore the last flush() call. Thank you for reporting it, I changed the price in the last setPrice() call to avoid editing the explanation message.

Cheers!

1 Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.7", // v3.7.0
        "doctrine/doctrine-bundle": "^2.7", // 2.7.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.12", // 2.12.3
        "knplabs/knp-time-bundle": "^1.18", // v1.19.0
        "pagerfanta/doctrine-orm-adapter": "^3.6", // v3.6.1
        "pagerfanta/twig": "^3.6", // v3.6.1
        "sensio/framework-extra-bundle": "^6.2", // v6.2.6
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.0
        "symfony/asset": "6.1.*", // v6.1.0
        "symfony/console": "6.1.*", // v6.1.2
        "symfony/dotenv": "6.1.*", // v6.1.0
        "symfony/flex": "^2", // v2.2.2
        "symfony/framework-bundle": "6.1.*", // v6.1.2
        "symfony/http-client": "6.1.*", // v6.1.2
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "6.1.*", // v6.1.0
        "symfony/runtime": "6.1.*", // v6.1.1
        "symfony/twig-bundle": "6.1.*", // v6.1.1
        "symfony/ux-turbo": "^2.0", // v2.3.0
        "symfony/webpack-encore-bundle": "^1.13", // v1.15.1
        "symfony/yaml": "6.1.*", // v6.1.2
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.1
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
        "symfony/debug-bundle": "6.1.*", // v6.1.0
        "symfony/maker-bundle": "^1.41", // v1.44.0
        "symfony/stopwatch": "6.1.*", // v6.1.0
        "symfony/web-profiler-bundle": "6.1.*", // v6.1.2
        "zenstruck/foundry": "^1.21" // v1.21.0
    }
}
userVoice