■概要
書籍「プロフェッショナルWebプログラミング Laravel」を参考にしつつ、Laravel9を検証
以下の公式ドキュメントも参考にしている
9.x Laravel
https://readouble.com/laravel/9.x/ja/
Laravel Sailについては、以下も参考になりそう
【Docker】Laravel Sailのインストールと使い方を確認 | アールエフェクト
https://reffect.co.jp/laravel/laravel-sail
Laravel9はLTSでは無くなった
リリースノート 9.x Laravel
https://readouble.com/laravel/9.x/ja/releases.html
Laravel9はLTSをやめた・・・? クライマー株式会社 | 福岡・東京
https://c-limber.co.jp/blog/2499
【Laravel9】いつまでも、あると思うな、LTS - Qiita
https://qiita.com/wadakatu/items/1038d5a020383e54ca5b
Laravelバージョン
https://laravelversions.com/ja
■環境構築
■準備
\\wsl$\Ubuntu-20.04\home\refirio\docker\laravel\code
C:/windows/System32/drivers/etc/hosts
127.0.0.1 laravel.local
■インストール
インストール 9.x Laravel
https://readouble.com/laravel/9.x/ja/installation.html
Sailを使用する場合、以下のようなコマンドから始める
Sailを使用しない場合、これまでどおりcomposer create-projectから始めることもできる(詳細は上記のページを参照)
$ cd /home/refirio/docker/laravel/code
$ curl -s
https://laravel.build/test1 | bash
curl によってイメージ「laravelsail/php81-composer:latest」がダウンロードされる
また、test1 が作成され、その中に必要なファイルも配置される
この時点で、test1 をGit管理対象にしておく
具体的にはSourcetreeで「Create」からフォルダを選択し、コミット対象のファイルは初期コミットとしてコミットしておく
11:53に以下を実行
$ cd test1
$ ./vendor/bin/sail up
12:08にイメージのダウンロードが完了した
引き続きDockerfileの内容により諸々が取得される
12:25起動したっぽい? -d を付けていないからバックグラウンドでは無い?
ブラウザから以下にアクセスして、Laravelの画面が表示された
http://localhost/
表示を確認出来たら、いったん Ctrl+C で終了する
引き続き、書籍のP.26から確認しつつ、コマンド省略やデーモン起動などを試す
■環境の調整
$ cd /home/refirio/docker/laravel/code/test1
$ sail
Command 'sail' not found
.profile の最後にaliasのための設定を追加
$ vi ~/.profile
# set alias for sail
alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'
コンソールを再起動し、パス指定なしでsailコマンドを実行できることを確認する
$ cd /home/refirio/docker/laravel/code/test1
$ sail
Laravel Sail
以下でデーモンを起動できる
$ cd /home/refirio/docker/laravel/code/test1
$ sail up -d
http://laravel.local/
以下のように操作できる
「sail shell」でシェルに入ることができるが、sailコマンド経由で直接操作することもできる
$ sail shell
$ sail php -v
$ sail composer -V
$ sail artisan -V
$ sail node -v
$ sail npm -v
$ sail mysql
$ sail test
以下でデーモンを終了できる
$ sail down
必要に応じて、PHPのタイムゾーンやMySQLの文字コードなどを調整する(P.32)
■アプリケーションの作成
■コントローラー作成の検証
$ sail artisan make:controller Sample/IndexController
以下のファイルが作成される
app/Http/Controllers/Sample/IndexController.php
<?php
namespace App\Http\Controllers\Sample;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class IndexController extends Controller
{
//
}
以下のように変更してみる
app/Http/Controllers/Sample/IndexController.php
<?php
namespace App\Http\Controllers\Sample;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class IndexController extends Controller
{
public function show()
{
return 'Hello';
}
public function showId($id)
{
return 'Hello ' . $id;
}
}
ルーティングも変更
routes/web.php
Route::get('/sample', [\App\Http\Controllers\Sample\IndexController::class, 'show']);
Route::get('/sample/{id}', [\App\Http\Controllers\Sample\IndexController::class, 'showId']);
以下にアクセスして表示を確認する
http://laravel.local/sample/
http://laravel.local/sample/10
■アプリケーションの作成
シングルアクションコントローラーを作成
$ sail artisan make:controller Article/IndexController --invokable
以下のファイルが作成される(「invoke」は、ここでは英語の「呼び出す」の意味で使われていると思われる)
app/Http/Controllers/Article/IndexController.php
<?php
namespace App\Http\Controllers\Article;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class IndexController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
//
}
}
以下のように変更してみる
app/Http/Controllers/Article/IndexController.php
<?php
namespace App\Http\Controllers\Article;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class IndexController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
return 'Article';
}
}
ルーティングも変更
routes/web.php
Route::get('/article', \App\Http\Controllers\Article\IndexController::class);
以下にアクセスして表示を確認する
http://laravel.local/article/
ビューに対応
app/Http/Controllers/Article/IndexController.php
public function __invoke(Request $request)
{
return view('article.index', [
'name' => 'Laravel',
'code' => '<script>console.log(\'Laravel\');</script>'
]);
}
resources/views/article/index.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Article</title>
</head>
<body>
<h1>Article</h1>
<p>{{ $name }}</p>
{!! $code !!}
</body>
</html>
引き続き、データベースの検証をしたい(P.51)
■テスト
Laravel×テスト駆動開発で初テストを書いてみた - Qiita
https://qiita.com/makimoch/items/7388b17aa8c13f638e4c
■デプロイ
サーバ要件やnginxの設定など、以下のページが参考になる
デプロイ 9.x Laravel
https://readouble.com/laravel/9.x/ja/deployment.html
■認証
Laravel の認証・認可パッケージが多すぎてわけわからんので図にまとめた - Qiita
https://qiita.com/mpyw/items/c944d4fcbb45c1a3924c
自前で認証機能を実装する場合、
・初心者のポートフォリオ制作などでは Breeze が最適
・一般的な商用ユースケースには Fortify が最適
・JetStream は積極的に使うべきではないが、「管理画面用途であるため UI デザインは関心がない」かつ「Breeze では機能不足」というときには有用
らしい
それぞれ実際に試したい
■認証
composerからAdminLTEをインストールできるみたい
管理画面は基本的にこれを使えば良さそう
Laravel-AdminLTEの導入手順 - Qiita
https://qiita.com/sasao3/items/bde9cc9b8336b7724002
【Laravel】AdminLTEを導入 | チグサウェブ
https://chigusa-web.com/blog/laravel-adminlte/
■検索
Laravel9の話というわけでは無いが、以下は参考にできそう
Laravelでほんの少しハイレベルな検索機能を作ってみた。(初心者向け) - Qiita
https://qiita.com/howaito01/items/7c7ce20410b29337ac63
意外と簡単!Laravel で全文検索をつくる(Laravel Scout + Algolia) - console dot log
https://blog.capilano-fw.com/?p=3843
以下も参考にできるか
新刊『検索システム ― 実務者のための開発改善ガイドブック』のお知らせ - 技術書出版と販売のラムダノート
https://www.lambdanote.com/blogs/news/ir-system
■スケジュール
タスクスケジュール 9.x Laravel
https://readouble.com/laravel/9.x/ja/scheduling.html
Laravel5のときの検証した内容が以下にある
Laravel.txt
以下のようにすると、フォアグラウンドで1分ごとにスケジュールが実行される
ローカルでの動作確認などに使える
$ php artisan schedule:work
■キュー
キュー 9.x Laravel
https://readouble.com/laravel/9.x/ja/queues.html
SupervisorでLaravelのQueue worker管理 | ソフトウェア開発のギークフィード
https://www.geekfeed.co.jp/geekblog/laravel_queue_with_supervisor/
supervisorとLaravelのQueueを使ってみた - Qiita
https://qiita.com/kenta_kitagawa/items/c9144fe0e33e4e98d844
バックグラウンド処理のため、「php artisan queue:work」を使用することができる
永続的に実行させ続けるためには、Supervisorなどのプロセスモニタを使用して、キューワーカの実行が停止しないようにする必要がある
Supervisorについては、以下ファイルの「バックグラウンドで処理を実行する(Supervisor)」を参照
Dropbox\サーバ\Etcetera.txt
■メンテナンスモード
【Laravel】メンテナンスモードが便利すぎるので広めたい!10分でマスターできます。 | Web Apps Labo
https://e-seventh.com/laravel8-maintenance-mode/
以下のコメントでメンテナンスモードになる
$ php artisan down
以下のコメントでメンテナンスモードが解除される
$ php artisan up
メンテナンス中は以下のファイルを作成することで、任意のメンテナンス画面を表示できる
resources/views/errors/503.blade.php
なお、メンテナンス中はCronによるスケジュールが動かなくなるので注意
以下のように、「スケジュールされたコマンドは無い」となる
$ php artisan schedule:run
No scheduled commands are ready to run.
■未整理メモ
■Service層とRepository層
LaravelでService層とRepository層を取り入れる | システム開発部Blog
https://enjoyworks.jp/tech-blog/7743
・Service層を持つことで、クラスの責任範囲を分けることができる。業務ロジック単位で扱う
・Repository層を持つことで、処理の差し替えやテストを容易にする。データベーステーブル単位で扱う
Repositoryをモック化すると、テストを容易にできる
案件によっては、そんな思想で作られている
色々参考にしつつ、最初にそんなレールを敷いたが、案件規模によっては無駄に複雑ではある
単体テストなど厳密に書いているわけでは無いし
案件の規模に応じて「コントローラー → サービス → モデル」や「コントローラー → モデル」でも問題無いと思う
リポジトリパターンについては、以下なども参考になる
LaravelでRepositoryパターンを実装する-入門編-
https://www.ritolab.com/entry/165
Laravelアプリケーションでリポジトリパターンを使う方法
https://www.twilio.com/blog/repository-pattern-in-laravel-application-jp
「例えば、注文管理をサードパーティアプリケーションにアウトソースする場合」
で処理を差し替える場合などが大きなメリットだと思う
ただし現実的には「注文管理をサードパーティアプリケーションにアウトソースしますが、それに伴いビューとかCSSも変わります。新規の機能も追加します」とかはありそうなので、そんな単純にはいかないとは思う
また
「小規模のプロジェクトでは、このアプローチは多くの作業が必要で」
というデメリットもあるので、ケースバイケースではある
■サービスコンテナ
サービスコンテナの仕組みに乗っておけば、処理の差し替えは契約インターフェイスの紐付けを変えるだけで対応できる?ただし小規模アプリケーションの場合は、無駄に複雑になる感は否めないが
サービスプロバイダで処理の紐づけを変更できる
■リポジトリパターン考察
「例えば、注文管理をサードパーティアプリケーションにアウトソースする場合」
で処理を差し替える場合などが大きなメリットだと思う
とするなら、リポジトリにwhereを長々書くのは思想的におかしいかもしれない
とは言え、柔軟な検索をどう実現すべきか、そもそも汎用的な検索メソッドではなく、専用の検索メソッドを用意すべきなのかもしれない
interfaceの継承がアリなら、契約用のインターフェイスはすべて共通の親クラスを作るか
以下などによると、クラス設計的にはおかしなことは無さそう
【PHP】interfaceは継承・多重継承が可能。読み込みの順番もあり?【697日目】 - エンジニアのひよこ_level10
https://www.nyamucoro.com/entry/2019/09/11/012246
ただし以下によると、機械的にCRUDを実装するのは良くないらしい。とは言え、同じ内容のインターフェイスが量産されるのも微妙だが
Laravel におけるリポジトリ実装のポイント - Shin x Blog
https://blog.shin1x1.com/entry/laravel-repository
「3. 機械的に CRUD メソッドを実装しない」
「機械的に CRUD を付けるというのは、データベーステーブルに対応するリポジトリを実装するという発想から来るものでしょう。そうではなく、リポジトリでは、対象のドメインデータが永続化層にどのような操作が必要かを考えて、それのみを実装すると良いです。」
CRUDな契約をinterfaceで定義して、その実装を抽象クラスとして実装するのはどうか
そういう書き方が駄目なら、以前検証したとおりリポジトリごとにインターフェイスを作るか
画一的に書くべきで無いなら、参照登録編集削除crudもしくは参照専用master、とか
外部APIであっても、基本的にはそのどちらかになるはず
PHPにおけるインターフェースと抽象クラス、多重継承、トレイトの使い方:PHPオブジェクト指向プログラミング入門(5)(1/2 ページ) - @IT
https://atmarkit.itmedia.co.jp/ait/articles/1511/02/news016.html
運用時と開発時で、データの取得内容を差し替えられる
また、リポジトリとモデルは対になることが多いが、それは絶対ではない
常に別のリポジトリ経由でモデルを扱うことも考えられる
リポジトリパターンと Laravel アプリケーションでのディレクトリ構造 - Qiita
https://qiita.com/karayok/items/d7740ab2bd0adbab2e06
「AppServiceProvider で環境ごとに注入する Repository を変更します。」
「これにより、テスト環境のときはデータの取得方法を変更することができます。」
「Model と Repository は 1:1 とは限りません。」
■その他
Service層とRepository層を作る意味
具体例はLaravel6を参照
ただし後述しているように、Repository層は無くてもいいかもしれない
以下は公式の説明だが、あまり解りやすいとは思わない
サービスコンテナ 9.x Laravel
https://readouble.com/laravel/9.x/ja/container.html
【Laravel】サービスコンテナとは?2つの強力な武器を持ったインスタンス化マシーン。簡単に解説。 - Qiita
https://qiita.com/minato-naka/items/afa4b930a2afac23261b
Laravel6.txt
https://refirio.org/memos/technology/?file=Laravel6.txt
以前の勉強メモ
「サービスとリポジトリを作成」部分を参照
以下、Laravel経験者の方の意見
ORMではEloquentとCollectionを使っている
Eloquentの準備 9.x Laravel
https://readouble.com/laravel/9.x/ja/eloquent.html
コレクション 9.x Laravel
https://readouble.com/laravel/9.x/ja/collections.html
…がRepositoryがあることで、この恩恵を受けにくくなっている
Repositoryをしっかり設計して思想を統一することで改善できるかもしれないが、中規模での開発なら
「コントローラー → サービス → リポジトリ → モデル」
よりも
「コントローラー → サービス → モデル」
の方がいいのでは
非常に大規模な開発ならリポジトリ層が活きるかもしれないが、それならLaravelではなくSymfonyの方がいいかもしれない
Laravelは色々簡単にできるようになっているが、Laravelの恩恵を受けるなら、リポジトリパターンは向いていないのでは
検索の一部の処理だけ使っていたり、はある
「こういう条件ではこういうwhereを書く」のような分岐処理など
ただ、これはサービス層で吸収できるかもしれない
以下も参考になりそう
5年間 Laravel を使って辿り着いた,全然頑張らない「なんちゃってクリーンアーキテクチャ」という落としどころ
https://zenn.dev/mpyw/articles/ce7d09eb6d8117