20210123のlaravelに関する記事は8件です。

キューで重い動作を非同期で動かしてみた

経緯

移行元のデータベースから開発側にデータを移行することになった。
だが、データ量が膨大なので非同期で処理をしてみました。

事前準備

  • キューのジョブテーブルとキューが失敗した時のテーブルを作成
# ジョブを記録するためのデータベーステーブルを作成する
php artisan queue:table
php artisan migrate
  • envファイルに以下を追加で記述
QUEUE_CONNECTION=database

ジョブを作成する

 php artisan make:job InsettJob

非同期で処理する処理をジョブ内に作成する

<?php

namespace App\Jobs;

use App\Domains\Facility\UseList;
use DateTime;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use PDO;
use PDOException;

class InsettJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * タイムアウトまでの秒数
     *
     * @var int
     */
    public $timeout = 60;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * ANCHOR [connectionToBase 移行元のデータベースに接続]
     *
     * @return  [type]  [return description]
     */
    public function connectionToBase()
    {
        try {
            $db = 'データベース名';
            // データベースに接続
            $pdo = new PDO(
                "mysql:dbname={$db};host=mysql;charset=utf8mb4",
                'ユーザー名',
                'パスワード',
                [
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                ]
            );
            return $pdo;
        } catch (PDOException $e) {
            header('Content-Type: text/plain; charset=UTF-8', true, 500);
            exit($e->getMessage());
        }
    }

    /**
     * ANCHOR [getTableData 指定したテーブルデータを取得]
     *
     * @param   [type]  $db     [$db description]
     * @param   string  $query  [$query description]
     *
     * @return  object          [return description]
     */
    public function getTableData($db, string $query): object
    {
        return  $db->query($query);
    }

    /**
     * ANCHOR[registrationPreparation インサート準備]
     *
     * @param   object  $facilityList  [$facilityList description]
     *
     * @return  void
     */
    public function registrationPreparation(object $facilityList): void
    {
        DB::table('移行先テーブル')->truncate();

        $insertList = [];
        foreach ($facilityList as $v) {
            $insertList[] = [
                'id' => $v['code'],
                'name' => $v['name'],
                'name_kana' => $v['name_kana'],
                'created_at' => $v['insert_date'],
                'updated_at' => $v['update_date']
            ];
         }
        $this->registrationExecution($insertList);
        }
    }

    /**
     * [registrationExecution インサート処理]
     *
     * @param   array  $insertList  [$insertList description]
     *
     * @return  void                [return description]
     */
    public function registrationExecution(array $insertList): void
    {
        DB::transaction(function () use ($insertList) {
            try {
                DB::table('移行先テーブル')->insert($insertList);
            } catch (Exception $e) {
                header('Content-Type: text/plain; charset=UTF-8', true, 500);
                exit($e->getMessage());
            }
        });
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // DB接続
        $db = $this->connectionToBase();
        $sql = 'SELECT * FROM テーブル名 ORDER BY code ASC';

        // クエリ実行
        $facilityList = $this->getTableData($db, $sql);
        $this->registrationPreparation($facilityList);
    }

    public function failed(Exception $exception)
    {
        header('Content-Type: text/plain; charset=UTF-8', true, 500);
        exit($exception->getMessage());
    }
}

コントローラーでジョブを呼び出す

<?php

namespace App\Http\Controllers;

use App\Jobs\FacilityCategoryImportJob;
use App\Jobs\InsettJob;
use DateTime;
use Exception;
use Illuminate\Http\RedirectResponse;

class DatabaseMigrationController extends Controller
{
    /**
     * 施設データ移行事前準備
     * php artisan queue:work --sleep=3 --tries=1 --stop-when-empty --queue=facility
     * php artisan queue:restart キューの設定反映
     *
     * @return  void    [return description]
     */
    public function facilityImport(): void
    {
        try {
            InsettJob::dispatch()->onQueue('facility');
        } catch (Exception $e) {
            header('Content-Type: text/plain; charset=UTF-8', true, 500);
            exit($e->getMessage());
        }
    }
}

ジョブ内容を反映させる

php artisan queue:restart

キューを動かす

php artisan queue:work --sleep=3 --tries=1 --stop-when-empty --queue=facility
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

キューで重い処理を非同期で動かしてみた

経緯

移行元のデータベースから開発側にデータを移行することになった。
だが、データ量が膨大なので非同期で処理をしてみました。

事前準備

  • キューのジョブテーブルとキューが失敗した時のテーブルを作成
# ジョブを記録するためのデータベーステーブルを作成する
php artisan queue:table
php artisan migrate
  • envファイルに以下を追加で記述
QUEUE_CONNECTION=database

ジョブを作成する

 php artisan make:job InsettJob

非同期で処理する処理をジョブ内に作成する

<?php

namespace App\Jobs;

use App\Domains\Facility\UseList;
use DateTime;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use PDO;
use PDOException;

class InsettJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * タイムアウトまでの秒数
     *
     * @var int
     */
    public $timeout = 60;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * ANCHOR [connectionToBase 移行元のデータベースに接続]
     *
     * @return  [type]  [return description]
     */
    public function connectionToBase()
    {
        try {
            $db = 'データベース名';
            // データベースに接続
            $pdo = new PDO(
                "mysql:dbname={$db};host=mysql;charset=utf8mb4",
                'ユーザー名',
                'パスワード',
                [
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                ]
            );
            return $pdo;
        } catch (PDOException $e) {
            header('Content-Type: text/plain; charset=UTF-8', true, 500);
            exit($e->getMessage());
        }
    }

    /**
     * ANCHOR [getTableData 指定したテーブルデータを取得]
     *
     * @param   [type]  $db     [$db description]
     * @param   string  $query  [$query description]
     *
     * @return  object          [return description]
     */
    public function getTableData($db, string $query): object
    {
        return  $db->query($query);
    }

    /**
     * ANCHOR[registrationPreparation インサート準備]
     *
     * @param   object  $facilityList  [$facilityList description]
     *
     * @return  void
     */
    public function registrationPreparation(object $facilityList): void
    {
        DB::table('移行先テーブル')->truncate();

        $insertList = [];
        foreach ($facilityList as $v) {
            $insertList[] = [
                'id' => $v['code'],
                'name' => $v['name'],
                'name_kana' => $v['name_kana'],
                'created_at' => $v['insert_date'],
                'updated_at' => $v['update_date']
            ];
         }
        $this->registrationExecution($insertList);
        }
    }

    /**
     * [registrationExecution インサート処理]
     *
     * @param   array  $insertList  [$insertList description]
     *
     * @return  void                [return description]
     */
    public function registrationExecution(array $insertList): void
    {
        DB::transaction(function () use ($insertList) {
            try {
                DB::table('移行先テーブル')->insert($insertList);
            } catch (Exception $e) {
                header('Content-Type: text/plain; charset=UTF-8', true, 500);
                exit($e->getMessage());
            }
        });
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // DB接続
        $db = $this->connectionToBase();
        $sql = 'SELECT * FROM テーブル名 ORDER BY code ASC';

        // クエリ実行
        $facilityList = $this->getTableData($db, $sql);
        $this->registrationPreparation($facilityList);
    }

    public function failed(Exception $exception)
    {
        header('Content-Type: text/plain; charset=UTF-8', true, 500);
        exit($exception->getMessage());
    }
}

