- 投稿日:2020-10-15T22:13:19+09:00
使っているLaravelを6.x→8.xへアップデートしたときのメモ
はじめに
当方のメインサイトはLaravelで作られているのですが、トップページに1行しか無い寂しいサイト。そろそろ本格的に作ろうということでしたが、結構色々ありまして…最初、laravel/uiをインストールしようとしたら、laravelのバージョンが古すぎて入れないというのがきっかけで、バージョンアップしようということにしました。
背景
当方のサイトは、開発環境としてローカルマシン上でDockerを使って構築、本番環境にGithub(プライベートリポジトリ)を介して適応しています。
取り急ぎバージョンアップ
取り急ぎ着手しなければとなったのはLaravelのバージョン。
調べてみると、6.17という結構古いものでした。root@78e089450650:/var/www# php artisan --version Laravel Framework 6.17.1Composerのアップデート
しかも、Composereを使ってみると「バージョンが古すぎる!」というメッセージが出ていました。
root@***:~# curl -sS https://getcomposer.org/installer | php All settings correct for using Composer Downloading... Composer (version 1.10.15) successfully installed to: /root/composer.phar Use it: php composer.phar root@***:~# mv composer.phar /usr/local/bin/composer root@***:~# composer --version Composer version 1.10.15 2020-10-13 15:59:09これで、Composerのアップデートが出来ました。
6.x -> 7.x へのバージョンアップ
基本的に、Qiitaの記事で書かれている内容で対応できました(サイトの中身がほとんど無いので変更点は少なかった模様)。
この記事を基にファイルを編集、
composer update
かけることで7.xにアップデートできます。root@***:/var/www# composer update Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 12 installs, 58 updates, 3 removals - Removing symfony/debug (v4.4.4) - Removing jakub-onderka/php-console-highlighter (v0.4) - Removing jakub-onderka/php-console-color (v0.2) : Discovered Package: nesbot/carbon Discovered Package: nunomaduro/collision Package manifest generated successfully. 49 packages you are using are looking for funding. Use the `composer fund` command to find out more! root@***:/var/www# php artisan --version Laravel Framework 7.28.4念の為、
npm install
->npm run dev
しておいたほうがいいと思います。7.x -> 8.x へのバージョンアップ
基本的に、以下のサイトで書かれている内容で対応できました(サイトの中身がほとんどなかったため、
composer.json
の依存性のみを設定すればOKでした)root@***:/var/www# composer update Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 6 installs, 23 updates, 1 removal - Removing phpunit/php-token-stream (3.1.1) - Installing graham-campbell/result-type (v1.0.1): Downloading (100%) - Updating vlucas/phpdotenv (v4.1.8 => v5.2.0): Downloading (100%) : Discovered Package: nesbot/carbon Discovered Package: nunomaduro/collision Package manifest generated successfully. 71 packages you are using are looking for funding. Use the `composer fund` command to find out more! root@***:/var/www# php artisan --version Laravel Framework 8.10.0バージョンアップのコツ
対応を端折らずに、1バージョンずつ上げることをお勧めします(6.x -> 7.x -> 8.x)。
最後に
開発環境で動作を確認したら、Githubにソースをpush、本番環境でpullして
composer update
->npm install
->npm run production
すれば、両方の環境でバージョンを揃えられると思います。
- 投稿日:2020-10-15T21:28:02+09:00
Laravel7タグ付き投稿記事の検索機能(リレーション)
やりたいこと
タグを付けて口コミを投稿することができるサイトを作っています。その投稿のタイトルや本文、タグを対象に検索する機能を実装します。検索自体は難しくないかもしれませんが、複数テーブルにまたがるデータを全て検索する必要があるので、ほんの少し厄介でした。でも想像していたより簡単にできました。
前提
データベースは下記の通り、多対多、お互いbelongsToManyのリレーションになっています。
reviews:投稿
tags:タグ
review_tag:中間テーブルちなみに
uses:reviewsテーブルと一対多の関係になっている。環境:Laravel 7
実装!
ビュー1(検索画面)
今回のアプリはヘッダーのコンポーネントに検索を作りました。iタグはFontawesomeの検索虫眼鏡です。
header.blade.php<form action="{{ url('/search')}}" method="get"> <i class="fas fa-search"></i> <input id="header-search-text" type="search" name="keyword" placeholder="キーワードで検索"> </form>ボタンは付けませんでしたが、ユーザーがEnterを叩くと送信されます。
URLはmethod属性をget
にすることで、?
をセパレータとして、action属性のURLに続けて生成してくれます。参考→https://developer.mozilla.org/ja/docs/Web/HTML/Element/formビュー2(検索結果表示)
かなり簡素化してますがコーディング例を下に書いておきます。
親レイアウトとして、views/layouts/myapp.blade.phpを用意しています。
head内、titleタグに@yield('title')
というディレクティブを仕込んでいます。
Bladeレイアウトはこちらで→Laravel7継承レイアウトの基本を図解してみたsearch.blade.php@extends('layouts.myapp') @section('title') 「{{$keyword}}」の検索結果 @endsection @section('main') <h1 class="main-title">「{{$keyword}}」の検索結果</h1> @foreach ($reviews as $review) <h2>{{$review->live_date}} {{$review->title}}</h2> @foreach ($review->tags as $tag) <a>{{$tag->tag_name}}</a> @endforeach <p>{{$review->text}}</p> <span>by {{$review->user->account_name}}さん</span> <span>{{$review->created_at}}</span> @endforeach {{ $reviews->links('vendor.pagination.bootstrap-4')}} @endsectionルート
web.phpRoute::get('search', 'SearchController@search')->name('search');コントローラ
SearchController<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; use App\Review; use App\Tag; use App\User; class SearchController extends Controller { public function search(Request $request) { $keyword = $request->input('keyword'); if (!empty($keyword)) { $reviews = Review::where('title', 'like', '%' . $keyword . '%') ->orWhere('text', 'like', '%' . $keyword . '%') ->orWhereHas('tags', function ($query) use ($keyword){ $query->where('tag_name', 'like', '%' . $keyword . '%'); }) ->paginate(10); } else { return redirect('/'); } return view('reviews.search', [ 'keyword' => $keyword, 'reviews' => $reviews ]); } }個人的にポイントは下記です。
- まずwhereメソッドでreviewテーブルのtitleフィールドで検索かける
- orWhereメソッドでtextにも検索かける
- orWhereHasでreviewテーブルにとって多対多の関係にあるtagsテーブルにアクセスし検索をかける
- where、orWhere、orWhereHasの第2パラメータにlike検索の条件設定をする
- %記号で前後に検索キーワードの前後に何があってもOKなので、その検索キーワードが引っかかるようになります
- %を''で囲うのはwhereがパラメータ結合に対応していないため
おしまい
もしご指摘やご質問、うまくいかなかったなどしたら、お気軽にコメントください!
- 投稿日:2020-10-15T21:10:54+09:00
Laravel php アウトプット
__constructメソッド,authorizeResourceメソッド
__constructメソッド
PHPのクラスでは、__constructメソッドを定義すると、クラスのインスタンスが生成された時に初期処理として特に呼び出さなくても必ず実行されます。
authorizeResourceメソッド
authorizeResourceメソッドの第一引数には、モデルのクラス名を渡します。
(なお、第一引数に渡したArticle::classは'App/Article'という文字列を返すので、第一引数には直接'App/Article'を渡しても構いません)
第二引数には、そのモデルのIDがセットされる、ルーティングのパラメータ名を渡します。
- 投稿日:2020-10-15T19:27:17+09:00
[Laravel] 残りのキューの数を調べる
Laravelでその時のキューの数を調べるには次のようにする。
Queue::connection('キュー名')->size();数の内訳について、バックエンドにRedisを使っている場合はこちらにある通り、通常のキューに加え:delayedと:reservedが付くキューも含まれる(下記参照)。
/** * Get the size of the queue. * * @param string|null $queue * @return int */ public function size($queue = null) { $queue = $this->getQueue($queue); return $this->getConnection()->eval( LuaScripts::size(), 3, $queue, $queue.':delayed', $queue.':reserved' ); }framework/RedisQueue.php at 8.x · laravel/framework
:delayedと:reservedとは、mpywさんのQiitaにあるようにそれぞれ遅延ジョブとリトライジョブ用のキューである。
queues:キュー名:delayed は発火時刻をスコア,値をジョブペイロードとする ZSET(ソート済みセット型)であり,以下のような処理が行われている。
queues:キュー名:reserved に関しても同様で,こちらは遅延ジョブではなくリトライジョブが対象になる。発火時刻を算出するパラメータとして queue.connections.redis.retry_after で設定した秒数が用いられる。
【Laravel】 Redis Queue Worker のソースコードリーディング - Qiita
ちなみに
queues:キュー名
はリスト型となっているが、queues:キュー名:delayed
はソート済みセット型となっている。中身を見たり数をカウントするRedisのコマンドは次の通り。
- 数のカウント
llen queues:キュー名
zcard queues:キュー名:delayed
- 中身を見る
lrange queues:キュー名 0 -1
zrange queues:キュー名:delayed 0 -1
- 投稿日:2020-10-15T18:53:49+09:00
Cannot end a section without first starting one.エラー
【概要】
1.結論
2.Cannot end a section without first starting one.とは何か
3.どのように解決するのか
4.開発環境
1.結論
{{-- --}} でコメントアウトする。
2.Cannot end a section without first starting one.とは何か
Google翻訳すると、"最初にセクションを開始せずにセクションを終了することはできません"という意味になります。
3.どのように解決するのか
resorces/views/hoge/index.blade.php@section('content') #---❶ @foreach($data as $item) <tr> <th>{{$item['name']}}</th> <td>{{$item['mail']}}</td> </tr> @endforeach </table> @endsection #---❶ <!--{{-- <p>必要な時だけ記述できます</p> #---❷(1) @include('components.message' , ['msg_title'=>'OK']) @slot('msg_title') タイトル @endslot @endsection --}}--> #---❷(2)
❶で@section @endsectionをコーディングしていました。そして❷の部分は"command + /"でコメントアウトしていました。しかし、Vscode上のblade.phpでは<!-- -->緑色でコメントアウトになるものの❷(2)がコメントアウト されてないためか、"Cannot end a section without first starting one."というエラーが起きてしまいます。@endsectionが適用されてないことになってしまいました。{!-- --}}だけ囲っても色がついたコメントアウトにならないので<-- {-- --} -->というコーディングにしました。
4.開発環境
Mac catalina 10.15.4
Vscode
PHP 7.4.10
Laravel 8.9.0
Apache 2.4.41
- 投稿日:2020-10-15T18:36:37+09:00
Laravelの設定とファイルについて
Laravelプロジェクトを作成。
#laravelのバージョンは今回5.7でインストール。 $ composer create-project laravel/laravel=6.0 laravel_project※バージョンを設定してインストールしないと最新版が自動的にインストールされます。
今回はエディタはvsCodeを使用。
タイムゾーンと言語設定
#configのapp.phpの上から70行目を以下に変更する事で日本の時間に設定できる。 'timezone' => 'UTC', ↓ 'timezone' => 'Asia/Tokyo', #configのapp.phpの上から83行目を以下に変更する事で日本語に設定変更できる。 'locale' => 'en', ↓ 'locale' => 'ja',DBの文字コード変更
#configのdatabase.phpの文字コードを変更。 'charset' => 'utf8mb4', ↓ 'charset' => 'utf8',デバックバーのインストール
$ composer require barryvdh/laravel-debugbar以下のようにデバックバーが表示される。Viewsで表示されているファイルの情報、Queriesでデータベースとのやりとりなどが確認できる。
もしデバックバーを非表示にしたい場合は、envファイルを以下のように設定
#envファイルの上から4行めをfalseにする事で非表示にできる。 APP_DEBUG=falseそれでも画面に残っている場合は、以下を実行する。
php artisan cache:clear php artisan config:clear php artisan route:clear php artisan view:clearデータベース設定
.envファイルの以下の部分になる。
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=データベースの名前 DB_USERNAME=root DB_PASSWORD=データベース接続確認
今回はSequel Proを使用。Sequel Proにデータベース名を追加。
#以下のコマンドを実行 $ php artisan migrate #テーブルが作成されます。ルートについて
#routesのweb.phpファイル Route::get('/', function () { return view('welcome); }); //アクセスするとwelcome.blade.phpを表示する。 #resourcesのviewsフォルダの中にビューファイルを保存していく。Laravel Artisanコマンド(Laravel 専用のコマンド)
#artisanが持っているコマンドの一覧を表示できる。 $ php artisan list #サーバの機能を立ち上げる $ php artisan serveモデルについて
DBとのやりとりをPHPで書く事ができる。
モデルファイルの作り方
モデルの場合は単数形(例:Test)
#例1 appフォルダにTest.phpファイルができる。 $ php artisan make:model Test #例2 appフォルダにModelsフォルダができて、Test.phpファイルが中に入る $ php artisan make:model Models/Test #例3 マイグレーションファイルとコントローラーファイルをまとめて作る場合マイグレーションについて
DBのテーブルの履歴を管理する仕組み。
マイグレーションの場合は複数形で作る(例:Tests)#以下のようなコマンドでマイグレーションファイルを作成できる。databaseフォルダの中のmigrationsフォルダの中に作成される。 $ php artisan make:migration create_tests_table #マイグレーションファイルを実行 $ php artisan migratetinker(DB簡易接続)
tinkerとはRailsで言うrails cのようなものでデータを簡単に追加したりできる。
例: $ php artisan tinker >>> $test=new App\Modesl\Test; => App\Models\Test{#3034} >>> $test->text="aaa"; => "aaa" >>> $test->save(); => true //Testに入っている全てのデータを確認できる。データベースでも確認できる。 >>> App\Models|Test::all()コントローラーについて
#以下のコマンドでコントローラーを作成できる。 $ php artisan make:controller TestControllerファイルの場所はappフォルダのHttpフォルダの中にControllersと言うフォルダがあり、その中に作成される。
web.phpに記載する場合
<?php /* |-------------------------------------------------------------------------- | 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'); // }); /*tests/testにアクセスしたらTestControllerに飛ばしてねと言うことになる。*/ Route::get('tests/test','TestController@index');TestController.phpに記載する場合
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class TestController extends Controller { public function index(){ return view('tests.test'); } }resources/views/tests/test.blade.phpに記載
//これでアクセスするとtestと表示される。 testDBから値を持ってきて中身を表示させる方法
TestController.phpを編集
<?php namespace App\Http\Controllers; //リクエスト処理に関して依存性の注入(DI)を利用 use Illuminate\Http\Request; //モデルのデータを持ってくるために記載 use App\Models\Test; class TestController extends Controller { public function index(){ //一旦変数に渡す $values=Test::all(); //ddは処理を止めて変数の中身を表示できる。 //dd($values); //valuesと言う変数をビューファイルに持っていくためにcompact関数を使用。 return view('tests.test',compact('values')); } }test.blade.phpに記載
test //コレクション型を表示させるためには@foreach(配列の要素がある分だけ繰り返し処理する)を使う.DBに入っている一覧が表示できる。 @foreach($values as $value) {{$value->id}}<br> {{$value->text}}<br> @endforeachヘルパ関数とは
Laravelが用意してくれている便利な関数のことである。
例:route、auth(認証)、app、bcrypt(パスワードの暗号化)、collect、dd(処理を止めて変数の中身を表示)、env、factory、old、viewなど
以下参照
https://readouble.com/laravel/5.5/ja/helpers.htmlコレクション型とは
配列を拡張した型(Laravel独自の型)。データベースからデータを取得したときはコレクション型になっている。
//ddでcollectionをみれる。
dd($values);今回は試しにchunkで実行する。
<?php namespace App\Http\Controllers; //リクエスト処理に関して依存性の注入(DI)を利用 use Illuminate\Http\Request; //モデルのデータを持ってくるために記載 use App\Models\Test; class TestController extends Controller { public function index(){ //一旦変数に渡す $values=Test::all(); //collectと言うヘルパ関数を作る。 $collection = collect([1, 2, 3, 4, 5, 6, 7]); //chunkでグループ分けをする $chunks = $collection->chunk(4); //配列に変えている。 $chunks->toArray(); //ddは処理を止めて変数の中身を表示できる。 //dd($chunks); //valuesと言う変数をビューファイルに持っていくためにcompact関数を使用。 return view('tests.test',compact('values')); } }クエリビルダとは
SQL文で書く所をPHPの構文で記載したもの。
SQLインジェクションから守るために常にセキュアな状態になっている。※ただデータを取得するだけならコレクションでも良いが、条件が細かくなってくるとクエリビルダの方がよりSQLに近い形で書ける。
クエリを書くにはDBファサードのtableを使う。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; //名前空間でDBファサードがインポートできたことになる。 use Illuminate\Support\Facades\DB; use App\Models\Test; class TestController extends Controller { public function index(){ $values=Test::all(); //データを取得(以下のようにselectで指定するとIDのみを取得する) $tests = DB::table('tests') ->select('id') ->get(); dd($tests); return view('tests.test',compact('values')); } }※注意
#以下のようなrawを使用した文だとSQLインジェクションの脆弱性に注意する必要がある。ユーザーから入力があるものは特に注意。 $users = DB::table('users') ->select(DB::raw('count(*) as user_count, status')) ->where('status', '<>', 1) ->groupBy('status') ->get();ファサード
アクセスする箇所を1つにしてそこにアクセスしたら中に色んなシステムがあるが、使う側としてはその入口だけ知っていればOKと言うような形の作り方。
Authやbladeなどがある。
https://readouble.com/laravel/6.x/ja/facades.htmlファサードの設定はconfigフォルダのapp.phpファイル内に記載ある。
191行目に定義されているものがファサードとして使えるものになる。
'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Arr' => Illuminate\Support\Arr::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'Str' => Illuminate\Support\Str::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, ], 定義する場合は、以下のように記載。 #TestController.php #以下の部分はvenderフォルダの中にlaravelと言うフォルダが入っていてframeworkがあってIlluminateがある。後は順番に見ていく。 use Illuminate\Support\Facades\DB;Laravel起動処理DIとサービスコンテナ
以下参考記事になります。
https://qiita.com/namizatork/items/801da1d03dc322fad70cbladeとは
Laravelで組み込まれているテンプレートエンジンのこと。
bladeビューにはファイル名に.blade.phpをつける。例:welcome.blade.phpの場合
#@ifと@endifやログイン機能用の@authと@endauthなど <body> <div class="flex-center position-ref full-height"> @if (Route::has('login')) <div class="top-right links"> @auth //以下のような{{}}は文はXSS攻撃を防ぐために、PHPのhtmlspecialchars関数を自動的に通されます <a href="{{ url('/home') }}">Home</a> @else <a href="{{ route('login') }}">Login</a> @if (Route::has('register')) <a href="{{ route('register') }}">Register</a> @endif @endauth </div> @endifフロントエンドに向けて
※設定が必要だがインストールした際に以下のものはファイルが既に存在するものもある。
laravel-ui ...Laravel6.xから
laravel-mix...webpackのラッパー
webpack.mix.js...laravel-mixの設定ファイル
Node.js/npm...別途インストール
package.json/package.lock 設定ファイル#webpack.mix.js //laravel-mixの記載あり const mix = require('laravel-mix'); /* |-------------------------------------------------------------------------- | Mix Asset Management |-------------------------------------------------------------------------- | | Mix provides a clean, fluent API for defining some Webpack build steps | for your Laravel application. By default, we are compiling the Sass | file for the application as well as bundling up all the JS files. | */ //'resources/js/app.js'は元のファイルでそれを'public/js'に1個にまとめて入れている。'resources/sass/app.scss'は元のファイルでそれを'public/css'にに1個にまとめて入れている mix.js('resources/js/app.js', 'public/js') .sass('resources/sass/app.scss', 'public/css');Laravel-uiと認証
Laravel6からフロント側が分離された。uiはユーザーインタフェース。
LaravelはJavaScriptやCSSプリプロセッサの使用を規定してはいませんが、開発時点の元としてほとんどのアプリケーションで役立つだろうBootstrapやReact、Vueを提供しています。これらのフロントエンドパッケージをインストールするため、LaravelはNPMを使用しています。
Laravelが提供するBootstrapとVueのスカフォールドは、Composerを使いインストールするlaravel/uiパッケージに用意してあります。
//laravel6の場合 $ composer require laravel/ui:^1.0 --dev $ composer require laravel/ui "^1.2" //laravel7の場合 $ composer require laravel/ui:^2.4 --devlaravel/uiパッケージをインストールできたら、ui Artisanコマンドを使いフロントエンドのスカフォールドをインストールします。
// 基本的なスカフォールドを生成 php artisan ui bootstrap php artisan ui vue php artisan ui react// ログイン/ユーザー登録スカフォールドを生成 php artisan ui bootstrap --auth php artisan ui vue --auth php artisan ui react --authvue.js+bootstrapの場合$ composer require laravel/ui $ php artisan ui vue --auth $ npm install bootstrap-vue bootstrap import BootstrapVue from 'bootstrap-vue'; Vue.use(BootstrapVue);$ npm install && npm run dev //補足 $ npm run dev ・・開発用にビルド $ npm run watch ・・常時ビルド $ npm run prod ・・本番用にビルド新規登録後の移行先を変更
RegisterControll.php#before homeを消す protected $redirectTo = '/home'; #after protected $redirectTo = '/';ログイン後の移行先を変更
//laravel6の場合 loginControll.phpファイル #before homeを消す protected $redirectTo = '/home'; #after protected $redirectTo = '/'; //larvel6.8以降の場合 Providers/RouteServiceProvider.phpファイルエラーメッセージの日本語化
resources/lang/elの中のファイルにエラーメッセージの記載あり。
https://github.com/minoryorg/laravel-resources-lang-ja
解凍してjaフォルダをコピーして既存のフォルダに格納する。日本語か英語かの設定はconfigのapp.phpに記載がある。 83行目の 'locale' => 'ja',