- 投稿日:2020-03-25T23:23:57+09:00
【Laravel】 From句にサブクエリを使用する
結論
laravel 5.6.3から
joinSub、leftJoinSubが使える.$subQuery = ProfileUserView::select(['user_id', 'company_id']) ->whereBetween('created_at', [$from, $to]) ->distinct(); $mostViewQuery = \DB::query() ->selectRaw('company_id, COUNT(user_id) AS pv') ->fromSub($subQuery, 'sub') ->groupBy('company_id');ver 5.6.3以前
それより以前は mergeBindings使う.
https://github.com/laravel/framework/issues/19711
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") ) ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder ->count();こんな感じ
$subQuery = ProfileUserView::select(['user_id', 'company_id']) ->whereBetween('created_at', [$from, $to]) ->distinct(); $mostViewQuery = \DB::table(\DB::raw("({$subQuery->toSql()}) as sub") ) ->mergeBindings($subQuery->getQuery()) ->selectRaw('company_id, COUNT(user_id) AS pv') ->groupBy('company_id');ただしmergeBindingsは、bindするパラメーターの順序を気をつけないといけないので注意する
- 投稿日:2020-03-25T23:11:50+09:00
Laravel base64エンコードされた画像を保存する
/** * 画像保存 * @param string $base64Context * @param string $storage * @param string $dir * @return App\Models\Image */ public function storeImage($base64Context, $storage, $dir) { try { preg_match('/data:image\/(\w+);base64,/', $base64Context, $matches); $extension = $matches[1]; $img = preg_replace('/^data:image.*base64,/', '', $base64Context); $img = str_replace(' ', '+', $img); $fileData = base64_decode($img); $dir = rtrim($dir, '/').'/'; $fileName = md5($img); $path = $dir.$fileName.'.'.$extension; Storage::disk($storage)->put($path, $fileData); return $path; } catch (Exception $e) { Log::error($e); return null; } }
- 投稿日:2020-03-25T23:11:50+09:00
【Laravel】 base64エンコードされた画像を保存する
/** * 画像保存 * @param string $base64Context * @param string $storage * @param string $dir * @return App\Models\Image */ public function storeImage($base64Context, $storage, $dir) { try { preg_match('/data:image\/(\w+);base64,/', $base64Context, $matches); $extension = $matches[1]; $img = preg_replace('/^data:image.*base64,/', '', $base64Context); $img = str_replace(' ', '+', $img); $fileData = base64_decode($img); $dir = rtrim($dir, '/').'/'; $fileName = md5($img); $path = $dir.$fileName.'.'.$extension; Storage::disk($storage)->put($path, $fileData); return $path; } catch (Exception $e) { Log::error($e); return null; } }
- 投稿日:2020-03-25T22:35:54+09:00
セッション
Request->session()->put('キー', 値);$変数 = Request->session()->get('キー');sessionの格納先は
strage/framework/sessions
になる。データベースでセッションを使う
下記設定に変更する
config/session.php'driver' => env('SESSION_DRIVER', 'database')SESSION_DRIVER=databaseコマンド実行
php artisan session:tableマイグレーションファイルが作成されるので
php artisan migrate
すればDBでセッションを扱えるようになる
- 投稿日:2020-03-25T21:05:26+09:00
Elastic BeanstalkでのLaravelにてstorageへのシンボリックリンクを張る方法
はじめに
Elastic BeanstalkでのLaravelにてstorageへのシンボリックリンクを張る方法で手こずったので備忘録です
TL;DR
container_commandsにて「ln」を使用して、相対パスでシンボリックリンクを貼りました
コード
ebextensions/commands.configcontainer_commands: 0x_storage_link: command: "ln -s ../storage/app/public storage" cwd: "/var/app/ondeck/public"最後に
他に良い方法がありそうですが。。。
補足
「php artisan storage:link」でシンボリックリンクを貼ると絶対パスになりました。(参考サイトと同事象)
参考
- 投稿日:2020-03-25T17:53:16+09:00
Laravelを利用したWebアプリ制作を学べる教材まとめ
はじめに
あらゆる教材に手を出すと、結局この教材はどういうことが学べるんだっけ??と失念しがちなので自分用に作ってみました。
※随時更新予定※
Techpitの教材編
Laravel(+Vue.js)でSNS風Webサービスを作ろう!
ページリンク
https://www.techpit.jp/p/laravel-vue-sns完成見本サンプル(※私がデプロイしたもの。Mail機能のみ未実装。)
http://laravel-vue-sns.herokuapp.com/
開発環境
Mac,Docker(Laradock)
PHP 7.3、Node.js 10、Vue.js 2.6.11、Laravel 6.8、PostgreSQL 11.6
~Dockerを利用するメリット~Webサーバーやデータベース本体やその設定内容をファイル化できるという点が挙げられます。
そのようなファイルをほかの人に配布することで、誰でも同じ環境を構築できます。
本教材では、そうしたDocker用に作られたファイルを利用して開発環境を作ります。
活用ライブラリ
MDBootStrap、Vue Tags Input
学べる内容
初学者がポートフォリオ作成で躓く(私含め)であろうミドルウェア、リクエスト、認可、ポリシー、さらにはフロンドエンドフレームワーク(Vue.js)との連携まで、実際にアプリを作りながら体験できる。以下、以前書いた感想記事。
https://chobimusic.com/laravel_vue_sns/
進め方
2章・3章:ログイン機能4章:記事投稿機能
4-3 authミドルウェア 4-4 フォームリクエストの作成 4-5 依存性の注入(DI)、fillableの利用5章:記事更新・削除機能
5-2 null演算子 5-5 認可(ポリシーの作成)によるユーザー権限の考慮6章:パスワード再設定メール(MailHogでのテストメール/Sendgridでの本番メール)
7章:いいね機能(VueコンポーネントをBladeに組み込み)
7-5 @json 7-7 いいね機能のアクションメソッド追加(web.php)8章:タグ機能
8-6 フォームリクエストのバリデーション(鬼門)9章:フォロー&ユーザーページ機能
10章:Googleアカウントを使ったログイン機能
11章:デバッグバーの活用(SQLの改善)
12章:Herokuへデプロイ
所感
このチュートリアルで連携するVue.jsに関しては、Vue Routerなどの公式ライブラリを活用しない。また、blade側に@jsonディレクティブを記載してデータ転送(サーバー上にあげる。Vueで取り出し。)しているのが印象的。
SPA開発ではないのでVueで非同期のデータ受け渡し&装飾をしている感じ。(フォローボタン・いいね機能)
URLの遷移がある部分は全てLaravel側で構築している。
内容自体かなり濃いので、Laravel、Vue.js共にある程度わかっていないと理解が難しいが、とても勉強になる。
SPA開発まではいかずともLaravelとVue.jsを連携させたい!といった方にはとてもおすすめ!!
Googleアカウントでログイン機能を実装することで、アプリ運用に伴うセキュリティ面のハードルが少し下がる。
どこからどこまでBladeで作ってVue側で補うか、境目の判断が難しい。。。
ちょっと動的なコンテンツを入れるだけならならjQueryを活用するのもアリ??
【Laravel x Vue.js】SPAクイズアプリケーションを作ってみよう!
ページリンク
https://www.techpit.jp/p/laravel-vue-quiz完成見本サンプル
https://laravel-vue-quiz.herokuapp.com/
開発環境
Mac,Homebrew
PHP 7.3、Node.js 10、Vue.js 2.6.10、Laravel 6.8、SQLite
活用ライブラリ
Chart.js,Axios(API※非同期でのサーバーアクセス※をより使いやすくしたもの),Laravel-Admin
学べる内容
サーバーサイドにLaravel、フロントサイド(表示部分)は、Vueで作成。メインとなるビューはトップ("/")と("/quiz")クイズの2画面。
Vue Router(ルーティング制御ができる公式プラグイン)でSPA化("/"と"/quiz"ページの遷移がリロードせずにできる)。
進め方
3章:Laravelプロジェクトとは別のディレクトリでVue.jsのプロジェクトを作成。4章:LaravelディレクトリとVueディレクトリをがっちゃんこ。index.blade.phpでvueを読み込み。
5章:Vou Router(router.js)の導入でSPA化
6章:API連携の実装(api.phpの編集)。Laravel側で取得したDB情報 をVue(フロントサイド)からAPIで読み込む。
7章・8章:ログイン、ユーザー登録もVue側でビューを作成。
9章:ランキング機能、キーワード画面の実装 ※いずれもAPIを使う
10章:ブラッシュアップ
11章:Laravel-Adminの導入
12章:Herokuへデプロイ
所感
LaravelにVueを組み込むにしてもどこまで組み込むのかで難易度が大きく変わることに気付けた。例えばいいねボタンの実装とかであれば簡単だが、SPA化するとなるとAxiosやVue Routerなどの知識も必要になる。
また、Laravel-adminが使いこなせればWordPressを使用することなくブログ運営なんかもできるなと感じた。(同じようなものだと他にはVoyagerなどがあるみたい。これを駆使したチュートリアルが見つからなかったのは残念。)
Laravel6とAWSで作るブックレビューサイト
ページリンク
https://www.techpit.jp/p/laravel6-aws完成見本サンプル
https://laravel-vue-quiz.herokuapp.com/
開発環境
AWS,cloud9(win,mac共通)
PHP 7.3、Node.js 10、MySQL5.7、Laravel 6
学べる内容
AWSでのアプリ開発画像投稿機能(シンボリックリンク)
GitHubリポジトリの作成~cloud9からの独自ドメインへのデプロイ
EC2インスタンスの立ち上げ、TeraTermでのSSH接続
所感
最初に作ったポートフォリオはこちらの教材を参考にした。削除・編集機能までは実装しないのが残念だが、AWSの活用を学べるのはありがたい。
最後にカスタマイズ提案があり、いいね機能やコメント機能など。
こちらはまだ未実装なので試してみてもいいかもしれない。
無料でできるチュートリアル
Vue + Vue Router + Vuex + Laravelで写真共有アプリを作ろう
ページリンク
https://www.hypertextcandy.com/vue-laravel-tutorial-introduction/
開発環境
Mac,Docker(Laradockを用いていない!!)
PHP 7.4、Node.js 10、Vue.js 2.6、Laravel 6、PostgreSQL、AWS S3(写真保存)
学べる内容
フロントエンドに Vue.js + Vue Router + Vuex 、サーバーサイドに Laravel を使用したSPAアプリ開発。
進め方
3章:Laravelプロジェクト作成。Laravel Mixでフロントをビルド。Vue Routerを導入。4章:api.phpを編集してサーバーサイドのAPIを実装。(会員登録,ログイン,ログアウト)
6章・7章:状態管理ライブラリVuexの導入。ユーザー認証データなどコンポーネントをまたいで参照したいデータを入れておけるストアの実装。
10章:写真投稿フォーム Vue.jsで投稿機能を実装。
11章:JSONへの変換。
16章:Herokuへのデプロイ&カスタマイズ提案
所感
無料のチュートリアルとしては断トツで深いところまで学べる。Laradockを使わずともDockerでLaravelは使えることにも気づいたので挑戦してみたい。
データの受け渡しやいいねなどあらゆる機能をVue.jsで実装。
教本含め、ここまで複雑なアプリ開発ができるチュートリアルを見たことがない。
もっとこういうチュートリアルが増えてほしい!!
おわりに
1つの教材ですべてを網羅することはできないので、いろんなチュートリアルをこなしながらスキルアップを目指したい。
- 投稿日:2020-03-25T17:34:12+09:00
【Docker+Laravel】テスト用のダミーファイルの生成の際に出たエラーたち
状況
Dockerの環境でLaravelアプリのテストの際、ダミーの画像ファイルを作ろうと思い、公式リファレンスにもある
file()
を利用しました。$file = UploadedFile::fake()->image('avatar.jpg');テストしてみるとこんなエラーが...
Tests\Feature\InformationControllerTest::testStore Call to undefined function Illuminate\Http\Testing\imagecreatetruecolor()最初はクラスをuseしてないのかな?とかLaravelアプリ側の問題だと思いましたが、どうやらこの
file()
メソッドが定義されるIlluminate\Http\UploadedFileクラスを使うには、PHP GDというPHPのライブラリが必要なようです。PHP GDのインストール
DockerfileにPHP GDのインストールを追加してみます。
RUN apt-get update && apt-get install -y \ zlib1g-dev \ libzip-dev \ mariadb-client \ && docker-php-ext-install zip pdo_mysql gd上のように書き換え、再構築してみると、次はこんなエラーが
configure: error: png.h not found調べると
docker-php-ext-install gd
をするだけでは足りず、
libfreetype6-dev
libjpeg62-turbo-dev
libpng-dev
依存関係のある三つのパッケージを事前に apt-get install する必要があるみたいです。Dockerfileを修正します。
docker-php-ext-install gd
の実行前に三つのパッケージのapt-get install
を書きます。RUN apt-get update && apt-get install -y \ zlib1g-dev \ libzip-dev \ mariadb-client \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ && docker-php-ext-install zip pdo_mysql gd再度buildしてみると正常に構築できました。
本当にインストールできているか確認してみます。
gd GD Support => enabled GD Version => bundled (2.1.0 compatible) GIF Read Support => enabled GIF Create Support => enabled PNG Support => enabled libPNG Version => 1.6.36 WBMP Support => enabled XBM Support => enabledちゃんとインストールできたようですね。
- 投稿日:2020-03-25T16:21:03+09:00
Laravelでいいね機能を実装しよう
1. はじめに
いいね機能とは、最近のSNSにはほとんどと言ってもいいほど実装されている機能で、「好き」,「わかる」,「支持できる」などの意思表示を表すコミュニケーションツールの一種です。
いいね機能があることによって、
・(ユーザー視点)多くの投稿からどの投稿が人気もしくは信憑性があるのか。 ・(投稿者視点)これまで投稿した記事でどの記事がユーザーの求めている記事なのか。などを判断する1つの材料となります。
今回はPHPのフレームワークLaravelを使用して、
いいね機能
を実装していきます。
※今回はLaravelの勉強を兼ねているため、いいね機能をサーバーサイドで処理を実装しています。本来のプロダクトであれば処理を軽くするためにもフロント側で処理を実装するかと思いますので、その点についてはご了承ください。1-1. 開発環境
PHPとLaravelのバージョンは下記のグラフの通りとします。
言語・FW バージョン PHP 7.2.26 Laravel 6.17.1 2. どのような仕様にするか
仕様としては1つの投稿(discussion)に複数のリプライ(Reply)が紐づくようになっていて、リプライに対していいね(Like)をつけることができます。
細かい仕様は以下のように定義します。・初期値はいいねボタンがグレーで、いいねボタンを押すとボタンが緑色になる ・いいね数をいいねボタンの右横に表示する ・いいねボタンを2度押すといいねを取り消すことができる ・自分のリプライに対してもいいねをすることができる ・ログイン中のみに限り、リプライにいいねすることができる3. いいね機能の実装
それでは実際にいいね機能の実装に入っていきます。
3-1. ルーティング
まずはじめにいいね機能を実装する上でのルーティングを定義します。
リプライにいいねをする処理をRepliesControllerのlike()
に、
リプライに付けたいいねを解除する処理をRepliesControllerのunlike()
に記述するという定義を行います。web.phpRoute::get('/reply/like/{id}', 'RepliesController@like')->name('reply.like'); Route::get('/reply/unlike/{id}', 'RepliesController@unlike')->name('reply.unlike');3-2. 情報の関係性について考える
リプライ(Reply)といいね(Like)の関係性は以下のようになります。
・1つのリプライに対して複数のいいねが紐づく ・1つのいいねに対して紐づくリプライは1つのみユーザー(User)といいね(Like)の関係性は以下のようになります。
・1人のユーザーに対して複数のいいねが紐づく ・1つのいいねに対して紐づくユーザーは1人のみ3-3. モデルの作成と修正
artisan
コマンドでLikeモデルとマイグレーションファイルを生成します。$ php artisan make:model Like -m
3-2の情報の関係性
を基にしてマイグレーションファイルとモデルを修正します。create_likes_teble.phpclass CreateLikesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('likes', function (Blueprint $table) { $table->bigIncrements('id'); $table->integer('reply_id')->unsigned(); $table->integer('user_id')->unsigned(); $table->timestamps(); }); ... } }Like.phpclass Like extends Model { // 配列内の要素を書き込み可能にする protected $fillable = ['reply_id','user_id']; public function reply() { return $this->belongsTo(Reply::class); } public function user() { return $this->belongsTo(User::class); } }Reply.phpclass Reply extends Model { ... public function likes() { return $this->hasMany(Like::class, 'reply_id'); } }3-4. いいね機能のビジネスロジックの実装
いいね機能のロジックを実装する上で以下の2点がポイントとなります。
・いいねボタンを押下したら、Likeテーブルに新たにレコードが生成されて、ユーザーIDとリプライIDが保存される。 ・いいねしたボタンに対して、再度いいねボタンを押すと上記で生成したレコードが削除される。上記のポイントを基に実装すると下記のようになります。
RepliesController.phpclass RepliesController extends Controller { // only()の引数内のメソッドはログイン時のみ有効 public function __construct() { $this->middleware(['auth', 'verified'])->only(['like', 'unlike']); } ... /** * 引数のIDに紐づくリプライにLIKEする * * @param $id リプライID * @return \Illuminate\Http\RedirectResponse */ public function like($id) { Like::create([ 'reply_id' => $id, 'user_id' => Auth::id(), ]); session()->flash('success', 'You Liked the Reply.'); return redirect()->back(); } /** * 引数のIDに紐づくリプライにUNLIKEする * * @param $id リプライID * @return \Illuminate\Http\RedirectResponse */ public function unlike($id) { $like = Like::where('reply_id', $id)->where('user_id', Auth::id())->first(); $like->delete(); session()->flash('success', 'You Unliked the Reply.'); return redirect()->back(); } ... }4. いいねボタンの実装
4-1.
いいね状態
と非いいね状態
の表示制御初期表示ではリプライにいいねがついておらず、いいねボタンはグレーでカウントは0、いいねをいている状態だと、いいねボタンが緑色になりカウントが1加算されます。
いいねがついているかどうかの判定を、
is_liked_by_auth_user()
内で判定して判定値をbooleanで返してあげます。show.blade.php<div> @if($reply->is_liked_by_auth_user()) <a href="{{ route('reply.unlike', ['id' => $reply->id]) }}" class="btn btn-success btn-sm">いいね<span class="badge">{{ $reply->likes->count() }}</span></a> @else <a href="{{ route('reply.like', ['id' => $reply->id]) }}" class="btn btn-secondary btn-sm">いいね<span class="badge">{{ $reply->likes->count() }}</span></a> @endif </div>Replay.php/** * リプライにLIKEを付いているかの判定 * * @return bool true:Likeがついてる false:Likeがついてない */ public function is_liked_by_auth_user() { $id = Auth::id(); $likers = array(); foreach($this->likes as $like) { array_push($likers, $like->user_id); } if (in_array($id, $likers)) { return true; } else { return false; } }4-2. いいね数の表示
いいね数の表示は、
Reply
とLike
は既にアソシエーションされているので、count()
でいいね数を取得することができます。shwo.blade.php{{ $reply->likes->count() }}最後に
以上でLaravelでの
いいね機能
の実装のご紹介でした!!
誤字脱字や、もっとこうした方がいいという箇所がございましたらコメント欄から教えてください!!
- 投稿日:2020-03-25T13:32:50+09:00
Laravelのモデル結合ルート【暗黙の結合】を使ってみる
暗黙の結合とは
暗黙結合とはLaravelのルートURIセグメント名と一致するEloquentモデルを
勝手に紐付けてくれる機能です
また、入力されたセグメントと一致するモデルが存在しない場合は404が返ってきますこの説明だけではパッとしないと思いますが
とても便利な機能なので是非積極的に使っていきたい機能だと思い
私も調べて試してみたので記事にしてみました準備
まずはデフォルトのUsersテーブルを作成します
$ php artisan migrateシーダファイルを用意してUsersテーブルに値を用意しておきます
$ php artisan make:seeder UserSeeder作成されたシーダファイルに記述します
UserSeeder.php<?php use Illuminate\Database\Seeder; class PersonTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { $param = [ 'name' => '太郎', 'email' => 'taro@gmail.com', 'password' => '99999999' ]; DB::table('users')->insert($param); $param = [ 'name' => '花子', 'email' => 'hanako@gmail.com', 'password' => '99999999' ]; DB::table('users')->insert($param); $param = [ 'name' => '次郎', 'email' => 'ziro@gmail.com', 'password' => '99999999' ]; DB::table('users')->insert($param); } }作成したシーダファイルを実行します
$ php artisan db:seed3件のダミーデータを用意しておきました
次に今回所得したデータを表示するviweを作成します
resources
にmain
フォルダを作成しその中にindex.blade.php
を作成してください
中身はこんな感じにしておきますindex.blade.php<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>ユーザー表示</title> </head> <body> {{ $user->name }} </body> </html>コントローラーを作成します
$ php artisan make:controller MainControllerここまでは準備です
では実際に暗黙結合でUsersのデータを所得して表示してみます実際に試す
ルート定義していきます
web.phpRoute::get('/users/{user}', 'MainController@index');コントローラーを修正します
MainController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\User; class MainController extends Controller { public function index(User $user) { return view('main.index', compact('user')); } }これで実際に
/users/1
とURLを叩いてみてください
ブラウザには太郎
と表示されるかと思います
これが、暗黙に結合された結果ですルートセグメントで
/users/{user}
としてEloquentモデルのUserと紐づけています
{user}
に入ってきた数字がUserモデルのidと合致するものが結合されます
そのモデルがコントローラーのpublic function index(User $user ){
この部分の引数に渡されています
暗黙の結合があることで、仮にそのUserの情報を所得したりしたい場合に
User::find($id)
みたいなことを書くことなくそのまま受け取れるのでとてもスマートで
便利な機能だなと思いましたおまけ
今回の場合はすでにあるUserモデルに新たにコントローラーを作成して利用しましたが
Userモデルのリソースコントローラーを作成することも多くあるかと思います
その際にこのコマンドを実行しコントローラーを作成することで
暗黙の結合を行うのに楽に実装できるリソースコントローラーを簡単に用意できます
コマンドにて下記を実行$ php artisan make:controller UserController --model=UserこれでUserのリソースコントローラーで下記のようにいい感じに作成してくれます
UserController.php<?php namespace App\Http\Controllers; use App\User; use Illuminate\Http\Request; class UserController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // } /** * Display the specified resource. * * @param \App\User $user * @return \Illuminate\Http\Response */ public function show(User $user) { // } /** * Show the form for editing the specified resource. * * @param \App\User $user * @return \Illuminate\Http\Response */ public function edit(User $user) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param \App\User $user * @return \Illuminate\Http\Response */ public function update(Request $request, User $user) { // } /** * Remove the specified resource from storage. * * @param \App\User $user * @return \Illuminate\Http\Response */ public function destroy(User $user) { // } }アクションの引数には予め、指定してUserモデルが指定されていますね
これでこのリソースコントローラーもそのまま使うだけで、暗黙結合したものが利用できとても便利な機能です今後はもっとこの機能を活用していこうと思います
- 投稿日:2020-03-25T13:17:29+09:00
Laravel 新規プロジェクト作成手順(laravel コマンドが使えなかったとき、composerコマンドでやってみよう)
- 投稿日:2020-03-25T12:46:31+09:00
$thisとは。
$thisとは。
簡潔にいう。
$thisを使っているクラスのことだ。具体的にいうと、コントローラーを見てみよう。
sample_controller.phpclass NewsController extends Controller { public function add_index() { $this->なんやかんや; } }注目するのは、最初のここ!
class NewsController extends Controller {これは、
Controllerクラスを継承して、NewsControllerクラスを作ります。中身は{}の中!!
という意味です。結論!!
$thisとは、ここでいうNewsControllerクラスのオブジェクトのこと!!
- 投稿日:2020-03-25T11:26:08+09:00
Laravel 7とSnappyでPDFを出力する
はじめに
LaravelでPDFを出力する方法です。
完成版のソースは以下に置いてあります。
https://github.com/naga3/snappy-sampleLaravelで使えるPDF出力ライブラリ
- Laravel Browsershot: https://github.com/verumconsilium/laravel-browsershot
- Puppeteerを使う
- 正確さでは一番か?
- Laravel DOMPDF: https://github.com/barryvdh/laravel-dompdf
- DOMPDFのLaravelラッパー
- PHPだけあれば動くのでお手軽
- Laravel Snappy: https://github.com/barryvdh/laravel-snappy
- Qt WebKitレンダリングエンジンを使ってPDFを出力するツールであるwkhtmltopdfのPHPラッパーであるSnappyのLaravelラッパー(ややこしい)
- Laravel DOMPDFより高速
今回はバランスを考えてLaravel Snappyを選択しました。
Laravelプロジェクト作成
https://readouble.com/laravel/7.x/ja/installation.html
コチラを参考に適当なプロジェクトを作成します。Composerがインストールされていれば簡単に作成できます。
composer create-project --prefer-dist laravel/laravel snappy-sample cd snappy-sampleLaravel Snappyのインストール
Laravel Snappyのドキュメントを見て進めて行きます。
まずwkhtmltopdfをインストールしますが、こちらもComposerで簡単に導入できます。WindowsやMacなど、バイナリが適合しない場合は上記ドキュメントを参照してください。
composer require h4cc/wkhtmltopdf-amd64 0.12.x次にLaravel Snappy本体をインストールします。
composer require barryvdh/laravel-snappyconfigファイルを作ります。
php artisan vendor:publish --provider="Barryvdh\Snappy\ServiceProvider"configファイルにwkhtmltopdfの場所を書きます。上記のようにComposerからインストールした場合は
config/snappy.php'binary' => base_path('vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf-amd64'),PDF出力のテスト
正常にインストールできたかチェックしてみます。
routes/web.phpRoute::get('/hello', function () { return PDF::loadHTML('<h1>Hello!</h1>')->inline(); });大丈夫そうですね。
Bladeを使ってPDFを出力する。
Snappyは、BladeにそのままHTMLを書いて出力できるので大変楽です。CSSも2くらいまでは正確に効きます。
まずRouteの部分です。
routes/web.phpRoute::get('/members', function () { $member = Faker\Factory::create('ja_JP'); return PDF::loadView('members', compact('member'))->inline(); });Fakerでランダムなデータを生成してviewに渡しています。
次にテンプレートの部分です。
resources/views/members.blade.php<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>名簿</title> <style> table { border-collapse: collapse; } tr { page-break-inside: avoid; } th, td { border: 1px solid black; } </style> </head> <body> <h1>名簿</h1> <table> <tr> <th>No.</th> <th>氏名</th> <th>住所</th> <th>電話番号</th> <th>備考</th> @for ($no = 1; $no <= 50; $no++) <tr> <td>{{ $no }}</td> <td style="white-space: nowrap">{{ $member->name }}</td> <td>{{ $member->address }}</td> <td>{{ $member->phoneNumber }}</td> <td>{{ $member->realText }}</td> </tr> @endfor </table> </body> </html>ブラウザで確認してみます。
良さそうですね。
tr要素に
page-break-inside: avoid;
を適用することによって、セルの途中で改ページされなくなります。こんな感じ。
- 投稿日:2020-03-25T10:57:21+09:00
artisanコマンドもっと便利なものを使っておくべきだった話
今までの自分
今までコントローラーを作成する際は
$ php artisan make:controller HogeControllerそれに加えて、モデルも必要だな...と思い
$ php artisan make:model Hogeモデルがあるってことはマイグレーションも必要だ
$ php artisan make:migration hoges_create_tableダミーデータも必要だからシーダも必要だから作る
$ php artisan make:seeder HogesSeeder今までこんな感じで個別で必要になった際に、毎回コマンドを実行していました
もうお気づきの方もおられるかもしれませんがとても効率悪いですね。これからの自分
すると先生から、このコマンドで一発で全部できる
これを使う方が良いと教えていただいたのです
それがこれ$ php artisan make:model Hoge --allなんとこれだけなんですよね
聞いたことはあったものの、いつも自分の使い慣れていたコマンドを使って使ったことがなかったこのコマンド
めちゃくちゃ便利でした。。このコマンドで、コントローラー、モデル、マイグレーション、シーダと
必要な物全て作ってくれますとても素敵ですね
今までの自分何してたんだと言う気持ちと
便利すぎて感動する気持ちになりましたこれからは間違いなくこれを使っていくことになると思います
弱々エンジニアの気付きと新たな発見でした
- 投稿日:2020-03-25T08:11:15+09:00
Laravelのライブラリ「laravel-dompdf」を使ってビューの表示をPDFとして表示しよう
目的
- ライブラリを使用して現在のビューとして表示しているコードをそのままPDFで表示する方法をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.3) ハードウェア MacBook Air (11-inch ,2012) プロセッサ 1.7 GHz デュアルコアIntel Core i5 メモリ 8 GB 1600 MHz DDR3 グラフィックス Intel HD Graphics 4000 1536 MB
- ソフトウェア環境
項目 情報 PHP バージョン 7.4.3 Laravel バージョン 7.0.8
- ライブラリ環境
項目 情報 備考 laravel-dompdf v0.8.6 アプリ名ディレクトリに移動後コマンド`composer show -i 実施条件
- 下記の記事に沿って環境構築を行っていること。
- ローカル開発環境でブラウザから確認可能なLaravelアプリがあること。
実施方法概要
- コントローラの確認
- アクションの記載変更
- 確認
実施方法詳細
コントローラの確認
PDFとして表示したいビューファイルが呼び出されているコントローラファイルを表示する。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; ・ ・ ・
use Illuminate\Http\Request;
の下に下記の内容を記載する。use PDF;コントローラファイルの設定部分が下記の様になっていることを確認する。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use PDF; ・ ・ ・アクションの記載変更
先に確認したコントローラファイルのビューを表示しているアクションを確認する。
return view('ビューファイルディレクトリ名.ビューファイル名');先に確認した
return
部分を下記の様に記載する。$pdf = PDF::loadView('ビューファイルディレクトリ名.ビューファイル名'); #変数などの引数を伴ってビューを呼んでいる場合 $pdf = PDF::loadView('ビューファイルディレクトリ名.ビューファイル名', compact('変数や配列などの引数')); return $pdf->stream();確認
下記コマンドを実行してローカルサーバを起動する。
$ cd アプリ名ディレクトリ $ php artisan serve修正したアクションとリンクするURLにアクセスする。
PDFで表示されればOKである。(日本語は文字化け表示されるが、現在の設定だと正常である。)
- 投稿日:2020-03-25T01:15:32+09:00
【Laravel】初学者が更なる高みを目指して学ぶべきこと
はじめに
自分のために更なるスキルアップを目指して書いてみました。
同じく簡易的なポートフォリオサイトを作れるくらいの方々の参考になれば幸いです。
※以下、私のレベル感。
https://chobimusic.com/laravel_craftbeers/
現状
・基礎的なRESTfulサービスは作れる。(index,createstore,show,edit,update,destroyまで実装)・ユーザー認証機能は実装できる。
・Eloquentの基本は理解している。
学ぶべきこと
①ミドルウェア
②リクエスト
③依存性の注入
④認可機能(ポリシー)
①ミドルウェア
未ログインユーザーが投稿などできないようにするために必要。以下はindex、show以外にアクセスしようとするとログイン画面へリダイレクトされるようにしている。
//web.php <?php Auth::routes(); Route::get('/', 'ArticleController@index')->name('articles.index'); Route::resource('/articles', 'ArticleController')->except(['index', 'show'])->middleware('auth'); Route::resource('/articles', 'ArticleController')->only(['show']);
※app/Http/MiddlewareディレクトリのAuthenticate.phpファイル記載のroute('login')の部分を編集すればリダイレクト先を変更できる。また、上記のようにルーティングにもいろいろ使えるメソッドが存在する。
・nameメソッド(別名:名前付きルート)
URLを生成したり、リダイレクトしたりできる。・onlyメソッド
resourceメソッドにそのアクションのみを指定できる。・exceptメソッド
resourceメソッドからそのアクションを除外できる。
②リクエスト
以下でリクエストは作成できる。主にフォーム周りで送信された値のバリデーションを行う。
$ php artisan make:request ArticleRequest
(コントローラーでバリデーションを行わせることもできるが、一般的にコントローラーにはあまり多くの処理を持たせないようにすることが望ましい。)・authorizeメソッド
リクエストの対象となるリソース(ここでは記事)をユーザーが更新して良いかどうかを判定する。・rulesメソッド
バリデーションのルールを定義する。・attributesメソッド
バリデーションエラーメッセージに表示される項目名をカスタマイズできる。
③依存性の注入 , DI(Dependency Injection)
コントローラーにおいて、アクションメソッドの引数で型宣言を行うと、そのクラスのインスタンスが自動で生成されてメソッド内で使えるようになる。以下のように、外で生成されたクラスのインスタンスをメソッドの引数として受け取る流れのことをDIという。
//〇〇Controller public function edit(Article $article) { return view('articles.edit', ['article' => $article]); }
最初はチュートリアルをやっていると、よくこのタイプの引数を見かけて、毎度意味が分からず頭を抱えていた。例えば、URLがarticles/1/editだとすると、idが1であるArticleモデルのインスタンスが代入される形になる。
また、ビューには'article'というキー名で、変数$articleの値(Articleモデルのインスタンス)を渡している。
④認可機能(ポリシー)
①のミドルウェアでログイン有無によるアクセスの制限はできる。しかし、ログイン後に考慮すべき投稿コンテンツの更新・削除・編集に関してはミドルウェアだけでは制限できない。
他人の投稿を編集などできないようにするのに必要になるのが認可機能の1つであるポリシー。
ポリシーの作成
$ php artisan make:policy ArticlePolicy --model=Article //--modelをつけることでモデルに対応したポリシーになる。
ポリシーのメソッドとコントローラーのアクションメソッド対応表
ポリシーのメソッド
コントローラーのアクションメソッド
viewAny
index
view
show
create
create,store
update
edit,update
destroy
destroy
ポリシーでfalse
を返す場合、対応するアクションメソッドは処理されず、ステータスコード403
のHTTPレスポンスがクライアントに返さる。
public function view(?User $user, Article $article) //?を付けることで引数がnullでも許容される。(未ログインでも可) { return true; //誰でも詳細画面は見れることにする。 } public function delete(User $user, Article $article) { return $user->id === $article->user_id; //投稿したユーザーしか削除できないようにする。 }
コントローラーに加えることでポリシーを適用。
public function construct() { $this->authorizeResource(Article::class, 'article'); }
・constructメソッド
クラスのインスタンスが生成された時に初期処理として呼び出さなくても必ず実行される。・authorizeResourceメソッド
第1引数にモデルのクラス名(App/Articleでも可)、第2引数にルーティングのパラメータ名。($ php artisan route:listで出力されるURIの{}内の部分)
知っておくと便利だなと思ったもの
Null合体演算子(??)
式1 ?? 式2
という形式で記述。式1がnull
でない場合は式1、式1がnull
である場合は、式2が結果となる。
ルーティングの確認
$ php artisan route:list
最初のころは無視してチュートリアル進めていたけれどもこれみるとミドルウェアがどのアクションメソッドに適用されているか確認できたりする。
RESTfulに関して
ほぼほぼ以下のような規則になっているので、知っているとなにかと良い。
メソッドアクション
ルート情報
引数
メソッド
index
/コントローラ
GET|HEAD
create
/コントローラ/create
GET|HEAD
store
/コントローラ
Request $request
POST
show
/コントローラ/{id}
$id
GET|HEAD
edit
/コントローラ/{id}/edit
$id
GET|HEAD
update
/コントローラ/{id}
Request $request, $id
PUT|PATCH
delete
/コントローラ/{id}
$id
DELETE
更なる高みを目指して
まずはこれらの機能をポートフォリオに実装してみます。今後はProviderやフロントエンドフレームワーク(Vue.js)との連携を目指します。
読んでいただきありがとうございました。
おしまい。