AppleWatchを活かしたい

ただそれだけ。

最近は完全にSuica端末になりきっているAppleWatch。
走っているときはRunkeeperの子機として十分に役立つが、日常生活では?

完全にFitbitが一枚上手。なぜかといえばバッテリーライフの関係から、睡眠中もつけていられる。
そうなると、睡眠時間のデータもFitbitに入るため、つけない訳にはいかなくなる。

そんな中、社内LTを行うという事があり、これはチャンスと実装をした。
家の近くのバス停に到着するバスの時間を、Webページから取得しWatchに表示するだけの機能。

実際にやってみるといろいろハマった。

ハマったこと

  • そもそもiOS / watch OSと複数のターゲットが存在する(CodeSigning)
  • table view とラベルの紐付け
  • watch OSのデバッグは(process を atach する必要がある)
  • Cocoa Pods を利用する場合は、xxx.xcodeproj -> xxx.xcworkspace を利用する
  • Httpクライアント(Alamofire)の利用方法
  • HTML parser(Kanna)の利用方法
  • 取得したいページがhttpなので、ATS無効
  • 実機で確認する為のXcode + iPhone + Apple Watchの設定というかデバッグする為の設定
  • Apple Watch のイベント(awake -> willActive -> didDiactive)

このあたりは細かくブログに書きたいが、今日はクリスマスという事で家族との時間に充てる。

AppleWatchが認識されない

Xcode8 WatchOS3.1

error 内容

  • Xcode の実機選択で + (paired device unavailable for development)と表示される

対応

このあたりの手順で改善した。 なぜかたまに起こるが、いつのまにか直っている事がおおい。

参考記事

PHPでTemplate Method パターン

DBへの接続オブジェクトを継承した各テーブル毎のクラスでinsert() / update() 実装を想定

  • ハリウッドの法則
    • 親クラスが子クラスのメソッドを必要なタイミングで呼ぶ
    • 今回でいくと、regist(親クラス)から子クラスで実装したinsert / update をcallする
  • 同じ処理を集約し、抽象クラス、抽象メソッドとしてインターフェースを用意する
<?php

// DBへの接続、validateを行うようなDB処理のスーパークラスを想定
abstract class DBObject {
    private $target_object;
    public function __construct($obj) {
        $this->target_object = $obj;
    }

    public abstract function insert();
    public abstract function update();
    public function regist() {
        if ($this->target_object->id) {
            $this->update();
        } else {
            $this->insert();
        }
    }
}

// 各テーブルへの実装を、具象クラスでテーブル毎に行う想定
class ObjectA extends DBObject {
    public function insert() {
        // insert 処理
        echo "--insert--" , PHP_EOL;
    }

    public function update() {
        // update 処理
        echo "--update--" , PHP_EOL;
    }
}

// 実際に利用する場合は、idの有無でinsert / update を判定する事を想定
$sample = new stdClass();
$sample->id = 111; // idがありのため、updateを行う
//$sample->id = null;

$obj = new ObjectA($sample);
$obj->regist(); // cliantからはオブジェクトを生成し、registメソッドをcallするのみ。

雑感

さっと思った事を実装してみたが、Template Methodパターンにマッチする仕様なのか不明な部分が残る
他パターンをサンプル実装していく中で、戻って修正する事もあると思う
何か気になる箇所があったら是非コメント下さい

PHPでStrategyパターン

使うメリット

  • メール、SMS、プッシュ通知、今後増える可能性がある通知手段を、他実装に影響せず追加が行える

2016/12/11 に追記し、本記事最下部に変更したソースあり

<?php

// 抽象クラス
abstract class MessageStrategy {
    public abstract function send();
}

// コンテキストクラス
class MessageContext {
    private $strategy;

    public function __construct(MessageStrategy $message) {
       $this->strategy = $message;
    }

    public function send() {
        $this->strategy->send();
    }
}

// 具象クラス
class ConcreteMailMessage extends MessageStrategy {
    public function __construct() {
        // 前処理
    }

    public function send() {
        echo 'mail'.PHP_EOL;
    }
}
class ConcreteSMSMessage extends MessageStrategy {
    public function __construct() {
        // 前処理
    }

    public function send() {
        echo 'sms'.PHP_EOL;;
    }
}
class ConcretePushNotificationMessage extends MessageStrategy {
    public function __construct() {
        // 前処理
    }

    public function send() {
        echo 'push'.PHP_EOL;;
    }
}

$strategy = new ConcreteMailMessage();
$contextMessage = new MessageContext($strategy);
$contextMessage->send();

これから調べる事

  • 送信時にユーザクラスからmail/tel/token などを取得したいが、どのクラスで行うか
  • Userクラスに依存するので、Strategyパターンを使うのではなく、違うパターンが正解かもしれない

