20211015のlaravelに関する記事は6件です。

PHP,Laravelでメモアプリを作った際の忘却録

Dockerのインストールとdockerコマンドの使用 私が使用しているMacにdockerをインストールしてdockerコマンドを使えるようにするらしい この前のrailsを使ったLINE-botもそうだが 何かの外部からのコマンドを使えるようにするには 外部からインストールするというのが方法のようだ Dockerとは Dockerとは現在使用しているパソコンにnginx(最も高い稼働率を誇るサイトのうち約65%以上で広範囲に支持されている高信頼のWebサーバシステム)やMySQL(オープンソースのリレーショナルデータベース管理システム)などの開発に必要とされるソフトウェアを簡単にインストールして動かせる技術のこと。 確認 そんなDockerをインストールして実際にターミナルでコマンド入力できるか確認 すると > docker-compose -v unknown shorthand flag: 'v' in -v とでた docker-compose --version Docker Compose version v2.0.0-rc.3 このようにコマンド入力したらバージョンが出た。 よかった。 PHPの環境構築の際のエラー さて、今回はPHPを使用するのだが Git Hubから環境構築用のファイルを取得し、 docker-composeコマンドを使って環境の立ち上げを行なった docker-compose -f .docker_memo/docker-compose.yml up -d このコマンドを使用することで環境構築を自動で行なってくれるらしい Recreating php_simple_memo_mysql ... done Recreating php_simple_memo_phpmyadmin ... done Creating php_simple_memo_php ... done Creating php_simple_memo_nginx ... done 無事完了した これで、mysql, phpmyadmin, php, nginxが起動している状態になった。 また docker ps こちらのコマンドで起動状況の確認ができた 実行されているアプリケーションの環境の停止と起動 停止 docker-compose -f .docker_memo/docker-compose.yml down 起動 docker-compose -f .docker_memo/docker-compose.yml up -d Laravel createメソッド→モデルに$fillableまたは$guarded変数を作成して、設定をしないといけません。 $guarded→更新できないカラムを列挙した一覧を設定 $fillable→更新できるカラムを列挙した一覧を設定 dockerコンテナに入ってlaravelのマイグレーションを行なった際に発生したエラー dockerコンテナに入って php artisan migrate を実行したところ Nothing to migrate というエラーが発生した どうやらmigrateするものはないとのこと php artisan migrate:fresh で実行したところ Dropped all tables successfully. Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (78.65ms) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (51.53ms) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (61.13ms) Migrating: 2021_10_09_122745_create_memos_table Migrated: 2021_10_09_122745_create_memos_table (30.86ms) となって成功した。 この:freshを行うことで全てのテーブルをドロップしてから再びマイグレーションできるらしい PHPとLaravelのファイルやディレクトリの作成の違い PHP→mkdirやcd,vimを使用してファイルやディレクトリの作成を行う Laravel→dockreコンテナに入ってコマンドを実行して作成
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】RefreshDatabaseでデータがロールバックされない問題を解決する

