So the idea is that first i try to soft delete the product which soft deletes reviews also. After doing this I try to forcedelete the review decrementing from category and product which for the trashed product results in that error.
Ok, Call to a member function decrement() on null suggests that the Category instance does not exist (or at least, it does not load) - do you also delete or soft-delete the category?
Exactly my point; $review->category is null, why? Even when the Review is trashed, the associated Category, if (i) the foreign key is valid on categories and (ii) the referenced Category is not itself not soft-deleted, should load; but you get null
I don't really understand why, yes it throws me that error but the review itself with the last method is deleted, the category is decremented, but the product which is softdeleted is not decremented.
I may think that the category has nothing to do with that...
You have a soft-deleted Review instance, which has a related Category, and a related soft-deleted Product? On each of the related instances, you want to decrement a total_reviews property and a total_yes or total_no property?
Well, the method product() will return a BelongsTo relation; whereas the property productshould return the result of the relation query. If you listen for, and dump, the executed query, we should expect to see select * from products where id = ? and deleted_at is null:
onlyTrashed means that the Product must be soft-deleted, whereas withTrashed means the Product might be soft-deleted. Subtle, but important difference.
It's impossible & disappointing that no one could give me even an ugly solution to my problem. Anyway I'm sharing my solution because in the future someone will need it and I don't want anyone to struggle.
My ugly solution consists on doing it all this in vanilla sql:
public function deletePermanentlyService(int $id) :void
{
$review = Review::onlyTrashed()->findOrFail($id);
$productId = $review->product_id;
$categoryId = $review->category_id;
DB::select("update categories set total_reviews = total_reviews-1 where id = '$categoryId'");
DB::select("update products set total_reviews = total_reviews-1 where id = '$productId'");
if ($review->no_yes == 'yes') {
DB::select("update categories set total_yes = total_yes-1 where id = '$categoryId'");
DB::select("update products set total_yes = total_yes-1 where id = '$productId'");
} elseif ($review->no_yes == 'no') {
DB::select("update categories set total_no = total_no-1 where id = '$categoryId'");
DB::select("update products set total_no = total_no-1 where id = '$productId'");
}
$review->forceDelete();
}
I hope this will help someone in the future and that laravel could give more options on working with soft-deleted models...
Also, is that method used in a for loop or the like? It may appear that the category is okay, but if you are doing it in a loop maybe most are okay but some of them are not.
ps. if you may register in larachat.slack.com, there is a community it may help you more with this problem.
Like I specified before dd($review->category) it gives me same results as dd($review->product):
Call to a member function withTrashed() on null
The problem is only when a related belongsTo is soft-deleted. I managed it in a very bad way but I had no choice at the moment and I don't have time right now to go and find a better solution.