Laravel 5.5 で接続先DBを動的に変更する

接続先のDBを動的に変更したい要件があったのですが、少々癖があって解決まで時間がかかったので備忘録としてメモしておきます。

具体的には、接続先ホストがユーザーの入力値によって変更されるとか、そんな感じです。

下記 stackoverflow で議論されているのですが、少々情報が古いので、現在のLTSである ver 5.5 で使えるように適宜脳内変換していきます。

stackoverflow.com

参考

解決までに以下の3ページを参考にしました。

  1. 設定 5.5 Laravel
  2. データベース:利用開始 5.5 Laravel
  3. [Laravel5.1]複数のDBに接続させる

解決までの流れ

  1. 接続先のDBをデフォルトから切り替えるためには、 config/database.php の中にある connections のリスト内から変更先の設定( 'hoge'とする)を選んで、 DB::connection('hoge')->select([SQL]); のようにする
  2. 今回は動的に接続先を変更したいので、ユーザーからの入力値を使って config/database.php 内の connections リストに新しい設定を追加し、それを使用して接続する、と考える
  3. 動的にconfigをセットするためには config ヘルパに配列の形で設定値を渡せばOK。例えば、config/database.php 内の connections リストに foo という接続名の設定を追加したい場合は、 config([database.connections.foo] => [接続先のホスト名、ポート番号などを配列で渡す]); とする
  4. 設定が追加できたら DB::connections('foo')->select([SQL]); で目的達成!

DBファサードを使用するときは use Illuminate\Support\Facades\DB; するのをお忘れなく。

僕はconfig ヘルパに渡す配列の database.connections.foo の辺りでちょっとつまづきました。ドットで繋いでいく、覚えておいたほうが良さそうです。

React で <select> を使いたいけどちょっと困った話

constructor

this.state({value: ''});

としておいて、 render

render () {
  const hoge = [{name: 'test'}]; // セレクトボックスの選択候補となる要素。実際には Redux で管理していて store.getState().hoge みたいにしてとってくることを想定。状況によって値が変わる
  
  const options = hoge.map(e => {
    return <option value={e.name} key={e.name}>{e.name}</option>;  
  });

  return (
    <select value={this.state.value} size="3" onChange={this.handleChange}>
      {options}
    </select>
  );
}

みたいにすると、初期状態で「test」という選択肢だけが存在するセレクトボックスが表示されますが、この「test」をクリックしても onChange が発火しません。

this.state.value が空文字列のまんま更新されず、困っておりました。

React の公式ドキュメントの <select> の項目 Forms - React を見ると、

this.state = {value: 'coconut'};

と初期値を constructor 内で設定していますが、自分の例で言うところの options はその時々で中身が変わるため、初期値をハードコードすることもできない状況です。

対処法がないものかと考えて、componentWillReceiveProps を使って this.state.valueoptions の先頭要素を突っ込んでしまうというのを思いつきました。

componentWillReceiveProps() {
  const { hoge } = store.getState(); // hoge には [{name: 'test'}] が入ると想定
  if (hoge.length > 0) {
    this.setState({
      value: hoge[0].name,
    });
  }
}

みたいな感じです。こうすればレンダリングされるときには this.state.valuehoge.name が入っているので、submit するなりなんなりできます。

もっと賢い解決方法があったら知りたいですが、とりあえずこれで所望の挙動は得られました。

Laravelの勉強を始めた

どちらかというとフロントエンドを書くことが多くて、バックエンドを書くとしても Node.js の Express でゴリゴリと愚直に処理を書いていくみたいなことが多かったので、今度作るWebアプリでは何かしらフレームワークを使ってみたいと思っていました。

Rails か Laravel かなと考えていたのですが、Laravel にビビっときたので今回はLaravelで。Laravel ってなんか文字の高さが左右対称できれいですよね。

教材

Kindle unlimited の30日無料体験で読んでいます。まだ途中ですが、基本的なCRUDアプリを作る工程が丁寧に書かれていて読みやすいです。

Vue.js との組み合わせでCRUDアプリを作るハンズオン。こちらも非常に丁寧に書かれておりありがたい限りです。

上2つと同じくCRUDアプリですが、JWTを使ったログイン機構まで説明されているのが特筆点。僕がこれから作るWebアプリも認証機能をつける必要があるので、とても参考になります。

よりシンプルな認証機能の実装について。

electronでspread operatorは使えない

ちょっと語弊のあるタイトルです。

正確にはオブジェクトに対するスプレッド演算子が使えない模様。

const hoge = {
  a: 1,
  b: 2,
};

const fuga = {
  ...hoge,
  b: 999,
  c: 3,
};

console.log(fuga);  // -> { a: 1, b:999, c: 3} になることを期待

みたいに、 オブジェクトをマージするようなスプレッド演算子の使い方のことです。

このように書くと SyntaxError: Unexpected token ... で怒られる。

少し調べた結果、

stackoverflow.com

にあるように、Node.js の古いバージョンではオブジェクトに対するスプレッド演算子が未定義で使えないという事情らしい。

あれ、でも electron で使ってる Node.js ってそんなに古いの?と思って electron のリポジトリ

github.com

を見に行ってみたら、ルート直下にある .node-version 内で Node.js のバージョンが指定されてて、現在の安定バージョンである electron v1.8.3 では Node.js のバージョンは 8.2.1 らしいです。

先のstack overflow によると Node.js v8.3 以降でオブジェクトに対するスプレッド演算子に対応したらしいので、非常に惜しい感じですね。

Release electron v2.0.0-beta.1 · electron/electron · GitHub にあるように v2.0.0 beta1 では Node.js v8.9.3 になるらしいので、これが正式リリースされるのを待ちましょう。それか、babel でうまいことトランスパイルするかですね。

スプレッド演算子を最近覚えて意気揚々と使ってみようとしたら出鼻を挫かれ、いろいろ調べることになったのでまとめておきました。おとなしく Object.assign 使います。