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

[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.yml
version: 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/phpunit

circleci/config.yml
      - run:
          name: Install php-gd
          command: |
            sudo apt-get -y install libpng-dev
            sudo docker-php-ext-install  gd
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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のコンテナ名 bash

Laravelプロジェクト配下へ移動し、下記コマンドで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つを追加。

Dockerfile
RUN 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/dusk

3. LarvelでDusk関係のファイルを作成

引き続きphpコンテナでの作業。Laravelプロジェクト配下で書きのコマンドでDusk関係のファイルを作成する。

 php artisan dusk:install

無事完了するとtestsディレクトリにBrowserディレクトリとDuskTestCase.phpが作成される。

4. 動作確認用に「VNC Viewer」をインストール

せっかくなのでテスト実行中の様子を確認したい。したがってVNC Viewerを使ってコンテナ内で実行されるテストの様子を確認できるようにする。ちなみにテストの実行自体はViewerなくてもできる。
下記からインストール。

インストールしたらDockerで指定したlocalhost:5900で接続。passwordを要求されるが、公式通りデフォルトは「secret」でログインできる。
VNC Viewer 2021_03_06 18_12_17.png

ログインできて下記のような画面がでればOK。
localhost_5900 (111074b15212_99.0) - VNC Viewer 2021_03_06 14_54_58.png

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.

failure-Tests_Browser_ExampleTest_testBasicExample-0.png

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)

無事通過!これで一通りテスト環境が準備できた。公式リファレンスには様々なチェック項目があるのでテストが捗りそう。いろいろ試して行こうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

マイグレーション時 Table '◯◯' already existsの対処法

マイグレーション時、こんなエラーが出た

スクリーンショット 2021-03-06 17.42.09.png

freshするのも怖いので、こう解決

テーブル名を『articles → article』に変更することで、解決。ロールバック・refreshしても直らなかったため。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【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.php
Route::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();

この$articlesddd()でデバッグしてみます。

スクリーンショット 2021-03-06 10.57.48.png

データの型は"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)にメソッドがたんまり書いてあるので見ておくべし(最後に参考に載せてます)

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

これで画像が表示されました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

自作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の部分みたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む