Play Frameworkハンズオン

※ [環境構築](https://qiita.com/yuichi0301/items/4785e3fe490736d4ee50) が完了していることを前提とします。
# 今日作成するアプリ
画面表示

<img width="350" alt="11-0-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/44bd9df1-ff03-6f14-ba93-6f8c8142acaf.png">

登録後

<img width="350" alt="11-0-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/1850bf08-8df1-04d4-a311-d0d01f2e6813.png">

# 1.ScalaとPlay Frameworkの簡単な説明
## Scalaについて
- オブジェクト指向言語と関数型言語の特徴を統合した言語
- Javaプラットフォーム（Java仮想マシン）上で動作する
- 既存のJavaのプログラムと容易に連携できるため、Javaの豊富なライブラリが使える

## Scalaの採用事例
主な採用事例

- Twitter
- 株式会社ドワンゴ
- 株式会社はてな(mackerel)
- SmartNews
- LINE株式会社
- ヌーラボ(Typetalk, Backlog)

[Scalaの採用事例一覧](https://qiita.com/oubakiou/items/31fd45ca337d76113a1e)
## Play Frameworkについて
- ScalaとJava言語で書かれたオープンソースのWebアプリケーションフレームワーク
- Ruby on RailsやDjangoと似た同種のフレームワーク

# 2.ディレクトリ構成についての説明

```
.
├── app アプリケーションのソースコード
│   ├── controllers アプリケーションのコントローラ
│   └── views テンプレート
├── build.gradle
├── build.sbt アプリケーションのビルドスクリプト
├── conf アプリケーションの設定ファイル
│   ├── application.conf メイン設定ファイル
│   ├── logback.xml ログ出力設定ファイル
│   ├── messages 国際化対応用言語ファイル
│   └── routes ルート定義
├── gradle
├── gradlew
├── gradlew.bat
├── project sbt 設定ファイル群
│   ├── build.properties sbt プロジェクトの目印
│   ├── plugins.sbt Play 自身の定義を含む sbt プラグイン
│   ├── project
│   ├── scaffold.sbt scaffolding 用の sbt プラグイン使用時に使用
│   └── target
├── public 公開アセット
├── target ビルド成果物
└── test 単体、および機能テスト用のソースフォルダ
```

# 3.sbtシェル
## 1)sbtコマンド
作成したプロジェクト直下でsbtコマンドを実行するとsbtシェルに入り、sbtなしで様々なコマンドを実行することができます。

```
$ sbt
```

## 2)実行コマンド

```
> run
```

scalaシェルに入っていない場合は次のコマンドになります

```
$ sbt run
```

## 3) ビルド定義の再読み込み

```
> reload
```

> ビルド定義（build.sbt、 project/*.scala、 project/*.sbt ファイル）を再読み込みする。 ビルド定義を変更した場合に必要。

# 4.開発環境チェック
## 1)Java
次のコマンドを実行します。

```
$ java -version
```

次のように表示されたら成功です。バージョンは1.8以上であれば大丈夫です。
(2019年1月9日時点の最新バージョン：1.8.0_192)

```
openjdk version "1.8.0_192"
OpenJDK Runtime Environment (build 1.8.0_192-amazon-corretto-preview2-b12)
OpenJDK 64-Bit Server VM (build 25.192-b12, mixed mode)
```

## 2)sbt
次のコマンドを実行します。

```
$ sbt sbtVersion
```

次のように表示されれば大丈夫です。(バージョンは1.0.0以上である必要があります。)

```
[info] Loading settings for project play-hands-on-build from plugins.sbt,scaffold.sbt ...
[info] Loading project definition from /Users/yuichi/Desktop/play-hands-on/project
[info] Loading settings for project root from build.sbt ...
[info] Set current project to play-hands-on (in build file:/Users/yuichi/Desktop/play-hands-on/)
[info] 1.2.8
[INFO] [01/09/2019 14:15:34.369] [Thread-3] [CoordinatedShutdown(akka://sbt-web)] Starting coordinated shutdown from JVM shutdown hook
```

## 3)プロジェクト
IntelliJを起動し次のように画面が表示されれば大丈夫です。

<img width="300" alt="prepare.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/7b561f02-9997-565d-5c91-0ee8eacdb139.png">

# 5.作成前の準備
## 1)サンプルファイルの削除
この時点でサンプルのファイルが入っているため削除します。
プロジェクトのルートディレクトリ配下のappディレクトリの下にあるファイルを全て削除します。
次のように選択し

<img width="140" alt="5-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/fe2a757d-adce-194a-df10-931d7ac81571.png">

右クリックし[Delete]を選択します。(safe deleteのチェックは外します。)

<img width="152" alt="5-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/fe622f0c-a312-a60e-7080-98567db010fc.png">

<img width="200" alt="5-3.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/62f7fe01-1d4e-1d9a-d7cb-2f0044bfbde6.png">

## 2)routesの不要ルートの削除
<img width="149" alt="5-4.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/195ff5ec-11f9-6272-f399-0463c6d6d42d.png">

play-hands-on/conf/routesファイルで[GET     /assets/*file ...]の行を残して他の行を削除します。
次のようになります。

```
GET     /assets/*file               controllers.Assets.versioned(path="/public", file: Asset)
```

# 6.Hello World
目的：コントローラーの書き方、routesの書き方
![6-0-1.png](https://qiita-image-store.s3.amazonaws.com/0/124660/6cc3f4ed-2aaa-cf83-2397-e5f6c69e2933.png)
次のような画面を作成します。
<img width="350" alt="6-2-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/7dd059ef-5be8-c885-81dd-244ac3827ff6.png">

## 1)routesにhelloworld用のルートを追加
/play-hands-on/conf/routes
> この一行を書いてみましょう

```
GET     /todo/helloworld                       controllers.TodoController.helloworld()
```

## 2)TodoControllerの作成
controllersパッケージにTodoControllerクラスを作成します。
IntelliJ上でcontrollersディレクトリを右クリックし、[New]の[Scala Class]をクリックしします。

<img width="342" alt="6-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/92cc9ae5-6d1f-a4cc-d9c6-657e83d26a05.png">

表示されたダイアログに[TodoController]と入力しOKをクリックします。
<img width="177" alt="6-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/1d68431d-0284-1a06-44eb-a68d3d35e977.png">

/play-hands-on/app/controllers/TodoController.scala

> importの部分はコピーしてそれ以外は書いてください

```scala
package controllers

//コピペ
import javax.inject._
import play.api.mvc._

import play.api.data._
import play.api.data.Forms._
//コピペ

//入力
class TodoController @Inject()(mcc: MessagesControllerComponents) 
extends MessagesAbstractController(mcc) {

  def helloworld() = Action { implicit request: MessagesRequest[AnyContent] =>
    Ok("Hello World")
  }

}
//入力
```

<table>
<thead>
<tr><th align="left">メソッド</th><th align="right">ステータスコード</th></tr>
</thead>
<tbody>
<tr><td align="left">Ok</td><td align="right">200</td></tr>
<tr><td align="left">BadRequest</td><td align="right">400</td></tr>
<tr><td align="left">Forbidden</td><td align="right">403</td></tr>
<tr><td align="left">NotFound</td><td align="right">404</td></tr>
<tr><td align="left">Redirect</td><td align="right">リダイレクト処理</td></tr>
</tbody>
</table>

## 3)サーバー起動
プロジェクト直下で次のコマンドを実行しsbtシェルに入ります。

```
$ sbt
```

runコマンドでサーバーを起動します。

```
> run
```

次のように表示されます。

```
--- (Running the application, auto-reloading is enabled) ---

[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Enter to stop and go back to the console...)
```

## 4)画面をブラウザで見てみましょう
こちらのリンクをクリックしてください
<p><a href="http://localhost:9000/todo/helloworld" target="_blank">Hello World画面</a></p>
次の画面が表示されたら成功です！
<img width="350" alt="6-2-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/b49b91eb-7f83-9f4c-6e2d-1ec39fd7de77.png">



# 7.リスト画面の作成(テンプレート)
目的：テンプレートの使い方、Scalaの変数の書き方
![7-a-1.png](https://qiita-image-store.s3.amazonaws.com/0/124660/092da083-3d6b-19f6-8dd8-16e49abb12b6.png)

次のような画面を作成します。
<img width="350" alt="7-0.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/4ec6e67c-34c4-fa4f-bf40-e3cb3c802b4b.png">

## 1)routesにlist用のルートを追加

/play-hands-on/conf/routes

> この一行を書いてみましょう

```
GET     /todo                       controllers.TodoController.list()
```

## 2)TodoControllerにlistメソッドを追加

次のlistメソッドを追加します。
/play-hands-on/app/controllers/TodoController.scala

> こちらのメソッドを実装してください

```scala
  def list() = Action { implicit request: MessagesRequest[AnyContent] =>
    val message: String = "ここにリストを表示"
    Ok(views.html.list(message))
  }
```

> varはmutableな変数を定義する時に使用します。再代入可であることを示します。
> valはimmutableな変数を定義する時に使用します。再代入不可であることを示します。

## 3)listテンプレートの作成
/play-hands-on/app/viewsの下に[list]テンプレートを作成します。
IntelliJ上でviewsディレクトリを右クリックし、[New]の[File]をクリックします。

<img width="338" alt="7-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/cfb9dbe1-d93e-48d1-7990-5e7e6bd5406b.png">

表示されたダイアログに[list.scala.html]と入力しOKをクリックします。
<img width="200" alt="7-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/41151a46-53c2-4ec2-4c97-d7947c40a2a5.png">

> こちらのHTMLをコピーして貼り付けてください

```html
ここを実装してください
<html>
    <head>
        <title>Todo</title>
    </head>
    <body>

        <section>
        ここを実装してください
        </section>

    </body>
</html>
```

/play-hands-on/app/views/list.scala.html
> [ここを実装してください]と書いている箇所に次の内容と同じものを実装してください

```html
@(message: String)

<html>
    <head>
        <title>Todo</title>
    </head>
    <body>

        <section>
        @message
        </section>

    </body>
</html>
```

## 4)画面をブラウザで見てみましょう
こちらのリンクをクリックしてください
<p><a href="http://localhost:9000/todo" target="_blank">リスト画面</a></p>
次の画面が表示されたら成功です！
<img width="350" alt="7-0.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/e4950a36-2eff-ec62-9dce-117afce64781.png">

# 8.リスト画面の作成(case class)
目的：case class、Seq()、viewでのループ
<img width="350" alt="8-0.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/510180b6-cb93-72d5-efca-0344830aecb6.png">

## 1)サービスの作成
### servicesパッケージを作成する
appディレクトリを右クリックし、[New]の[Package]をクリックします。
<img width="305" alt="8-1-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/bc6de914-31a3-353e-b1f4-f705ed9f73d5.png">

表示されたダイアログに[services]と入力しOKをクリックします。
<img width="179" alt="8-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/7e01c1f2-641e-baee-ae2d-1cd31e223ebe.png">

## Todoクラスを作成する
servicesパッケージの下にTodoクラスを作成します。
IntelliJ上でservicesディレクトリを右クリックし、[New]の[Scala Class]をクリックします。
<img width="305" alt="8-3-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/aa326c22-cb3f-6684-ed2a-462b6f22d2ed.png">

表示されたダイアログに[Todo]と入力しOKをクリックします。
<img width="180" alt="8-4.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/d03e23fc-1d94-a6c6-d327-1e704b48f08d.png">

/play-hands-on/app/services/Todo.scala

> こちらの内容を実装してください

```scala
package services

case class Todo(name: String)
```

> case classのいいところ
> - プロパティが公開される(todo.nameなど)
> - インスタンスを作る時にnewが必要なくなる(val todo = Todo())
> - equals,hashCode,toStringなどが実装される


## 2)TodoControllerの編集
/play-hands-on/app/controllers/TodoController.scala

> servicesのパッケージを追加します

```scala
import services._
```

> listメソッドを編集します

```scala
  def list() = Action { implicit request: MessagesRequest[AnyContent] =>
    val items: Seq[Todo] = Seq(Todo("Todo1"), Todo("Todo2"))
    Ok(views.html.list(items))
  }
```

## 3)listテンプレートの編集
/play-hands-on/app/views/list.scala.html

> こちらのHTMLをコピーして上書きして貼り付けてください

```scala
ここを実装してください
<html>
    <head>
        <title>Todo</title>
    </head>
    <body>

        <section>
            <table>
                <thead>
                    <tr>
                        <th>名前</th>
                    </tr>
                </thead>
                <tbody>
                ここを実装してください
                </tbody>
            </table>
            <a href="/todo/new">登録画面</a>
        </section>

    </body>
</html>
```

/play-hands-on/app/views/list.scala.html

> [ここを実装してください]と書いている箇所に次の内容と同じものを実装してください

```scala
@import services._
@(items: Seq[Todo])

<html>
    <head>
        <title>Todo</title>
    </head>
    <body>

        <section>
            <table>
                <thead>
                    <tr>
                        <th>名前</th>
                    </tr>
                </thead>
                <tbody>
                @items.map { todo =>
                    <tr>
                        <td>@todo.name</td>
                    </tr>
                }
                </tbody>
            </table>
            <a href="/todo/new">登録画面</a>
        </section>

    </body>
</html>
```

> リバースルーティングを使用したリンクの書き方 href="@controllers.routes.TodoController.todoNew()"

## 4)画面をブラウザで見てみましょう
こちらのリンクをクリックしてください
<p><a href="http://localhost:9000/todo" target="_blank">リスト画面</a></p>
次の画面が表示されたら成功です！
<img width="350" alt="8-0.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/dda426e4-4d0a-04c9-4993-3b086a4ec6b9.png">



# 9.データベースの設定
目的：evolutions、anormの使い方
## 1)evolutionsについて
今回データベースを使用するにあたりDBマイグレーションツールを使用します。DBマイグレーションツールとは、スキーマのバージョン管理のようなもので、スキーマの変更に対してデータベースを追随させることができます。evolutionsはPlayframeworkで使われているDBマイグレーションツールです。

## 2)Anormについて
データベースアクセスにはAnormというライブラリを使用します。SQLを直接記述できSQL実行/結果解析をサポートします。

## 3)build.sbtの設定
プロジェクトルートディレクトリ配下のbuild.sbtを編集します。
<img width="152" alt="9-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/4c3b1680-8b29-937a-ab5d-296497ea53c0.png">

次の4行を追加してください。
/play-hands-on/build.sbt

> コピーして貼り付けてください

```
libraryDependencies += jdbc
libraryDependencies += evolutions
libraryDependencies += "org.playframework.anorm" %% "anorm" % "2.6.4"
libraryDependencies += "com.h2database" % "h2" % "1.4.196"
```
「Import Changes」をクリックするとライブラリの情報をIntelliJに読み込んで、ライブラリ内のクラスを自由に参照できるようになります。
![pasted-2019.01.11-15.15.06.png](https://qiita-image-store.s3.amazonaws.com/0/124660/b037ce05-6a1f-707d-e03a-04588578c1ee.png)

## 4)evolutionsの設定ファイルの作成
/play-hands-on/confディレクトリの下に[evolutions/default]ディレクトリを作成します。

<img width="159" alt="9-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/b23fa0eb-8f46-4e3d-e773-79ae5b429c42.png">

IntelliJ上で[conf]ディレクトリを右クリックし、[New]の[Directory]をクリックします。
<img width="264" alt="9-3.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/3305463b-efac-8392-ec92-3c61f4720000.png">

表示されたダイアログに[evolutions/default]と入力しOKをクリックします。
<img width="236" alt="9-4.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/7fc785a9-8c78-1255-7a37-7e9ce3c4ef6b.png">

## 5)マイグレーションファイルの作成
作成したディレクトリにマイグレーションファイルを作成します。
IntelliJ上で[evolutions.default]ディレクトリを右クリックし、[New]の[File]をクリックします。
<img width="347" alt="9-5.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/3555ccdc-4222-af9b-3def-bd54fe2aa4d5.png">

表示されたダイアログに[1.sql]と入力しOKをクリックします。
<img width="198" alt="9-6.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/3a175511-8e4f-f0ed-937a-d4b8af38f8aa.png">

/play-hands-on/conf/evolutions/default/1.sql

> コピーして貼り付けてください

```
# --- First database schema

# --- !Ups
create table todo (
  id                        bigint not null auto_increment,
  name                      varchar(255) not null,
  constraint pk_todo primary key (id))
;
create sequence todo_seq start with 1000;

insert into todo (id,name) values (1,'書類の整理');
insert into todo (id,name) values (2,'本の返却');

# --- !Downs
drop table if exists todo;

drop sequence if exists todo_seq;
```

## 6)データベースの設定
confディレクトリの下のapplication.confに次の2行を追加します。
<img width="160" alt="9-7.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/affa5c01-023e-12dc-5829-c60f2a14b362.png">

/play-hands-on/conf/application.conf

> コピーして貼り付けてください

```
db.default.driver = org.h2.Driver
db.default.url = "jdbc:h2:mem:play"
```

H2 Databaseと言うJavaプラットフォーム上で動く、インメモリデータベースを使用するように設定されます。

## 7)データベースを作成しましょう
一旦、Ctrl + Dでサーバーを停止したのち、ビルド定義を再読み込みしサーバーを起動します。

```
> reload
> run
```

次のリンクをクリックします。
<p><a href="http://localhost:9000/todo" target="_blank">リスト表示画面</a></p>
データベース作成画面が表示されます。
[Apply this script now!]ボタンをクリックしデータベースを作成しましょう。
<img width="350" alt="9-0.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/373517f7-62b2-7357-c6f3-b328c94d7505.png">


# 10.リスト画面の作成(データベース)
目的：Scalaでのデータベースの使い方
![10-a-2.png](https://qiita-image-store.s3.amazonaws.com/0/124660/292a4384-bc3c-c240-c04f-76710f3fa1bb.png)

---

<img width="350" alt="10-0.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/f1bf614e-0b25-68f6-3715-3065f32ab386.png">

## 1)モデルの編集
/play-hands-on/app/services/Todo.scala
> 全部コピーして上書きしてください

```scala
package services

import javax.inject.Inject

import anorm.SqlParser._
import anorm._
import play.api.db.DBApi

import scala.language.postfixOps

case class Todo(name: String)

@javax.inject.Singleton
class TodoService @Inject() (dbapi: DBApi) {

  private val db = dbapi.database("default")

  val simple = {
    get[String]("todo.name") map {
      case name => Todo(name)
    }
  }

  def list(): Seq[Todo] = {

    db.withConnection { implicit connection =>

      SQL(
        """
          select * from todo
        """
      ).as(simple *)

    }

  }
  
}
```

## 2)TodoControllerでTodoServiceを使えるように設定する
/play-hands-on/app/controllers/TodoController.scala

> todoService: TodoService,を追加してください

```scala
class TodoController @Inject()(todoService: TodoService, mcc: MessagesControllerComponents) extends MessagesAbstractController(mcc) {
```

## 3)TodoControllerのlistメソッドの編集
/play-hands-on/app/controllers/TodoController.scala

> こちらの内容で編集してください

```scala
  def list() = Action { implicit request: MessagesRequest[AnyContent] =>
    val items: Seq[Todo] = todoService.list()
    Ok(views.html.list(items))
  }
```

## 4)画面をブラウザで見てみましょう
こちらのリンクをクリックしてください
<p><a href="http://localhost:9000/todo" target="_blank">リスト画面</a></p>
次の画面が表示されたら成功です！
<img width="350" alt="10-0.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/f1bf614e-0b25-68f6-3715-3065f32ab386.png">


# 11.登録画面の作成(テンプレート)
目的：Playのフォームテンプレートヘルパーの使い方
![11-a-1.png](https://qiita-image-store.s3.amazonaws.com/0/124660/6fb924eb-5b15-c15a-a99d-46728f7805d9.png)

画面表示
<img width="350" alt="10-0-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/b6d33dda-7cec-963c-2a5b-fb3f00199230.png">

登録後
<img width="350" alt="10-0-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/c567f911-0a5c-a0ab-c421-a7e83399528d.png">

## 1)routesに登録画面表示と登録用のルートを追加
/play-hands-on/conf/routes
> 次の2行を追加してください

```
GET     /todo/new                   controllers.TodoController.todoNew()
POST    /todo                       controllers.TodoController.todoAdd()
```

## 2)TodoControllerにメソッドを追加
/play-hands-on/app/controllers/TodoController.scala

> 次の2つのメソッドを実装してください

```scala
  val todoForm: Form[String] = Form("name" -> nonEmptyText)

  def todoNew = Action { implicit request: MessagesRequest[AnyContent] =>
    Ok(views.html.createForm(todoForm))
  }

  def todoAdd() = Action { implicit request: MessagesRequest[AnyContent] =>
    val name: String = todoForm.bindFromRequest().get
    println(name)
    Ok("Save")
  }
```

## 3)createFormテンプレートの作成
/play-hands-on/app/viewsの下にcreateFormテンプレートを作成します。
IntelliJ上で[views]パッケージを右クリックし、[New]の[File]をクリックします。
<img width="309" alt="11-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/220c119c-05f6-08cf-1ad0-cdd1443b3ab9.png">

表示されたダイアログに[createForm.scala.html]と入力しOKをクリックします。
<img width="200" alt="11-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/7c47f7b6-83a3-c9a8-07c7-ff4a3f29f087.png">

/play-hands-on/app/views/createForm.scala.html

> こちらのHTMLをコピーして貼り付けてください

```html
ここを実装してください
<html>
    <head>
        <title>Todo</title>
    </head>
    <body>

        <h1>Todo登録</h1>
        
        ここを実装してください

    </body>
</html>
```

/play-hands-on/app/views/createForm.scala.html
> [ここを実装してください]と書いている箇所に次の内容と同じものを実装してください

```html
@(todoForm: Form[String])(implicit request: MessagesRequestHeader)

<html>
<head>
    <title>Todo</title>
</head>
<body>

<h1>Todo登録</h1>

@helper.form(action = routes.TodoController.todoAdd()) {
@helper.CSRF.formField

<fieldset>

    @helper.inputText(todoForm("name"), '_label -> "名前")

</fieldset>

<input type="submit" value="登録">

}

</body>
</html>
```

## 4)画面をブラウザで見てみましょう
こちらのリンクをクリックしてください
<p><a href="http://localhost:9000/todo/new" target="_blank">登録画面</a></p>
次の画面が表示されたら成功です！
画面表示
<img width="350" alt="10-0-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/05209323-bc96-d9a5-9e20-dfb014abc656.png">

登録後
<img width="350" alt="10-0-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/9303c75c-5d8e-9e94-28a3-423d8b9424e8.png">



# 12.登録画面の作成(データベース)
目的：データベースの利用(登録編)
![12-b-1.png](https://qiita-image-store.s3.amazonaws.com/0/124660/d84e8f13-e66f-d901-8775-7fc0067bfc42.png)


画面表示
<img width="350" alt="11-0-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/f11e02c8-25ca-3a0f-fc76-1afaf9562224.png">

登録後
<img width="350" alt="11-0-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/e9680215-73fd-f43e-6649-66fb335f9299.png">

## 1)TodoServiceにメソッドを追加します。
/play-hands-on/app/services/Todo.scala
TodoServiceの中
> コピーして追加してください

```scala
  def insert(todo: Todo) = {
    db.withConnection { implicit connection =>
      SQL(
        """
        insert into todo values ((select next value for todo_seq), {name})
        """
      ).on(
        'name -> todo.name
      ).executeUpdate()
    }
  }
```

## 2)TodoControllerのtodoAddメソッドを次のように編集します。
/play-hands-on/app/controllers/TodoController.scala
> 次の内容で編集してください

```scala
  def todoAdd() = Action { implicit request: MessagesRequest[AnyContent] =>
    val name: String = todoForm.bindFromRequest().get
    todoService.insert(Todo(name))
    Redirect(routes.TodoController.list())
  }
```

## 3)画面をブラウザで見てみましょう
こちらのリンクをクリックしてください
<p><a href="http://localhost:9000/todo/new" target="_blank">登録画面</a></p>
次の画面が表示されたら成功です！
画面表示
<img width="350" alt="11-0-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/f11e02c8-25ca-3a0f-fc76-1afaf9562224.png">
登録後
<img width="350" alt="11-0-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/124660/e9680215-73fd-f43e-6649-66fb335f9299.png">


# 13.更新処理の実装
## 1)routesにupdate用のルートを追加
/play-hands-on/conf/routes
> 次の2行を追加してください

```
GET     /todo/edit/:todoId                  controllers.TodoController.todoEdit(todoId:Long)
POST   /todo/:todoId                       controllers.TodoController.todoUpdate(todoId:Long)
```

## 2)TodoControllerにメソッドを追加
/play-hands-on/app/controllers/TodoController.scala
> 次の2つのメソッドを実装してください

```scala
  def todoEdit(todoId: Long) = Action { implicit request: MessagesRequest[AnyContent] =>
    todoService.findById(todoId).map { todo =>
      Ok(views.html.editForm(todoId, todoForm.fill(todo.name)))
    }.getOrElse(NotFound)
  }

  def todoUpdate(todoId: Long) = Action { implicit request: MessagesRequest[AnyContent] =>
    val name: String = todoForm.bindFromRequest().get
    todoService.update(todoId, Todo(Some(todoId), name))
    Redirect(routes.TodoController.list())
  }
```

todoAddメソッドを次のように編集します。Todoにidが増えたのでNoneを渡しています。

```scala
  def todoAdd() = Action { implicit request: MessagesRequest[AnyContent] =>
    val name: String = todoForm.bindFromRequest().get
    todoService.insert(Todo(id = None, name))
    Redirect(routes.TodoController.list())
  }
```

## 3)TodoServiceにメソッドを追加し、Todoにidを追加します。
/play-hands-on/app/services/Todo.scala

```scala
package services

import javax.inject.Inject

import anorm.SqlParser._
import anorm._
import play.api.db.DBApi

import scala.language.postfixOps

case class Todo(id:Option[Long], name: String)

@javax.inject.Singleton
class TodoService @Inject() (dbapi: DBApi) {

  private val db = dbapi.database("default")

  val simple = {
    get[Option[Long]]("todo.id") ~
    get[String]("todo.name") map {
      case id~name => Todo(id, name)
    }
  }

  def list(): Seq[Todo] = {

    db.withConnection { implicit connection =>

      SQL(
        """
          select * from todo
        """
      ).as(simple *)

    }

  }

  def insert(todo: Todo) = {
    db.withConnection { implicit connection =>
      SQL(
        """
        insert into todo values ((select next value for todo_seq), {name})
        """
      ).on(
        'name -> todo.name
      ).executeUpdate()
    }
  }

  def findById(id: Long): Option[Todo] = {
    db.withConnection { implicit connection =>
      SQL("select * from todo where id = {id}").on('id -> id).as(simple.singleOpt)
    }
  }

  def update(id: Long, todo: Todo) = {
    db.withConnection { implicit connection =>
      SQL(
        """
          update todo
          set name = {name}
          where id = {id}
        """
      ).on(
        'id -> id,
        'name -> todo.name
      ).executeUpdate()
    }
  }

}
```

## 4)editFormテンプレートの作成
/play-hands-on/app/views/editForm.scala.html

```html
@(id: Long, todoForm: Form[String])(implicit request: MessagesRequestHeader)

<html>
<head>
    <title>Todo</title>
</head>
<body>

<h1>Todo更新</h1>

@helper.form(action = routes.TodoController.todoUpdate(id)) {
@helper.CSRF.formField

<fieldset>

    @helper.inputText(todoForm("name"), '_label -> "名前")

</fieldset>

<input type="submit" value="更新">

}

</body>
</html>
```

## 5)list.scala.htmlのリストをリンクにします

```html
@import services._
@(items: Seq[Todo])

<html>
<head>
    <title>Todo</title>
</head>
<body>

<section>
    <table>
        <thead>
        <tr>
            <th>名前</th>
        </tr>
        </thead>
        <tbody>
        @items.map { todo =>
        <tr>
            <td><a href="@controllers.routes.TodoController.todoEdit(todo.id.get)">@todo.name</a></td>
        </tr>
        }
        </tbody>
    </table>
    <a href="@controllers.routes.TodoController.todoNew()">登録画面</a>
</section>

</body>
</html>
```


# 14.削除処理の実装
## 1)routesにdelete用のルートを追加
/play-hands-on/conf/routes
> 次の行を追加してください

```
POST   /todo/:todoId/delete                controllers.TodoController.todoDelete(todoId:Long)
```

## 2)TodoServiceに削除メソッドを追加します
/play-hands-on/app/services/Todo.scala

```scala
  def delete(id: Long) = {
    db.withConnection { implicit connection =>
      SQL("delete from todo where id = {id}").on('id -> id).executeUpdate()
    }
  }
```

## 3)TodoControllerにメソッドを追加
/play-hands-on/app/controllers/TodoController.scala
> 次のメソッドを実装してください

```scala
  def todoDelete(todoId: Long) = Action { implicit request: MessagesRequest[AnyContent] =>
    todoService.delete(todoId)
    Redirect(routes.TodoController.list())
  }
```

## 4)editFormテンプレートの編集
削除ボタンを追加します。
/play-hands-on/app/views/editForm.scala.html

```html
@helper.form(action = routes.TodoController.todoDelete(id)) {
@helper.CSRF.formField
<input type="submit" value="削除" class="btn danger">
}
```