Removing Items from a Collection
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.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeOur brand-new user is the proud owner of two treasures with IDs 7
and 44
. Let's update this user to see if we can make some changes to $dragonTreasures
. Use the PUT
endpoint, click "Try it out", and... let's see... the id
we need is 14
... so I'll enter that. I'll also remove every field except for dragonTreasures
so we can focus.
We know that this currently has two dazzling treasures - /api/treasures/7
and /api/treasures/44
. So if we send this request, in theory, that should do... nothing! And if we look down here... yeah: it made no changes at all.
Suppose we want to add a new DragonTreasure
to this resource. To do that, we list the two that it already has, along with /api/treasures/8
. I'm totally guessing that's a valid id
. When we hit "Execute"... that works beautifully. The serializer system noticed that it already had these first two, so it didn't do anything with those. It just added the new one with id 8
.
Removing an Item from a Collection
That's cool, but what I really want to talk about is removing a treasure. Let's say that our dragon left one of these treasures in their pants pocket and accidentally washed it in the laundry. I can't blame them. I lose my lip balm in there all the time. Since the treasure is soggy and useless now, we need to remove it from the list of treasures. No problem! We'll just mention the two our dragon still has and remove the other one. When we hit "Execute"... it explodes!
An exception occurred while executing a query: [...] Not null violation: 7. null value in column "owner_id"
What happened? Well, our app set the $owner
property for the DragonTreasure
we just removed to null
... and is now trying to save it. But since we have it set to nullable: false
, it's failing.
// ... lines 1 - 55 | |
class DragonTreasure | |
{ | |
// ... lines 58 - 97 | |
#[ORM\ManyToOne(inversedBy: 'dragonTreasures')] | |
#[ORM\JoinColumn(nullable: false)] | |
// ... lines 100 - 101 | |
private ?User $owner = null; | |
// ... lines 103 - 214 | |
} |
But... let's take a step back and look at the whole picture. First, the serializer noticed that treasures 7
and 8
are already owned by the User
... so it did nothing with those. But then it noticed that the treasure with id 44 - which was owned by this User
- is missing!
Because of that, over on our User
class, the serializer called removeDragonTreasure()
. What's really important is that it takes that DragonTreasure
and set the owner
to null
to break the relationship. Depending on your app, that might be exactly what you want. Maybe you allow dragonTreasures
to have no owner
... like... they're still undiscovered and waiting for a dragon to find them. If that's the case, you'll just want to make sure that your relationship allows null
... and everything will save just fine.
But in our case, if a DragonTreasure
no longer has an owner
, we want to delete it completely. We can do that in User
... way up on the dragonTreasures
property. After cascade
, add one more option here: orphanRemoval: true
.
// ... lines 1 - 22 | |
class User implements UserInterface, PasswordAuthenticatedUserInterface | |
{ | |
// ... lines 25 - 50 | |
#[ORM\OneToMany(mappedBy: 'owner', targetEntity: DragonTreasure::class, cascade: ['persist'], orphanRemoval: true)] | |
// ... lines 52 - 53 | |
private Collection $dragonTreasures; | |
// ... lines 55 - 171 | |
} |
This tells Doctrine that if any of these dragonTreasures
become "orphaned" - meaning they no longer have any owner - they should be deleted.
Let's try it. When we hit "Execute" again... got it! It saves just fine.
Next: Let's circle back to filters and see how we can use them to search across related resources.
At 45 second of the video, it didn't work as expected in my code, it's throwing error.
When I send this in PATCH request, to add treasure for user with id of 15,
I get 500 Error: Also one more thing I noticed is that PUT doesn't work here at the end of video, I just tried PATCH and it works, like when sending treasures IRI using PATCH, the previously linked treasures get deleted and only new one specified during PATCH request is available on database
{
"@id": "/api/users/15",
"dragonTreasures": [
]
}
The Error:
{
"@id": "/api/errors",
"@type": "hydra:Error",
"title": "An error occurred",
"detail": "An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'owner_id' cannot be null",