コントローラーでジョブを呼び出す

<?php

namespace App\Http\Controllers;

use App\Jobs\FacilityCategoryImportJob;
use App\Jobs\InsettJob;
use DateTime;
use Exception;
use Illuminate\Http\RedirectResponse;

class DatabaseMigrationController extends Controller
{
    /**
     * 施設データ移行事前準備
     * php artisan queue:work --sleep=3 --tries=1 --stop-when-empty --queue=facility
     * php artisan queue:restart キューの設定反映
     *
     * @return  void    [return description]
     */
    public function facilityImport(): void
    {
        try {
            InsettJob::dispatch()->onQueue('facility');
        } catch (Exception $e) {
            header('Content-Type: text/plain; charset=UTF-8', true, 500);
            exit($e->getMessage());
        }
    }
}

ジョブ内容を反映させる

php artisan queue:restart

キューを動かす

php artisan queue:work --sleep=3 --tries=1 --stop-when-empty --queue=facility
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel-mixのコンパイルでSyntaxError: Unexpected token = と怒られたら

発生したエラー

laravel-mixでコンパイルしたところ下記のエラーで怒られた
触ってないファイルでsyntax errorとか言われて困った

ubuntu
# npm run dev
npm WARN npm npm does not support Node.js v10.23.1
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm Supported releases of Node.js are the latest release of 4, 6, 7, 8, 9.
npm WARN npm You can find the latest version at https://nodejs.org/

> @ dev /var/www/vue-laravel-spa
> npm run development

npm WARN npm npm does not support Node.js v10.23.1
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm Supported releases of Node.js are the latest release of 4, 6, 7, 8, 9.
npm WARN npm You can find the latest version at https://nodejs.org/

> @ development /var/www/vue-laravel-spa
> mix

[webpack-cli] /var/www/vue-laravel-spa/node_modules/laravel-mix/src/Mix.js:18
    static _primary = null;
                    ^

