Торт PHP соответствует связанным данным, возвращаются не все значения - PullRequest
0 голосов
/ 06 марта 2020

У меня есть События и Расстояния, модели выглядят так: "

/* EventsTable.php */
class EventsTable extends Table
{
    public function initialize(array $config): void
    {
        ...
        $this->belongsToMany('Distances', [
            'foreignKey' => 'event_id',
            'targetForeignKey' => 'distance_id',
            'joinTable' => 'distances_events',
            'dependent' => true
        ]);

/*DistancesTable.php*/
class DistancesTable extends Table
{
    public function initialize(array $config): void
    {
        ...
        $this->belongsToMany('Events', [
            'foreignKey' => 'distance_id',
            'targetForeignKey' => 'event_id',
            'joinTable' => 'distances_events'
        ]);
    }

Со следующими событиями (и расстояниями)

  • Событие 1: 25 км, 500 км
  • Событие 2: 25 км
  • Событие 3: 100 км

Я пытаюсь выбрать все события, которые имеют хотя бы одно расстояние между заданными минимальным и максимальным расстояниями Поэтому я использую этот код:

$mindistance = 50;
$maxdistance = 550;
$events = $this->Events
    ->find()
    ->contain(['Distances'])
    ->matching('Distances', function ($q) use ($maxdistance, $mindistance) {
      return $q->where(['Distances.title <=' => $maxdistance, 'Distances.title >=' => $mindistance]);
    });

, который возвращает меня:

  • Событие 1: 500 км
  • Событие 3: 100 км

Мне не хватает 25-километрового расстояния в содержащихся данных. Как я могу применить этот фильтр, но с сохранением всех расстояний события?

Сгенерировано SQL:

SELECT 
  Events.id AS Events__id, 
  Events.user_id AS Events__user_id, 
  Events.title AS Events__title, 
  Events.slug AS Events__slug, 
  Events.type AS Events__type, 
  Events.description AS Events__description, 
  Events.datetime AS Events__datetime, 
  Events.country AS Events__country, 
  Events.province AS Events__province, 
  Events.city AS Events__city, 
  Events.street AS Events__street, 
  Events.housenumber AS Events__housenumber, 
  Events.zipcode AS Events__zipcode, 
  Events.lat AS Events__lat, 
  Events.lon AS Events__lon, 
  Events.price AS Events__price, 
  Events.active AS Events__active, 
  Events.created AS Events__created, 
  Events.modified AS Events__modified, 
  DistancesEvents.distance_id AS DistancesEvents__distance_id, 
  DistancesEvents.event_id AS DistancesEvents__event_id, 
  Distances.id AS Distances__id, 
  Distances.title AS Distances__title, 
  Distances.created AS Distances__created, 
  Distances.modified AS Distances__modified 
FROM 
  events Events 
  INNER JOIN distances_events DistancesEvents ON Events.id = (DistancesEvents.event_id) 
  INNER JOIN distances Distances ON (
    Distances.title <= '550' 
    AND Distances.title >= '50' 
    AND Distances.id = (DistancesEvents.distance_id)
  )


SELECT 
  DistancesEvents.distance_id AS Distances_CJoin__distance_id, 
  DistancesEvents.event_id AS Distances_CJoin__event_id, 
  Distances.id AS Distances__id, 
  Distances.title AS Distances__title, 
  Distances.created AS Distances__created, 
  Distances.modified AS Distances__modified 
FROM 
  distances Distances 
  INNER JOIN distances_events DistancesEvents ON Distances.id = (DistancesEvents.distance_id) 
WHERE 
  DistancesEvents.event_id in (8, 10)

1 Ответ

0 голосов
/ 06 марта 2020

В EventsTable создайте две связи с расстояниями: сначала для сопоставления, затем для всех расстояний:

/* EventsTable.php */
class EventsTable extends Table
{
    public function initialize(array $config): void
    {
        ...
        $this->belongsToMany('MatchedDistances', [
            'foreignKey' => 'event_id',
            'targetForeignKey' => 'distance_id',
            'joinTable' => 'distances_events',
            'dependent' => true
        ]);
        $this->belongsToMany('Distances', [
            'foreignKey' => 'event_id',
            'targetForeignKey' => 'distance_id',
            'joinTable' => 'distances_events',
            'dependent' => true
        ]);

Затем:

$mindistance = 50;
$maxdistance = 550;
$events = $this->Events
    ->find()
    ->contain(['MatchedDistances'])
    ->contain(['Distances'])
    ->matching('MatchedDistances', function ($q) use ($maxdistance, $mindistance) {
      return $q->where(['MatchedDistances.title <=' => $maxdistance, 'MatchedDistances.title >=' => $mindistance]);
    });
...