I have a question maybe a little silly. I'm trying to replicate and store a model instance in a variable to call the loadMissing
method. The idea is to call the loadMissing
method without being affected by the original model. Let me explain.
I have the following method in my User
model:
class User extends Authenticatable
{
...
public function myCustomMethod()
{
$cloned = $this->replicate()
->loadMissing(['roles', 'roles.permissions'])
->getAttribute('roles')
->flatMap(function ($role) {
return $role->permissions
});
return $cloned;
}
The problem is that in this way the original model instance is affected, and it loads in the original instance all the relations that I am loading only in this method. My question is: is there a way to load and isolate relationships in a replica of the model instance without affecting the original model?
Thanks in advance.
EDIT 1
I have also tried cloning the instance and trying to use the loadMissing
method on the cloned instance, but the original instance is also affected. For example:
class User extends Authenticatable
{
...
public function myCustomMethod()
{
$original = $this;
$cloned = clone $original;
$cloned->loadMissing('roles.permissions');
dump($original);
dump($cloned);
die();
}
But in this way, I get the following results. Notice that both the original and the cloned instance are loading the relationships when I'm just trying to load the relationships in the cloned instance:
$original
$cloned
I was wondering if this is normal behavior. If it is a normal behavior, which I suppose it is not, I was wondering if there is any way to use the loadMissing
method on a copy, replica or clone of an instance without modifying the original instance. Thank you very much in advance.
EDIT 2
My controller looks like simple like this:
class HomeController extends Controller
{
public function index()
{
dd(User::find(1)->myCustomMethod());
}
}
SOLUTION
After several days looking for documentation, doing tests and pulling my hair a little, I have found the solution to my problem and share it in case someone comes here looking for similar information in the future.
Basically the answer that helped me find the right way was this:
https://stackoverflow.com/a/29787693/13066106
Which is documented in the official PHP documentation:
https://www.php.net/manual/en/language.oop5.cloning.php
I copy and paste verbatim the most relevant here:
When an object is cloned, PHP will perform a shallow copy of all of the object's properties. Any properties that are references to other variables will remain references.
When I got to this point, I understood why it wasn't working ... I was cloning a collection of type Illuminate\Database\Eloquent\Collection
and this collection contained multiple objects of type Role
, but according to the documentation, it is normal behavior that when I modify any property in the cloned instance, the changes will be reflected back to me in the original instance.
From here, I looked for more documentation about it and I found an article that definitely helped me solve my problem:
Don't clone your php objects, DeepCopy them
The article is quite descriptive and basically what it does is advise the use of the package DeepCopy
Fortunately, the package is already a Laravel dependency by default, so I didn't have to install it with composer. I just used the deep_copy
method to clone the instance.
Thank you very much to everyone who helped me in some way. I hope that the links to the documentation that I have shared will be of use to those who come here looking for similar information.