- 投稿日:2020-12-18T23:29:22+09:00
JavaScriptに頼りきらないLaravel開発
web開発で欠かせないJavaScript
webアプリケーションで動きをつけるならJavaScriptがまだまだ主流かと思います。
ただ、あまりにもできることが多く何でもかんでも
JavaScript
に頼る開発もなんだかなと思うところもあり、今回はLaravel
でフロント側に頼りきらず全画面共通のコンポーネントを作成
する方法を紹介したいと思います。環境
言語 :
PHP 7.3.18
フレームワーク :Laravel 6.18.43
サンプル
今回は
Qiita
のような記事投稿ができるサービスを作っている前提で、サイドバーに項目を設けて既読の記事があれば通知を出すような機能を作ってみたいと思います。・サイドバーは全画面共通でどの画面からも開くことができる
・各項目の横に既読があれば通知を出すView Composer
Laravel
にはすごく便利なView Composer
が存在しそれを使えばすごく簡単にモックの様な共通処理を作成することができます。使い方はドキュメントを見ればすぐにわかりますが、今回は汎用性も兼ね備えた実装をしたいと思います。
Providerを追加する
まずは以下コマンドで
Provider
を作成します
php artisan make:provider ViewServiceProvider
後々この
Provider
に最終的な処理を記述します。Interfaceを作成する
そして、
Interface
を作成しておきます。
View composer
を使うためにはcomposer
メソッドにターゲットとなるview
,compose
メソッドが必須になるのでそのメソッドが実装されたクラス名を引数に指定します。なのでそれらを作成するメソッドを必須メソッドとして管理しておきます。
compose
メソッドについて後々説明します。また、使用したい
blade
ファイルは複数指定が可能なので、PHPDoc
でarray
が使用可能なのも記述しておきます。<?php declare(strict_types=1); use Illuminate\View\View; interface ViewComposer { /** * @return string|array */ public static function getTargetComponents(); /** * @param View $view */ public function compose(View $view): void; }具象クラスを実装する
先ほど作成した抽象クラス(
Interface
)の具象クラスを実装します。
getTargetComponents
メソッドは対象としたいview
を返す,compose
メソッドにはblade
ファイルで使用したい変数とデータを返すように実装していきます。<?php declare(strict_types=1); use Illuminate\View\View; class SidebarCompose implements ViewComposer { public static function getTargetComponents(): string { return 'parts.sidebar'; } /** * @param View $view */ public function compose(View $view): void { $view->with('countPer', APIなどで取得した各項目ごとの件数データなど); } }今回使用したいのはサイドバーなので、
parts/sidebar.blade.php
の様なディレクトリ構造を想定してparts.sidebar
と指定します。
compose
でwith
メソッドの中に第一引数に変数を, 第二引数に変数に格納するデータを指定します。Providerで使える様にする
一番最初に作成した
ViewServiceProvider
に実際に使えるように処理を追記します。declare(strict_types=1); use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; use PrtimesAdmin\View\Composers\SidebarCompose; class ViewServiceProvider extends ServiceProvider { /** * Register services. * * @return void */ public function register() { View::composer(SidebarCompose::getTargetComponents(), SidebarCompose::class); } }
View
ファサードを使用し、composer
を呼び出します。第一引数に、使用したい
blade
ファイルを指定するので、先ほど実装したSidebarCompose
クラスからgetTargetComponents
を呼び、第二引数には呼び出すクラスを指定するのでclass
をそのまま指定します。
composer
メソッドは、第二引数に指定されたクラス名に実装されているcompose
メソッドを呼び出し第一引数に指定されたview
で適用できるようにしてくれます。bladeファイルで作成した変数を使う
最後に
blade
側で変数を記述すれば実際に表示できる様になります。<div> . . . <p>{{ $countPer }}</p> </div>JavaScriptに頼りきらないLaravel開発
今回紹介した機能は
JavaScript
だと例えばページが読み込まれたときに表示するような処理が実装できるかと思います。
余裕があればそうすれば良さそうですね。しかし、チーム開発をしているとフロント側の実装者が少なくフロントの工数をあまり使いたくない場合も出てくるかと思います。そんなときに
Javascript
に頼らずバックエンドで実装してしまうのも手かと思います。
- 投稿日:2020-12-18T20:51:31+09:00
LaravelでAPIのレスポンスにバリデーションの内容をのせる方法
- 投稿日:2020-12-18T20:00:51+09:00
【備忘録】GCEでのLaravelの環境構築
GCEでLaravelの環境構築をよく行うので備忘録です。
間違い等ございましたら、ご指摘いただけますと幸いです。目次
- 構築する環境
- PHPの導入
- Gitの導入
- Composerの導入
- Apacheの導入
- Laravelの導入
- LaravelとApacheの設定
構築する環境
- debian 10
- PHP 7.3
- Composer
- Laravel 6.0
- git
- Apache2
PHPの導入
パッケージ一覧を更新
sudo apt update && sudo apt -y upgradePHP7.3 と 必要なPHPモジュールのインストール
sudo apt-get install php7.3 php-pear sudo apt-get install libapache2-mod-php7.3 php7.3-xml php7.3-gd php7.3-opcache php7.3-mbstring php7.3-curl zip unzip php7.3-zip php7.3-mysqlPHPが導入されたか確認
php -v
バージョンが表示されればOK!
Gitの導入
sudo apt-get install gitComposerの導入
composer-setup.phpのダウンロード
curl -sS https://getcomposer.org/installer -o composer-setup.php公式サイトにてHash値を確認し、変数に格納
HASH=公式サイトで確認したHash値 # (v2.0.8の場合は756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3) php -r "if (hash_file('SHA384', 'composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" # 実行結果: Installer verified sudo php composer-setup.php --install-dir=/bin --filename=composer # 実行結果 # All settings correct for using Composer # Downloading... # Composer (version 2.0.8) successfully installed to: /bin/composer # Use it: php /bin/composerComposerが導入されたか確認
composer # 実行結果 # ______ # / ____/___ ____ ___ ____ ____ ________ _____ # / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/ # / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / # \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/ # /_/ # Composer version 2.0.8 2020-12-03 17:20:38Composerの文字がデカデカと出力されればOK!!
Apacheの導入
Apacheと必要なモジュールのインストール
sudo apt-get install apache2 sudo a2dismod mpm_event sudo a2enmod mpm_prefork sudo systemctl restart apache2Laravelの導入
Laravelの導入場所に移動
cd /var/www/html
/var/www/html内のユーザーの権限を変更
sudo chown -R ユーザー名 /var/www/html既存のプロジェクトを使用する場合は、gitでcloneする
新規でプロジェクトを作成する場合は、sudo composer create-project --prefer-dist laravel/laravel プロジェクト名 "6.*"権限の変更
sudo chgrp -R www-data /var/www/html/プロジェクト名 sudo chmod -R 775 /var/www/html/プロジェクト名/storageLaravelとApacheの設定
cd /etc/apache2/sites-available sudo nano プロジェクト名.confプロジェクト名.confの記述は、
プロジェクト名.conf<VirtualHost *:80> ServerName 使用するサーバー名(なければプロジェクト名).com ServerAdmin webmaster@localhost DocumentRoot /var/www/html/プロジェクト名/public <Directory /var/www/html/プロジェクト名> AllowOverride All </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>次にsites-availableディレクトリからsites-enabledディレクトリへのシンボリックリンクの変更,
apacheの再起動を行います。sudo a2dissite 000-default.conf sudo a2ensite プロジェクト名.conf sudo a2enmod rewrite sudo service apache2 restart以上で設定は終了です!
Laravelの設定やDBはその都度で!!
- 投稿日:2020-12-18T18:47:19+09:00
Laravel(多対多)でphp artisan migrateエラー(SQLSTATE[42S01]: Base table or view already exists:)が出た時
Laravelで多対多のデータベース接続を行っている際、php artisan migrateコマンドを入力すると、下記のエラーが出ました。
すでにデータベースにテーブルが存在すると言われて困惑しましたが、
一度データベースから直接テーブルを削除して、再度php artisan migrateを行うと問題なく解決しました。何も変更を加えず、やり直すだけで解決する場合もあるので、一度試してみてください。
- 投稿日:2020-12-18T10:51:43+09:00
Laravel8 DBのデータを取得する処理をサービスに分割する
目的
- laravel8のアプリのコントローラでDBから値を取得する処理をサービス層に分割する方法をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.5) ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) プロセッサ 2 GHz クアッドコアIntel Core i5 メモリ 32 GB 3733 MHz LPDDR4 グラフィックス Intel Iris Plus Graphics 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.8 Homebrewを用いてこちらの方法で導入→Mac HomebrewでPHPをインストールする Laravel バージョン 8.X commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 前提条件
- 実施環境に近い環境が構築されていること
前提情報
- 今回サービスに処理を分割するlaravel8のアプリではAuthを用いた認証機能が付与されており、ログインができること。(データ取得処理をサービスに分割する本来の目的では必要ない作業だが説明の都合上こちらを記載させていただいた。)
- laravel8のアプリでの方法を紹介してるがルーティング情報の記載部分とusersテーブルのモデルファイルのデフォルト位置以外はlaravel7、laravel6でも方法は同じである。
- 筆者はMacのローカルに環境を構築し本記載の確認を行った。
- Laravel8のアプリでユーザ情報をDBから取得する処理をサービスに分割する方法を記載する。
どんなことをするかを簡単に図に記載する。
ルーティング、コントローラ、ビューにはそれぞれ下記の記載がされており、ログイン後に
/user
にアクセスするとログイン中のユーザIDとユーザ名が下記のように表示される。
ルーティングファイル
アプリ名ディレクトリ/routes/web.php<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\ContentController; use App\Http\Controllers\UserController; /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::get('/', function () { return view('welcome'); }); Auth::routes(); Route::get('/user', [UserController::class, 'index'])->name('user.index');コントローラ
アプリ名ディレクトリ/app/Http/Controllers/UserController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\User; use Illuminate\Support\Facades\Auth; class UserController extends Controller { public function index() { $user_id = Auth::id(); $user_info = User::select('*')->find($user_id); return view('users.index', ['user_info' => $user_info]); } }ビュー
アプリ名ディレクトリ/resources/views/users/index.blade.php<p>user_id: {{$user_info['id']}}</p> <p>user_name: {{$user_info['name']}}</p>概要
- サービスファイルの作成と記載
- コントローラファイルの修正
- 確認
詳細
サービスファイルの作成と記載
アプリ名ディレクトリで下記コマンドを実行してサービスファイルを格納するディレクトリを作成する。
$ mkdir app/Services下記コマンドを実行してサービスファイルを作成する。サービスファイル名はUserService.phpとする。
$ vi app/Services/UserService.php下記の内容を記載する。
アプリ名ディレクトリ/app/Services/UserService.php<?php namespace App\Services; use App\Models\User; class UserService { /** * * @var User */ private $user; public function __construct(User $user) { $this->user = $user; } /** * ユーザIDからユーザ情報を取得する * * @param int $user_id * @return model */ public function getUserInfoByUserId($user_id) { return $user_info = User::select('*')->find($user_id); } }コントローラファイルの修正
アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。
$ vi app/Http/Controllers/UserController.php下記のように修正する。
アプリ名ディレクトリ/app/Http/Controllers/UserController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\User; use Illuminate\Support\Facades\Auth; // 下記を追記 use App\Services\UserService; class UserController extends Controller { // 下記を追記 /** * * @var UserService */ private $userService; public function __construct(UserService $userService) { $this->userService = $userService; } // 上記までを追記 public function index() { $user_id = Auth::id(); // 下記を修正 $user_info = $this->userService->getUserInfoByUserId($user_id); return view('users.index', ['user_info' => $user_info]); } }確認
- ローカルサーバを起動しAuthで実装した認証機能にログイン後、下記にアクセスする。
下記のように表示されることを確認する。
- 投稿日:2020-12-18T04:13:25+09:00
Laravel(多対多)でphp artisan migrateエラー(SQLSTATE[HY000]: General error: 3780 Referencing column~are incompatible.)
Laravelでphp artisan migrateを実行し、SQLSTATE[HY000]: General error: 3780 Referencing column~are incompatibleといったエラーが出てきた場合、設定しているカラムタイプが異なることが原因である場合があります。
「are incompatible」は直訳すると互換性がないと言われています。//符号なしBIGINTを使用した自動増分ID(主キー) $table->bigIncrements('id'); //BIGINTカラム $table->bigInteger('votes');今一度、自分で設定したカラムタイプの整合性が取れているか確認してみてください。
- 投稿日:2020-12-18T01:22:29+09:00
インフラストラクチャ層のモジュール設計
この記事はLaravel Advent Calendar 2020の18日目です。
はじめに
ドメイン駆動設計で開発していてインフラストラクチャ層がとっ散らかりがちになるのが悩みの種でした。
『実践ドメイン駆動設計』の第9章にモジュールを使ってクラスを整理する方法が書かれていますが、ドメイン層のモジュールについての話がほとんどで、インフラストラクチャ層のモジュールについては書かれていません。そんな折に見つけた『Domain-Driven Design in PHP』という本に、いいなと思うインフラストラクチャ層のモジュール設計が書かれていたので紹介したいと思います。
『Domain-Driven Design in PHP』で推奨されているインフラストラクチャ層のモジュール設計
この本ではインフラストラクチャ層にドメイン層と同じ構成のモジュールを作ることを推奨しています。
|-- Domain | `-- Model `-- Infrastructure `-- Domain `-- Modelドメイン層のインターフェースをインフラストラクチャ層で実装するときは、対応するモジュールに配置します。
|-- Domain | `-- Model | `-- Bill | `-- BillRepositoryInterface.php `-- Infrastructure `-- Domain `-- Model `-- Bill `-- EloquentBillRepository.php私がこの設計をいいなと思った理由は、インターフェースの実装がどこにあるのかわかりやすくなる点と、インフラストラクチャ層のモジュール名にもユビキタス言語が使われるようになる点です。
ORMなどドメイン層に対応しないものは、その技術に関連したモジュールに配置します。
Infrastructure |-- Domain `-- Persistence `-- Eloquent `-- Models `-- Bill.php本には書かれていませんでしたが、アプリケーション層のインターフェースをインフラストラクチャ層で実装するときもドメイン層のときと同じようにするのがいいと思います。
|-- Application | `-- DataTransformer | `-- Bill | `-- BillDataTransformerInterface.php `-- Infrastructure `-- Application `-- DataTransformer `-- Bill `-- BillLaravelPaginatorDataTransformer.phpWebアプリケーションフレームワークとの付き合い方
この本にはWebアプリケーションフレームワークとの付き合い方についても書かれています。
Webアプリケーションフレームワークを使う場合は、インフラストラクチャ層にデリバリーメカニズム(Web、API、コンソールなど)ごとのモジュールを作り、さらにその中にフレームワークごとのモジュールを作ることを推奨しています。Infrastructure |-- Delivery | |-- Api | | `-- Laravel | |-- Console | | `-- Symfony | `-- Web | `-- Silex `-- Domain上記の例ではAPIにLaravelを使い、コンソールにSymfonyを使い、WebにSilexを使っています。
ユーザーインターフェイス(コントローラやビューのことだと思います)に関しては、各フレームワークのモジュールに配置することを推奨しています。
本では各フレームワークのモジュール内部については特に書かれていませんでしたが、
Frameworks should obey you, and not the other way around. (フレームワークがあなたに従うべきであり、その逆ではない。)
との言葉があったので、各フレームワークのモジュール内部はフレームワークの規約に縛られることなく自由に設計していいということだと思います。
Laravelの例
以下は本に書かれていることではないですが、本を読んでみてLaravelを使う場合どうするか自分なりに考えてみました。
Laravelモジュールの中に自分のアプリケーションで使うLaravel関連のファイルを好きなように配置します。
Infrastructure `-- Delivery `-- Web `-- Laravel |-- Controllers |-- Middleware |-- Providers |-- Requests |-- resources | |-- fonts | |-- js | |-- lang | |-- less | `-- views `-- routesこれらのファイルをLaravelに使わせるには設定ファイルを書き換えることになります。
また、設定ファイルを書き換える以外の方法として、パッケージ機能を使ってLaravelに公開することもできると思います。
この方法であれば設定ファイルを書き換えることすら不要になるので、Laravelをほとんど素のままで使うことができるはずです。Laravelのドキュメントには書かれていませんが、ミドルウェアやイベントもパッケージとして公開できます。
ミドルウェアは
Illuminate\Support\ServiceProvider
を継承したサービスプロバイダーを作って、boot
メソッドの中でLaravelのAPIを使うことで登録できます。ミドルウェアの登録public function boot() { $this->app['router']->aliasMiddleware('my_middleware', MyMiddleware::class); }イベントも
Illuminate\Foundation\Support\Providers\EventServiceProvider
を継承したサービスプロバイダーを作れば、あとは普通にイベントを登録するときと同じように登録できます。イベントの登録protected $listen = [ // ... ];おわりに
『Domain-Driven Design in PHP』に書かれていたインフラストラクチャ層のモジュール設計について紹介しました。
また、Laravelを使う場合どうするか自分なりに考えてみました。参考
- 投稿日:2020-12-18T01:22:29+09:00
インフラストラクチャ層のモジュール設計について
この記事はLaravel Advent Calendar 2020の18日目です。
はじめに
ドメイン駆動設計で開発していてインフラストラクチャ層がとっ散らかりがちになるのが悩みの種でした。
『実践ドメイン駆動設計』の第9章にモジュールを使ってクラスを整理する方法が書かれていますが、ドメイン層のモジュールについての話がほとんどで、インフラストラクチャ層のモジュールについては書かれていません。そんな折に見つけた『Domain-Driven Design in PHP』という本に、いいなと思うインフラストラクチャ層のモジュール設計が書かれていたので紹介したいと思います。
『Domain-Driven Design in PHP』で推奨されているインフラストラクチャ層のモジュール設計
この本ではインフラストラクチャ層にドメイン層と同じ構成のモジュールを作ることを推奨しています。
|-- Domain | `-- Model `-- Infrastructure `-- Domain `-- Modelドメイン層のインターフェースをインフラストラクチャ層で実装するときは、対応するモジュールに配置します。
|-- Domain | `-- Model | `-- Bill | `-- BillRepositoryInterface.php `-- Infrastructure `-- Domain `-- Model `-- Bill `-- EloquentBillRepository.php私がこの設計をいいなと思った理由は、インターフェースの実装がどこにあるのかわかりやすくなる点と、インフラストラクチャ層のモジュール名にもユビキタス言語が使われるようになる点です。
ORMなどドメイン層に対応しないものは、その技術に関連したモジュールに配置します。
Infrastructure |-- Domain `-- Persistence `-- Eloquent `-- Models `-- Bill.php本には書かれていませんでしたが、アプリケーション層のインターフェースをインフラストラクチャ層で実装するときもドメイン層のときと同じようにするのがいいと思います。
|-- Application | `-- DataTransformer | `-- Bill | `-- BillDataTransformerInterface.php `-- Infrastructure `-- Application `-- DataTransformer `-- Bill `-- BillLaravelPaginatorDataTransformer.phpWebアプリケーションフレームワークとの付き合い方
この本にはWebアプリケーションフレームワークとの付き合い方についても書かれています。
Webアプリケーションフレームワークを使う場合は、インフラストラクチャ層にデリバリーメカニズム(Web、API、コンソールなど)ごとのモジュールを作り、さらにその中にフレームワークごとのモジュールを作ることを推奨しています。Infrastructure |-- Delivery | |-- Api | | `-- Laravel | |-- Console | | `-- Symfony | `-- Web | `-- Silex `-- Domain上記の例ではAPIにLaravelを使い、コンソールにSymfonyを使い、WebにSilexを使っています。
ユーザーインターフェイス(コントローラやビューのことだと思います)に関しては、各フレームワークのモジュールに配置することを推奨しています。
本では各フレームワークのモジュール内部については特に書かれていませんでしたが、
Frameworks should obey you, and not the other way around. (フレームワークがあなたに従うべきであり、その逆ではない。)
との言葉があったので、各フレームワークのモジュール内部はフレームワークの規約に縛られることなく自由に設計していいということだと思います。
Laravelの例
以下は本に書かれていることではないですが、本を読んでみてLaravelを使う場合どうするか自分なりに考えてみました。
Laravelモジュールの中に自分のアプリケーションで使うLaravel関連のファイルを好きなように配置します。
Infrastructure `-- Delivery `-- Web `-- Laravel |-- Controllers |-- Middleware |-- Providers |-- Requests |-- resources | |-- fonts | |-- js | |-- lang | |-- less | `-- views `-- routesこれらのファイルをLaravelに使わせるには設定ファイルを書き換えることになります。
また、設定ファイルを書き換える以外の方法として、パッケージ機能を使ってLaravelに公開することもできると思います。
この方法であれば設定ファイルを書き換えることすら不要になるので、Laravelをほとんど素のままで使うことができるはずです。Laravelのドキュメントには書かれていませんが、ミドルウェアやイベントもパッケージとして公開できます。
ミドルウェアは
Illuminate\Support\ServiceProvider
を継承したサービスプロバイダーを作って、boot
メソッドの中でLaravelのAPIを使うことで登録できます。ミドルウェアの登録public function boot() { $this->app['router']->aliasMiddleware('my_middleware', MyMiddleware::class); }イベントも
Illuminate\Foundation\Support\Providers\EventServiceProvider
を継承したサービスプロバイダーを作れば、あとは普通にイベントを登録するときと同じように登録できます。イベントの登録protected $listen = [ // ... ];おわりに
『Domain-Driven Design in PHP』に書かれていたインフラストラクチャ層のモジュール設計について紹介しました。
また、Laravelを使う場合どうするか自分なりに考えてみました。参考