SyntaxError: Unexpected token =
    at new Script (vm.js:83:7)
    at NativeCompileCache._moduleCompile (/var/www/vue-laravel-spa/node_modules/v8-compile-cache/v8-compile-cache.js:240:18)
    at Module._compile (/var/www/vue-laravel-spa/node_modules/v8-compile-cache/v8-compile-cache.js:184:36)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (/var/www/vue-laravel-spa/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at module.exports (/var/www/vue-laravel-spa/node_modules/laravel-mix/setup/webpack.config.js:2:17)
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! @ development: `mix`
npm ERR! Exit status 2
npm ERR! 
npm ERR! Failed at the @ development script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2021-01-23T09_26_30_393Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! @ dev: `npm run development`
npm ERR! Exit status 2
npm ERR! 
npm ERR! Failed at the @ dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2021-01-23T09_26_30_443Z-debug.log

環境

% sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H2

% docker version
Client: Docker Engine - Community
 Cloud integration: 1.0.1
 Version:           19.03.13
 API version:       1.40

# php -v
PHP 7.4.7 (cli) (built: Jun 11 2020 18:41:17) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Xdebug v3.0.2, Copyright (c) 2002-2021, by Derick Rethans

# php artisan -v
Laravel Framework 8.24.0

原因

ググりまくった結果こちらのサイトに辿り着いた
https://github.com/JeffreyWay/laravel-mix/issues/2570
どうやらnode.jsのバージョンを最新にすると直るらしい

対処

こちらの記事を参考に対処した
https://qiita.com/seibe/items/36cef7df85fe2cefa3ea
https://qiita.com/kiwi-bird/items/e3e551938d09282cf4ee
今回初めて知ったのだがn packageを使うことでnpmパッケージとnode.js自体のバージョン管理をしてくれるらしい
こんな便利なものがあったのか

というわけでn packageをインストールする

ubuntu
# npm install n -g  # グローバルにインストールする
npm WARN npm npm does not support Node.js v10.23.1
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm Supported releases of Node.js are the latest release of 4, 6, 7, 8, 9.
npm WARN npm You can find the latest version at https://nodejs.org/
/usr/local/bin/n -> /usr/local/lib/node_modules/n/bin/n
+ n@7.0.0
added 1 package from 4 contributors in 0.858s

# n stable  # 最新のnodejsをインストール
  installing : node-v14.15.4
       mkdir : /usr/local/n/versions/node/14.15.4
       fetch : https://nodejs.org/dist/v14.15.4/node-v14.15.4-linux-x64.tar.xz
   installed : v14.15.4 (with npm 6.14.10)

Note: the node command changed location and the old location may be remembered in your current shell.
         old : /usr/bin/node
         new : /usr/local/bin/node
To reset the command location hash either start a new shell, or execute PATH="$PATH"

# apt purge -y nodejs npm   # aptで入れた古いnodejsとnpmを削除
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages were automatically installed and are no longer required:
  gyp javascript-common libbrotli1 libc-ares2 libexpat1 libjs-inherits libjs-is-typedarray libnode-dev libnode64 libpython-stdlib
  libpython2-stdlib libpython2.7-minimal libpython2.7-stdlib libreadline7 libssl-dev libuv1 libuv1-dev lsb-base mime-support nodejs-doc python
  python-minimal python-pkg-resources python2 python2-minimal python2.7 python2.7-minimal
Use 'apt autoremove' to remove them.
The following packages will be REMOVED:
  node-abbrev* node-ajv* node-ansi* node-ansi-align* node-ansi-regex* node-ansi-styles* node-ansistyles* node-aproba* node-archy*
  node-are-we-there-yet* node-asn1* node-assert-plus* node-asynckit* node-aws-sign2* node-aws4* node-balanced-match* node-bcrypt-pbkdf*
  node-bluebird* node-boxen* node-brace-expansion* node-builtin-modules* node-builtins* node-cacache* node-call-limit* node-camelcase*
  node-caseless* node-chalk* node-chownr* node-cli-boxes* node-cliui* node-clone* node-co* node-color-convert* node-color-name*
  node-combined-stream* node-concat-map* node-concat-stream* node-config-chain* node-console-control-strings* node-copy-concurrently*
  node-core-util-is* node-cross-spawn* node-cyclist* node-dashdash* node-decamelize* node-decompress-response* node-deep-extend* node-defaults*
  node-delayed-stream* node-delegates* node-detect-indent* node-detect-newline* node-duplexer3* node-duplexify* node-ecc-jsbn* node-editor*
  node-encoding* node-end-of-stream* node-errno* node-escape-string-regexp* node-execa* node-extend* node-extsprintf* node-find-up*
  node-flush-write-stream* node-forever-agent* node-form-data* node-from2* node-fs-vacuum* node-fs-write-stream-atomic* node-fs.realpath*
  node-gauge* node-get-caller-file* node-get-stream* node-getpass* node-glob* node-got* node-graceful-fs* node-gyp* node-har-schema*
  node-har-validator* node-has-flag* node-has-symbol-support-x* node-has-to-string-tag-x* node-has-unicode* node-hosted-git-info*
  node-http-signature* node-iconv-lite* node-iferr* node-import-lazy* node-imurmurhash* node-inflight* node-inherits* node-ini* node-invert-kv*
  node-is-builtin-module* node-is-npm* node-is-object* node-is-plain-obj* node-is-retry-allowed* node-is-stream* node-is-typedarray*
  node-isarray* node-isexe* node-isstream* node-isurl* node-jsbn* node-json-parse-better-errors* node-json-schema* node-json-stable-stringify*
  node-json-stringify-safe* node-jsonify* node-jsonparse* node-jsonstream* node-jsprim* node-latest-version* node-lazy-property* node-lcid*
  node-libnpx* node-locate-path* node-lockfile* node-lowercase-keys* node-lru-cache* node-mem* node-mime-types* node-mimic-fn*
  node-mimic-response* node-minimatch* node-minimist* node-mississippi* node-mkdirp* node-move-concurrently* node-mute-stream* node-node-uuid*
  node-nopt* node-normalize-package-data* node-npm-package-arg* node-npm-run-path* node-npmlog* node-oauth-sign* node-object-assign* node-once*
  node-opener* node-os-locale* node-osenv* node-p-cancelable* node-p-finally* node-p-limit* node-p-locate* node-p-timeout* node-package-json*
  node-parallel-transform* node-path-exists* node-path-is-absolute* node-path-is-inside* node-performance-now* node-prepend-http*
  node-process-nextick-args* node-promise-inflight* node-promzard* node-proto-list* node-prr* node-pump* node-pumpify* node-punycode* node-qs*
  node-qw* node-rc* node-read* node-read-package-json* node-readable-stream* node-registry-auth-token* node-registry-url* node-request*
  node-require-directory* node-require-main-filename* node-resolve-from* node-retry* node-rimraf* node-run-queue* node-safe-buffer* node-semver*
  node-semver-diff* node-set-blocking* node-sha* node-shebang-command* node-shebang-regex* node-signal-exit* node-slash* node-slide*
  node-sorted-object* node-spdx-correct* node-spdx-expression-parse* node-spdx-license-ids* node-sshpk* node-ssri* node-stream-each*
  node-stream-iterate* node-stream-shift* node-string-decoder* node-string-width* node-strip-ansi* node-strip-eof* node-strip-json-comments*
  node-supports-color* node-tar* node-term-size* node-text-table* node-through* node-through2* node-timed-out* node-tough-cookie*
  node-tunnel-agent* node-tweetnacl* node-typedarray* node-uid-number* node-unique-filename* node-unpipe* node-url-parse-lax*
  node-url-to-options* node-util-deprecate* node-uuid* node-validate-npm-package-license* node-validate-npm-package-name* node-verror*
  node-wcwidth.js* node-which* node-which-module* node-wide-align* node-widest-line* node-wrap-ansi* node-wrappy* node-write-file-atomic*
  node-xdg-basedir* node-xtend* node-y18n* node-yallist* node-yargs* node-yargs-parser* nodejs* npm*
0 upgraded, 0 newly installed, 241 to remove and 18 not upgraded.
After this operation, 16.7 MB disk space will be freed.
(Reading database ... 19266 files and directories currently installed.)
Removing npm (5.8.0+ds6-4+deb10u2) ...
Removing node-gyp (3.8.0-6) ...
Removing node-nopt (3.0.6-3) ...
Removing node-abbrev (1.1.1-1) ...
Removing node-request (2.88.1-2) ...
Removing node-har-validator (5.1.0-1) ...
Removing node-ajv (5.0.0-1) ...
Removing node-ansi (0.3.0-3) ...
Removing node-boxen (1.2.2-1) ...
Removing node-ansi-align (2.0.0-1) ...
Removing node-libnpx (10.2.0+repack-1) ...
Removing node-yargs (10.0.3-2) ...
Removing node-cliui (4.1.0-1) ...
Removing node-wrap-ansi (4.0.0-1) ...
Removing node-chalk (2.3.0-2) ...
Removing node-ansi-styles (3.2.1-1) ...
Removing node-ansistyles (0.1.3-1) ...
Removing node-npmlog (4.1.2-1) ...
Removing node-gauge (2.7.4-1) ...
Removing node-cacache (11.3.2-2) ...
Removing node-move-concurrently (1.0.1-2) ...
Removing node-archy (1.0.0-2) ...
Removing node-are-we-there-yet (1.1.4-1) ...
Removing node-http-signature (1.2.0-1) ...
Removing node-sshpk (1.13.1+dfsg-2) ...
Removing node-asn1 (0.2.3-1) ...
Removing node-dashdash (1.14.1-2) ...
Removing node-jsprim (1.4.0-1) ...
Removing node-verror (1.10.0-1) ...
Removing node-form-data (2.3.2-2) ...
Removing node-asynckit (0.4.0-2) ...
Removing node-aws-sign2 (0.7.1-1) ...
Removing node-aws4 (1.8.0-1) ...
Removing node-read-package-json (2.0.13-1) ...
Removing node-copy-concurrently (1.0.5-4) ...
Removing node-bcrypt-pbkdf (1.0.1-1) ...
Removing node-bluebird (3.5.1+dfsg2-2) ...
Removing node-normalize-package-data (2.4.0-1) ...
Removing node-is-builtin-module (2.0.0-1) ...
Removing node-builtin-modules (3.0.0-1) ...
Removing node-npm-package-arg (6.0.0-2) ...
Removing node-validate-npm-package-name (3.0.0-1) ...
Removing node-builtins (1.0.3-1) ...
Removing node-call-limit (1.1.0-1) ...
Removing node-yargs-parser (11.1.1-1+deb10u1) ...
Removing node-camelcase (5.0.0-1) ...
Removing node-caseless (0.12.0-1) ...
Removing node-tar (4.4.6+ds1-3) ...
Removing node-chownr (1.1.1-1) ...
Removing node-cli-boxes (1.0.0-1) ...
Removing node-widest-line (1.2.2-1) ...
Removing node-co (4.6.0-1) ...
Removing node-color-convert (1.9.0-3) ...
Removing node-color-name (1.1.3-1) ...
Removing node-combined-stream (1.0.7-1) ...
Removing node-mississippi (3.0.0-1) ...
Removing node-concat-stream (1.6.2-1) ...
Removing node-config-chain (1.1.11-1) ...
Removing node-console-control-strings (1.1.0-1) ...
Removing node-through2 (2.0.5-2) ...
Removing node-flush-write-stream (1.0.3-1) ...
Removing node-term-size (1.2.0+dfsg-2) ...
Removing node-os-locale (2.0.0-1) ...
Removing node-execa (0.10.0+dfsg-1) ...
Removing node-cross-spawn (5.1.0-2) ...
Removing node-parallel-transform (1.1.0-2) ...
Removing node-cyclist (1.0.1-2) ...
Removing node-decamelize (1.2.0-1) ...
Removing node-latest-version (3.1.0-1) ...
Removing node-package-json (4.0.1-1) ...
Removing node-got (7.1.0-1) ...
Removing node-decompress-response (3.3.0-1) ...
Removing node-registry-url (3.1.0-1) ...
Removing node-registry-auth-token (3.3.1-1) ...
Removing node-rc (1.1.6-2) ...
Removing node-deep-extend (0.4.1-2) ...
Removing node-delayed-stream (0.0.5-1) ...
Removing node-delegates (1.0.0-1) ...
Removing node-detect-indent (5.0.0-1) ...
Removing node-detect-newline (2.1.0-1) ...
Removing node-duplexer3 (0.1.4-4) ...
Removing node-pumpify (1.5.1-1) ...
Removing node-duplexify (3.6.1-1) ...
Removing node-ecc-jsbn (0.1.1-1) ...
Removing node-editor (1.0.0-1) ...
Removing node-encoding (0.1.12-2) ...
Removing node-stream-each (1.2.2-2) ...
Removing node-pump (3.0.0-1) ...
Removing node-end-of-stream (1.4.1-1) ...
Removing node-errno (0.1.4-1) ...
Removing node-escape-string-regexp (1.0.5-1) ...
Removing node-extend (3.0.2-1) ...
Removing node-extsprintf (1.3.0-1) ...
Removing node-find-up (2.1.0-1) ...
Removing node-forever-agent (0.6.1-1) ...
Removing node-from2 (2.3.0-1) ...
Removing node-fs-vacuum (1.2.10-2) ...
Removing node-fs-write-stream-atomic (1.0.10-4) ...
Removing node-get-caller-file (1.0.2-1) ...
Removing node-get-stream (3.0.0-1) ...
Removing node-getpass (0.1.7-1) ...
Removing node-write-file-atomic (2.3.0-1) ...
Removing node-sha (2.0.1-1) ...
Removing node-graceful-fs (4.1.11-1) ...
Removing node-har-schema (2.0.0-1) ...
Removing node-supports-color (4.4.0-2) ...
Removing node-has-flag (2.0.0-1) ...
Removing node-isurl (1.0.0-1) ...
Removing node-has-to-string-tag-x (1.4.1+dfsg-1) ...
Removing node-has-symbol-support-x (1.4.1+dfsg-1) ...
Removing node-has-unicode (2.0.1-2) ...
Removing node-hosted-git-info (2.7.1-1) ...
Removing node-iconv-lite (0.4.13-2) ...
Removing node-iferr (1.0.2-1) ...
Removing node-import-lazy (3.0.0.REALLY.2.1.0-1) ...
Removing node-unique-filename (1.1.0+ds-2) ...
Removing node-imurmurhash (0.1.4-1) ...
Removing node-ini (1.3.5-1) ...
Removing node-lcid (1.0.0-1) ...
Removing node-invert-kv (1.0.0-1) ...
Removing node-is-npm (1.0.0-1) ...
Removing node-is-object (1.0.1-1) ...
Removing node-is-plain-obj (1.1.0-1) ...
Removing node-is-retry-allowed (1.1.0-1) ...
Removing node-is-stream (1.1.0-1) ...
Removing node-is-typedarray (1.0.0-2) ...
Removing node-which (1.3.0-2) ...
Removing node-isexe (2.0.0-4) ...
Removing node-isstream (0.1.2+dfsg-1) ...
Removing node-jsbn (1.1.0-1) ...
Removing node-json-parse-better-errors (1.0.2-2) ...
Removing node-json-schema (0.2.3-1) ...
Removing node-json-stable-stringify (1.0.1-1) ...
Removing node-json-stringify-safe (5.0.1-1) ...
Removing node-jsonify (0.0.0-1) ...
Removing node-jsonstream (1.3.2-1) ...
Removing node-jsonparse (1.3.1-6) ...
Removing node-lazy-property (1.0.0-3) ...
Removing node-locate-path (2.0.0-1) ...
Removing node-lockfile (1.0.4-1) ...
Removing node-lowercase-keys (1.0.0-2) ...
Removing node-lru-cache (5.1.1-4) ...
Removing node-mem (1.1.0-1) ...
Removing node-mime-types (2.1.21-1) ...
Removing node-mimic-fn (1.1.0-1) ...
Removing node-mimic-response (1.0.0-1) ...
Removing node-minimist (1.2.0-1+deb10u1) ...
Removing node-mkdirp (0.5.1-1) ...
Removing node-promzard (0.3.0-1) ...
Removing node-read (1.0.7-1) ...
Removing node-mute-stream (0.0.8-1) ...
Removing node-node-uuid (3.3.2-2) ...
Removing node-npm-run-path (2.0.2-2) ...
Removing node-oauth-sign (0.9.0-1) ...
Removing node-object-assign (4.1.1-2) ...
Removing node-opener (1.4.3-1) ...
Removing node-osenv (0.1.5-1) ...
Removing node-p-cancelable (0.3.0-1) ...
Removing node-p-timeout (1.2.0-1) ...
Removing node-p-finally (1.0.0-2) ...
Removing node-p-locate (2.0.0-1) ...
Removing node-p-limit (1.1.0-1) ...
Removing node-path-exists (3.0.0-1) ...
Removing node-path-is-inside (1.0.2-1) ...
Removing node-performance-now (2.1.0+debian-1) ...
Removing node-url-parse-lax (1.0.0-1) ...
Removing node-prepend-http (2.0.0-1) ...
Removing node-promise-inflight (1.0.1-1) ...
Removing node-proto-list (1.2.4-1) ...
Removing node-prr (1.0.1-1) ...
Removing node-tough-cookie (2.3.4+dfsg-1) ...
Removing node-punycode (2.1.1-2) ...
Removing node-qs (6.5.2-1) ...
Removing node-qw (1.0.1-1) ...
Removing node-require-directory (2.1.1-1) ...
Removing node-require-main-filename (1.0.1-1) ...
Removing node-resolve-from (4.0.0-1) ...
Removing node-retry (0.10.1-1) ...
Removing node-tunnel-agent (0.6.1-1) ...
Removing node-semver-diff (2.1.0-2) ...
Removing node-semver (5.5.1-1) ...
Removing node-set-blocking (2.0.0-1) ...
Removing node-shebang-command (1.2.0-1) ...
Removing node-shebang-regex (2.0.0-1) ...
Removing node-signal-exit (3.0.2-1) ...
Removing node-slash (1.0.0-1) ...
Removing node-slide (1.1.6-2) ...
Removing node-sorted-object (2.0.1-1) ...
Removing node-validate-npm-package-license (3.0.1-1) ...
Removing node-spdx-correct (1.0.2-1) ...
Removing node-spdx-expression-parse (1.0.4-1) ...
Removing node-spdx-license-ids (1.2.2-1) ...
Removing node-ssri (5.2.4-2) ...
Removing node-stream-iterate (1.2.0-4) ...
Removing node-stream-shift (1.0.0-1) ...
Removing node-strip-eof (1.0.0-2) ...
Removing node-strip-json-comments (2.0.1-2) ...
Removing node-text-table (0.2.0-2) ...
Removing node-through (2.3.8-1) ...
Removing node-timed-out (4.0.1-4) ...
Removing node-tweetnacl (0.14.5+dfsg-3) ...
Removing node-typedarray (0.0.6-1) ...
Removing node-uid-number (0.0.6-1) ...
Removing node-unpipe (1.0.0-1) ...
Removing node-url-to-options (1.0.1-1) ...
Removing node-uuid (3.3.2-2) ...
Removing node-which-module (2.0.0-1) ...
Removing node-wide-align (1.1.0-1) ...
Removing node-xdg-basedir (3.0.0-1) ...
Removing node-xtend (4.0.1-2) ...
Removing node-y18n (3.2.1-2) ...
Removing node-yallist (3.0.3-1) ...
Removing node-run-queue (1.0.3-1) ...
Removing node-aproba (1.2.0-1) ...
Removing node-assert-plus (1.0.0-1) ...
Removing node-rimraf (2.6.2-1) ...
Removing node-glob (7.1.3-2) ...
Removing node-minimatch (3.0.4-3) ...
Removing node-brace-expansion (1.1.8-1) ...
Removing node-balanced-match (0.4.2-1) ...
Removing node-string-width (2.1.1-1) ...
Removing node-wcwidth.js (1.0.0-1) ...
Removing node-defaults (1.0.3-1) ...
Removing node-clone (2.1.2-1) ...
Removing node-concat-map (0.0.1-1) ...
Removing node-readable-stream (2.3.6-1) ...
Removing node-core-util-is (1.0.2-1) ...
Removing node-fs.realpath (1.0.0-1) ...
Removing node-inflight (1.0.6-1) ...
Removing node-inherits (2.0.3-1) ...
Removing node-isarray (2.0.4-1) ...
Removing node-once (1.4.0-3) ...
Removing node-path-is-absolute (1.0.0-1) ...
Removing node-process-nextick-args (2.0.0-1) ...
Removing node-string-decoder (1.2.0-1) ...
Removing node-safe-buffer (5.1.2-1) ...
Removing node-util-deprecate (1.0.2-1) ...
Removing node-wrappy (1.0.2-1) ...
Removing node-strip-ansi (4.0.0-1) ...
Removing node-ansi-regex (3.0.0-1) ...
Removing nodejs (10.23.1~dfsg-1~deb10u1) ...
(Reading database ... 14507 files and directories currently installed.)
Purging configuration files for npm (5.8.0+ds6-4+deb10u2) ...

##### 一度ログインしなおす #######

# npm run dev   # いざコンパイル

> @ dev /var/www/vue-laravel-spa
> npm run development


> @ development /var/www/vue-laravel-spa
> mix

    Additional dependencies must be installed. This will only take a moment.

    Running: npm install vue-loader@^15.9.5 --save-dev --legacy-peer-deps

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.1 (node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.1: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

    Finished. Please run Mix again.


# npm run dev   # againとのことなので

> @ dev /var/www/vue-laravel-spa
> npm run development


> @ development /var/www/vue-laravel-spa
> mix

99% done plugins BuildOutputPlugin



   Laravel Mix v6.0.10   


✔ Compiled Successfully in 16791ms
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────┐
│                                                                                                                                  File │ Size    │
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────┤
│                                                                                                                            /js/app.js │ 1.4 MiB │
│                                                                                                                           css/app.css │ 179 KiB │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────┘

成功しました
/public/js/app.js/public/css/app.cssが生成されました

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

ポートフォリオ ー店舗管理システム作ってみた

初めに

バックエンドをLaravel,フロントエンドをVue.jsを用いて実装しています。
この記事ではアプリ開発の説明や工夫した点を記載したいと思います。

アプリの概要

実際に飲食店舗の従業員は活用することをイメージしながら作成した店舗管理システムです。

・店長の事務業務負荷
・実際に生じている店舗の問題点

を解決できるようにすることをコンセプトとして作成しました。
「Cafe de Drip」という喫茶店で活用されることを想定しています。

アプリURL:https://cafe-de-drip.herokuapp.com/
※ユーザー認証が必要なので閲覧できません....。

GitHub:https://github.com/Tanaka-Kizuki/Store-management-system

↓ユーザー認証後のホーム画面
Cafe de Drip ホーム画面.png

実際に店舗で起きている問題点

◉勤怠管理システム(打刻式)がなくタイムカードもしくはシステム上に手打ち
 →店長がシステム上に勤怠入力もしくは実績と入力に相違がないか確認・承認作業

◉ノートを使った共有事項の伝達
 →ノートを手書きで書く作業負荷

◉日々の発注業務
 →発注が出来る能力者が限られており、休みの日でも出勤もしくは遠隔発注

上記問題点解決策(具体的なアプリ実装・機能)

◉勤怠管理システムの導入
スクリーンショット 2021-01-23 18.03.23.png

◉掲示板形式の連絡ノート
スクリーンショット 2021-01-23 18.36.22.png

◉店舗在庫を入力することで必要数が発注される発注システム
スクリーンショット 2021-01-23 18.38.04.png

機能一覧

◉ユーザー管理登録
 ○管理者権限
 ○新規登録(管理者のみ有効)
 ○ログイン、ログアウト機能
◉勤怠管理システム
 ○出退勤
 ○休憩開始、終了
 ○出退勤時刻、休憩時間より勤務時間の算出(15分繰り上げ)
 ○ユーザーの勤怠実積照合(ログイン従業員の指定月の勤務実積表示)
 ○日次勤怠照合(指定日に勤務していた従業員、勤務時間等表示)
◉コミュニケーションノート
 ○新規作成
 ○編集
 ○削除
◉発注システム
 ○アイテムの追加、編集
 ○発注(データベース登録)
 ○発注履歴の表示

使用技術

◉フロントエンド
 ○HTML/CSS
 ○JavaScript
 ○Vue.js 4.3.1
◉バックエンド
 ○PHP 7.4.9
 ○Laravel 7.27.0
◉インフラ
 ○mysql 8.0.21

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

Laravelにおけるテストについて

ユニットテストとは?

関数やメソッドごとに行うテスト。単体テストともいう。
(逆にプログラム全体のテストを結合テストという)

PHPUnitとは?

Laravelに標準で用意されている単体テストツール。
コマンドを打つことですべてのユニットテストを自動で実行してくれる

ユニットテストのメリット

1. 問題の早期発見
他の関数との結合度が高い場合などはユニットテストですべてを解決できるわけではないが、関数単体ではテストを行うことができる。

2. ツールを使うことでテストを自動化できる
PHPUnitを使用することでコマンドを打つことで複数の単体テストを同時に実行してくれ、作業量が少なくて済む。

3. テスト自体をコードとして残しておくこができる
ユニットテストはコードを書いて実行するので、コードを残しておけば同じテストを何度も利用することができる。

テストの種類

テストには、UnitTest, FeatureTest, BrowserTestが存在する

UnitTest

/tests/Unit配下にテストを配置する。
一番粒度の細かなテスト。
Model, Policy, Middlewareなどのクラス一つにテストファイル一つが対応するように作成する。
その対象クラスのメソッド一つ一つを検証していく。

FeatureTest

/tests/Feature配下にテストを配置する。
UnitTestより粒度が大きなテスト。

1つのHTTPリクエスト単位でテストを実行する。
= ルーティングごとにテストファイルを作成する
= コントローラのアクションメソッドごとにテストする

UnitTestでクラス内部を細かくテストし、FeatureTestでコントローラの動き全体(つまりリクエストを受けてからレスポンスを返すまで)をテストする。

1つのコントローラアクションに対応したテストクラス(ファイル)の中で、
・ログインした状態でアクセス時の動作
・未ログインアクセス時の動作
・検索パラメータ付けたアクセス時の動作
・ユーザに特定ロールを付けた状態の動作
など1つ1つのケースをテストケースとしてコードを書く。

BrowserTest

/tests/Browser配下にテストを配置する。
実際にブラウザを使って画面にリクエスト、
ボタンをクリック、
マウスホバー、
フォーム送信などの操作をするテストをコードで実行できる。

FeatureTestにさらに
・複数HTTPリクエストの遷移
・画面操作時のJsの動作
のような観点を加えてテストできるイメージ。

Unit、FeatureはPHPUnitで動作するテストなのに対し、
BrowserTestはlaravel/duskというパッケージを使ったテスト。

テストをしてみる

FeatureテストとUnitテストを試しながらPHPUnitの基本的な使い方を学んでいく。

テスト対象のコードの確認

テストの対象となるルーティング、コントローラ、モデルを例にとり確認しておく。
本に関するアプリケーション。

マイグレーション

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateBooksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('books',function(Blueprint $table){
            $table->id();
            $table->string('author');
            $table->string('title');
            $table->string('description');
            $table->integer('status')->default(\App\Book::Available);
            $table->integer('rent_count')->default(0);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('books');
    }

ルーティング

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::resource('books','BookController');

コントローラ

<?php

namespace App\Http\Controllers;

use App\Book;
use Illuminate\Http\Request;

class BookController extends Controller
{
    public function index()
    {
        returnBook::all();
    }
    public function store(Request $request)
    {
        $book = newBook();
        $book->title = $request->title;
        $book->author = $request->author;
        $book->description = $request->description;
        $book->save();
        return $book;
    }
}

モデル

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{

}

まずはテスト用データベースの作成

MySQLやPostgresとは別のインメモリのSQLiteデータベースを使用することで、テストするごとにデータが削除され無駄なデータが保存されない。

まず config/database.php の connections に以下の接続情報を追加する。

database.php

'sqlite_testing' => [
    'driver' => 'sqlite',
    'database' => ':memory:',
    'prefix' => '',
],

そしてphpunit.xmlで、タグの中に、タグを使用すると、テスト時にenvファイルの設定を上書きすることができる。つまりテストのときは別のデータベースを利用することができるようになる。

<php>
   <server name="APP_ENV"value="testing"/>
   ・・・省略・・・
   <!-- 以下を追記 -->
   <server name="DB_CONNECTION" value="sqlite_testing"/>
</php>

Featureテスト

Featureテストを用いてWebAPIのテストコードを実装してみる。

テストファイルの作成

$php artisan make:testBookTest

tests/Featureディレクトリに、テストコードの雛形が作成される。ここにテストコードを実装していく。

テストコードを記述

以下は「/api/books」に正しくアクセスできるかを検証するコード

<?php

namespaceTests\Feature;

useIlluminate\Foundation\Testing\RefreshDatabase;
useTests\TestCase;

classBookTestextendsTestCase
{
    useRefreshDatabase;

    publicfunctiontestFetchBook()
    {
        $response=$this->get('/api/books');

        $response->assertStatus(200);
    }
}

getメソッドを使用することで第1引数に指定したパスにリクエストでき、戻り値がそのレスポンスとなる。
postメソッドでPOSTリクエストをすることも可能。その場合第2引数に送信するデータを配列形式で設定する。

テストの検証

テストコード内のアサーションで検証することができる。

例1)ステータスコードの検証

$response->assertStatus(200);

例2)JSONパラメータの検証

assertJsonFragment()メソッドを使用すると、引数に渡したJSONが、レスポンスに含まれているか検証する。

$response->assertJsonFragment([
    'title'=>'Laravel入門',
    'author'=>'Lara太郎',
    'description'=>'Laravel入門書です。'
]);

テストの実行

以下のコマンドで実行可能

$php artisan test

Unitテスト

Unitテストを使用して、単体テストを実装してみる。

テスト対象の追加

先ほどのBookモデルに、本の貸し出し・返却用のメソッドを追加する。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    public const Available = 1;
    public const LoanedOut = 2;

    public function checkOut() {
        $this->increment('rent_count',1);
        $this->status=self::LoanedOut;
        $this->save();
    }

    public function returnBook(){
        $this->status=self::Available;
        $this->save();
    }
}

