Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Relaciones e IRIs

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

Acabo de intentar crear un CheeseListing poniendo la propiedad owner a 1: el id de un usuario real en la base de datos. Pero... ¡no le ha gustado! ¿Por qué? Porque en la Plataforma API y, comúnmente, en el desarrollo moderno de APIs en general, no utilizamos ids para referirnos a los recursos: utilizamos IRIs. Para mí, esto fue extraño al principio... pero rápidamente me enamoré de esto. ¿Por qué pasar ids enteros cuando las URLs son mucho más útiles?

Mira la respuesta del usuario que acabamos de crear: como toda respuesta JSON-LD, contiene una propiedad @id... que no es un id, ¡es un IRI! Y esto es lo que utilizarás siempre que necesites referirte a este recurso.

Vuelve a la operación POST CheeseListing y establece owner como/api/users/1. Ejecuta eso. Esta vez... ¡funciona!

Y fíjate, cuando transforma el nuevo CheeseListing en JSON, la propiedad owneres ese mismo IRI. Por eso Swagger lo documenta como una "cadena"... lo cual no es del todo exacto. Claro, en la superficie, owner es una cadena... y eso es lo que muestra Swagger en el modelo cheeses-Write.

Pero sabemos... con nuestro cerebro humano, que esta cadena es especial: en realidad representa un "enlace" a un recurso relacionado. Y... aunque Swagger no lo entienda del todo, echa un vistazo a la documentación de JSON-LD: en /api/docs.jsonld. Veamos, busca propietario. ¡Ja! Esto es un poco más inteligente: JSON-LD sabe que se trata de un Enlace... con algunos metadatos extravagantes para decir básicamente que el enlace es a un recurso deUser.

La gran conclusión es ésta: una relación es sólo una propiedad normal, excepto que se representa en tu API con su IRI. Muy bueno.

Añadir quesosListados a Usuario

¿Qué pasa con el otro lado de la relación? Utiliza los documentos para ir a buscar elCheeseListing con id = 1. Sí, aquí está toda la información, incluido el owner como IRI. ¿Pero qué pasa si queremos ir en la otra dirección?

Actualicemos para cerrar todo. Ve a buscar el recurso User con id 1. Bastante aburrido: email y username. ¿Y si también quieres ver qué quesos ha publicado este usuario?

Eso es igual de fácil. Dentro de User encuentra la propiedad $username, copia la anotación@Groups y pégala encima de la propiedad $cheeseListings. Pero... por ahora, sólo vamos a hacer esto legible: sólo user:read. Más adelante hablaremos de cómo puedes modificar las relaciones de colección.

... lines 1 - 22
class User implements UserInterface
{
... lines 25 - 58
/**
... line 60
* @Groups("user:read")
*/
private $cheeseListings;
... lines 64 - 184
}

Bien, actualiza y abre la operación de elemento GET para Usuario. Antes de intentarlo, ya anuncia que ahora devolverá una propiedad cheeseListings que, curiosamente, será un array de cadenas. Veamos qué aspecto tiene User id 1. ¡Ejecuta!

Ah... ¡es una matriz! Una matriz de cadenas IRI, por supuesto. Por defecto, cuando relacionas dos recursos, la Plataforma API mostrará el recurso relacionado como un IRI o una matriz de IRIs, lo cual es maravillosamente sencillo. Si el cliente de la API necesita más información, puede hacer otra petición a esa URL.

O... si quieres evitar esa petición adicional, puedes optar por incrustar los datos del listado de quesos directamente en el JSON del recurso del usuario. Hablemos de eso a continuación.

Leave a comment!

Este tutorial funciona muy bien para Symfony 5 y la Plataforma API 2.5/2.6.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "api-platform/core": "^2.1", // v2.4.3
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/annotations": "^1.0", // 1.10.2
        "doctrine/doctrine-bundle": "^1.6", // 1.11.2
        "doctrine/doctrine-migrations-bundle": "^2.0", // v2.0.0
        "doctrine/orm": "^2.4.5", // v2.7.2
        "nelmio/cors-bundle": "^1.5", // 1.5.5
        "nesbot/carbon": "^2.17", // 2.19.2
        "phpdocumentor/reflection-docblock": "^3.0 || ^4.0", // 4.3.1
        "symfony/asset": "4.2.*|4.3.*|4.4.*", // v4.3.11
        "symfony/console": "4.2.*", // v4.2.12
        "symfony/dotenv": "4.2.*", // v4.2.12
        "symfony/expression-language": "4.2.*|4.3.*|4.4.*", // v4.3.11
        "symfony/flex": "^1.1", // v1.17.6
        "symfony/framework-bundle": "4.2.*", // v4.2.12
        "symfony/security-bundle": "4.2.*|4.3.*", // v4.3.3
        "symfony/twig-bundle": "4.2.*|4.3.*", // v4.2.12
        "symfony/validator": "4.2.*|4.3.*", // v4.3.11
        "symfony/yaml": "4.2.*" // v4.2.12
    },
    "require-dev": {
        "symfony/maker-bundle": "^1.11", // v1.11.6
        "symfony/stopwatch": "4.2.*|4.3.*", // v4.2.9
        "symfony/web-profiler-bundle": "4.2.*|4.3.*" // v4.2.9
    }
}