Усовершенствованные данные / модели Laravel - можно ли это сделать на уровне модели? - PullRequest
0 голосов
/ 13 июня 2018

У нас есть база данных COMMON, а затем базы данных клиентов для каждой организации, которая использует наше приложение.У нас есть базовые значения в базе данных COMMON для некоторых таблиц, например
COMMON.widgets.Затем в базах данных арендаторов, если таблица с именемified_widgets существует и имеет значения, они объединяются с таблицей COMMON.widgets.

Прямо сейчас мы делаем это в контроллерах следующим образом:

public function index(Request $request)
{
  $widgets = Widget::where('active', '1')->orderBy('name')->get();
  if(Schema::connection('tenant')->hasTable('modified_widgets')) {
    $modified = ModifiedWidget::where('active', '1')->get();
    $merged = $widgets->merge($modified);
    $merged = array_values(array_sort($merged, function ($value) {
      return $value['name'];
    }));
    return $merged;
  }
  return $countries;
}

Как видите, у нас есть модель для каждой таблицы, и это работает нормально.Мы получаем ожидаемые результаты для запросов GET, подобных этим, от контроллеров, но мы хотели бы объединиться на уровне Laravel MODEL, если это возможно.Таким образом, идентификаторы связываются с правильными таблицами, например, при заполнении форм этими значениями.Объединение означает, что один и тот же идентификатор может существовать в обеих таблицах.Мы ВСЕГДА хотим воздействовать на объединенные данные, если таковые существуют.Таким образом, кажется, что уровень модели - место для этого, но мы попробуем любые предложения, которые помогут удовлетворить потребность.Надеюсь, что все это имеет смысл.

Может кто-нибудь помочь с этим или у кого-нибудь есть идеи, чтобы попробовать?Мы играли с главными конструкторами моделей и тому подобным, но пока не смогли этого понять.Любые мысли приветствуются и TIA!

Ответы [ 2 ]

0 голосов
/ 14 июня 2018

ОК, вот что мы придумали.

Теперь мы используем одну модель, и имена таблиц ДОЛЖНЫ быть одинаковыми в обеих базах данных (setTable, похоже, не работает, даже если существует в исходном коде базы данных / Eloquent / Model - возможно, поэтомуне задокументировано).В любом случае = просто используйте обычную модель и убедитесь, что таблицы идентичны (или, по крайней мере, поля, которые вы используете):

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Widget extends Model
{

}

Тогда у нас есть универсальный «контроллер слияния», где модель и дополнительная сортировкапередаются в запросе (мы жестко закодировали здесь «где» и ключ, но их также можно сделать динамическими).Обратите внимание, что это не будет работать со статическими методами, которые создают новые инстансы, такие как $ model :: all (), поэтому вам нужно использовать $ model-> get () в этом случае:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class MergeController extends Controller
{

  public function index(Request $request)
  {
    //TODO: add some validations to ensure model is provided
    $model = app("App\\Models\\{$request['model']}");
    $sort = $request['sort'] ? $request['sort'] : 'id';

    $src_collection = $model->where('active', '1')->orderBy('name')->get();
    // we setup the tenants connection elsewhere, but use it here
    if(Schema::connection('tenant')->hasTable($model->getTable())) {
      $model->setConnection('tenant');
      $tenant_collection = $model->get()->where('active', '1');
      $src_collection = $src_collection->keyBy('id')->merge($tenant_collection->keyBy('id'))->sortBy('name');
    }
    return $src_collection;
  }

}

Если вы dd ($ src_collection);перед его возвратом вы увидите правильное соединение для каждой строки (в зависимости от данных в таблицах).Если вы обновите строку:

$test = $src_collection->find(2); // this is a row from the tenant db in our data
$test->name = 'Test';
$test->save();
$test2 = $src_collection->find(1); // this is a row from the tenant db in our data
$test2->name = 'Test2'; // this is a row from the COMMON db in our data
$test2->save();
dd($src_collection);

Вы увидите, что правильные данные обновляются независимо от того, из какой таблицы получены строки.

В результате каждый арендатор может по желаниюпереопределять и / или добавлять к данным базовой таблицы, не влияя на данные самой базовой таблицы или других арендаторов, минимизируя дублирование данных, тем самым упрощая обслуживание (очевидно, что управление данными и заполнением таблицы в другом месте, как и в любой другой таблице).Если у арендатора нет переопределений, то возвращаются данные базовой таблицы.Документация по слиянию и пользовательскому сбору имеет минимальную документацию, так что это заняло некоторое время, чтобы выяснить.Надеюсь, что это поможет кому-то еще когда-нибудь!

0 голосов
/ 13 июня 2018

Если вы включите эту функцию в модель Widget, вы получите 2 раза больше запросов.Вы должны подумать о Widget как об экземпляре, и я пытаюсь сказать, что текущий подход выполняет минимум 2 запроса и +1, если tenant имеет modified_widgets таблицу.Теперь представьте, что вы делаете это внутри модели, каждый экземпляр Widget будет извлекать, в лучшем случае его эквивалент из другой базы данных, поэтому для набора виджетов вы будете делать 1 (->all()) + n (n = числоModifiedWidgets) запросов - поскольку каждый экземпляр Widget будет извлекать собственное зеркало, если оно существует, невозможная загрузка невозможна .

Вы можете улучшить свой код следующим образом:

$widgets = Widget::where('active', '1')->orderBy('name')->get();

if(Schema::connection('tenant')->hasTable('modified_widgets')) {
    $modified = ModifiedWidget::where('active', '1')->whereIn('id', $widgets->pluck('id'))->get(); // remove whereIn if thats not the case
    return $widgets->merge($modified)->unique()->sortBy('name');
}

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