はじめてのPlay Framework個人的メモ

# Play Framework


##よく使うもの
* ソースファイルの置き場所　`app`
* ビルドのためのスクリプトファイル　`sbt.bat`
* 設定ファイル置き場　`conf`
* 全体のレイアウトを記述するファイルや画像などのリソースを置くフォルダ　`public`
* ビルド生成物が置かれるフォルダ　`target`


### appフォルダ

* controllers ロジック
* views　HTML (Scalaのコードを埋め込んだ.scala.htmlという拡張子のファイル
* モデルの定義もここに置く
* ここに作るディレクトリは、フォルダではなくパッケージになる

### Welcome to Play!　が表示される仕組み
routesというファイルでルーティング設定

（クライアントからサーバに送る要求の種類とURLの組み合わせを、プラグラムのメソッドに結びつける）



GETメソッドでルート（デフォルトではlocalhost:9000）にアクセスすると、
`app/controllers`フォルダにある`HomeController`クラスの`index`メソッドが呼ばれる

```scala:conf/routes
GET     /                           controllers.HomeController.index
```


↓


```scala:app/views/index.scala.html
@()

@main("Welcome to Play") {
  <h1>Welcome to Play!</h1>
  }

```

indexメソッドによって、テンプレートindexを呼び出す
main関数を実行。
（引数として、
<li>title:Stringである"Welcome to Play
<li>content:Htmlである\<h1>Welcome to Play!</h1>
を渡している）
↓

```scala:app/views/main.scala.html
 *@
@(title: String)(content: Html)

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>@title</title>
        <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
        <link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
    </head>
    <body>
        
        @content

      <script src="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript"></script>
    </body>
</html>
```

テンプレートindexによって、さらにmainを呼び出す
渡されてきた変数をHtmlに埋め込むには、`@変数名`とする。

## リンクの貼り方

`routes`に記載された情報を利用する

```play:routes
GET     /                           controllers.HomeController.index

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

GET     /viewtest                   controllers.ViewTestController.index　　 #ここへのリンクを貼りたい
```

html内にて、

```HTML
<a href="@routes.ViewTestController.index">view test</a>
```
のようにする。

### 注意点
* `""`で囲んでも、Twirlテンプレートとしてちゃんと動いてくれる
* `routes`内では`controllers.~~ `となっているが、リンクを貼る際はroutes.~~に変えること

## テンプレートへの変数の渡し方

こんな感じでテンプレートがあるとする。

```HTML:viewtest_index.scala.html
@(title: String="自分で作ったファイル")

@viewtest_main("自分で作ったファイル"){
    <h1>@(title+"です")</h1>
}
```

titleという変数を受け取れるようしているが、初期値が設定してあるのでcontrollerでは

```scala
package controllers

import javax.inject._
import play.api._
import play.api.mvc._

@Singleton // 「シングルトン」の指定。「このクラスからは、たったひとつのオブジェクトしか作ってはいけない」という指示
class ViewTestController @Inject()(cc: ControllerComponents)
  extends AbstractController(cc) { // @Inject 「ccは、フレームワークで作る」というフレームワーク内部への指示

  def index() = Action { implicit request: Request[AnyContent] =>
    Ok(views.html.viewtest_index())
  }
}
```

この記述でOK。

しかし

```scala
@(title: String="自分で作ったファイル")(rnum: Int = 1)

@viewtest_main("自分で作ったファイル"){
    <h1>@(title+"です")</h1>
    <p>末尾が @rnum の方に大チャンス！！</p>
```

このように、テンプレートに変数を二つ定義しており、かつ初期値を持っている場合は、コントローラにて、
**二つの変数どちらにも値を渡さず、初期値のままにする**　ということを伝えなければいけません。
その際は、
```Ok(views.html.viewtest_index())```
ではなく、（エラーが起きる）
```Ok(views.html.viewtest_index()())```
このように、メソッドの呼び出しにおいて()を二つ、（変数の数分）記述してプログラムに意図を伝えなければいけない。

テンプレート最上段の、`@(title: String="自分で作ったファイル")(rnum: Int = 1)`に、
コントローラの`views.html.viewtest_index()()`が対応している形ですね。

そして、初期値を使わずに、コントローラから変数の値を指定する場合にも、変数の数だけ()を二つ並べます。

```play
Ok(views.html.viewtest_index("コントローラから渡したtitle")(5))
```

また、テンプレート側で、変数の受け取り方を
`@(title: String="自分で作ったファイル", rnum: Int = 1)`
このように一つの()の中にカンマ区切りで納めると、渡し方のほうも、
`Ok(views.html.viewtest_index("コントローラから渡したtitle", 5)`
このように「普通の関数みたいな書き方」になります。

**状況に応じて使い分けが必要**
()を並べる方法は
* <font color="blue">渡す値が関数オブジェクトやHTMLブロックの際に見やすい</font>
* <font color="blue">「変数を渡さない」という記述を、()を書くだけで簡単にできる</font>
その反面、
* <font color="red">引数が多くなった時にコンパイルに時間がかかる</font>

という特徴があるため。

## TwirlでのFor文の書き方

```scala
@(title: String= "for loopの練習", topics: Array[String])

<ul>
    @for(topic <- topics) {
        <li>@topic</li>
    }

</ul>
```

@の場所がちょっとややこしいですね。