追記 2016/12/11

  • Uesrクラスは具象クラスにコンストラクタインジェクションする事にした
    • コンストラクタで注入する事で、各通知処理の前処理が行えると考えた
    • 仮にアプリユーザというクラス(mail / name を持たずtokenだけ持つクラスを利用する事があっても、具象クラスのみ影響があるため、他クラスは影響を受けないと考えた
    • テストコードを追加したい
<?php

// 送信対象のUserクラス
class User {
    private $name;
    private $mail;
    private $tel;

    // 仮に利用するpropertyを定義
    public function __construct($name, $mail, $tel) {
        $this->name = $name;
        $this->mail = $mail;
        $this->tel  = $tel;
    }

    // 仮に名前だけ出力するためにgetter設置
    public function getName() {
        return $this->name;
    }

}

// 抽象クラス
abstract class MessageStrategy {
    protected $user;
    public abstract function send();
    public abstract function __construct(User $user);
}

// コンテキストクラス
class MessageContext {
    private $strategy;

    public function __construct(MessageStrategy $message) {
        $this->strategy = $message;

    }

    public function send() {
        $this->strategy->send();
    }
}

// 具象クラス(Mail)
class ConcreteMailMessage extends MessageStrategy {
    public function __construct(User $user) {
        $this->user = $user;
        // mailに関する前処理
        // ...
    }

    public function send() {
        echo 'mail->to('. $this->user->getName(). ')'. PHP_EOL;
    }
}

// 具象クラス(SMS)
class ConcreteSMSMessage extends MessageStrategy {
    public function __construct(User $user) {
        $this->user = $user;
        // smsに関する前処理
        // ...
    }

    public function send() {
        echo 'sms->to('. $this->user->getName(). ')'. PHP_EOL;
    }
}

// 具象クラス(PushNotification)
class ConcretePushNotificationMessage extends MessageStrategy {
    public function __construct(User $user) {
        $this->user = $user;
        // Push通知に関する前処理
        // ...
    }

    public function send() {
        echo 'push->to('.$this->user->getName(). ')'. PHP_EOL;
    }
}

// 送信対象のテストUserインスタンス
$user = new User('Pさん', 'test@example.com', '090xxxxyyyy');

// Mail送信
$strategy = new ConcreteMailMessage($user);

// $strategyにどのクラスを代入するかでMail / SMS / PushNotification とsend()の振る舞いを変える
// SMS送信
// $strategy = new ConcreteSMSMessage($user);

// Push通知
// $strategy = new ConcretePushNotificationMessage($user);

// Contextクラスにstrategyクラスを注入
$contextMessage = new MessageContext($strategy);

// 送信処理 注入されたオブジェクトのsend()メソッドをcall
$contextMessage->send();

// mail->to(Pさん) と出力される

TravisCIで実行したPHPUnitの結果がCoverallsに反映されない

TravisCI Build時のRowLogで、environment variablesをSetしろの文言あり。

Read environment variables
Requirements are not satisfied.
  - TRAVIS='true'
  - TRAVIS_JOB_ID='1713xxxxx'
  - CI_NAME='travis-ci'
  - COVERALLS_REPO_TOKEN='********(HIDDEN)'

Set environment variables properly like the following.
For Travis users:

  - TRAVIS
  - TRAVIS_JOB_ID

対応としてTravisCIのEnvironment VariablesにSet

TravisCI Repository > Settings > Environment Variables
参考:php-coveralls issue

export CI_BUILD_NUMBER="$TRAVIS_BUILD_NUMBER"
export CI_PULL_REQUEST="$TRAVIS_PULL_REQUEST"
export CI_BRANCH="$TRAVIS_BRANCH"

f:id:tbrhdys:20161029001340p:plain

こういう場合は、UIからではなく、.travis.yml の before_script; にexport書くのが良いのか。

gitでまとめてrevert

git push -f ではなくまとめてrevertする方法メモ(いつも忘れるし、push -f とか一人のときはやっちゃう)

流れ

  • revertをする(--no-edit つけてeditorを起動しない)
    • ここでresetのように過去のcommit指定する方法はないのか?
    • HEAD~5 みたいにかけるのか
  • rebase で squashする(=押しつぶす/統合する)
  • squashしたコメントをeditorで編集
  • push

参考にさせて頂きました

$ git log --oneline
2f05e27 aaa
d56fd0f bbb
8c1c711 ccc
f7d9739 ddd
00fdd3d eee

$ git revert --no-edit 2f05e27
$ git revert --no-edit d56fd0f
$ git revert --no-edit 8c1c711
$ git revert --no-edit f7d9739
$ git revert --no-edit 00fdd3d

$ git rebase -i HEAD~5

editor起動
pick => squash に書き換える

英語圏だと-(ハイフン)ではなくダッシュというようだ。--はダッシュダッシュとでも言うのか。(不明) squash a cockroach(ゴキブリを押し潰す)でsquashは完全に覚えた

PHPプロジェクト(Laravel)をHerokuへpush時にFailed to detect set buildpack

$ git push heroku master
Counting objects: 255, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (226/226), done.
Writing objects: 100% (255/255), 46.83 KiB | 0 bytes/s, done.
Total 255 (delta 110), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Failed to detect set buildpack https://github.com/heroku/heroku-buildpack-php
remote: More info: https://devcenter.heroku.com/articles/buildpacks#detection-failure
remote:
remote:  !     Push failed
remote: Verifying deploy...
remote:
remote: !   Push rejected to xxxxxxxxxxxxxxxxx.
remote:
To https://git.heroku.com/xxxxxxxxxxxxxx.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/xxxxxxxxxxxxx.git'

確認する事

  • composer.lock がpush 対象になっているか
    • なぜかignore global でcomposer.lockを含めていた(過去追加したので経緯は覚えてない)
    • ignore 対象のファイルの場合は git add -f xxx
  • composer.json が存在するか
  • buildpack がheroku/php と指定されているか
    • Laravel のroot にはpackage.json が存在しNodeと勘違いが発生するらしい(明示的にPHPとする必要あり)
  • heroku laravel のドキュメントを読む

試した事

  • 上記を試したが改善せず
  • 結局は、git init -> heroku create -> git push heroku master を行い、git remote add でGithubを追加し、Githubリポジトリをmergeして回避
    • remote が複数ある事が原因ではない事は確認済だが、git init -> heroku create の順に実行する必要があるのか原因は不明

利用したコマンド

  • heroku config -- 設定状況を確認
  • heroku buildpacks -- buildpackが何か確認