Factory

Factoryとは?

Factoryはダミーレコードを生成できる機能。
以下の型によってダミーレコードとなるデータを生成する。

「$factory->define」というメソッドにて、モデル(ダミーレコード)を生成する処理内容を設定する。

$factory->define(モデルクラス, function (Faker $faker) {

   処理を用意する

   return [データ配列];

});


defineメソッドは、第1引数に生成するモデルクラス、第2引数にクロージを用意する。
クロージャにはFaker\Genetaterクラスのインスタンスが渡されており、これを利用してフェイクデータを用意し、レコードに入れる値を連想配列にまとめてreturnする。
このreturnされた値を使ってモデルが生成され、データベースに保存される。

Factoryを使用する

今回は、あらかじめ貸し出す本を登録しておくため、Factoryを使用して、booksテーブルにインサートしていく。
まず、Factoryファイルを作成。

$php artisan make:factory BookFactory --model=Book

--modelオプションで、ファクトリで生成するモデルを指定する。ここで指定したモデルが、ファクトリ内で定義される。
このモデルクラスを指定しないと、ファクトリでデータを生成しようとしても、エラーとなるため、必ず指定する。

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Book;
use Faker\Generator as Faker;

$factory->define(Book::class, function(Faker $faker){
    return[
        'author'=>$faker->name,
        'title'=>$faker->title.$faker->randomNumber().$faker->time(),
        'description'=>$faker->paragraph,
        'status'=>$faker->numberBetween(1,2),
        'rent_count'=>$faker->randomNumber()
    ];
});

