Chapters
39 Chapters
|
4:45:13
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.1.3, <8.0
Subscribe to download the code!Compatible PHP versions: ^7.1.3, <8.0
-
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!
31.
A "Normalizer Aware" Normalizer
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, <8.0",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^2.1", // v2.4.5
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/annotations": "^1.0", // 1.13.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.6
"nesbot/carbon": "^2.17", // 2.21.3
"phpdocumentor/reflection-docblock": "^3.0 || ^4.0", // 4.3.1
"symfony/asset": "4.3.*", // v4.3.2
"symfony/console": "4.3.*", // v4.3.2
"symfony/dotenv": "4.3.*", // v4.3.2
"symfony/expression-language": "4.3.*", // v4.3.2
"symfony/flex": "^1.1", // v1.21.6
"symfony/framework-bundle": "4.3.*", // v4.3.2
"symfony/http-client": "4.3.*", // v4.3.3
"symfony/monolog-bundle": "^3.4", // v3.4.0
"symfony/security-bundle": "4.3.*", // v4.3.2
"symfony/twig-bundle": "4.3.*", // v4.3.2
"symfony/validator": "4.3.*", // v4.3.2
"symfony/webpack-encore-bundle": "^1.6", // v1.6.2
"symfony/yaml": "4.3.*" // v4.3.2
},
"require-dev": {
"hautelook/alice-bundle": "^2.5", // 2.7.3
"symfony/browser-kit": "4.3.*", // v4.3.3
"symfony/css-selector": "4.3.*", // v4.3.3
"symfony/maker-bundle": "^1.11", // v1.12.0
"symfony/phpunit-bridge": "^4.3", // v4.3.3
"symfony/stopwatch": "4.3.*", // v4.3.2
"symfony/web-profiler-bundle": "4.3.*" // v4.3.2
}
}
23 Comments
Hey there
I found an issue with this approach.
When you have nested objects the custom normalizer is not called on the embedded object, because the context seems preserved and the flag is up (set in the parent object) and the normalizer is skipped. :(
Hey @Georgi!
Ah! Is it an object with a self referencing relationship (and so the embedded objects are of the same class)? Indeed, this is very possible. I think what you would need to do is, instead of storing a Boolean to track if our normalizer is called, store a list of spl_object_id.
So basically, set a new key on the context - like ALREADY_NORMALIZED_OBJECT_IDS that is an array. Then, use spl_object_id() on the object that’s being normalized. Use that to see if that object has been normalized. And set the id onto that context array.
I may be overlooking some detail - but let me know if that works :). In general, I do wish custom normalizers were a bit easier to create ;).
Cheers!
there when I tried to create a custom Normalizer the embedded objects are not being denormalized. So I have the following:
`
"objects": {
"1": {
}
`
How can I avoid this?
Hey Anton B.!
Hmmm. Can you post your denormalizer and the API class that's in question? This stuff is complex :p.
Cheers!
Hi there!
I am trying to build the deserialization version. My goal if to give permission for a user (with no ROLE_ADMIN) to update some of his own properties.
So in the entity User, there is for example:
`
`
Here is my deserializer:
`
<?php
namespace App\Serializer\Denormalizer;
use App\Entity\UserObject;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
class UserObjectDenormalizer implements ContextAwareDenormalizerInterface, CacheableSupportsMethodInterface, DenormalizerAwareInterface
{
}
`
So I wrote the problem inside the code: I have to check if the user requesting the update is the user described in $data, but $data is just an array which can be like that:
<br />['firstName' => 'Alice']<br />So I can't just do for example:
<br />if ($data === $this->security->getUser()) {...<br />How can I do to achive my goal please?
I found where the information about the object is:
$context[AbstractItemNormalizer::OBJECT_TO_POPULATE]
So I did
<br />if ($context[AbstractItemNormalizer::OBJECT_TO_POPULATE] === $this->security->getUser()) {<br />And it worked
Hey Simon L.
Nice to see that you solved your issue! Probably better will be to compare users ID instead of complete user objects
Cheers!
Hi sadikoff !
Yes I noticed that @weaverryan is usually comparing Ids instead of the full objects themselves. Is there any reason for this, like performance? Or is it a matter of taste?
I feel like comparing Ids make the software computing for 2 more methods (->getId() x2) , so my intuition tells me it is less optimized.
Waiting to hear from you :)
Your thought makes sense, but what if somehow you get 2 instances of the same object? Then
===will not work. From performance viewgetId()doesn't compute anything, it just returns pre-populated data so the win of not using it will be soooo minimal :) Probably even no win at all!So as a result:
Cheers!
"Let me put my groups and then do your job again but this time, ignore me."
I find the decorator pattern for the ContextBuilder far more intuitive. Am I comparing apples to oranges?
Hey @keuwa!
You're 100% correct. I really dislike how hard it is to decorate normalizers - I think it's a design flaw. So... I agree ;). It did not *need* to be built this way - it would be better if you could hook into the normalization process to change groups, but without completely "taking over" the process and requiring us to call the system again.
Cheers!
there
Error
*in \src/Serializer/Normalizer/UserNormalizer.php (line 37)
private function userIsOwner(User $user): bool
*UserNormalizer->userIsOwner(object(User))
UserNormalizer->normalize(object(User), 'jsonld', array('groups' => array('owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read', 'owner:read',......
hm this look weird! Why there is so many groups?
sadikoff the code looks allright there must be an issue somewhere else :(((
hanen I resolved when I clearing the cache for the dev environment :))))
My computer did not stop at 256 recursion levels, I just restarted it. Thanks, team ! 😂
Hey AymDev,
Wooops, we are sorry about that! :) Yeah, without Xdebug installed it might hang :p Btw, in theory you can just restart your php-fpm and it should do the trick. We probably need to add a warning if you don't have Xdebug installed :)
Cheers!
Oh, right ! I don't have Xdebug installed...
Well, maybe restarting php-fpm does the trick but the computer completely froze, I had to do an evil manual reboot. Thank you for the advices !
Hey AymDev,
Oh, sorry for this again! Seems it's more heavy than I thought :/ Yeah, that exact "Maximum function nesting level of 256 reached, aborting!" message is coming from Xdebug, IIRC the directive for this is "xdebug.max_nesting_level=256", so you can control it in your PHP ini config but only when Xdebug extension is installed :)
Cheers!
Hello Victor , I got the same error .. I set the xdebug.max_nesting_level up to 500 in php .ini and restart all services when I m running the command composer update Im getting error in my cheeselistingRepository :
Cannot autowire service "App\Repository\CheeseListingRepository": argument "$registry" of method "__construct()" references interface "Symfony\
Bridge\Doctrine\RegistryInterface" but no such service exists. Try changing the type-hint to "Doctrine\Persistence\ManagerRegistry" instead.
I get Xdebug working with PhpStorm..
in php .ini the Xdebug section:
[Xdebug]
zend_extension="c:\xampp\php\ext\php_xdebug-2.9.1-7.3-vc15.dll"
xdebug.remote_enable=1
xdebug.remote_port=9000
xdebug.max_nesting_level=500
Hey @henene
Sounds like some bundle or symfony version was updated, have you tried to change type-hint, as described in error?
Cheers
Hi , I solve the cheeselisting & user Repository error but what about this error message "Maximum function nesting level of '500' reached, aborting!" after I increased the maximum nesting level of function !!
Have you passed all chapter and put every line of code at needed place? Looks like you have some object that doesn't stops recursive normalization. Can you show exact error, and your normalizer class?
Cheers!
"Houston: no signs of life"
Start the conversation!