Swift:配列の宣言、初期化と要素の追加

配列の初期化に苦労といいますが、バリエーションが多くてまいりましたw

宣言のみ

配列の場合、宣言のみはできないっぽい(普通の変数であればできるみたい) 例えば、このようにするとVariable 'myArray' passed by reference before being initializedとエラーになる:

func hoge () {
    var myArray: [String]
    myArray.append("koji")
    print(myArray[0])
}

hoge()

宣言+空の値で初期化

// Swift Tourに出てくる、空の配列を作るためのInitializer Syntax
var countries = [String]()

// こちらのほうがしっくりくる
var prefectures: [String] = []

宣言+空ではない値で初期化

// 型を推測してもらう
var planets = ["earth", "mars", "venus"]

// 型を明示的に指定
var oceans: [String] = ["Pacific", "Atlantic"]

要素の追加

// 1つだけ追加
prefectures.append("Aichi")

// 2つ以上追加
prefectures.append(contentsOf: ["Yamagata","Hokkaido"])

Javascript:Firefox/Safariでbeforeunloadが効かない

FirefoxSafariでは、beforeunloadが呼ばれても何も処理をしてくれないことがありました。 (ポップアップを表示するのはできるんですが…)

<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<a href="https://www.google.com">Google</a>
<script>

window.addEventListener("beforeunload",function() {
    axios.get('/test.txt')
    .then(function(response) {
      console.log("OK" + response)
    })
    .catch(function(error) {
      console.log("NG" + error);
    });
});

</script>
</body>
</html>

このファイルを設置して、Chromeで開いて、リンクをクリックするとサーバのアクセスログに/test.txtが記録されます。 FirefoxSafariだと記録されません。

使い方が間違っているのかな?

Git:ワーキングコピーへの変更をすべて戻したい

まず、ドライランを行います:

git clean -nd

すると、何を削除するかの一覧が出力されます:

Would remove src/Controller/ArticlesController.php
Would remove src/Controller/AuthorsController.php
Would remove src/Controller/PostsController.php

問題がなければ、ドライではない本番実行します:

git clean -fd

CakePHP3:containとmatchingとinnerJoinWithの違い

メソッド 関連するデータを取得するか? 関連するデータに対して条件を設定し、元のテーブルを絞り込めるか?
contain
matching
innerJoinWith

注意事項:containとmatchingは排他利用ではない

CakePHP3:bakeの落とし穴

とても便利なbakeですが、hasOneのリレーションを設定してくれないという特徴があります。

テーブルの例

例えば、次のようなテーブルがあるとします: usersテーブル

f:id:thebaker:20181021001722p:plain

user_profilesテーブル

f:id:thebaker:20181021000750p:plain

bakeした結果

Users hasMany UserProfilesというモデルが生成されます。

UsersTable.php

    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('users');
        $this->setDisplayField('id');
        $this->setPrimaryKey('id');

        $this->hasMany('UserProfiles', [
            'foreignKey' => 'user_id'
        ]);
    }

UserProfilesTable.php

    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('user_profiles');
        $this->setDisplayField('id');
        $this->setPrimaryKey('id');

        $this->belongsTo('Users', [
            'foreignKey' => 'user_id',
            'joinType' => 'INNER'
        ]);
    }

なお、この挙動はuser_profiles.user_idカラムにユニークキーを貼っても変わりありません。

このままhasManyにしたまま進むとどうなるか?

bakeへの影響

コントローラやテンプレートをbakeした際に、hasMany前提でbakeされてしまいます。

その他の影響

フォームで関連するデータの保存を行う場合に、添字の指定が必要になります:

$this->Form->control('email');
$this->Form->control('user_profile.0.first_name'); // hasOneでbakeしていればuser_profile.first_nameと書ける
$this->Form->control('user_profile.0.last_name');

bake allは使わないほうが良さそう

bake allをすると、hasOneにしたいのにhasManyになり、hasMany前提でコントローラとテンプレートが生成されてしまいます。 よって、次のような手順が良さそうです:

  • まず、モデルをbakeして適宜hasManyをhasOneに修正する
  • コントローラ、テンプレートをbakeする

CakePHP3:アソシエーションされているデータをsaveの前に変更する

リクエストデータを変更する場合

$data = $this->request->getData();
$data['order_data']['name'] = "新しい名前";
$order = $this->Orders->patchEntity($order, $data);

エンティティのプロパティを変更する場合

$order->order_data->name = "新しい名前";
$order->dirty('order_data',true);
$this->Orders->save($order);

2行目のdirtyの指定を忘れると、保存されません