カラム名をキーとして値を代入していく。$fakerとしている箇所はランダムな値が入る。

fakerの主なメソッド

Fakeメソッド 内容
randomNumber() ランダムな整数値を生成
numberBetween(min, max) min~maxまでの整数値を生成
email ランダムなメールアドレスを生成
phone ランダムな電話番号を生成
name ランダムな人物名
sentence() ランダムな1文を生成
paragraph ランダムな1段落の文章を生成

ユニットテストの実装

ユニットテストのファイルを作成する。オプションで--unitをつけることでtests/Unitディレクトリに作成するファイルが格納される。

$php artisan make:test BookTest --unit
<?php

namespace Tests\Unit;


use App\Book;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;


class BookTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp():void
    {
        parent::setUp();
        // BookFactoryを使用してbookを100レコード用意する
        for($i=0; $i<100; $i++){
            factory(Book::class)->create();
        }
    }

    /**
     * 本の貸し出しテスト
     */
    public function testCheckOut()
    {
        $book = Book::where('status',Book::Available)->first();
        $count = $book->rent_count;
        $book->checkOut();

        // 貸し出し回数が、元の+1になっていることを確認
        $this->assertEquals($book->rent_count,$count+1);
        // ステータスが貸し出し中になっていることを確認
        $this->assertEquals($book->status,Book::LoanedOut);
    }

    /**
     * 本の返却テスト
     */
    public function testReturnBook()
    {
        $book = Book::where('status',Book::Available)->first();
        $count = $book->rent_count;
        $book->returnBook();

        // 返却時は、貸し出しが変化していないことを確認
        $this->assertEquals($book->rent_count,$count);
        // ステータスが利用可能になっていることを確認
        $this->assertEquals($book->status,Book::Available);
    }
}