問題 LaravelでMySQLのDBテストを書いていたら、RefreshDatabaseでロールバックされないデータが発生した。 原因 テストで使っていたシーダー内でtruncate()を実行していたため。 解決方法 truncate()を使用しない。 状況の再現 たとえばhogeシーダーでは、truncate()で最初にテーブルデータの全件削除を行って、つぎにデータを投入している。 HogeTableSeeder.php <?php use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class HogeSeeder extends Seeder { public function run() { DB::table('hoge')->truncate(); DB::table('hoge')->insert(['name'=>'事前投入ほげほげ']); } } 下記のようなDBテストで、RefreshSeederの実行&シーダーでのデータの流し込みをしているとする。 HogeTest.php <?php namespace Tests\Unit; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Tests\TestCase; use App\Hoge; class HogeTest extends TestCase { use RefreshDatabase; // テストごとにデータをリフレッシュする public function setUp(): void { parent::setUp(); $this->seed(); // テスト開始時にシーダを実行する } public function testHoge1() { // hogeテーブルにデータを追加する $hoge = new Hoge(); $hoge->name = "テストほげほげ"; $hoge->save(); // このテスト内ではデータは存在するはず $this->assertDatabaseHas('hoge', ['name' => "テストほげほげ"]); } public function testHoge2() { // 別のテストではtestHoge1()で追加したデータは存在しないことを期待している $this->assertDatabaseMissing('hoge', ['name' => "テストほげほげ"]); } } シーダーで流し込んだデータは全てのテストで共通して存在しており、各テストで追加したデータはそのテスト内のみで完結するように期待している。 しかしこのテストを実行すると、1つめのテストで追加したデータが残ったままで、2つめのテストは失敗する。 また、テスト終了後のテーブルの中身はシーディングデータ含めすべて残っている(ロールバックされていない)。 id name 1 事前投入ほげほげ 2 テストほげほげ 3 事前投入ほげほげ RefreshDatabaseとtruncate()を同時につかってはいけない DB::table()->truncate()はテーブルの全件削除のメソッドで、sqlのtruncateを実行する。 db:seed時に前回のシーディングデータを削除したいがために使用されていたようだった。 一方、RefreshDatabaseはmirate:refreshを実行し、トランザクションを貼って最後にロールバックするメソッドである。 これら2つが併用されるとどうなるかというと、下記の様になる。 --テスト開始-- 1. migrate:refresh実行 2. トランザクッション開始 3. シーダー実行 4. truncateの実行(暗黙的なコミットがはしる) 5. テストメソッドの処理 6. tearDown()が呼ばれる 7. ロールバックができない --テスト終了-- sqlで書くとこんなかんじ。 BEGIN; TRUNCATE `test`.`hoge`; INSERT INTO `test`.`hoge` (`id`, `name`) VALUES ('1', '事前投入ほげほげ'); INSERT INTO `test`.`hoge` (`id`, `name`) VALUES ('2', 'テストほげほげ'); ROLLBACK; 実行するとわかるが、トランザクション内でtruncateを実行するとcommitが走るので、その後のinsertで追加したデータは残ったままである。 解決方法 truncateを使用しない migrate:fresh --seedすればいいだけなので、そもそもシーダーでtruncate()を呼ぶのはナンセンスである。 これだけのことを探すのにすごい時間がかかった。 参考:https://dev.mysql.com/doc/refman/8.0/ja/implicit-commit.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel unit テストでcommand 実行時の出力ログをテストする方法

commandのUnitテストは、普通に実行するとログ出力の処理でエラーになってしまいます。 CommandTester を使うとテストできました! SampleTest.php <?php namespace Tests\Unit\Commands; use Mockery; use Illuminate\Foundation\Testing\TestCase; use Illuminate\Contracts\Console\Kernel; use Illuminate\Foundation\Application; use Symfony\Component\Console\Tester\CommandTester; use App\Console\Commands\SampleCommand; class SampleTest extends TestCase { /** * @test * * @return void */ public function 正常系_既読率をログ出力する() { /** * expected */ $message = "testtest"; /** * mock */ /** @var \Mockery\MockInterface|Hoge */ $mockHoge = Mockery::mock(Hoge::class); $mockHoge->shouldReceive('isHoge')->andReturn(true); /** * test */ $command = new SampleCommand($mockHoge); $command->setLaravel($this->app); $commandTester = new CommandTester($command); $commandTester->execute([]); $output = $commandTester->getDisplay(); $this->assertSame($message, $output, 'メッセージ'); } /** * @return Application */ public function createApplication(): Application { $app = require __DIR__ . '/../../../../bootstrap/app.php'; $app->make(Kernel::class)->bootstrap(); return $app; } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】テーブルのidをUUID(ランダム)に変更しようとしてやめた時のメモ

状況 Laravel:6.2 DB:MySQL 会員制SNS風サイトの個人開発。 当初はuserテーブルとarticleテーブルの主キーを連番のidにしていたが ユーザーや記事の個別ページのURLにidを使いたくなったため 主キーをUUIDに変更しようと思った。 以下、かなり個人的な事情や判断が含まれるため参考になるか不明ですが 自分用のメモも兼ねて書かせて頂いています。 やってみたこと ■カラム型を変更しようとした まず、テーブルに入ってるデータ消したくなかったので、 ロールバックはせずにカラム型変更用のマイグレーションファイルを作成して対応しようと思った。 カラム型を変更するには doctrine/dbalというライブラリのインストールが必要らしい。 Laravel 6.* ではdoctrine/dbalの対応バージョンが3.* ではなく2.* らしいので バージョン指定してインストールする それとUUIDを使うのにもパッケージをインストールしなければならないので下記コマンド実行 composer require goldspecdigital/laravel-eloquent-uuid:^6.2 (バージョンはlalavelのバージョンに合わせて適宜変更する) 各インストールが終わったのでマイグレーションファイル作成して $table->uuid('id')->primary()->change(); などとしてマイグレーションを実行するもエラー。 調べてみると、UUIDはchangeには対応してない様子。 カラム型変更はあきらめる。 ■テーブルを作り直そうとした 上記の通りカラム型変更では対応できなかったので テーブルのデータを消して改めてmigrateしようと思った。 ロールバック後にマイグレーションファイルのuserテーブルとarticleテーブルを $table->bigIncrements('id'); から $table->uuid('id')->primary(); に変更してmigrateしてみた。しかしエラーが出た。 原因として、今回uuidにしようとしたuserのidは userテーブルのidは、articleテーブルのほうで $table->bigInteger('user_id')->unsigned(); $table->foreign('user_id')->references('id')->on('users'); といった感じで関連付けされてるので、articleテーブルのuser_idカラムを userテーブルのidと同じ形式(つまりUUID)にしなければいけないらしい。 ここで今更ながら、「本当にUUIDを使わなければならないのか?」と疑問に思う。 UUIDの使用をやめた理由 改めて考えてみた結果、 uuidは長すぎる 5e4e81de-45ae-468b-b33c-4c6109ded561(こんな感じになる) ので、urlに使うには不格好なのではないかと感じ始める。 また、 「ちなみにUUIDをプライマリキーにする人もいますが、 外部キーとして使用することもある場合は、別にUUID用のカラムを作った方が良きです。 リレーれション先でも128ビットの数値をデータとして持っておくのは非効率ですからね。」 という意見も目にし、主キーにUUIDを使用するのはやめることにする。 参考にさせて頂いた記事 https://qiita.com/howaito01/items/b529af6f4d3112b91818) 最終的な対応 主キーとは別にurl表示用のランダム値(に見える)のカラムを作ることにした。 そもそも 連番にしたくなかった理由は 「urlに数字を入力すれば会員数や投稿数が簡単にわかってしまうから」 だったので 「idに9999をかけて16進数に変換した値」等でも充分だと思った。 一見では規則性はわからないし、idを元にしているので重複することもないため。 処理としては、 userなりarticleなりの新しいレコードを登録してからでないと、そのレコードのIDがわからないので 下記のような感じで、一度saveしてからdisplay_id(url表示用のランダム風id)を設定し、もう一度save。 $article->title = $request->title; $article->user_id = $request->user()->id; article->save(); $article->display_id = "a-".dechex($article->id * 9999); $article->save(); //dechexは10進数を16進数に変換する関数
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP8でJITの設定方法

はじめに PHP8からJITというプログラムを高速に実行させる機能が導入されたようです。 その導入方法を残して起きます。 方法 php.iniファイルに以下を追記 php.ini zend_extension = opcache opcache.enable = 1 opcache.enable_cli = 1 opcache.jit = tracing opcache.jit_buffer_size = 128M ターミナルでphp -i | grepを実行し以下のようになっていたらOK opcache.jit => tracing => tracing opcache.jit_bisect_limit => 0 => 0 opcache.jit_blacklist_root_trace => 16 => 16 opcache.jit_blacklist_side_trace => 8 => 8 opcache.jit_buffer_size => 128M => 128M opcache.jit_debug => 0 => 0 opcache.jit_hot_func => 127 => 127 opcache.jit_hot_loop => 64 => 64 opcache.jit_hot_return => 8 => 8 opcache.jit_hot_side_exit => 8 => 8 opcache.jit_max_exit_counters => 8192 => 8192 opcache.jit_max_loop_unrolls => 8 => 8 opcache.jit_max_polymorphic_calls => 2 => 2 opcache.jit_max_recursive_calls => 2 => 2 opcache.jit_max_recursive_returns => 2 => 2 opcache.jit_max_root_traces => 1024 => 1024 opcache.jit_max_side_traces => 128 => 128 opcache.jit_prof_threshold => 0.005 => 0.005 DBのIOがあまり関係ないけど処理が遅い部分で試してみてください。 その速さに驚愕することでしょう(それほど速くならないこともありますが)。 もしDocker環境などでphp.iniをマウントしているようであれば一度docker downしてからお試しください ちなみに、Xdebugは使えなくなるとどこかの記事に書いてあった気がします。。 最後に ここまで来たかPHP...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelのアプリケーションの理解①

本記事ではLaravelのアプリケーションを理解し、より良い設計・アーキテクチャを構築できるように学習したことを簡潔にまとめています。 目次 1.Laravelのアーキテクチャ 2.アプリケーションのアーキテクチャ 3.HTTPリクエストとレスポンス 4.データベース 5.認証と許可 6.イベントとキューによる処理の分離 7.コンソールアプリケーション 8.テスト 9.エラーハンドリングとログの活用 10.テスト駆動開発の実践 1.Laravelのアーキテクチャ 1-1.ライフサイクル laravelアプリケーションのHTTPリクエストからHTTPレスポンス返却までの流れを以下に示す。 HTTPリクエスト →①エントリーポイント(public/index.php) →②HTTPカーネル(app/Http/Kernel.php) →③ルータ(Illuminate\Routing\Router\routers/web.php) →④各ミドルウェア→⑤5コントローラ、クロージャ →⑥各ミドルウェア→⑦ルータ→⑧HTTPカーネル→⑨エントリーポイント →HTTPレスポンス ①エントリーポイント pulic/index.phpが該当し、アプリケーションの起点となる。 //①オートローダの読み込み define('LARAVEL_START', microtime(true)); require __DIR__.'/../vendor/autoload.php'; //②フレームワークの起動 $app = require_once __DIR__.'/../bootstrap/app.php'; //③アプリケーション実行およびHTTPレスポンスの送信 $kernel = $app->make(Kernel::class); $response = tap($kernel->handle( $request = Request::capture() ))->send(); //④ 終了処理 $kernel->terminate($request, $response); <コード解説> ①オートローダの読み込み。これによりフレームワーク内のクラスをrequireしなくても利用できる ②bootstrap/app.phpにフレームワークをセットするコードが含まれており、実行結果として、Illuminate\Foundation\Application(サービスコンテナの中核)のインスタンスを返す。 ③生成されたサービスコンテナを利用し、HTTPカーネルを生成してhandle()を実行してアプリケーションを実行している。Illuminate\Http\Request::capture()でHTTPリクエストからRequestを生成している。 ②HTTPカーネル App\Http\Kernelクラスはミドルウェア設定を、Illuminate\Foundation\Http\Kernelクラスにはアプリケーションのセットアップの処理が記載。 // HTTPカーネルのhandleメソッド(Illuminate\Foundation\Http\Kernel) public function handle($request) { try { $request->enableHttpMethodParameterOverride(); //①ルータの実行 $response = $this->sendRequestThroughRouter($request); } catch (Throwable $e) { $this->reportException($e); $response = $this->renderException($request, $e); } //②イベント発火 $this->app['event']->dispatch( new Events\RequestHandled($request, $response) ); return $response; } <コード解説> ①sendRequestThrouchRouterの引数でRequestを受け取り、ルータにRequestを渡して実行する。 ②Events\RequestHandledイベントが発火されるため、これに対するリスナーを設定すればこの時点で呼び出される。 (dispatchはジョブをキューに登録するメソッド) ③ルータ 定義されたルートの中からRequestにマッチするルートを探して、ルートに定義されたコントローラやアクション、クロージャを実行する。 ④ミドルウェア ミドルウェアでは、ルートで指定された処理の前後に任意の処理を実行できる。 具体的には、RequestやResponseに含まれる値の変更や暗号化(復号)やセッション実行、認証処理など。 下記にCookieの暗号化や複合を行うIlluminate\Coocke\Middleware\EncryptCookieクラスのhandleメソッドを示す。 <?php namespace Illuminate\Cookie\Middleware; class EncryptCookies { public function handle($request, Closure $next) { //①descryptメソッドで暗号化されたCookieを復号してRequestを取得 //②次のミドルウェアを実行して、Responseを取得 //③encryptメソッドでResponseを暗号化して返す return $this->encrypt($next($this->decrypt($request))); } } <コード解説> 引数のClosure $nextには次に実行するミドルウェアが、なければコントローラが入る。 ⑤コントローラ HTTPリクエストに対応する処理を実行する。処理が完了すれば、Responseを生成して戻り値として返す。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む