Flutter_DB操作（firebase）

# 概要
firebaseを使用したデータ操作方法（登録、更新、削除、取得）を説明します。

# 準備
## プロジェクト追加（firebase）

下記のページからコンソール画面を開きます。
https://firebase.google.com/?hl=ja

![firebase_0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/bae1cec1-9f38-e34b-4dee-5210a6814867.jpeg)

プロジェクトを追加します。
![firebase_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/ee2a0b7d-03ec-21c0-d2e6-a178fe3db5f2.jpeg)
![firebase_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/b0e91f6e-2500-0124-d5db-f4505fabaa10.jpeg)
![firebase_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/5245cfb9-9a21-3288-06e9-a49e87b81834.jpeg)
![firebase_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/7e69f2d5-f6b7-1660-68c8-b94b5084e8ab.jpeg)


## アプリケーション追加（firebase）
アンドロイドのアイコン部分をクリックします。
![firebase_0_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/fd8e9c01-e1eb-338d-1791-17158c023c47.jpeg)

パッケージ名を入力する箇所があるので、
app配下の「build.gradle」をを開き、パッケージ名を貼り付けます。
![firebase_7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/0c10574c-b06a-f490-1f92-08fad55eb5f8.jpeg)
![firebase_6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/26a7a780-2b6f-8195-b3b6-3a6cdd4386b2.jpeg)

JSONファイルをダウンロードし、「app」配下に配置します。
![firebase_8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/b92f3150-9c4a-d3d0-8da8-ef697a26acb2.jpeg)

記載されている通り、
- プロジェクト配下の「build.gradle」
- app配下の「build.gradle」
それぞれを変更します。
![firebase_9.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/cb3cb33d-5c66-4925-3ff1-68a20b6ae86e.jpeg)

アプリケーションを実行、手順は完了です。
![firebase_15.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/ad95c526-9d0e-98a5-fb60-e7e927a6ed5d.jpeg)


### Database作成
![firebase_database1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/9def3949-ab2e-aa57-12b6-3d21b8dd28a3.jpeg)
![firebase_database2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/067ea6f7-208d-7e1d-2646-40ce959a3c5b.jpeg)
![firebase_database3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/635df844-05bd-fcfd-41a6-fe4e1f9a7cac.jpeg)

![firebase_database4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/c5e836f6-cac4-195b-de90-e1f60895aab8.jpeg)
![firebase_database5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/faa35722-66aa-c25a-7842-ecc1391fdc88.jpeg)
データを更新できるように設定を変更します。
allow read, write: if false;
↓
allow read, write: if true;
![firebase_database6_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/3483db18-57ae-6a6e-fc08-6b0f393cceca.jpeg)
![firebase_database6_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/b96138b5-2b08-1755-a43b-4af16eb940a7.jpeg)


「pubspec.yaml」の「dependencies」に、下記の2行を追加します。

```
firebase_core: ^0.3.4
cloud_firestore: ^0.9.13
```

![firebase_0_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/d70b2a33-b535-cebe-a080-9302029b4bb7.jpeg)


「\app\build.gradle」に
```
multiDexEnabled true
```
を追加します。
![firebase_0_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/53d9acc6-c3f8-ecb2-eeda-18144de27f1e.jpeg)
この設定をしないと、実行時に下記のエラーが表示されます。

```
FAILURE: Build failed with an exception.
```
このエラーは、
Androidアプリのビルドシステムの都合で、
メソッド数が65536を超えるとビルドできないという制約があるために起こるそうです。


# プログラミング
以下の通りファイルを作成します。
・\lib\entity\User.dart

```
/**
 * ユーザクラス
 */
class User {
  String name;

  // コンストラクタ
  User();

  // コンストラクタ
  User.fromMap(Map<String, dynamic> map) {
    this.name = map[UserField.name];
  }

  // Firestore用のMapに変換
  Map<String, dynamic> toMap() {
    return {
      UserField.name: this.name,
    };
  }
}
/**
 * フィールド名
 */
class UserField {
  static const name = "name";
}

class UserDocument {
  String documentId;
  User user;

  UserDocument(this.documentId, this.user);
}
```


