制作 Laravel 集合的副本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29741763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Making copies of Laravel collections
提问by Djave
I'm trying to give a copy of a collection of users
to an eloquent model jobs
. So I'd effectively have:
我正在尝试将 的集合的副本提供给users
雄辩的模型jobs
。所以我实际上有:
jobs : [
1 : {
users : {
1: {}
2: {}
3: {}
}
}
2 : {
users : {
1: {}
2: {}
3: {}
}
}
]
Once I get this, I'm going to sum some numbers from another query to essentially give myself a total for each user on each job, so the above may end up looking like this:
一旦我得到这个,我将把另一个查询中的一些数字相加,从本质上给我自己每个工作的每个用户的总数,所以上面的结果可能是这样的:
jobs : [
1 : {
users : {
1: {
total: 120
}
2: {
total: 45
}
3: {
total: 12
}
}
}
2 : {
users : {
1: {
total: 32
}
2: {
total: 4
}
3: {
total: 17
}
}
}
]
Except I can't seem to clone this users list, and I'm effectively ending up with all the totals being the same as each other:
除了我似乎无法克隆此用户列表之外,我实际上最终使所有总数彼此相同:
{
1:{
id:1,
users:{
1:{
id:1,
total:807
},
2:{
id:2,
total:9
}
}
},
2:{
id:2,
users:{
1:{
id:1,
total:807
},
2:{
id:2,
total:9
}
}
},
3:{
id:3,
users:{
1:{
id:1,
total:807
},
2:{
id:2,
total:9
}
}
}
}
Here is what I am doing:
这是我在做什么:
public function summary()
{
$jobs = Job::all()->keyBy('id');
$users = User::with('closed_time_chunks')->get();
$users_list = User::all(['id'])->keyBy('id');
// I think this is the problem statement:
foreach ($jobs as $job):
$job->users = clone $users_list;
endforeach;
Log::info('Starting');
foreach ($users as $user):
foreach ($user->closed_time_chunks as $chunk):
Log::info('Adding ' . ($chunk->stop_time - $chunk->start_time) . ' to job: ' . $chunk->job_id);
$jobs[$chunk->job_id]->users[$chunk->user_id]['total'] += $chunk->stop_time - $chunk->start_time;
endforeach;
endforeach;
}
My guess is that I am actually just creating a reference to the same thing and any addition is in fact just adding to the 'master' collection. How can I successfully clone the users so that the totals will be unique across jobs?
我的猜测是,我实际上只是在创建对同一事物的引用,而任何添加实际上只是添加到“主”集合中。如何成功克隆用户,以便总数在作业中是唯一的?
Edit
编辑
Using an array (as Matheos recommends) results in a really bizarre error:
使用数组(如 Matheos 推荐的)会导致一个非常奇怪的错误:
ErrorException (E_NOTICE)
Indirect modification of overloaded property Job::$users has no effect
错误异常 (E_NOTICE)
间接修改重载属性 Job::$users 无效
回答by Jeff Berry
Your problem is that you are cloning your $users_list
, but that is a Collection
of User
objects. In PHP, when you clone an object, any of it's properties that are references to objects remain references to those objects, in other words those child objects do not get cloned themselves. See __clone
你的问题是,你是克隆的$users_list
,但是这是一个Collection
的User
对象。在 PHP 中,当您克隆一个对象时,它的任何引用对象的属性仍然是对这些对象的引用,换句话说,这些子对象本身不会被克隆。见__clone
Being that your code is dynamically adding a 'total' property to every User
instance in the Collection
, it is effectively altering that total value of all instances of that particular User
, because they are all references to themselves. What you would need to do is clone every child member (User
) of your Collection
, along with the Collection
itself.
由于您的代码正在向 中的每个User
实例动态添加“总计”属性Collection
,因此它有效地改变了该特定 的所有实例的总值User
,因为它们都是对自身的引用。什么,你需要做的是克隆每个子成员(User
你的)Collection
,与一起Collection
本身。
foreach ($jobs as $job):
$job->users = clone $users_list;
$job->users->transform(function($user) { return clone $user; });
endforeach;
There are probably better ways to do what you're trying to do, but this should get you going and hopefully answer your question of why too.
可能有更好的方法来做你想做的事情,但这应该能让你继续前进,并希望也能回答你为什么的问题。
回答by Matheos
Instead of an eloquent collection try using an array:
尝试使用数组而不是雄辩的集合:
$users_list = User::all(['id'])->keyBy('id')->toArray();
You may also want to set an initial value for 'total'
您可能还想为“总计”设置一个初始值
foreach ($users as $user) {
foreach ($user->closed_time_chunks as $chunk) {
Log::info('Adding ' . ($chunk->stop_time - $chunk->start_time) . ' to job: ' . $chunk->job_id);
if (! isset($jobs[$chunk->job_id]->users[$chunk->user_id]['total'])) {
$jobs[$chunk->job_id]->users[$chunk->user_id]['total'] = 0;
}
$jobs[$chunk->job_id]->users[$chunk->user_id]['total'] += $chunk->stop_time - $chunk->start_time;
}
}