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 SubscribeAntes hemos añadido un montón de filtros a DragonTreasure
. Vamos a añadir unos cuantos más -empezando por User
- para que podamos mostrar algunos superpoderes de filtrado en las relaciones.
Empieza como de costumbre: ApiFilter
y utilicemos primero PropertyFilter::class
. Recuerda: se trata de una especie de filtro falso que permite a nuestro cliente de la API seleccionar los campos que desee. Y todo esto es bastante familiar hasta ahora.
... lines 1 - 4 | |
use ApiPlatform\Metadata\ApiFilter; | |
... line 6 | |
use ApiPlatform\Serializer\Filter\PropertyFilter; | |
... lines 8 - 22 | |
PropertyFilter::class) ( | |
... lines 24 - 25 | |
class User implements UserInterface, PasswordAuthenticatedUserInterface | |
{ | |
... lines 28 - 174 | |
} |
Cuando nos dirigimos, actualizamos y vamos a la ruta de recolección GET
... vemos un nuevo campoproperties[]
. Podríamos elegir devolver sólo username
... o username
y dragonTreasures
.
Cuando pulsamos "Ejecutar"... ¡perfecto! Vemos los dos campos... donde dragonTreasures
es una matriz de objetos, cada uno de los cuales contiene los campos que elegimos incrustar.
De nuevo, esto es super duper normal. Así que vamos a intentar algo más interesante. De hecho, lo que vamos a intentar no está soportado directamente en los documentos interactivos.
Así que, copia esta URL... pégala y añade .jsonld
al final.
Éste es el objetivo: quiero devolver el campo username
y después sólo el campo name
de cada tesoro dragón. La sintaxis es un poco fea: es [dragonTreasures]
, seguido de []=name
.
Y así... ¡sólo muestra name
! Así que, directamente,PropertyFilter
nos permite llegar a través de las relaciones.
Hagamos otra cosa. Volvamos a DragonTreasure
. Podría ser útil filtrar por $owner
: podríamos obtener rápidamente una lista de todos los tesoros de un usuario concreto.
¡No te preocupes! Sólo tienes que añadir ApiFilter
por encima de la propiedad $owner
, pasando el fiel SearchFilter::class
seguido de strategy: 'exact'
.
... lines 1 - 55 | |
class DragonTreasure | |
{ | |
... lines 58 - 101 | |
SearchFilter::class, strategy: 'exact') ( | |
private ?User $owner = null; | |
... lines 104 - 215 | |
} |
Volviendo a los documentos, si abrimos la ruta de la colección de tesoros GET
y le damos una vuelta... veamos... aquí está: "propietario". Introduce algo como /api/users/4
... suponiendo que se trate de un usuario real en nuestra base de datos, y... ¡sí! ¡Aquí están los cinco tesoros propiedad de ese usuario!
Pero quiero volverme más loco: quiero encontrar todos los tesoros que sean propiedad de un usuario que coincida con un nombre de usuario concreto. Así que en lugar de filtrar porowner
, tenemos que filtrar por owner.username
.
¿Cómo? Bueno, cuando queremos filtrar simplemente por owner
, podemos poner el ApiFilter
justo encima de esa propiedad. Pero como queremos filtrar por owner.username
, no podemos ponerlo encima de una propiedad... porque owner.username
no es una propiedad. Éste es uno de los casos en los que necesitamos poner el filtro encima de la clase. Y... eso también significa que tenemos que añadir una opción properties
establecida en una matriz. Dentro, digamos 'owner.username'
y establecerla en la estrategia partial
.
... lines 1 - 55 | |
SearchFilter::class, properties: [ ( | |
'owner.username' => 'partial', | |
]) | |
class DragonTreasure | |
{ | |
... lines 61 - 218 | |
} |
¡Vale! Vuelve y actualiza. Sabemos que tenemos un propietario cuyo nombre de usuario es "Smaug"... así que volvamos a la ruta de la colección GET
y... aquí en owner.username
, busquemos "maug"... y pulsemos "Ejecutar".
Veamos... ¡Ha funcionado! Esto muestra todos los tesoros propiedad de cualquier usuario cuyo nombre de usuario contenga maug
. ¡Genial!
Bien, escuadrón: prepárate para la gran final: los Subrecursos. Éstos han cambiado mucho en API Platform 3. Vamos a sumergirnos en ellos.
Hey @David-S
I think that's unexpected. Have you watched this chapter? You may find it helpful https://symfonycasts.com/screencast/api-platform-extending/uuid-identifier
By the way, I don't recommend using UUIDs as the primary key because it will slow down your queries. It's better to keep a traditional integer id as the primary key and add a UUID as your "public id"
Cheers!
Hey @MolloKhan,
thanks for your reply. I wasn't sure that "slowing down" is a real world problem (at least for my application).
So, to keep it simple, I wanted to use the uuid instead of integer id. But Ok, I will use int as primary and add uuids as identifiers.
I used Symfony\Component\Uid\Uuid
. In that Symfony 5 API Tutorial Ramsey\Uuid\Uuid
is used. Which one shpuld be uses now with Symfony 6 and API Platform 3?
Good question. Since Symfony 5.2 there's a UID component that basically replaces Ramsey's library. You can read more about it here https://symfony.com/doc/current/components/uid.html#storing-uuids-in-databases
Cheers!
Hi everyone,
I am working on an application with API Platform 3. I have an Entity called "Users" and another Entity called "Prospects". I have created a route: /api/users/{partner_id}/prospects/{id}, where {partner_id} represents the custom id of users and {id} represents the id of prospects.
This setup is functioning correctly, but I want to apply a filter on the subresource "prospects," and I am having trouble understanding how to do this. I have encountered some issues, but I haven't found a solution yet.
Here is a portion of my code:
#[ApiResource(
operations: [
new Get(
shortName: "Users",
uriTemplate: '/users/{partner_id}/prospects/{id}',
uriVariables: [
'partner_id' => new Link(fromClass: Users::class, fromProperty: 'prospects'),
'id' => new Link(fromClass: Prospects::class)
],
)
],
)]
#[ApiFilter(SearchFilter::class, properties:[
'status',
'lastname' => 'ipartial',
'upline'
])]
Please let me know if you have any suggestions or solutions. Thank you!
Hey @David-G!
This is not a use-case I had thought of before! You said this isn't working. What does it do? An error? Just not work at all?
Cheers!
Hi,
The bug was between the chair and the screen because I didn't realize that I was trying to apply a filter on a Get operation when filters only work on GetCollection operations.
Thanks !
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^3.0", // v3.0.8
"doctrine/annotations": "^1.0", // 1.14.2
"doctrine/doctrine-bundle": "^2.8", // 2.8.0
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
"doctrine/orm": "^2.14", // 2.14.0
"nelmio/cors-bundle": "^2.2", // 2.2.0
"nesbot/carbon": "^2.64", // 2.64.1
"phpdocumentor/reflection-docblock": "^5.3", // 5.3.0
"phpstan/phpdoc-parser": "^1.15", // 1.15.3
"symfony/asset": "6.2.*", // v6.2.0
"symfony/console": "6.2.*", // v6.2.3
"symfony/dotenv": "6.2.*", // v6.2.0
"symfony/expression-language": "6.2.*", // v6.2.2
"symfony/flex": "^2", // v2.2.4
"symfony/framework-bundle": "6.2.*", // v6.2.3
"symfony/property-access": "6.2.*", // v6.2.3
"symfony/property-info": "6.2.*", // v6.2.3
"symfony/runtime": "6.2.*", // v6.2.0
"symfony/security-bundle": "6.2.*", // v6.2.3
"symfony/serializer": "6.2.*", // v6.2.3
"symfony/twig-bundle": "6.2.*", // v6.2.3
"symfony/ux-react": "^2.6", // v2.6.1
"symfony/validator": "6.2.*", // v6.2.3
"symfony/webpack-encore-bundle": "^1.16", // v1.16.0
"symfony/yaml": "6.2.*" // v6.2.2
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
"symfony/debug-bundle": "6.2.*", // v6.2.1
"symfony/maker-bundle": "^1.48", // v1.48.0
"symfony/monolog-bundle": "^3.0", // v3.8.0
"symfony/stopwatch": "6.2.*", // v6.2.0
"symfony/web-profiler-bundle": "6.2.*", // v6.2.4
"zenstruck/foundry": "^1.26" // v1.26.0
}
}
Hi everyone,
so I have an interesting error. Instead of integer ids I use uuids (as primary key).
When searching "DreagonTreasures" with a specific user e.g. /api/users/0189d986-1e5c-7205-8e1c-466b139ceda1
I get a 200 response with
Here is what id looks like in my class:
I'm using MySQL. The id (with uuid value) apparently is of type binary(16) in MySQL. Does it have something to do with that?
What am I missing / how can I fix this?
(When I use integer ids it works as it should.)
Thanks for your help.