(コード解説)

RefreshDatabaseをトレイトしておくと、テスト前に未実行のマイグレーションファイルを実行し、テスト後データベースを初期化してくれる。

use RefreshDatabase;

setUpメソッドはテストが始まる前に必ず呼ばれるメソッドのため、ここでfactoryを発動しダミーレコードがテスト前にセッティングされるように設定する。

protected function setUp():void
    {
        parent::setUp();
        // BookFactoryを使用してbookを100レコード用意する
        for($i=0; $i<100; $i++){
            factory(Book::class)->create();
        }
    }

factory(モデル名::class)->createで実際にダミーレコードを生成することができる。
つまり、上記で書いたfactoryファイルはダミーなデータを準備する段階で実際にダミーレコードを生成するのはこの宣言があって初めて実行される。

factory(Book::class)->create();

ここでは設定されていないが、tearDown()メソッドは、テスト終了時に毎度呼ばれるメソッドで、各テスト後の後処理に使用する。

まとめ

一見複雑に見えるが、やっていることは

1. テストファイルの作成
2. テストしたいデータをテストファイル内で準備する
3. 「asser~メソッド」で検証する
4. テストの実行

ただこれだけの実はシンプルな処理しかしていない。
コードが長くなって分かりづらいかもしれないが、上の4つに分解すると理解しやすい。