・\lib\entity\UserDatastore.dart

```
import 'User.dart';
import 'package:cloud_firestore/cloud_firestore.dart'; //

class UserDatastore {
  static String getCollectionPath() {
    return "users";
  }

  static String getDocumentPath(String documentId) {
    return "users/$documentId";
  }

  /**
   * 登録
   */
  static String registration(User user) {
    final newDocument = Firestore.instance.collection(getCollectionPath()).document();
    newDocument.setData(user.toMap());

    return newDocument.documentID;
  }

  /**
   * 取得
   */
  static Future<User> findById(String documentId) async {
    final snapshot = await Firestore.instance.document(getDocumentPath(documentId)).get();

    if (snapshot.exists) {
      return User.fromMap(snapshot.data);
    } else {
      throw Error();
    }
  }

  /**
   * 削除
   */
  static void delete(String documentId) {
    Firestore.instance.document(getDocumentPath(documentId)).delete();
  }

  /**
   * 更新
   */
  static void update(String documentId, User user) {
    Firestore.instance
        .document(getDocumentPath(documentId))
        .setData(user.toMap());
  }
}
```

・\lib\main.dart

```
import 'package:flutter/material.dart';
import './entity/User.dart';
import './entity/UserDatastore.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget  {
  @override
  State createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
  UserDocument userDocument;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Flutter Firestore Example"),
        ),
        body: Column(
          children: <Widget>[
            Text(userDocument == null
                ? "No user"
                : "User Name: ${userDocument.user.name}"),
            FlatButton(
              child: Text("「nameA」で登録"),
              onPressed: () {
                final user = User();
                user.name = "nameA";

                // 登録したデータを保持
                final documentId = UserDatastore.registration(user);
                setState(() {
                  userDocument = UserDocument(documentId, user);
                });
              },
            ),

            FlatButton(
              child: Text("取得"),
              onPressed: () async {
                final user = await UserDatastore.findById(userDocument.documentId);

                setState(() {
                  userDocument = UserDocument(userDocument.documentId, user);
                });
              },
            ),

            FlatButton(
              child: Text("「nameB」で更新"),
              onPressed: () {
                setState(() {
                  userDocument.user.name = "nameB";
                });

                UserDatastore.update(
                  userDocument.documentId, userDocument.user
                );
              },
            ),

            FlatButton(
              child: Text("削除"),
              onPressed: () {
                UserDatastore.delete(userDocument.documentId);

                // 削除したデータを保持状態から外す
                setState(() {
                  userDocument = null;
                });
              },
            ),
          ],
        ),
      ),
    );
  }
}
```

# 動作確認
実際に画面を操作して、動作を確認していきます。

## 登録
「nameAで登録」ボタンをタップ後、firebaseに登録されることを確認します。
![firebase_database_実行_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/dd2f7fde-cca9-5743-b3a9-58d585507b68.jpeg)
![firebase_database_実行_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/d911d6d7-5949-5bde-1610-c2e25483b01f.jpeg)

## 取得
firebase上でmameを「テスト」に変更し「取得」ボタンをタップすると、
上段の名前が「テスト」に変わることが確認できます。
![firebase_database_実行_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/48cb5ef7-94e0-0ea5-ecf4-ff83bab7ad47.jpeg)
![firebase_database_実行_6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/2d892f98-86d0-c4ae-e868-0f4538a6520d.jpeg)

## 更新
「nameBで更新」ボタンをタップ後、firebaseの登録内容が変わることが確認できます。
![firebase_database_実行_7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/554b0010-9c43-d4d5-7e6f-a17953e9b2d0.jpeg)
![firebase_database_実行_8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/43b0e50b-3c75-048e-9714-13c2e1e1cdc9.jpeg)

## 削除
「削除」ボタンをタップ後、firebaseの登録データが削除されていることが確認できます。
![firebase_database_実行_9.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/33bb7dd4-b9bd-9866-c387-3a3b4b213471.jpeg)
![firebase_database_実行_10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/a62cb457-2bb0-0b2c-241b-f042c189ad62.jpeg)