Коллекция Eloquent содержит () работу, но diff () или intersect () считает, что все разные

#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() начал работать, как ожидалось!