Google Cloud ShellでLaravel開発環境を用意してサクッとチュートリアル


# 目的

ハンズオン形式で、受講者の環境を統一したいという考えがあって、それにはGoogle Cloud Shellが便利かと思い環境を作ってみました。

開発でLaravelのチュートリアルなんかをやるために開発環境を作ったりするのですが、今から学ぼうとしている人にはなかなか難しいことだと思います。公式にはHomesteadというvagrant環境があるのですが、vagrantの意味がわからないと、「vagrantで環境用意してください」と言われても、、という気もするので調査してみました。

# 環境
- Laravel 5.5系
- 開発環境 Google Cloud Shell
    - php 7.0
    - データベース sqlite3

# Google Cloud Shellについて

<https://cloud.google.com/shell/>

- Googleが提供するテンポラリーなVM
- ブラウザから使える端末
- ホームディレクトリはアカウントに紐付いて永続化
- ホーム以外は、シャットダウンとともに消える
- ありがちなツールが一通りインストール済み
- 無料

※料金体系は、無料とのことなんですが、ブースト機能とか使っても無料なのかちょっとよくわかっていない。

# チュートリアル

## Cloud Shellの起動
<https://console.cloud.google.com/getting-started>
から右上のコンソールのアイコンをクリックして、端末の起動。（初回の起動は少し時間がかかる）