参考

Laravelでテストコードを書くには? Featureテスト/Unitテスト

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

Laravel 7以降のBladeコンポーネントはどう便利になったか

Laravel 7で、Bladeコンポーネントが拡張された。最初知ったときは、わざわざHTML風の
文法になっているのがいまいちだと感じたが、よく調べてみるとしっかりとした意図のあ
る仕様で、便利そうだった。

どう変わったのか、またどう便利になったのか、具体的に紹介する。

参考:
リリースノート 7.x Laravel の"Bladeコンポーネントタグと向上"以下。

変更点

ほかにも細かいものはあるが、主に以下の3つが重要だろう。

1. <x-.../>とHTMLタグのように呼び出せるようになった

HTMLタグのように書くことができる。この呼び出し方では、自動的にresources/views/components以下のビューがコンポーネントとして呼び出される。

渡すデータも、HTML属性のように表記できる。PHPの変数を渡したい場合は、先頭に:を付加する。

{{-- Laravel 6まで --}}
@component('form.input.number', ['name' => 'foo', 'min' => 0, 'max' => $max])
@endocmponent
{{-- Laravel 7から --}}
<x-input.number name="foo" min="0" :max="$max" />

あるいは、

<x-input.number name="foo" min="0" :max="$max">
</x-input.number>

