Chapters
27 Chapters
|
2:54:11
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.1.3
Subscribe to download the code!Compatible PHP versions: ^7.1.3
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
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.
This tutorial works great for Symfony 5 and API Platform 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.21.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
}
}
62 Comments
To get the @Groups annotation to work, I had to add this use statement:
use Symfony\Component\Serializer\Annotation\Groups;Unless I missed something earlier, that step should be added to the <i>Adding a Group for Normalization</i> section.
Hey John,
You're totally right, we forgot to show the namespace in the code block, I fixed it in https://github.com/SymfonyC... - the correct code block will be available very soon on the website.
Thank you for reporting it!
Cheers!
I had troubles with serialization groups. For thouse with similar problem, maybe my solution will help.
Try to add
`serializer:
to framework settings (config/packages/framework.yaml).
(I'm on symfony 6.0.3 and PHP 8)
Hey Krzysztof R.
Can you please provide more info about issue you got?
I guess it's related to PHP Attributes, some packages uses attributes instead of annotation, when supported PHP version is installed
Cheers!
Yes I'm using attributes, but annotations also did't work for me.
It was working fine for regular entity fields. But when I try to add e.g. textDescription field to the API it was not present in schema or endpoint (I tried to send it anyway, but didn't work).
When I enabled annotations in serializer config it started to work ;)
interesting Attributes should work without additional configuration IIRC...
Thanks again for investigation
I was starting from this boilerplate
https://github.com/martinso...
maybe there was something wrong with config. I'm not that much into symfony to check that. Anyway it is working perfect now so all good ;)
Cheers ;)
Hi,
I'm having a problem with Serialization groups and Inhetitance.
Let you have two related entities: Blog and Comment. Both inerit from an abstract base "Content" class.
The column "body" is on the Content Class. As usual a Blog can have one or more Comment.
The problem is that I cannot figure out how to handle the body; In the Blog detail endpoint, I want to show the list of comment with some details ( ex: the title of the comment). Cause the body is a property shared between Blog and Comment, and I want to show the body on Blog endpoint, the body will be visible also con each comment of the blog.
I just want to see the body of the blog, not for all related comments.
I tried with a common "content:item:read", but this group show the body of the comment also in blog entrypoint.
Which is the best way to handle groups with Inheritance?
Hey Gianluca-F!
Yea, this is tricky because, thanks to the inheritance, you can't control make the serialization groups (at when using attributes) different on the
bodyfield forBlogvsComment. Using simple methods, I can't think of a way to do this: no matter what serialization group you add tobody, if that group is returned on the Blog detail endpoint, then it will definitely also be returned in the embedded comments from that endpoint. So, unless I'm missing some nice trick, I also don't see an easy solution!What options do we have? I can think of a few, none of which are super great:
A) You could use XML for your serialization configuration. This would allow you to put different serialization groups for
bodyon each class. The problem, of course, is that using attributes is way nicer. I'm not sure if you can mix XML and attributes (like use attributes for everything, but then just XML for thebodyfield). My guess is that you can't.B) Stop using inheritance. I'm sure you have some good reasons to use inheritance, but if you stopped, the problem goes away. If there is some logic you want to share, you could move the methods it into a trait (but not the property itself). Then, use the trait in
BlogandCommentbut then manually add the property to each class individually.Beyond that, you could probably find some more technical trick... like maybe decorating the normalizer and then, if you detect that you are able to normalize a
Commentin the context of aBlog, you change the normalization groups in$contextbefore calling the inner normalizer. Probably possible, but pretty technical.Let me know what you end up doing!
Cheers!
Hi Ryan,
thanks for your reply; yes as I go ahead with development, I'm having some issues with inheritance.
The reason why I choose the inheritance is that all these entities share up to 90% of properties ( a blog or a commet IS a generic content ) , so inheritance is natural BUT ... with API I'm having problems.
Another problem is with ApiIdentifier.
For news, I have that ID is the ApiIdentifier ( id is not shared ) but for another entity, SLUG is the ApiIdentifier ( slug is shared in base class ).
Also in this case, I have to copy the property also on Child entity, to have only one prop as ApiIdentifier.
I could continue to use BaseClass for setter and getter, instead of dozen of traits ... not very clear but ... who really care ?? :-)
Hi,
Is there a way to set the serialization group dynamically, using, for example, a parameter on query string?
Hello GianlucaF
If I understood you correctly, then you can do it with context builder. You will find it in the security part of ApiPlatform series
PS fast link https://symfonycasts.com/sc...
StayTuned! Cheers!
I am having a strange issue whereby my setTextDescription is not coming through on my swagger page for the post action
Hey Sam Z.
Did you add the
cheese_listing:writegroup on it?Hey, Diego!
I have the same problem as Sam. My setTextDescription just won't show up for the POST action when I use this serialization groups. I tried to change the name to setDescription and then it shows.
Hey @Alexsander!
Thanks for the extra info! This is interesting. I'm wondering 2 things:
1) If you use setTextDescription() (where it son't show up for the POST action), can you actually *send* a textDescription field in the JSON and have it update?
2) If you use setTextDescription() with an @SerializedName("description") above the method, does it show up then?
This is odd enough that I'm wondering if something changed in newer versions of ApiPlatform. If they did, my guess is that would be unintentional (i.e. a bug).
Cheers!
With SerializedName works. Thanks
Hey Ryan!
So I tried to do all over again and the problem is still the same.
1) When I (as shown in the tutorials) delete setDescription() and use setTextDescription() method instead everything is working fine. I have textDescription field and I can send/update database with this field. But as soon as I use serialization groups this field is gone from POST operation. I have only "title" and "price" fields. I also want to point out that in my "write model/schema" the "textDescription" field is shown, but in POST operation it is not shown.
2) No even in this case it won't show up. But since I can see this textDescription field in my "write model", this command updates it from "textDescription" to "description" as expected.
So when I use the post action along with @SerializedName("description") then the method works so it seems to be working as planned the only issue is it does not show up on the swagger page
Hey Sam Z. & @Aleksander!
Sorry for the slow reply - I had some time off this week :). Ok, with these new updates... and the fact that there are two of you having the issue - I'm *fairly* sure that this is some bug in API Platform in a newer version (than we use in the tutorial). I'd recommend opening an issue in API Platform if you can with the details. I can't (at the moment) test this myself... because I'm on SUCH slow internet that Composer barely works 🤦♂️
Anyways, if either if you DO create an issue, please link me to it and I can look / add any extra info to the issue :).
Cheers!
Did anyone open an issue yet? I can't find any on GitHub.
I happen to have the exact same problem as @Aleksander and @Sam Zlotnick.
Did you guys open an issue or find out how to work around that bug?
I also made the following observation:
the description field is shown in the Schemas/Model section from the swagger doc:
<blockquote>cheeses-Write{
title string
minLength: 2
maxLength: 50
price* integer
description string
writeOnly: true
The description of the cheese as raw text.
}</blockquote>
But under
POST /api/cheeses Creates a cheeses resourcethe field is missing, as the Example Value just shows:<br />{<br /> "title": "string",<br /> "price": 0<br />}<br />But when i click on "Schema", just next to "Example Value" it says:
<br />cheeses.jsonld-Read{<br />title string<br />minLength: 2<br />maxLength: 50<br />price* integer<br />}<br />Am i confused, or shouldn't it say"Write" instead of read here?
Hey Tristan P.!
As I just mentioned on a different chapter, I think this issue is the same as the other one - https://symfonycasts.com/sc...
I am also not aware of any issue that's been opened yet - I would love if you could open it!
Cheers!
Thanks for the reply, I opnened an issue on friday: https://github.com/api-plat...
btw: great course and teacher!
Ah, great work Tristan P.! And it looks like someone has linked to another issue - https://github.com/api-plat... and another issue https://github.com/api-plat... which might be the same thing. That is GREAT news... because it makes it seem like the bug is definitely real and (hopefully) it should get attention. One user says that downgrading to 2.6.3 fixes it. I've added a comment to https://github.com/api-plat... to see if I can motivate someone to do some extra digging ;).
Cheers!
The below are the 2 setters I have for the description however in the swagger page under post it only shows title and price for the inputs
Hi, I'm using api-platform configuration with yaml and not with annotations, also the serializer, so, I'm struggling to get a getProperty() to work with groups, like your example of getCreatedAtAgo(), but, in my case, I can't or I shouldn't put "Groups({"read"})" annotation on that method, I must set it in the yaml. Is this possible anyway?
PD: Sorry for my english :)
Hey Nestor B.
I think that's possible, you can configure your groups by entity like shown in this example: https://api-platform.com/do...
Cheers!
Hello. I have 2 groups to read:
* @ApiResource(
* normalizationContext={"groups"={"group:read","group_clear:read"}}
* )
By default works "group:read" context. How can I make a request to the api platform to get data in context "group_clear:read"?
Hey Dmitriy!
It sounds like you want to be able to add a group dynamically - maybe based on the currently-authenticated user or maybe a query parameter. Is that right? If so check out a custom context builder - we do something (sort of) similar here - https://symfonycasts.com/sc...
I hope that helps! Cheers!
Thank you, Ryan. I solved this problem with:
https://api-platform.com/do...
Your solution is interesting, but so far too complicated for me )
Hey Dmitriy!
Happy you got it working - my solutions are not always the only, or even the best ones ;).
Cheers!
Properties not showing up when I use normalization contexts groups. Any ideas? Code example here: https://pastebin.com/UtyHsZt5
Hey David B.
Hmm, your code looks correct. It makes me wonder if for some reason your cache didn't refresh automatically. Try deleting it manually
rm var/cache/*and try again. Also, double-check that you're running in the dev environment because if you're in prod, then you have to refresh the cache after every single changeCheers!
Thank you for responding so quickly! I manged to figure it out shortly after I posted the question. Out of pure frustration I did a cache:clear and that resolved the issue. My DEV evn is running on a virtual machine so i'll chalk it up to a VM issue.
Hello,
Thanks for the tutorial. I am following it and trying to code along with an example project.
But as soon as I added the serialization groups I had a problem with the properties. For example one is only read-only anymore but has the write group as well. I also tried to make the request and ignore the docs but it didn't work.
I pushed the project to github: https://github.com/schnetzi...
Can you explain to me if I made any mistakes? Is the indentation in the comments important?
Thanks in advance!
I investigated a little bit further and it seems like the underscore in the property is causing the problem/error. For example `group_name` is read-only even though it has the serialization group to write but `position` works just fine. It's also with all the other underscore-properties.
When I set the properties to public the readonly is gone and it works.
Hey Paul
That's happening because you have an inconsistency in your "casing", I noticed that you have some "camel cased" properties and others in the "snake case" form. In theory, you should not do that, if you can refactor it, great! If not, you can choose which "Name Converter" to use (check this out: https://api-platform.com/do... ), or, you can use the "@SerializedName" annotation to choose a valid name https://symfony.com/doc/mas...
I hope this helps. Cheers!
Wow good catch! Thanks a lot. I changed my properties to be camel-case now and it works as `private` properties.
Hello,
Thanks for this awesome tutorial! But I did notice one small thing, in the video for this chapter, the symbols under the SymfonyCast logo and in the popup prompt are shown as question mark boxes.
Cheers!
The weird question marks have been fixed, thank you so much for pointing that out Hintay !
Hey Hintay
ha that's a great catch! Thanks for the feedback, we will investigate this questions marks! )))
Cheers!
HI
Thanks for nice tutorial. I got two questions:
1. Can I add multiple read and write groups?
2. How can I differentiate between multiple read and write groups, while making API call?
TIA
Hey infete
1) Yes, you can add as many groups as you want to your API resources
2) I don't fully get your question. What you want to achieve?
Cheers!
Hello,
I think MolloKhan is talking about conditional API response.
ie "Is there a way to ask for a specific normalization/denormalization context or group while consuming the API?"
use case:
User A can GET Title and price (cheese_listing:read_limited)
User B can GET Title, price and description (cheese_listing:read)
Hey JulienG
In that case what you are looking for is "voters". In this chapter you can see a good example of how to implement them with ApiPlatform https://symfonycasts.com/sc...
I also recommend watching this chapter (and a few more after it) https://symfonycasts.com/sc...
Cheers!
I figured this out. I noticed in the video that the groups annotation can be set above the getter methods so that fixed my issue. I move all group tags to getter methods.
I have a situation with the groups annotation is not showing all of the properties that I have labeled with groups. @Groups({"pharmacies_list:read"})
<br />{<br /> "@context": "string",<br /> "@id": "string",<br /> "@type": "string",<br /> "ncpdp": "string",<br /> "npi": "string",<br /> "city": "string",<br /> "state": "string",<br /> "zipcode": "string"<br />}These are what I am getting back but business, address, and phone number is missing. How can I figure out what I wrong when there are no error message in the logs
Thought I would throw this in for good measure.
`
*
I noticed that the properties that were skipped have underscores in them. How do I fix this?
Hey sherwingaddis
> I noticed that the properties that were skipped have underscores in them. How do I fix this?
What you mean with that? I would need to see your code to get a better idea of what's going on (at least just that entity)
Cheers!
MolloKhan i have the same as Sherwin expierences. For example if a property in my Entity is named: "$elapsed_time" (notice the underscore) it's not showing when it's assigned to a serialization group. And for example the property $distance (without underscore) is showing up.
`
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;
use Carbon\Carbon;
use Doctrine\ORM\Mapping as ORM;
/**
*/
class DetailedSegmentEffort
{
.....
}
`
Hey lexhartman
Seems like it's related to this problem https://github.com/api-platform/core/issues/1554
What you can do is to play with the
@SerializedName()annotation to make it match to your property getter/setterFrom the docs: https://symfony.com/doc/current/components/serializer.html#using-camelized-method-names-for-underscored-attributes - just scroll down a bit
Cheers!
Nice, thanks!
"Houston: no signs of life"
Start the conversation!