![コンソールアイコンをクリック](https://qiita-image-store.s3.amazonaws.com/0/8221/f9575cd1-af88-5de7-f9ff-da72f5e57e00.png)

下部にコンソールウィンドウが開いて、ログイン済みの状態になる。

## 必要なミドルウェアをインストール

php-zip, php-sqlite3ライブラリが入っていないので入れる。

```shell
$ sudo apt install -y php-zip php-sqlite3
```
こういったaptでのインストールは、ホーム外へのインストールなので、VMがシャットダウンされると消えてクリーンな状態になる。ハンズオン講習のような一時的な開発で消えて良い場合は環境がクリーンに戻るので便利。
*（永続的な開発でのツール導入であればホームディレクトリ下にインストールする）*

## Laravelプロジェクト"blog"の作成
```shell
$ composer create-project --prefer-dist laravel/laravel blog "5.5.*"
```

Composerはすでにインストールずみなので、Laravelのインストールとプロジェクトを作成する。Laravelのバージョンは5.5系最新を指定。blogというプロジェクト名で作成。

## blogディレクトリでサーバ起動

開発用のWebサーバーが提供されているのでそれを使って起動。apacheやnginxを別途インストールすることもできる。

```shell
$ cd blog
$ php artisan serve
```
artisanは、Laravelで用意されている便利コマンド群を提供するツール。`php artisan`で実行してみると使用できるコマンドがたくさんあるのが分かる。開発でも頻繁に使用する。

ポート8000番でサーバーが起動する。Cloud Shellはクラウド上のシェルだが、一部のポートのみ開放してインターネット経由でアクセスできる。

## ポート開放とWebアクセス。
クラウドシェルのタブの右側にあるアイコンからポート開放する。デフォルトでは8080を開放してプレビューするようになっているが、8000番に変更する。

![ポートの変更](https://qiita-image-store.s3.amazonaws.com/0/8221/8d26a8f2-b615-5285-8d1e-b6d0ba173c96.png)

変更してプレビューでブラウザのタブが開き、自分のCloud ShellセッションにHTTP経由でアクセスする。
![8000番に書き換えて](https://qiita-image-store.s3.amazonaws.com/0/8221/e0345f89-ab55-2e6e-d23f-39011c0c29b6.png)

ブラウザにはLaravelインストール直後の状態が表示される。
![Laravelインストール直後の状態](https://qiita-image-store.s3.amazonaws.com/0/8221/73490ebe-4fb1-ab5c-508e-c0d9e049c6db.png)

とても簡単。

## コードエディタ
右側にある鉛筆アイコンからコードエディタを起動。
![コードエディタの起動](https://qiita-image-store.s3.amazonaws.com/0/8221/00d3b4f2-61fb-6f94-e520-0d8688e27ca3.png)

ホームディレクトリ配下のファイルを開いて編集できる。今まで開いていた端末もコードエディタの下部に移行してくる。今後はこちらの端末を使う。

`blog/resources/views/welcome.blade.php`を開いて、タイトル部分を編集。
これはHTMLのテンプレートのようなもの。
![コードエディタ](https://qiita-image-store.s3.amazonaws.com/0/8221/e309fbc7-fed8-72f7-19f7-c64d58fbf356.png)

ブラウザで開いたページをリロードすると表示が変わることを確認できる。
![表示結果](https://qiita-image-store.s3.amazonaws.com/0/8221/fb57941a-8e50-1f39-1366-e43544a50a57.png)

Ctrl+Cで一旦Webサーバーは終了。

## 設定ファイルの編集

laravelアプリケーションの設定ファイルである`.env`ファイルを編集する。

ドットファイルは非表示になっているので、コードエディタの設定を変更して表示されるようにする。

デフォルトでは、`.git, .DS_Store, .*`となっているが、`.git, .DS_Store`と修正する。`.*`をフィルタ対象外にする。（,だけ残したりすると設定が正しく動作しないようです）

![設定の編集](https://qiita-image-store.s3.amazonaws.com/0/8221/41ae70b0-54e6-ac60-6a21-26c56d6b68c6.png)

ファイルツリーに戻ると、.envファイルが表示されているので、それを編集してデータベースの設定を変える。
今回はデータベースにsqlite3を使用する。
（Cloud Shellでmysql-serverをインストールして、mysqlを使用することも可能です。）

DB_CONNECTIONにsqliteを設定する。

sqliteのデータベースファイルは、DB_DATABASEでパスを指定することができるが、今回はデフォルトのパス(`database/database.sqlite`になる)を使用する。その他のDB設定は使用しないのでコメントアウトしておく。

```shell
DB_CONNECTION=sqlite
#DB_HOST=127.0.0.1
#DB_PORT=3306
#DB_DATABASE=
#DB_USERNAME=
#DB_PASSWORD=
```

## データベースマイグレーション
sqliteのデータベースファイルが生成されていないので空のファイルとして生成する。
touch コマンドで生成。

```shell
$ touch database/database.sqlite
```

artisanのmigrateコマンドでデータベーステーブル生成。

```shell
$ php artisan migrate
Migration table created successfully.
〜〜〜
```
sqliteでテーブルが作成されていることを確認。

```shell
$ sqlite3 database/database.sqlite ".tables"
migrations       password_resets  users
```
## モデルの作成

`artisan make:model`でブログ投稿"Post" のモデルの雛形を作成しつつ、migrationファイルも生成する。

```shell
$ php artisan make:model -m Post
Model created successfully.
Created Migration: xxx_create_posts_table
```
`blog/app`のフォルダに Postモデルのファイル`Post.php`が、
`blog/database/migrations`のフォルダにpostsテーブルのマイグレーションファイルが生成されます。

マイグレーションファイルを編集して、postsテーブルの定義を記述。

```php:blog/database/migrations/xxx_create_posts_table.php
#...中略...
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');  	#追加
            $table->string('body');  	#追加
            $table->timestamps();
        });
    }
#...中略...
```

postsのテーブル定義ができたので、これもmigrationで生成する。

```shell
$ php artisan migrate
Migrating: 2018_xx_xx_xxxxxx_create_posts_table
Migrated:  2018_xx_xx_xxxxxx_create_posts_table
```

## tinkerで対話的にデータを投入

Postのデータが何もないので、データを投入します。SQLを書いてINSERTしても良いのですが、作成したモデルを確かめるつもりで tinkerという対話シェル上で実行します。

ちょっとわかりにくいですが、Postのオブジェクトを生成→値を設定して→saveというのを2回繰り返しています。

```shell
$ php artisan tinker
Psy Shell v0.9.4 (PHP 7.0.27-0+deb9u1 — cli) by Justin Hileman
>>> $p = new App\Post()
=> App\Post {#2283}
>>> $p->title = "Title1"
=> "Title1"
>>> $p->body = "Body text1";
=> "Body text1"
>>> $p->save()
=> true
>>> $p = new App\Post()
=> App\Post {#2287}
>>> $p->title = "Title2"
=> "Title2"
>>> $p->body = "Body text2";
=> "Body text2"
>>> $p->save()
=> true
>>> exit
```
tinkerシェルを抜けたあとに、sqliteでデータを確認すると、postsに2レコード増えています。

```shell
sqlite3 database/database.sqlite "SELECT * FROM posts"
1|Title1|Body text1|2018-05-30 01:00:00|2018-05-30 01:00:00
2|Title2|Body text2|2018-05-30 01:00:10|2018-05-30 01:00:10
```
※laravelにはSeederという仕組みも用意されてあって初期データを生成するのもコードで準備しておいて、いつでも再生成できるようになります。

## ルーティングに処理追加
`blog/routes/web.php`にwelcomeビューへのルーティングが記述されています。

postsの全検索結果を、ビューに渡すようにします。

```php:blog/routes/web.php
Route::get('/', function () {
    $posts = App\Post::all();
    return view('welcome', ['posts'=>$posts]);
});
```

## ビュー修正

`resources/views/welcome.blade.php`のテンプレートの大部分を削除して、postをforeachでレンダリングするように修正します。

```php:resources/views/welcome.blade.php
<!doctype html>
<html lang="{{ app()->getLocale() }}">
	<ul>
	@foreach($posts as $post)
		<li>{{$post->title}} : {{$post->body}}</li>
	@endforeach
	</ul>
</html>
```

## ブラウザで確認

再び Webサーバーを起動してブラウザから確認。

```shell
$ php artisan serve
```

![ブラウザ表示](https://qiita-image-store.s3.amazonaws.com/0/8221/ba5f3147-658a-8259-fdaf-9d8a0788f752.png)

レンダリングされることが確認できる。

## コントローラーの作成

web.phpでpostsを検索する処理を書いたが、web.phpはコントローラーへの振り分けのみ記述し、データを取得する処理はPostControllerで記述するようにする。

`artisan make:Controller`コマンドでコントローラー作成。

```shell
$ php artisan make:Controller PostController
Controller created successfully
```

```php:blog/app/Http/Controllers/PostController.php
# ...中略...
use App\Post; //Postクラスのuse

class PostController extends Controller
{
    public function index(){
        $posts = Post::all();
        return view('welcome', ['posts'=>$posts]);    	
    }
}
```

web.phpのルーティングをコントローラーの呼び出しに修正。

```php:blog/routes/views/web.php
Route::get('/', 'PostController@index');
```

再び Webサーバーを起動してブラウザから同様に動作することを確認。

```shell
$ php artisan serve
```

# 参考記事

- https://readouble.com/laravel/5.5/ja/installation.html