Многократная аренда в Laravel Eloquent ORM

Это своего рода следующий вопрос:

Принуждение моделей Eloquent для повторного подключения к базе данных

С несколькими подключениями к базе данных:

return [ 'default' => 'mysql-key1', 'connections' => [ 'mysql-key1' => [ 'driver' => 'mysql', 'database' => 'key1_dbname, // etc ], 'mysql-key2' => [ 'driver' => 'mysql', 'database' => 'key2_dbname', // etc ] ] ]; 

У меня есть репозиторий продуктов, который использует Model setConnection для изменения атрибута подключения:

 public function setConnection($name) { // assumes $this->product is your Product model $this->product->setConnection($name); } 

Тем не менее, я узнал, что он работал только с методами запросов, а не с такими методами, как Model :: create ::

 $productRepo = new ProductRepository(); foreach ($array as $key => $value) { $productRepo->setConnection($key . '_' . $database); // this works $products = $productRepo->all(); // this doesn't work and will use the old connection $product = $productRepo->create($data); } 

Кажется, что метод :: create не разрешает соединение после создания экземпляра. Кто-нибудь знает исправление?

Проблема в том, что setConnection() работает с экземпляром класса, но метод create() является статическим методом для самого класса. В вашем репозитории $this->product является экземпляром класса Product. Использование setConnection() в этом экземпляре перед выполнением запросов будет работать нормально, но вам нужно будет сделать немного более ручную работу, если вы хотите использовать отдельные подключения для статических методов (например, create() ).

Весь метод create() создает экземпляр нового экземпляра с указанными атрибутами, а затем вызывает save() . Итак, вместо вызова create() в модели Product вам просто нужно сделать это вручную:

 class ProductRepository { public function create(array $attributes, $connection = null) { $product = $this->product->newInstance($attributes); $product->setConnection($connection ?: $this->product->getConnectionName()); $product->save(); return $product; } } 

Вы также можете переопределить статический метод create() в модели Product, чтобы принять соединение.

 class Product extends Model { public static function create(array $attributes, $connection = null) { $model = new static($attributes); $model->setConnection($connection ?: $this->connection); $model->save(); return $model; } } class ProductRepository { public function create(array $attributes, $connection = null) { $connection = $connection ?: $this->product->getConnectionName() return $this->product->create($attributes, $connection); } } 

Вы должны иметь возможность использовать Model Events & Observers для управления используемым соединением, документация доступна здесь:

Вы можете создать один DatabaseModelObserver (как показано ниже), который можно было бы привязать к каждой из соответствующих моделей, которые будут устанавливать соединение перед сохранением и сбросом после сохранения, как показано ниже:

 class DatabaseModelObserver { protected $databases = [ 'default' => 'mysql-key1', 'products' => 'mysql-key2' ]; protected $connection; public function __construct(Connection $connection) { $this->connection = $connection; } public function saving($model) { $this->connection->reconnect($this->databases['products']); } public function saved($model) { $this->connection->reconnect($this->databases['default']); } } по class DatabaseModelObserver { protected $databases = [ 'default' => 'mysql-key1', 'products' => 'mysql-key2' ]; protected $connection; public function __construct(Connection $connection) { $this->connection = $connection; } public function saving($model) { $this->connection->reconnect($this->databases['products']); } public function saved($model) { $this->connection->reconnect($this->databases['default']); } } 

Затем вы присоедините наблюдателя к соответствующим моделям через поставщика услуг, используя метод загрузки, как описано ниже:

 class ModelServiceProvider extends ServiceProvider { public function register() { } public function boot() { ProductModel::observe( $this->app->make('DatabaseModelObserver') ); } } 

Вы можете прикрепить этот же Наблюдатель к как можно большему количеству моделей, вам просто нужно добавить их к методу загрузки, например:

 public function boot() { ProductModel::observe( $this->app->make('DatabaseModelObserver') ); CategoryModel::observe( $this->app->make('DatabaseModelObserver') ); StoreModel::observe( $this->app->make('DatabaseModelObserver') ); } 

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

Вышеприведенный код не тестировался, и специфика, окружающая класс подключения, введенный в наблюдатель, может быть отключена, но основана на документации на DB Facade – не может размещать больше ссылок 🙁

РЕДАКТИРОВАТЬ

Заглянув в patricus, ответьте немного подробнее, использование модельного события должно решить его проблему со статическим характером метода create.

Экземпляр сохраняемой модели передается каждому событию модели, в моем примере выше, в качестве $model поэтому не должно быть проблем, выполняемых ниже в вашем наблюдателе модели:

 public function saving($model) { $model->setConnection($this->databases['products']); } public function saved($model) { $model->setConnection($this->databases['default']); } по public function saving($model) { $model->setConnection($this->databases['products']); } public function saved($model) { $model->setConnection($this->databases['default']); } 

Это должно быть гораздо более эффективным решением.