ComposerもSSHも使えないサーバへLaravel5.6+を納品するときのメモ

composerが使えない。sshも使えない。公開領域しかない。与えられたのはFTPアクセス権のみ。
…というような状態でLaravel5.6+のシステムを納品するときの手順メモです。

やってること：
1. Composerパッケージを本番用に切り替え
2. 開発中にできた不要ファイルの削除
3. 高速化のための本番環境用キャッシュ作成

本文より[まとめ](#まとめ) が見やすいです。

# 準備
## 設定ファイル.env等を本番環境用に更新
```laravel:.env
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com
```
その他DB設定値など、configディレクトリのファイルもチェック。

## Composerパッケージを本番用に切り替え
```
composer install --optimize-autoloader --no-dev
```
## 不要ファイルの削除

※2020.10.2追記：
Laravel5.7以上では、`php artisan optimize:clear` で以下の処理が自動化されます。

```bash:ターミナル出力結果
Compiled views cleared!
Application cache cleared!
Route cache cleared!
Configuration cache cleared!
Compiled services and packages files removed!
Caches cleared successfully!
```

### Laravel5.6以下で行う：キャッシュ、ログ削除
`artisan view:clear` と `artisan clear-compiled` ができなければ以下のディレクトリの中身を削除する

- storage/framework/views/* 
- storage/framework/cache/* 

ログを消すのも忘れずに
- storage/logs/laravel.log
## ファイル更新
### 確認：パッケージキャッシュ
※おそらく`composer install --optimize-autoloader`のときに作成されるものですが、念のため。
これがComposerの状態に合わせて更新されていないと、開発モードで使っていたパッケージ(Debugbarなど)関連のエラーが出続けます

- bootstrap/cache/packages.php
- bootstrap/cache/services.php

### laravel-mixでproduction用に出力する
```
npm run prod
```
### 直接アクセスされると困るファイルが設置されたディレクトリに.htaccessを設置
/storage/の中などに。特にログはURLの推測がしやすくて丸見え。

```text:.htaccess
Order Deny,Allow
Deny from all
```
### 設定キャッシュ (任意)
必ず`.env`ファイルを本番用に書き換えて行うこと。特にDB接続設定。
**フルパスが含まれるので、本番環境以外で実行するときは必ず内容を確認する。**
その時点・その環境のconfig設定値を素直にまとめてしまうため、
laravelを呼び出すindex.phpによって動的に値を変えている場合などには一工夫必要です。
※将来的に、config/以下の内容を変えたのに反映されないおっかしいなーの罠にもなりうる。

```
artisan config:cache
```
→ storage/framework/cache/config.php が出力されます
### ルートキャッシュ (任意)
※ルートにクロージャを使ってるときはエラーが出るだけなのでこの手順を飛ばしてOK

```
artisan route:cache
```
→ /bootstrap/cache/routes.php が出力されます
## 全体をアップロード
```text:参考最小構成
app/
bootstrap/
config/
database/  ※Artisan::call('migrate')等をし終わったら削除する
public/    ※storage/app/publicへのシンボリックリンクを忘れずに
resources/ ※laravel-mixを使っているときはassetsが不要のことも多い
routes/
storage/　 ※Debugbar関連が混入しないように注意、
vendor/　　※古いものがサーバにある時は一度消してから上げなおす
.env
.htaccess
composer.json ※Artisan::call()などを使うときに必要
index.php
```

## マイグレーションなど
やり方はまとめ参照。

# まとめ
1. .env変更
2. `composer install --optimize-autoloader --no-dev`実行
3. `npm run prod` 実行
4. その他ファイル配置確認
5. アップロード
6. Artisanコマンド一式はメンテナンス用ルートを追加してURLにアクセス(例参照↓)
7. 不要になったdatabase/ディレクトリ削除
8. routes/web.php は運用に必要なものだけ残して更新
9. 動作確認
10. ログ削除

### メンテナンス用ルートの例
```php:routes/web.php
//デバッグモードだけで使えるようにしたいけどキャッシュ類に影響があるためはずす
//if (config('app.debug')):
Route::get('maintenance', function($sample = null) {
  $commands=[
    'cache:clear',     //キャッシュ削除
    'view:clear',      //ビューキャッシュ削除
    'clear-compiled',  //bootstrap/cacheの一部を作成
    //'storage:link',  //必要があれば:シンボリックリンク作成
    //'config:cache',  //必要があれば:コンフィグキャッシュ作成
    //'route:cache',   //必要があれば：ルートキャッシュ作成
    //'key:generate',  //できればやっておきたい：鍵を作り直す
    'migrate',         //マイグレーション実行
    //...その他artisanコマンドを追加しておけば手順を自動化できます
  ];
  $str='';
  foreach($commands as $artisan){
    $str.="{$artisan}<br>" . PHP_EOL;
    $exitCode = Artisan::call($artisan);
    if ($exitCode !== 0) {
      return response($str . "Error! {$artisan} exit code: {$exitCode}");
    }
  }
  return response($str . ': ok');
});
//endif;
```
# おわりに
長い戦いであった。お疲れ様でした。

### 余談
PHPからexec関数でphpコマンドとcomposer.pharが動かせる場合は、本来SSHでやりたい内容をPHPファイルにしたためればここまで苦労しなくていいです。

#参考
[[Laravel]デプロイ時の最適化](https://qiita.com/qiita-kurara/items/d37dbc5b67e6b6dfbe1d)
[Laravel5.6 デプロイ](https://laravel.com/docs/5.6/deployment) ※5.6-5.8の内容は同じでした(2019.3.29現在)