Laravel модель для Place, которая может иметь псевдонимы (= повторяющиеся записи) - как рассматривать их как единое целое - PullRequest
1 голос
/ 07 января 2020

Данные GPS, которые я импортирую, могут иметь несколько точек маршрута для одного и того же места.
Я сохраняю эти данные GPS в базе данных, но хочу обработать все дубликаты как один.

My Laravel ( v6) Модель Place имеет id и parent_id (я мог бы изменить это при необходимости). Например,

id parent_id name
1  null      real place
2  1         same as real place

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

    public function scopeId($query, $id) {
        return $query->where('id', $id)->orWhere('parent_id', $id);
    }

Это позволяет мне делать, например, Place::id(1)->with('visits')->get(), что дает мне, например,

place 1
 - visit A
 - visit B
place 2
 - visit C

Есть ли способ "объединить" эти места чтобы ответы всегда возвращали только родительское место? Например:

place 1
 - visit A
 - visit B
 - visit C

with('visits') является примером. Хотелось бы, чтобы эта функция применялась ко всем запросам, связанным с Place.

Редактировать: полный пример

Place::id(1078)->select('id','parent_id')->with('visits:id,place_id')->get()
=> Illuminate\Database\Eloquent\Collection {#3092
     all: [
       App\Place {#3115
         id: 1068,
         parent_id: 1078,
         visits: Illuminate\Database\Eloquent\Collection {#3109
           all: [
             App\Timeline {#3087
               id: 8022,
               place_id: 1068,
             },
             App\Timeline {#3094
               id: 8023,
               place_id: 1068,
             },
           ],
         },
       },
       App\Place {#3137
         id: 1078,
         parent_id: null,
         visits: Illuminate\Database\Eloquent\Collection {#3139
           all: [
             App\Timeline {#3117
               id: 8304,
               place_id: 1078,
             },
             App\Timeline {#3084
               id: 8401,
               place_id: 1078,
             },
             App\Timeline {#3116
               id: 8513,
               place_id: 1078,
             },
             App\Timeline {#3119
               id: 9363,
               place_id: 1078,
             },
           ],
         },
       },
     ],
   }

1 Ответ

0 голосов
/ 07 января 2020
  1. Вы можете переопределить метод get() из Eloquent, создав новый класс CustomQueryBuilder, который расширяет Illuminate\Database\Query\Builder:

    Ваш индивидуальный get() метод в CustomQueryBuilder:

    <?php
     namespace App\Override;
    
    class CustomQueryBuilder extends \Illuminate\Database\Query\Builder {
    
        private $needVisitsCombined = false;
    
        public function needVisitsCombined() {
                $this->needVisitsCombined = true;
                return $this;
        }
    
        //@Override
        public function get($columns = ['*']) {
            //Get the raw query string with the PDO bindings
            $originalResult = parent::get($columns);
    
            if($this->needVisitsCombined == false){
                return $originalResult;
            }
    
            $parentRecord = $originalResult->filter(function ($result, $key) {
                return $result->parent_id != null;
            });
    
            $originalResult->each(function ($result, $key) {
                if($result->parent_id == null) {
                    $parentRecord->visits()->concat($result->visits())
                }
            });
    
            return $parentRecord;
    
        }
    } 
    ?>
    
  2. Создайте новый класс CustomModel, который расширяет Illuminate\Database\Eloquent\Model и там переопределяет newBaseQueryBuilder следующим образом:

    <?php
    namespace App\Override;
    
    use App\Override\CustomQueryBuilder;
    
    class CustomModel extends Illuminate\Database\Eloquent\Model {
    
        //@Override
        protected function newBaseQueryBuilder()
        {
            $connection = $this->getConnection();
    
            return new CustomQueryBuilder(
                $connection, $connection->getQueryGrammar(), $connection>getPostProcessor(), $this
            );
       }
    }
    ?>
    
  3. Наконец, теперь ваша модель места (или в зависимости от того, что требуется для этого пользовательского поведения get()) может расширяться CustomModel вместо.

  4. Теперь ваш запрос будет выглядеть примерно так:

    Place::id(1)->needVisitsCombined()->with('visits')->get() 
    

Примечание:

Помните, что все запросы сделанные из Моделей, расширяющих ваш CustomModel, получат это новое поведение, поэтому я добавил проверку методом needVisitsCombined().

Так что, если вы делаете больше настроек, сделайте все необходимые проверки, чтобы не испортить нормальное поведение Eloquent, что-то вроде этого

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...