- 投稿日:2021-03-06T20:32:26+09:00
[Laravel] CircleCIにphp-gdをインストールする
概要
CircleCIでテストを自動化している際に画像関連のテストで以下のエラーで引っかかってしまいました。
Error: Call to undefined function imagecreatetruecolor() /home/circleci/ci-demo/backend/vendor/laravel/framework/src/Illuminate/Http/Testing/FileFactory.php:75 /home/circleci/ci-demo/backend/vendor/laravel/framework/src/Illuminate/Support/helpers.php:263 /home/circleci/ci-demo/backend/vendor/laravel/framework/src/Illuminate/Http/Testing/FileFactory.php:87 /home/circleci/ci-demo/backend/vendor/laravel/framework/src/Illuminate/Http/Testing/FileFactory.php:58画像処理系のライブラリであるphp-gdがCircleCIイメージにインストールされていないために起こったエラーみたいです。
忘れないようにメモします。
環境
CircleCI 2.1
Laravel 8.12
PHP 7.3実装
circleci/config.ymlversion: 2.1 jobs: build: docker: - image: circleci/php:7.3.0-node-browsers - image: circleci/mysql:8.0.0 command: mysqld --default-authentication-plugin=mysql_native_password environment: - DB_CONNECTION: circle_testing - APP_ENV: testing - MYSQL_ALLOW_EMPTY_PASSWORD: true - MYSQL_ROOT_HOST: '%' - MYSQL_DATABASE: circle_test working_directory: ~/ci-demo steps: - checkout - run: name: Update apt-get command: sudo apt-get update //ここで追加 - run: name: Install php-gd command: | sudo apt-get -y install libpng-dev sudo docker-php-ext-install gd - run: name: Docker php extensions install command: sudo docker-php-ext-install pdo_mysql - run: name: Wait for DB command: dockerize -wait tcp://127.0.0.1:3306 -timeout 3m - restore_cache: keys: - v1-dependencies-{{ checksum "backend/composer.json" }} - v1-dependencies- - run: working_directory: backend name: Install PHP libraries command: composer install -n --prefer-dist - save_cache: paths: - ./vendor key: v1-dependencies-{{ checksum "backend/composer.json" }} - run: working_directory: backend command: composer install - run: working_directory: backend command: php artisan migrate - run: working_directory: backend name: Run PHPUnit command: ./vendor/bin/phpunitcircleci/config.yml- run: name: Install php-gd command: | sudo apt-get -y install libpng-dev sudo docker-php-ext-install gd
- 投稿日:2021-03-06T18:35:15+09:00
Laravel Dusk+Dockerでブラウザテスト環境を作る
経緯
「カチカチカチカチカチカチカチカチカチ」
静寂な開発オフィスに響き渡るマウスクリック。それはキーボードのタイプ音よりも顕著である。なぜこんなにもクリック音が鳴り響くのか?それは動作チェックをしているためである。テストは正しく動作するか確認するとても重要な作業だ。
しかし、この作業に一体どれだけの時間を費やすことになるのだろうか。もちろん開発規模によるところであるが、エディタでコード記述→ブラウザで動作確認・・・(LOOP)
これは大きな時間を費やすことになるだろう。インターフェイスもキーボードからマウスに切り替えなければならない。煩雑な作業である。
IT化を提供する立場であるにもかかわらず、アナログな作業をしてしまうのはなんとも皮肉である。そして何より「これはエンジニアらしくない」と感じることとなった。
この問題をどうにかできないだろうか?LaravelにはDuskというブラウザテストを効率よく行うことができる機能がある。今回はその導入について挑戦したときのメモである。
環境
・Windows
・Laravel 7.30.4
・Docker(nginx1.15.6、php7.4.15、mysql5.7)かねてよりLaravel開発用のDockerを使っているので、それに加える形での環境更新となる。既に上記のセットで動作している前提となる。mysqlは今回の更新作業に特に関係はしてこない。
今回の流れ
1. Dockerにseleniumコンテナを追加
2. Composerで「Laravel/Dusk」をインストール
3. LarvelでDusk関係のファイルを作成
4. 動作確認用に「VNC Viewer」をインストール
5. テストしてみる1. Dockerにseleniumコンテナを追加
selenium・・・webブラウザでのテストを自動化するツール。DockerHubに公式のイメージがあるのでそれを使う。余談だが、pythonでもこれを介してブラウザ操作ができたりする。
docker-compose.yml\\追加 selenium: image: selenium/standalone-chrome-debug ports: - 4444:4444 - 5900:5900 depends_on: - web privileged: true今回はデバッグ(テスト)用なので、下記のDebugging部分を参考にした。
ブラウザ操作をするにはdriverが必要だが、Laravelではデフォルトはchromeになっているので、そのままコンテナもchromeにする。
2. Composerで「Laravel/Dusk」をインストール
次はphpのコンテナでの作業。
docker exec -it phpのコンテナ名 bashLaravelプロジェクト配下へ移動し、下記コマンドでLaravelDuskをインストールする。
composer require --dev laravel/duskここで今回下記のエラーが出現。phpの拡張機能としてzipが有効になっていない旨の内容。
実は以前php7.4に更新したのだがzipが有効になっていなかったようである。Your requirements could not be resolved to an installable set of packages. Problem 1 - laravel/dusk[v6.13.0, ..., 6.x-dev] require ext-zip * -> it is missing fro m your system. Install or enable PHP's zip extension. - Root composer.json requires laravel/dusk ^6.13 -> satisfiable by laravel/d usk[v6.13.0, 6.x-dev]. To enable extensions, verify that they are enabled in your .ini files: - - /usr/local/etc/php/conf.d/docker-php-ext-mysqli.ini - /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini - /usr/local/etc/php/conf.d/docker-php-ext-pdo_pgsql.ini - /usr/local/etc/php/conf.d/docker-php-ext-sodium.ini You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode. Installation failed, reverting ./composer.json and ./composer.lock to their orig inal content.下記コマンドでzip有無を確認するも有効でないようである。
一旦コンテナ内での作業は中止でDockerfileを修正する。php --ri zip Extension 'zip' not present.phpコンテナ用のDockerfileも更新する。RUN apt-getの際、インストールするパッケージを追加した。
zlib1g-dev、libzip-dev、docker-php-ext-install zip
の3つを追加。DockerfileRUN apt-get update \ && apt-get install -y \ git \ zlib1g-dev \ libzip-dev \ zip \ unzip \ vim \ && docker-php-ext-install zip変更後コンテナコンテナを再構築する。
docker-compose build再度コンテナ内に入り、zipの再確認。無事有効になっている。
php --ri zip zip Zip => enabled Zip version => 1.15.6 Libzip headers version => 1.5.1 Libzip library version => 1.5.1再度LaravelDuskをインストール。無事インストール完了。
composer require --dev laravel/dusk3. LarvelでDusk関係のファイルを作成
引き続きphpコンテナでの作業。Laravelプロジェクト配下で書きのコマンドでDusk関係のファイルを作成する。
php artisan dusk:install無事完了するとtestsディレクトリにBrowserディレクトリとDuskTestCase.phpが作成される。
4. 動作確認用に「VNC Viewer」をインストール
せっかくなのでテスト実行中の様子を確認したい。したがってVNC Viewerを使ってコンテナ内で実行されるテストの様子を確認できるようにする。ちなみにテストの実行自体はViewerなくてもできる。
下記からインストール。
インストールしたらDockerで指定したlocalhost:5900で接続。passwordを要求されるが、公式通りデフォルトは「secret」でログインできる。
5. テストしてみる
Dusk作成時にサンプルテストが出来上がっている。HomeにアクセスしたらLaravelのWelcomeが画面が表示されるかというシンプルなテスト。
ExampleTest.php<?php namespace Tests\Browser; use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Browser; use Tests\DuskTestCase; class ExampleTest extends DuskTestCase { /** * A basic browser test example. * * @return void */ public function testBasicExample() { $this->browse(function (Browser $browser) { $browser->visit('/') ->assertSee('Laravel'); }); } }下記のコマンドでテスト実行。
php artisan duskところが下記のようなエラーになった。どうやらルートURLの設定がうまくできていないようである。
ちなみにエラーはtests/Browser/screenshotsにエラー時点のスクショができる。そして無事にテスト追加すると自動で削除される。PHPUnit 8.5.14 by Sebastian Bergmann and contributors. E 1 / 1 (100%) Time: 1.56 seconds, Memory: 18.00 MB There was 1 error: 1) Tests\Browser\ExampleTest::testBasicExample Facebook\WebDriver\Exception\UnknownErrorException: unknown error: net::ERR_CONNECTION_REFU SED (Session info: chrome=88.0.4324.96) /var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/Exception/WebDriverException.p hp:139 /var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/Remote/HttpCommandExecutor.php :371 /var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/Remote/RemoteWebDriver.php:604 /var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/Remote/RemoteExecuteMethod.php :27 /var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/WebDriverNavigation.php:41 /var/www/html/app/laravel/vendor/laravel/dusk/src/Browser.php:153 /var/www/html/app/laravel/tests/Browser/ExampleTest.php:19 /var/www/html/app/laravel/vendor/laravel/dusk/src/Concerns/ProvidesBrowser.php:68 /var/www/html/app/laravel/tests/Browser/ExampleTest.php:21 ERRORS! Tests: 1, Assertions: 0, Errors: 1.baseUrl()をオーバーライドするとことで対応。webはDockerのnginxコンテナの名前のことである。
DuskTestCase.php<?php namespace Tests; use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Laravel\Dusk\TestCase as BaseTestCase; abstract class DuskTestCase extends BaseTestCase { use CreatesApplication; //追加 protected function baseUrl() { return 'http://web'; } /** * Prepare for Dusk test execution. * * @beforeClass * @return void */ public static function prepare() { if (! static::runningInSail()) { static::startChromeDriver(); } } /** * Create the RemoteWebDriver instance. * * @return \Facebook\WebDriver\Remote\RemoteWebDriver */ protected function driver() { $options = (new ChromeOptions)->addArguments(collect([ '--window-size=1920,1080', ])->unless($this->hasHeadlessDisabled(), function ($items) { return $items->merge([ '--disable-gpu', '--headless', ]); })->all()); return RemoteWebDriver::create( 'http://selenium:4444/wd/hub', DesiredCapabilities::chrome() ); // return RemoteWebDriver::create( // $_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515', // DesiredCapabilities::chrome()->setCapability( // ChromeOptions::CAPABILITY, $options // ) // ); } /** * Determine whether the Dusk command has disabled headless mode. * * @return bool */ protected function hasHeadlessDisabled() { return isset($_SERVER['DUSK_HEADLESS_DISABLED']) || isset($_ENV['DUSK_HEADLESS_DISABLED']); } }再度テスト実行。
php artisan dusk PHPUnit 8.5.14 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 2.09 seconds, Memory: 18.00 MB OK (1 test, 1 assertion)無事通過!これで一通りテスト環境が準備できた。公式リファレンスには様々なチェック項目があるのでテストが捗りそう。いろいろ試して行こうと思います。
- 投稿日:2021-03-06T17:50:53+09:00
マイグレーション時 Table '◯◯' already existsの対処法
マイグレーション時、こんなエラーが出た
freshするのも怖いので、こう解決
テーブル名を『articles → article』に変更することで、解決。ロールバック・refreshしても直らなかったため。
- 投稿日:2021-03-06T15:08:20+09:00
【Laravel】一覧表示画面でDBのデータ有無で表示を切り替える方法(「◯◯はありません」と表示しよう)
概要
よくあるコンテンツ共有サービスの一覧画面で
DBにデータが 動作・表示 ある DBのデータを一覧表示 ない 「データはありません」というメッセージを表示する こんなよくある機能を実装する方法をちょっと詳しくまとめます。
環境
$ composer -V Composer version 1.10.20 2021-01-27 15:41:06 $ php artisan --version Laravel Framework 6.20.16一覧表示画面でDBのデータ有無で表示を切り替える方法
手順はざっくりこんな感じ
- ルーティング設定
- Controller
- Viewで切り替えを実装(←ここがメイン)
※DBからのデータ取得はシンプルなものにするのでModelではなくControllerで処理することにします。
ルーティング設定
routes/web.phpRoute::get('/', 'ArticleController@index')->name('index');
resource
メソッドで定義しても問題ないです。Controller
記事テーブル(articles)に対応する
Article
モデルを使用してORMを使ってDBからデータを取得するケースを想定。app/Http/Controllers/ArticleController.php/** * 記事一覧画面表示 * * @return \Illuminate\Http\Response */ public function index() { $articles = Article::all(); return view('articles.index', compact('articles')); }以下の項目などは本記事では省略してシンプルに全件取得のみにしています。
->with()
でN+1問題対策->orderBy()
メソッドでソート->paginate()
でページネーションViewで切り替えを実装(←ここがメイン)
今回ControllerでDBからデータを取得する処理は以下のコードで実装しています。
$articles = Article::all();この
$articles
をddd()
でデバッグしてみます。データの型は
"Illuminate\Database\Eloquent\Collection"
クラスのオブジェクトです。
(all()
を使うとCollection
になります)
ddd()
についてはこちらの記事で解説しています。
【Laravel6.x〜】デバッグするならdd()?いやいや、ddd()を使おう!!
Collection
でデータの有無を判定する方法は主に以下の3つです。
コード例 データがある データがない $article->isEmpty() false true $articles->count() true(1以上) false(0) $empty(articles->all()) false true 例として、
->isEmpty()
を使って以下のように書けます。resources/views/articles/index.blade.php@if (!$articles->isEmpty()) {{-- 記事データがDBにある場合の表示内容 --}} @else {{-- 記事データがDBにない場合の表示内容 --}} @endifこのように書くことによって
・データがある場合:データを一覧表示
・データがない場合:「データはありません」というメッセージを表示することができます。
注意点
Collection
の場合、文字列の時みたいに以下の書き方をするとうまく条件分岐できないのでご注意ください。resources/views/articles/index.blade.php{{-- これだとうまく条件分岐できない --}} @if (!$articles) {{-- 記事データがDBにある場合の表示内容 --}} @else {{-- 記事データがDBにない場合の表示内容 --}} @endifまとめ
- Collectionというクラスがあるのを理解しておくべし
- 公式ドキュメントの日本語訳(ReaDouble)にメソッドがたんまり書いてあるので見ておくべし(最後に参考に載せてます)
参考
- 投稿日:2021-03-06T12:58:23+09:00
Laravelで一度は画像が表示されたのに、いろいろイジくってたら画像が表示されなくなった話
概要
初めてDockerを用いてLaravelで画像アップロードができる掲示板アプリを作った時のお話です。
アプリ制作中せっかく画像アップロード機能が正常に動いたのに、はじめに作ったディレクトリ構造が気に食わずちょいと直した結果、画像表示がされなくなってしまいました。その時の解決方法を備忘録として残します。ディレクトリ構造
larapic ├── README.md ├── infra │ ├── mysql │ │ ├── data │ │ └── my.cnf │ ├── nginx │ │ ├── default.conf │ │ └── Dockerfile │ └── php │ ├── Dockerfile │ └── php.ini ├── docker-compose.yml └── laravel(以降laravel①) └── Laravel(以降laravel②) ├── app ├── bootstrap ├── config ├── ・・・このディレクトリ構造で始めてしまいました。laravelが1ついらないですね。
ある程度アプリが出来上がり、余裕が生まれたところでこのディレクトリ構造を直したいと思い立ちました。
laravel②を①の階層に上げて、①を削除。これでOK〜!…と思いきや、画像が表示されなくなってしまいました。ガーン。
解決方法
シンボリックリンクに原因がある模様です。一度シンボリックリンクを解除し、再度シンボリックリンクを貼ります。
terminal# publicフォルダに移動しシンボリックリンクを解除 % cd public % rm -rf storage # 戻って再度シンボリックリンクを張る % cd ../ % php artisan storage:linkこれで画像が表示されました。
- 投稿日:2021-03-06T10:35:35+09:00
自作apiでauthが効かない(laravel)
バックエンドにlaravel、フロントにreactを利用してSPAでwebアプリを作っているのですが、
authの処理ではまりました。
具体的には、フロント側からlaravelで自作したapiを利用する際、Authファサードを利用しても値がとれないという状態でした。解決方法
laravelで自作したapiのrouteはapi.phpに記述していたのですが、どうやらデフォルトではapi.phpはsession機能を読み込まないようです。
RouteServiceProvider.phpで以下の修正を行いました。
public function boot() { $this->configureRateLimiting(); $this->routes(function () { Route::prefix('api') // ->middleware('api') ← 元々 ->middleware('web') ← 修正後 ->namespace($this->namespace) ->group(base_path('routes/api.php')); Route::middleware('web') ->namespace($this->namespace) ->group(base_path('routes/web.php')); }); }ちなみに、middleware('web')などで読み込んでいるいるのは、Kernel.phpの$middlewareGroupsの部分みたいです。