laravel x モバイルアプリ
Post on 24-Jan-2017
878 Views
Preview:
TRANSCRIPT
laravel x モバイルアプリ
発表内容
• アプリ開発者という生き物について
• アプリ開発のDB事情
• モバイルアプリ用Web API 実装 tips
pochikawa
starfruits_j Azione Co., Ltd.
Oshikawa
• 元Webデザイナ
• iOSアプリ開発
• たまにWebも触る
• PHP7は未経験
• SQLが嫌い
• 元Webデザイナ
• iOSアプリ開発
• たまにWebも触る
• PHP7は未経験
• SQLが嫌い
発表内容
• アプリ開発者という生き物について
• アプリ開発のDB事情
• モバイルアプリ用Web API 実装 tips
アプリ開発者とはどんな生物? (所感です)
• ローカルでは主にSQLite
• アップデートの壁があるので、仕様変更はあまりしない(したくない)
• サーバサイドのように負荷分散等考えなくて良いので、あまりチューニングとかしない(したくない)
• Viewはアプリ側にあるので、たまにしかサーバサイドは触らない
• Swiftばっかり書いてると、Swift以外のコードは隠蔽したくなる
つまりたまにしかSQL書かない
忘れます!
SQL組み立てめんどい!
$sql = 'SELECT * FROM `laravel` WHERE ';
if ($user_id) { $sql .= ' `user_id` = ' . $user_id; } else { $sql .= ' 1 = 1'; }
連想配列で組み立てるクエリビルダ
$arr = [];
if ($user_id) { $arr['user_id'] = $user_id; }
$db->select('table', $fields, $arr);
$arrってなんだっけ?
• resultがarrayだったり?
• 久々に触ると仕様を確認したりコードを呼んだりしなければならない
• SQL読んだ方が分かりやすい
• SQLが複雑になると、もはや読めもしない
発表内容
• アプリ開発者という生き物について
• アプリ開発のDB事情
• モバイルアプリ用Web API 実装 tips
Realmrealm.io
RealmのModel
// Define your models like regular Swift classes class Dog: Object { dynamic var name = "" dynamic var age = 0 }
// Use them like regular Swift objects let mydog = Dog() mydog.name = "Rex" print("name of dog: \(mydog.name)")
// Persist your data easily let realm = try! Realm() try! realm.write { realm.add(mydog) }
https://realm.io/docs/swift/latest/
RealmのSelect
let tanDogs = realm.objects(Dog).filter("color = 'tan'") let tanDogsWithBNames = tanDogs.filter("name BEGINSWITH ‘B'")
※メソッドチェインでクエリを組み立てられる
https://realm.io/docs/swift/latest/#queries
よく使うクエリをclassメソッドで実装すると便利
class Dog: Object { dynamic var name = "" dynamic var age = 0 dynamic var color = "white" class func tanDogs() -> Results<Dog> { let realm = try! Realm() return realm.objects(Dog).filter("color = 'tan'") } }
Dog.tanDogs().sorted("age", ascending: false)
https://realm.io/docs/swift/latest/#queries
モデルを書くことで仕様が決まりモデルを見れば仕様が理解できる
コードが出来上がる👏
PHPでもメソッドチェインでクエリ書けないものか?
そう、laravelならね
発表内容
• アプリ開発者という生き物について
• アプリ開発のDB事情
• モバイルアプリ用Web API 実装 tips
可視性の高い設計
• サーバ側とアプリ側でモデルを統一化したい
• Realmと酷似しているのでGood!
• レコードを連想配列にしてJSON出力
• ModelのtoJson();でOK!レスポンスをJSONにするのも簡単。
• アプリ側はRealmにマッピングして保存
users.password等、ユーザに渡せない情報
• Modelのhidden propertyで指定
アプリ側の実装
class User: Object { dynamic var id = "" dynamic var name = "" }
https://realm.io/docs/swift/latest/#queries
laravel側の実装
/** * @property string $id // ID * @property string $name // 名前 * @property string $password // パスワード */ class User extends Model {
protected $hidden = ['password'];
}
https://realm.io/docs/swift/latest/#queries
deleted_at -> isDeleted
• カラムにないプロパティはget~~Attributeで追加できる
アプリ側の実装
class User: Object { dynamic var id = "" dynamic var name = “" dynamic var isDeleted = false }
https://realm.io/docs/swift/latest/#queries
laravel側の実装
/** * @property string $id // ID * @property string $name // 名前 * @property string $deleted_at // 削除日時 */ class User extends Model {
protected $hidden = [‘deleted_at’];
function getIsDeletedAttribute() { return (boolean) ($this->deleted_at); }
}
https://realm.io/docs/swift/latest/#queries
画像読み込みのストレスを減らす
• ローディング中に表示するプレースホルダ用にサムネイルをbase64したバイナリを返す
laravel側の実装
/** * @property string $id // ID * @property string $name // 名前 */ class User extends Model {
function getImageURLAttribute() { return sprintf('%s/images/%d.jpg',
Config::get('app.url'), $this->user_id); }
function getThumbnailAttribute() { $bin = file_get_contents(
$this->thumbnail_file_path); return base64encode($bin); }
}
https://realm.io/docs/swift/latest/#queries
時差を考慮する
海外展開する場合等に困るので、 ISO8601で返すようにしてあげると安全
class User extends Model {
public function getCreatedAtAttribute($date) { return date('c', strtotime($date)); } public function getUpdatedAtAttribute($date) { return date('c', strtotime($date)); } }
https://realm.io/docs/swift/latest/#queries
RESTfulは注意
• リクエストの回数が増える
• フリースポット等で予期せぬ200が返ります
• statusをjsonに含めてチェックする等してあげた方が無難
エラー発生時
App::error(function(Exception $exception, $code) use($self) { Log::error($exception);
$res = array( 'status' => 0, 'code' => $code, 'message' => $exception->getMessage(), 'trace' => $exception->getTraceAsString(), );
if ($self->isDebug()) { $res['sql_history'] = $self->sql_history; $res['post'] = $_POST; $res['get'] = $_GET; } return Response::json($res, $code); });
https://realm.io/docs/swift/latest/#queries
AfterFilter
$this->afterFilter(function($route, $request, $response) use($self) { $data = $response->getOriginalContent(); if (!$data) { $data = array(); } if (is_array($data)) { if (!isset($data['status'])) { $data['status'] = 1; } if ($self->isDebug()) { $data['sql_history'] = $self->sql_history; $data['post'] = $_POST; $data['get'] = $_GET; } $response->setContent($data); } });
https://realm.io/docs/swift/latest/#queries
レスポンスがタイムアウトするかも
• 通信状態が悪い場合、画像/動画のアップロードでタイムアウトが発生するが、PHPはアップロードが完了した時点でinsertしてしまう
• 極端に大きな通信はcommit用のAPIを用意して、送信完了のレスポンスを受け取ってからcommitする
ちょっとした変更でリクエストが複数回
• 通信量、速度のみでなく失敗のリスクも高まる
• JSON-RPC使う
• githubにあります (未確認)
laravelって素晴らしい!😉
• 優秀なQuery Builder
• 暗黙的でフレキシブルなORM
• SQLなんか書かなくて良い!
• 他FWに比べて並列分割のテーブルも扱いやすい
• API構築にも最適化されている
laravelって素晴らしい?😅
• CREATE TABLE必要
• Schema Builderもあるけど、やっぱり忘れる
• 複数テーブルをJOINし始めると辛い
• PHP7の新機能の活用に期待!
ご静聴ありがとう ございました!
top related