#php #laravel #collections #eloquent
#php #laravel #Коллекции #eloquent
Вопрос:
У меня есть массив строк, который помогает мне инициализировать и find()
связанные модели.
$arr = [
"AppPost" => 1,
"AppVideo" => 1
];
// this array is [Model => ModelId]
На этом этапе я инициирую класс model из string и использую find()
для поиска объекта model.
У меня также есть 2 отношения morphByMany()
в моей пользовательской модели, которая возвращает мне коллекцию обоих.
// class User
public function entities() {
// this returns merged collection successfully
return ($this->videos)->merge($this->posts);
}
На данный момент, если я попробую с contains()
, это сработает:
foreach ($arr as $modelString => $modelId) {
// this finds the related model:
$model = $modelString::find($modelId)->first();
$this->entities()->contains($model); // returns true
}
Однако, если я попытаюсь создать новую коллекцию на основе моих инициированных моделей, $collection->diff($collection2)
or $collection->intersect($collection)
не сработает.
$collection1 = $this->entities();
$collection2 = collect();
foreach ($arr as $modelString => $modelId) {
$model = $modelString::find($modelId)->first();
$collection2->push($model);
}
$collection1->diff($collection2); // returns all items
$collection1->intersect($collection2); // returns []
// intersect() and diff() should be other way around
(Просто для ясности, у обоих $this->entities()
и $arr
одинаковые модели. Единственное отличие заключается в том, что $this->entities()
возвращает сводные значения вместе с моделью, тогда как те, которые инициированы из $arr
, не contains()
работают. Однако.
Комментарии:
1. Я не могу повторить это. На какой версии Laravel вы работаете?
2. Можете ли вы поделиться миграциями базы данных и фабриками?
3. Довольно сложно поместить туда все миграции, однако я считаю, что проблема заключается в том, что в
entities()
коллекции есть модели с отношениями, а в других — нет4. Да, они считаются разными. Вы уверены, что contains возвращает true?
Ответ №1:
Я тестировал это на последней версии Laravel, и я не могу воспроизвести ту часть, где вы упоминаете ->contains
returns true
. Я получаю, false
когда я пытаюсь contains
сделать то же самое, что и вы, что и ожидаемое поведение, потому что модель с отношением и другая модель без отношения считаются разными.
Вы могли бы использовать функцию diffUsing
для передачи обратного вызова, чтобы проверить, совпадают ли класс и идентификатор элемента или нет.
$c1->diffUsing($c2, function ($a, $b) {
return get_class($a) != get_class($b) || $a->id != $b->id;
});
Комментарии:
1. Я тоже не смог заставить это работать по какой-то причине, хотя это имеет смысл.
diffUsing()
Заботьтесь о порядках — это может быть проблемой. Но я заставил это работать с unsettingRelation — спасибо за совет «потому что модель с отношением и другая модель без отношения считаются разными». Взгляните на мой ответ2. У меня были лучшие результаты, используя в качестве возврата обратного вызова diffUsing значение int, которое может быть расстоянием в разнице между двумя объектами, такими как
$a->id - $b->id
или что-то в этом роде.
Ответ №2:
«модель с отношениями и другая модель без отношений считаются разными» @Chin Leung. это дало мне возможность мыслить по-другому. подход.
$collection1 = $this->entities()->map(function($item) {
return $item->unsetRelation('pivot');
});
А затем, diff()
и intersect()
начал работать, как ожидалось!