2. HTML属性を簡単に渡せる"属性バッグ"が追加された

渡した変数を{{ $attributes }}だけで表示できる。下記の例のようにオプションとして使う場合にはより有用だ。

resources/views/form/input/number.blade.php
{{-- Laravel 6まで --}}
<input type="number" name="{{ $name }}" @isset ($min) min="{{ $min }}" @endisset @isset ($max) max="{{ $max }}"@endisset value="{{ old($name) }}">
resources/views/components/input/number.blade.php
{{-- Laravel 7から --}}
<input type="number" {{ $attributes }} value="{{ old($name) }}">

3. Bladeビューとしてではなく、PHPのクラスとしてコンポーネントを表現するコンポーネントクラスを作れるようになった

これにより、コンポーネントが受け取るデータを明示することができるようになったのが非常に強力だ。

ほかにも、コンポーネントクラスに実装したメソッドをビュー側で変数として使用することができる。

app/View/Components/Input/Number.php
<?php

namespace App\View\Components\Input;

use Illuminate\View\Component;

class Number extends Component
{
    /** @var string */
    public $name;

    /**
     * インスタンスを生成する
     *
     * @param  string $name
     * @return void
     */
    public function __construct(string $name)
    {
        $this->name = $name;
    }

    /**
     * ビューを取得する
     *
     * @return \Illuminate\Contracts\View\View
     */
    public function render()
    {
        return view('components.input.number'); # あるいは、文字列をそのまま返すこともできる
    }
}

まとめ: どう便利になったのか

上記のサンプルコードを見れば大体わかると思うが、もう少し説明すると、

  1. 呼び出し側はHTML風の文法のおかげで、短くわかりやすく書けるようになった。
  2. コンポーネント側は属性バッグのおかげで、オプションの属性を短くわかりやすく書けるようになった。
  3. コンポーネントクラスのおかげで、コンポーネントが受け取るデータを型を含めて明示することができるようになった。
  4. また、関連するロジックをコンポーネントクラスに入れることができるようになった。

といったところだろうか。

ただ個人的には、コンポーネントクラスはそこまで必要ないと思っている。追加の属性値に関しては属性バッグでシンプルに書けるようになり、また紹介しなかったが@props()を使うことでも受け取るデータの名前に関しては明示できるようになっているためだ。

どちらにしてもメリットが強力で、デメリットも特に見当たらないため、Laravel 7以上が使える環境であれば、Bladeコンポーネントの新機能を使わない理由はなさそうだ。

参考:
Bladeテンプレート 7.x Laravel の"コンポーネント"以下。

この記事のライセンス

クリエイティブ・コモンズ・ライセンス
この文書はCC BY(クリエイティブ・コモンズ表示4.0国際ライセンス)で公開する。

この文書内のサンプルコードはMITライセンスで公開する。

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

laravel with で limit take

laravel で with を使って関連モデルを読み込んだとき、
limit , take で取得数を制限したい場合がある

しかし、普通にやっても動かないので、

https://github.com/staudenmeir/eloquent-eager-limit

を使おう

インストール

composer require staudenmeir/eloquent-eager-limit:"^1.0"

database.php
//以下の箇所をすべて false に変更
'strict' => false,

キャッシュを消して有効に

php artisan config:clear
php artisan config:cache

使い方

Autotweet -> Social -> Answer

って感じで関連付けしたとき、
Answerを3件だけ取得したい

Social.php

class Social extends Model
{
    use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;

    public function answer()
    {
        return $this->hasMany('App\Answer');
    }


Answer.php
class Answer extends Model
{

    use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;

こんな感じ

使い方は

HogeController.php
$tweet = Autotweet::query()//単数形 User

    ->with([
        'social' => function ($q)  {
            $q->with(
                [
                    'answer' => function ($q2)  {
                        $q2->orderBy('id','DESC')->take(3);//3件のみ取得
                    },
                ]
            );
        },
    ])

    ->get();

で使えます。

注意点

・database.php の strict を変更すること
・関連付けするモデル(この場合はSocial.phpとAnswer.php)両方に
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
を設定することが大事

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

【PHP】Docker環境にphpMyadminを導入する

手順

docker-compose.ymlにphpMyadominのコンテナを追記します。

docker-compose.yml
#docker-compose.ymlのバージョン
version: "3.8"
#docker volumeの設定
volumes:
  docker-volume:

#services以下に各コンテナの設定を書く
services:
  #Webサーバーのコンテナ
  web:
    image: nginx:1.18
    ports:
      - "8000:80"
    depends_on:
      - app
    volumes:
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
      - .:/var/www/html
  #アプリケーションのコンテナ
  app:
    build: ./docker/php
    volumes:
      - .:/var/www/html
  #データベースのコンテナ
  db:
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: db_name
      MYSQL_USER: db_user
      MYSQL_PASSWORD: db_password
      MYSQL_ROOT_PASSWORD: root
      TZ: "Asia/Tokyo"
    volumes:
      - docker-volume:/var/lib/mysql
  # phpMyadominのコンテナ作成
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    depends_on:
      - db
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOSTS=db
      - PMA_USER=db_user
      - PMA_PASSWORD=db_password
    ports:
      - "8080:80"
    volumes:
      - ./docker/phpmyadmin/sessions:/sessions

コードの下部にある# phpMyadominのコンテナ作成からが追記する箇所です。
portsを8080に設定しているので、localhost:8080でphpmyadminの管理画面にアクセスできるように設定しています。
また、volumesにある./docker/phpmyadmin/sessions:/sessionsではセッション情報をボリュームに設定して永続化するようにします。

補足

参考までに作ってみた環境

https://github.com/yuyaamano23/Laravel_Docker_practice/tree/github-open




ちなみに僕は以下の記事を参考にphp+mysql+nginxの環境を構築しました。神記事です。:relaxed:
絶対に失敗しないDockerでLaravel+Vueの実行環境(LEMP環境)を構築する方法〜前編〜
絶対に失敗しないDockerでLaravel6.8+Vueの実行環境(LEMP環境)を構築する方法〜後編〜
Docker Composeでphpmyadminを導入する

各々構築したDocker環境のプロジェクトにあるdocker-compose.ymlnに追記していただければ良いと思います。

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