20210115のlaravelに関する記事は10件です。

Laravel × Dacapo データベースマイグレーションサポートツールの使い方

laravel-dacapo.png

ダカーポとは

https://github.com/ucan-lab/laravel-dacapo

Laravelマイグレーションのサポートライブラリです。
データベースのテーブル定義をYAMLファイル(スキーマファイル)で管理し、マイグレーションファイルの生成を行います。

※初期の開発時期に利用されることを想定しています。

2021.01.11 v4.0.0 リリース!

v3.0から1年の時を経て、ついにバージョンv4.0をリリース致しました!?‍♂️

以前の古いコードをすべて破棄して新しく書き直してます。
少し挙動が異なる部分もあるのでこの機会に改めて使い方をご紹介します。

以前のダカーポの記事

ダカーポの由来

ダ・カーポ(da capo)は音楽用語で「始めに戻って繰り返す」という意味があります。

PHPのパッケージ管理ツールであるComposerも作曲家という音楽用語であり、マイグレーションファイルをすべて削除して、最初から生成し直すことからピッタリな名前だなと思いました。

ダカーポを作った理由

  • @mpyw さんのLTに感化された
  • SymfonyのようにYAMLでテーブル定義するツールが欲しかった
  • ファイル名、クラス名、upメソッド、downメソッドを書くのが面倒だった

デフォルトのマイグレーションのツラミ

  • make:migration で自動生成された日付がバラバラで見にくい
  • make:migration のコマンドの実行時間が遅い
  • テーブル定義 → インデックス定義 → 外部キー制約の順に定義する手間
  • ゴミマイグレーションが残る
    • 最終的なテーブル構成はDBを直接見ないと把握しづらい

ダカーポの歴史

  • 2018.11.06 v0.0.1 4files 初回リリース
  • 2019.08.22 v1.0.0 22files 1ファイルで収まらなくなり、すべて書き直し
  • 2019.08.22 v2.0.0 24files schema.ymlを分割可能、全カラムタイプに対応
  • 2019.11.10 v3.0.0 35files 細々とバグFIXを続ける
  • 2021.01.11 v4.0.0 144files メタプロでメンテしづらく、すべて書き直し

v1.0では4ファイルだけで書いてました...1日で主機能を書き上げたのでとてもFatなソースコードになってましたね。
それに比べて最新のv4.0ではファイル数が36倍に増えましたww
今後のバージョンアップに備えてLaravelでサポートされているカラムタイプやカラム修飾子をすべてクラスで管理するようにしました。

ダカーポのインストール

$ composer require --dev ucan-lab/laravel-dacapo

ダカーポの執筆時バージョン

  • Dacapo: 4.0.1

ダカーポのサポート

  • PHP 7.4 以降
  • Laravel 6.x 以降
  • MySQL
  • PostgreSQL
  • SQL Server(サポート対象外)
  • SQLite(サポート対象外)

ダカーポの初期化

$ php artisan dacapo:init

dacapo:init Artisanコマンドを使用して、ダカーポの初期化を行います。

database/schemas/default.yml が生成されます。
また、database/migrations ディレクトリ内のマイグレーションファイルも削除されます。

--no-clear オプション

$ php artisan dacapo:init --no-clear

database/migrations ディレクトリ内のマイグレーションファイルの削除は行いません。

--laravel6, --laravel7 オプション

$ php artisan dacapo:init --laravel6
$ php artisan dacapo:init --laravel7
$ php artisan dacapo:init --laravel8 # default

それぞれLaravel6, Laravel7のマイグレーションファイルを生成します。

デフォルトでは、Laravel8のマイグレーションファイルを生成します。

それぞれのバージョンで微妙にテーブル定義内容が異なるので、テンプレートを分けています。

database/schemas/default.yml

database/schemas/default.yml には、Laravelフレームワークにて予め用意されている(database/migrations)マイグレーション3ファイルのテーブルの定義しています。

database/schemas/default.yml
users:
  columns:
    id: bigIncrements
    name: string
    email:
      type: string
      unique: true
    email_verified_at:
      type: timestamp
      nullable: true
    password: string
    rememberToken: true
    timestamps: true

password_resets:
  columns:
    email:
      type: string
      index: true
    token: string
    created_at:
      type: timestamp
      nullable: true

failed_jobs:
  columns:
    id: true
    uuid:
      type: string
      unique: true
    connection: text
    queue: text
    payload: longText
    exception: longText
    failed_at:
      type: timestamp
      useCurrent: true

ダカーポの実行

$ php artisan dacapo

database/schemas/*.yml からテーブル構成を読み込んで database/migrations/1970_01_01_*.php のLaravelマイグレーションファイルを生成します。
また、ダカーポで生成された古いマイグレーションファイルはコマンド実行の都度削除されます。

続けて、 php artisan migrate:fresh コマンドが実行されます。
すべてのテーブルの削除、及びマイグレーションの実行が行われます。

--seed オプション

$ php artisan dacapo --seed

php artisan migrate:fresh に続けて
php artisan db:seed コマンドが実行されます。

--no-migrate オプション

$ php artisan dacapo --no-migrate

スキーマファイルからマイグレーションファイルを実行したあと、 php artisan migrate:fresh コマンドを実行しまいオプションです。

--refresh オプション

$ php artisan dacapo --refresh

ロールバック処理が動作するか、動作確認のためのオプションです。

スキーマの定義フォーマット

テーブル名:
  columns:
    カラム名: カラムタイプ
    カラム名:
      type: カラムタイプ
      args: カラムタイプの引数(任意)

  indexes:
    - columns: [カラム名]
      type: [インデックス修飾子]
      name: インデックス名(任意)

  foreign_keys:
    - columns: [カラム名]
      references: [カラム名]
      on: テーブル名

スキーマの定義

カラムの定義

database/schemas/default.yml
users:
  columns:
    # カラムタイプのみ指定する場合
    votes: integer
    # カラムタイプに引数を指定する場合
    amount:
      type: double
      args: 8, 2

上記のYAMLを定義して php artisan dacapo を実行すると、下記のマイグレーションファイルが出力されます。

database/migrations/1970_01_01_000001_create_users_table.php
<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->integer('votes');
            $table->double('amount', 8, 2);
            $table->string('email')->nullable();
        });
    }

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

利用可能なカラムタイプ

*.columns.*.type に指定できるカラムタイプです。
Laravelマイグレーションで利用可能なカラムタイプはすべて対応してます。

bigIncrements, bigInteger, binary, boolean, char, dateTime, dateTimeTz, date, decimal, double, enum, float, foreignId, geometryCollection, geometry, id, increments, integer, ipAddress, jsonb, json, lineString, longText, macAddress, mediumIncrements, mediumInteger, mediumText, morphs, multiLineString, multiPoint, multiPolygon, nullableMorphs, nullableTimestamps, nullableUuidMorphs, point, polygon, rememberToken, set, smallIncrements, smallInteger, softDeletes, softDeletesTz, string, text, timestamps, timestampsTz, timestamp, timestampTz, time, timeTz, tinyIncrements, tinyInteger, unsignedBigInteger, unsignedDecimal, unsignedInteger, unsignedMediumInteger, unsignedSmallInteger, unsignedTinyInteger, uuidMorphs, uuid, year

カラム修飾子

上記リストのカラムタイプに加え、データベーステーブルにカラムを追加するときに使用できるカラム「修飾子」もあります。

users:
  columns:
    email:
      type: string
      nullable: true

上記のYAMLを定義して php artisan dacapo を実行すると、下記のマイグレーションファイルが出力されます。

database/migrations/1970_01_01_000001_create_users_table.php
<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->string('email')->nullable();
        });
    }

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

利用可能なカラム修飾子

alwaysModifier, autoIncrementModifier, charsetModifier, collationModifier, commentModifier, defaultModifier, defaultRawModifier, fromModifier, generatedAsModifier, indexModifier, nullableModifier, storedAsModifier, uniqueModifier, unsignedModifier, useCurrentModifier, useCurrentOnUpdateModifier, virtualAsModifier

利用不可なカラム修飾子

下記のカラム修飾子はダカーポではサポート対象外となっております。

after, change, first, renameColumn, dropColumn, dropMorphs, dropRememberToken, dropSoftDeletes, dropSoftDeletesTz, dropTimestamps, dropTimestampsTz, constrained, onUpdate, onDelete

インデックス修飾子

database/schemas/default.yml
users:
  columns:
    id: bigIncrements
    name: string
    email: string

  indexes:
    - columns: [name, email]
      type: index
      name: users_name_index
  • 1970_01_01_000001_create_users_table.php
  • 1970_01_01_000002_create_users_index.php
    • インデックスの定義ファイルは 000002 のプレフィックスが付きます。
database/migrations/1970_01_01_000001_create_users_table.php
<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}
database/migrations/1970_01_01_000002_create_users_index.php
<?php

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

class CreateUsersIndex extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->index(['name', 'email'], 'users_name_index');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropIndex('users_name_index');
        });
    }
}

利用可能なインデックス修飾子

primary, unique, index, spatialIndex

外部キー制約

database/schemas/default.yml
users:
  columns:
    id: bigIncrements
    name: string
    email: string

posts:
  columns:
    id: bigIncrements
    user_id: unsignedBigInteger
    content: string

  foreign_keys:
    - columns: [user_id]
      references: [id]
      on: users
  • 1970_01_01_000001_create_users_table.php
  • 1970_01_01_000001_create_posts_table.php
  • 1970_01_01_000003_constraint_posts_foreign_key.php
    • 外部キーの定義ファイルは 000003 のプレフィックスが付きます。
database/migrations/1970_01_01_000001_create_users_table.php
<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}
database/migrations/1970_01_01_000001_create_posts_table.php
<?php

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

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('user_id');
            $table->string('content');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
database/migrations/1970_01_01_000003_constraint_posts_foreign_key.php
<?php

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

class ConstraintPostsForeignKey extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->foreign(['user_id'])->references(['id'])->on('users');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropForeign(['user_id']);
        });
    }
}

その他

通常のマイグレーションファイルと併用可能

$ php artisan make:migration create_flights_table

php artisan dacapodatabase/migrations ディレクトリ内のマイグレーションファイルが削除されますが、
ダカーポで生成されたファイルのみ削除されます。(1970_01_01 のプレフィックスが付いたファイルのみ)

YAMLで表現できないようなテーブル定義は通常のマイグレーションファイルを作成してください。

複数のスキーマファイルを利用可能

database/schemas/*.yml ファイルを読み込むので、YAMLを分けて定義できます。

  • database/schemas/user.yml
  • database/schemas/staff.yml

ユーザー関連のテーブル、スタッフ関連のテーブル等、グループ分けをしてテーブルを定義していくこともできます。

今後の予定

ざっくり今後のダカーポについて検討していることを書きます。
あくまで予定で、全機能実装できるかは未定です...。

v4.0

年末年始に一気に書き殴ったので、しばらくはリファクタリングに勤しみます。

新機能 v4.1

dacapo --mixin オプション

SQLiteは外部キー制約を書く場合は、テーブル定義と同じタイミングで実行する必要があるみたいです。
懸念点としては、制約を貼る順番によってはエラーになりそうなので生成順序を気にしないといけなさそう...?
難しそうなのでこのオプションの実装悩んでます。。

dacapo --squash オプション

Laravel8に搭載されたマイグレーションスカッシングのイメージです。
ただ、mysqldump コマンド入れてる必要があったり、.sql ファイルで出力されちゃったりと不満があります。

--squash オプションは1ファイルのマイグレーションファイルにまとめるオプションです。
これは需要ありそうかなと思ってるんですけどどうでしょうか??

新機能 v4.2

テンプレート生成するコマンド

$ php artisan dacapo:generate:model
$ php artisan dacapo:generate:factory
$ php artisan dacapo:generate:seeder
$ php artisan dacapo:generate:validation

スキーマYAMLから各種テンプレートを生成する機能です。
v3系には合ったのですが、バージョンアップの兼ね合いで一旦コマンドを削除しました。

v4.0系でも実装しようと思ったのですが、
Laravel8でモデルファクトリ書き方が丸っと変わったのでちょっと断念しました。

新機能 v4.3

データベースからスキーマYAMLを逆生成するコマンド

$ php artisan dacapo:db:import

この機能が欲しくてv4.0の書き直しをしたので、なんとしてでもこの機能は実装する!

新機能 v4.4

データベースとスキーマYAMLの差分からマイグレーションを生成するコマンド

$ php artisan dacapo:db:diff

import コマンドが実装できたら現行のテーブル構成とスキーマYAMLの差分ができたらいいなと思ってます。
これは実装難しそうなので悩んでます。

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

Laravel ウェブサイト サイバーセキュリティ#2 -SQLインジェクション-

概要

Laravelを用いたウェブサイトのサイバーセキュリティについて考察。
サイバーセキュリティに関して全く考えずにコーディングした後、「あれ、セキュリティのこと全く考えてないな」と気づいて調べてみたところ、結果的にlaravelフレームワークでほとんど対策できていた。

第二回は、SQLインジェクションディレクトリトラバーサル
参考: https://www.ipa.go.jp/security/vuln/websecurity.html

環境

  • Windows 10
  • PHP 8.0.0
  • laravel 8.16.1

SQLインジェクション

概要

データベースを操作するSQL文を操作し、データベースを不正利用する攻撃。
【流れ】
1. 攻撃者が、入力フォームにSQL文の一部を入力し送信する。
2. サイト内で、入力情報をもとにSQL文を処理する際、意図しないデータベース操作が行われてしまう。

脅威

  • 非公開データの流出
  • データの改ざん、消去
  • 不正ログイン

Laravelにおける対策

まずは、クエリビルダを使うことを考える。
クエリビルダを使うことによって、PDO(*1)パラメータによるバインディング(*2)が自動的に使用されることになるため、追加の対策は不要。
*1: PHP Data Objectsの略。データベースの違いを吸収してくれる。
*2: 命令の一部を変数にすること。

クエリビルダを使わず、生のSQL文を使用する場合は、SQL文の条件となるユーザからの入力値に対して、エスケープ処理を施すことが対策となる。ここでは、
' => ''
\ => \\
の変換を行えばよい。
こちらは、laravel特有ではなく、一般的なSQLインジェクション対策。

ディレクトリトラバーサル

概要

設計者が意図しないファイルにアクセスされる攻撃。

脅威

  • ファイルの不正閲覧、ダウンロード

Laravelにおける対策

まずは、外部パラメータをファイルパスとして指定しないようにする。

それが避けられない場合、固定ディレクトリ+ファイル名の構成にする。ファイル名の抽出は、basename関数を用いる。

さらに保険として、ログイン中のユーザIDなどで、適切なアクセス制限をかけると尚良い。

まとめ

XSSやCSRFと同じく、外部からの入力を直接埋め込まないことが基本的な考え方になる。
今回は、Laravel特有のクエリビルダやPHPのbaseline関数を使う方法を紹介した。

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

【Laravel】php artisan コマンド

Laravelで使う php artisanコマンド
artisan アルチザンと読むらしい。

アルチザンとは、 職人。技工。とかの意味らしい。

対話モード

$ php artisan tinker

これで対話モードができる。
データベースの中身などを調べるときに使える。

例えば,,,

User::all()

このように行えば、Userテーブルのデータを確認することができる。

マイグレーション

$ php artisan migrate

これで、マイグレーションの実行ができる.

マイグレーションのやり直し

$ php artisan migrate:fresh

これで、一旦全てのテーブルを削除しマイグレーションをやりなおすことができる。

seedデータの投入

$ php artisan db:seed

seedファイルで作成したデータをDBに保存する

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

laravel をブラウザで表示しようとしてcould not be opened in append mode: failed to open stream: Permission deniedとなった時の解決法

larval をローカル環境であれこれ編集しようとして、
途中経過をブラウザで表示しようとしていたのですが、

could not be opened in append mode: failed to open stream: Permission denied

とエラーが起きていつまでも解決しませんでした。
上記のエラーメッセージの手前に該当箇所のファイルの階層が示されており
そこの編集権限がない?といったメッセージ内容。

解決できそうな参考記事をあれこれあたってみても、

sudo chmod 777 storage -R  

と書かれていて、バカ正直にそのまま打ち込むと、
-R なんてファイルは存在しません。(No such file or directory) と出てくる。。。
そりゃそうか。

誰かこの先詰まった時の参考になれば良いと思い書き残しておきます。

・エラーの意味

Permission denied : 権限が拒否されました。
つまり何かしら権限を書き換える必要がありそう。

・どこの権限がない?
laravel プロジェクトが入っているXAMMP内の、

~/laravelプロジェクト名/strage/logs/laravel.log で編集権限がないと言われました。
larval 開発の最初って多分このエラーにぶち当たることが多いのか。。?

・やったこと
logsディレクトリ以下の権限を書き換えられるように以下のコードを
自分のディレクトリ名に合わせて実行(エラーで表示されたディレクトリ名を最後のファイル名除いてコピペ)

$ sudo chmod 777 /Applications/XAMPP/xamppfiles/htdocs/laravelプロジェクト名/strage/logs
→ 実行

これで権限の書き換えができるのでエラーが起きているファイルをリロード。
表示されました!

参考にさせていただいた記事:
http://www.thirtyfive.info/entry/2018/06/07/laravel%E3%81%AE%E8%B5%B7%E5%8B%95%E8%A8%AD%E5%AE%9A%E3%81%A8%E3%82%A8%E3%83%A9%E3%83%BC#%E3%82%A8%E3%83%A9%E3%83%BC%E3%83%AD%E3%82%B0%E3%81%A7failed-to-open-stream-Permission-denied-in-

めちゃくちゃスッキリした。。

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

laravel/uiを利用した際に発生したエラーの解決

現在、Laravel(ver6.20.9)を使って、個人でWebサービスを制作している者です。

Laravel6.xからBootstrapやVueなどがデフォルトでは含まれなくなったそうなので、それらをLaravelで使えるようにしてくれる「laravel/ui」をダウンロードすることにしました。

しかし、その過程で出たエラーに詰まったのでメモしていきたいと思います。
(といっても非常に簡単なことでした。笑)

laravel/uiのダウンロード

laravel/uiのダウンロードについては、以下を参考にしました。
laravel/uiの公式ドキュメント
Laravel/UIのインストール(Qiita記事)

自分なりに手順をまとめると、

ターミナル
①cdコマンドで、laravel/uiを利用したいディレクトリまで移動

②composer require laravel/ui "1.x" --dev
(composer必須)

③php artisan ui bootstrap
(Bootstrapを使う場合)

php artisan ui vue
(Vueを使う場合)

php artisan ui react
(Reactを使う場合)

④npm install

⑤npm run dev

②の"1.x"部分については、以下の表を参考にご自身のLaravelのバージョンに合わせて変えてください。

laravel/uiのバージョン Laravelのバージョン
1.x 5.8、6.x
2.x 7.x
3.x 8.x

④と⑤については、Node.jsのパッケージを管理するNPM(Node Package Manager)を利用しています。

④npm installにより、用意されている便利な機能(パッケージ)をインストールすることができ、⑤でwebpack.mix.jsというファイル内に書いてある指示を実行できるようです。

ここでエラーが…

先ほどの手順④を実行した時に

ターミナル
(中略)
found 1 high severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details

ん? 何か出てきた。

日本語訳してみると

「1つの重要度の高い脆弱性が見つかりました。npm audit fixでこれらを修正してください。また、npm auditで詳細を確認できます」

とのことです。

そこで、指示通り「npm audit fix」を実行すると、

ターミナル
% npm audit fix

+ axios@0.21.1
added 1 package from 3 contributors and updated 1 package in 5.855s

51 packages are looking for funding
  run `npm fund` for details

fixed 1 of 1 vulnerability in 1096 scanned packages

無事解決できたようです。

「あ〜よかった」と思ったのも束の間、手順⑤の「npm run dev」を実行したところ…

ターミナル
Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.context: The provided value "/Users/ユーザー名/Laravel_CRUD/Atsumare!" contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.
   -> The base directory (absolute path!) for resolving the `entry` option. If `output.pathinfo` is set, the included pathinfo is shortened to this directory.
 - configuration.module.rules[8].exclude should be one of these:
   RegExp | string | function | [(recursive)] | object { and?, exclude?, include?, not?, or?, test? } | [RegExp | string | function | [(recursive)] | object { and?, exclude?, include?, not?, or?, test? }]
   -> One or multiple rule conditions
   Details:
    * configuration.module.rules[7].exclude[0]: The provided value "/Users/ユーザー名/Laravel_CRUD/Atsumare!/resources/sass/app.scss" contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.
    * configuration.module.rules[7].exclude[0]: The provided value "/Users/ユーザー名/Laravel_CRUD/Atsumare!/resources/sass/app.scss" contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.
    * configuration.module.rules[8].exclude[0]: The provided value "/Users/ユーザー名/Laravel_CRUD/Atsumare!/resources/sass/app.scss" contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.
    * configuration.module.rules[8].exclude[0]: The provided value "/Users/ユーザー名/Laravel_CRUD/Atsumare!/resources/sass/app.scss" contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.
 - configuration.output.path: The provided value "/Users/ユーザー名/Laravel_CRUD/Atsumare!/public" contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.
   -> The output directory as **absolute path** (required).

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ development: `cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js`
npm ERR! Exit status 1
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!     /Users/ユーザー名/.npm/_logs/2021-01-xxTxx_xx_xx_135Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ dev: `npm run development`
npm ERR! Exit status 1
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!     /Users/ユーザー名/.npm/_logs/2021-01-xxTxx_xx_xx_168Z-debug.log

なんか赤い字でいっぱい出てきた!

ここで僕は少し詰まってしまいましたが、ある記事を見つけました。

それがこちら

Shawn Dhaveさんの回答を引用します。

Had the same error. The problem seems to be in the path of your folder. It must not contain an exclamation mark(!). Change folder 'HelloWorld!' to just 'HelloWorld' without the exclamation mark.
Hope this solves the problem.

日本語訳すると

「自分も同じエラーを経験したよ。
フォルダーのパスに問題があるように見えるね。フォルダーのパスに感嘆符(!)を含めたらいけないんだ。だから、フォルダー名を『HelloWorld!』じゃなくて、感嘆符のない『HelloWorld』だけに変えてみて。これが解決策になりますように」

になります。

ん?
フォルダー名に「!」をつけたらだめ?

pwdコマンドで自分のフォルダ名(パス)を確認してみます。

ターミナル
/Users/ユーザー名/Laravel_CRUD/Atsumare!

image.png

つけてんじゃん!!

僕は「Atsumare!(あつまれ!)」という名前で募集掲示板型のサービスを作ろうとしており、それに合わせてフォルダー名も「Atsumare!」にしていたのですが…
どうやらそれがエラーの原因になっていたようです。

というわけで、「「Atsumare!」を「Atsumare」に修正しました。

そして⑤の「npm run dev」を実行すると…

ターミナル
> @ dev /Users/ユーザー名/Laravel_CRUD/Atsumare
> npm run development


> @ development /Users/ユーザー名/Laravel_CRUD/Atsumare
> cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js



 DONE  Compiled successfully in 7151ms                                  16:36:11

       Asset      Size   Chunks             Chunk Names
/css/app.css   178 KiB  /js/app  [emitted]  /js/app
  /js/app.js  1.08 MiB  /js/app  [emitted]  /js/app

無事実行できました!!

教訓

「フォルダー名(ディレクトリ名)に「感嘆符(!)」をつけるのはやめましょう」

という教訓でした?

皆様もお気をつけて!

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

Laravel8→6系に変えたら色々苦戦した

はじめに

私は現在、PHP/Laravelでポートフォリオ作成をしている学習中の者です。
もし間違っている箇所があればお知らせいただけたら幸いです。

ポートフォリオを作成中に、Laravelのバージョン8系では記述の仕方が変わっていたり、(新しいため)情報も少なく、長い目でみて時間ロスが多く発生すると思い、6系に変えてみようと思いました。

開発初期段階だったので、軽い気持ちで変えてみたら色々エラーが出たので記事にしました。


Laravel6系に変更後

バージョン変更に関しては割愛します。
プロジェクト内のデータが8系の時のままだと以下のようなエラーが出ます。

シーディング実行エラー

ターミナル
$ php artisan migrate:fresh --seed
//注意してお使いください。
//このコマンドはデータベースの中身を全部クリアにしてからシーディングデータを入れ直すものです。

このコマンドでデータベースにデータを入れようとしたところ以下のエラーが発生

エラー内容
Illuminate\Contracts\Container\BindingResolutionException  : Target class [PostTableSeeder] does not exist.

解決法

8系と6系とでは記述が変わっていた為、seederファイルを修正

database/seeds/PostTableSeeder.php
<?php

//namespace Database\Seeders;←削除

use Illuminate\Database\Seeder;
//use Illuminate\Support\Facades\DB;←削除

class PostsTableSeeder extends Seeder
{
//~~

Modelファイルエラー

$ php artisan serve

でlocalhostに繋ぎ確認してみると以下のエラーに

Trait 'Illuminate\Database\Eloquent\Factories\HasFactory' not found

解決法

Laravel8ではHttp/Modelディレクトリの配下に入ってましたが、Laravel6ではHttpディレクトリの配下に直接入れるのがデフォルトのようです。
Httpディレクトリ配下に移し空になったModelディレクトリを削除。
Modelファイルを一部書き換えます。

app/Http/Post.php
<?php

//namespace App\Models;
//↓以下に修正
namespace App;

use Illuminate\Database\Eloquent\Factories\HasFactory;//削除
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;//削除

Controllerエラー

Controllerファイルも書き換えます。

app/Http/Controllers/PostController.php
<?php

namespace App\Http\Controllers;

//use App\Models\Post;
//↓以下に修正
use App\Post;

use Illuminate\Http\Request;

class PostController extends Controller
{

Routingエラー

Routingファイルも書き換えます

routes/web.php
<?php
use Illuminate\Support\Facades\Route;

//use App\Http\Controllers\TestController; //削除
//Route::get('/',[PostController::class, 'index']);
//↓以下のように修正
Route::get('/', 'PostController@index');



ひとまずこれにて無事に6系での開発が進めらる状態になりました。
特に初学者の方はLaravelで何か作り始める前にバージョンはよく考えて決めましょう(笑)

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

Laravel/uiのインストールの注意

自分が出会ったエラーと解決法を書いています。

環境

laravel:7.30.2
php:7.4

※ php8だとlaravel/uiは使えない
laravel8ならjetstream??使うのがいいのかな?

laravel/ui インストールでエラー

composer require laravel/uiとコマンドを叩いた際に下記のエラーが出た。

Installation failed, reverting ./composer.json to its original content.

どうやらバージョンの重複が...という感じらしくこれを回避するコマンドを叩かないといけない。

composer require laravel/ui:3.*

自分はcomposer require laravel/ui:2.*で動いた。

web.phpでのエラー

インストールはできたけどweb.phpで新たなエラーが出ていた。
原因はlaravel/uiをインストールしたときにweb.phpにAuth::routes();が生成されるが、namespaceの問題みたい。
てことで、use Illuminate\Support\Facades\Auth;を記述すると解決する。

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

laravel6 ジョブを使ってみる

目的

  • laravel6のジョブを使って非同期処理を体験する

環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.5)
ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
プロセッサ 2 GHz クアッドコアIntel Core i5
メモリ 32 GB 3733 MHz LPDDR4
グラフィックス Intel Iris Plus Graphics 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHP バージョン 7.4.11 Homebrewを用いてこちらの方法で導入→Mac HomebrewでPHPをインストールする
Laravel バージョン 6.X commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う
MySQLバージョン 8.0.21 for osx10.15 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする

情報

  • jobの実行を体験することがメインなので非同期で実行される処理はログ出力のみとする。
  • 筆者はMacに直接構築したLaravel環境をもちいて本記事の検証を行った。
  • ログの出力はアプリ名ディレクトリ/storage/logs/laravel.logに出力されるものとする。
  • 実行するコマンドは特筆しない限り前のコマンドと同じディレクトリで実行するものとする。

条件

  • 下記または$ laravel newコマンドを実行してlaravel6のアプリが作成されていること。
  • 前述のlaravelアプリのローカルサーバを起動しブラウザからページを確認する事ができること。
  • 前述のlaravelアプリで$ php artisan migrateが実行できること。

概要

  1. ジョブの作成と記載
  2. ルーティング情報の記載
  3. 確認

詳細

  1. ジョブの作成と記載

    1. アプリ名ディレクトリで下記コマンドを実行してジョブクラスのファイルを作成する。

      $ php artisan make:job OutputLogJob
      
    2. 下記コマンドを実行して作成されたジョブクラスのファイルを開く。

      $ vi app/Jobs/OutputLogJob.php
      
    3. 下記のように処理を追記する。(ジョブとして動作させたい処理はジョブクラスのhandle()メソッド内部に記載する.)

      アプリ名ディレクトリ/app/Jobs/OutputLogJob.php
      <?php
      
      namespace App\Jobs;
      
      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\Log;
      
      class OutputLogJob implements ShouldQueue
      {
          use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
      
          /**
           * Create a new job instance.
           *
           * @return void
           */
          public function __construct()
          {
              //
          }
      
          /**
           * Execute the job.
           *
           * @return void
           */
          public function handle()
          {
              // 下記を追記
              Log::info('これはジョブのテストです。');
          }
      }
      
  2. ルーティング情報の記載

    1. 下記コマンドを実行してルーティングファイルを開く。

      $ vi routes/web.php
      
    2. 下記のルーティング情報を追記する。

      アプリ名ディレクトリ/routes/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!
      |
      */
      
      // 下記を追記
      use App\Jobs\OutputLogJob;
      
      Route::get('/', function () {
          return view('welcome');
      });
      
      Auth::routes();
      
      Route::get('/home', 'HomeController@index')->name('home');
      
      // 下記を追記
      Route::get('/output_log_job', function(){
          $job = new OutputLogJob;
          dispatch($job);
      
          return 'ジョブの実行完了';
      });
      // 上記までを追記
      
  3. 確認

    1. 下記コマンドを実行してローカルサーバを起動する。

      $ php artisan serve
      
    2. 下記にアクセスする。

    3. 下記のように表示される。

      127_0_0_1_8000_output_log_job.png

    4. 下記コマンドを実行してログファイルを開く。

      $ vi storage/logs/laravel.log
      
    5. 下記の一文がログに出力されていることを確認する。

      アプリ名ディレクトリ/storage/logs/laravel.log
      [YYYY-MM-DD HH:MM:SS] local.INFO: これはジョブのテストです。
      
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】モデル(Model)とは何か?命名規則やマイグレーションとの関連性について

Laravelでよく出てくるモデル(Model)や、マイグレーション、Eloquentの関係性などがわからなかったので調べてみた。

・参考:Laravel公式 Eloquent (Model)

目次

  1. Modelとは?
  2. ModelとDBテーブルの関連付け(命名規則)
  3. マイグレーションとは?
  4. マイグレーションとモデルの違い
  5. Eloquentとは?
  6. クエリビルダとは?


Modelとは?

Databaseのデータを操作する機能のこと。

DBのテーブルに対応するモデルがあり、コントローラでそのモデルを操作するとDBに書き込むデータを指定したりできる。

image.png
参考:steemit.com

コントローラはユーザーリクエストに基づいてDBデータが必要な場合にモデルに指令を出す。
 ↓
コントローラからの指令に基づいてDBからデータを抽出 or 保存する。
 ↓
コントローラは受け取ったデータをビューに渡す。
 ↓
ユーザーにはビューが描画される。


ModelとDBテーブルの関連付け

DBの各テーブル毎に対応するモデルを作成する。
テーブル名とモデル名の命名規則を守れば、laravelが自動で対応してくれる。

▼命名規則
DBのテーブル名は複数形とし、Model名はその単数形とする。

・DBのテーブル名: 複数形のスネークケース
・対応するModel名: 冒頭大文字のキャメルケース

<例1>
・DBのテーブル名: articles
・対応するModel名: Article

<例2>
・DBのテーブル名: maker_codes
・対応するModel名: MakerCode

(補足)テーブル名の主な命名規則

DBのテーブル名には命名規則がある。

  • 複数形
  • スネークケース
  • 省略表記しない
テーブル名(例) 判定
articles
article ×
Article ×
maker_codes
MakerCodes ×
maker_code ×
mk_code ×


マイグレーションとは?

DBに関連する機能でマイグレーションがある。

マイグレーション(migration)は移行という意味で、ここではDBの構造をLaravelに移行し連動させている。

DB操作ならModelだけあればいいのでは?と思ったので、マイグレーションの役割とモデルとの違いについて。


マイグレーションとモデルの違い

どちらもDBを操作するが、操作対象が異なる。

マイグレーションは、列(カラム)の追加や削除、型の指定を行う。

モデルはDBからデータの取り出し処理を記述する。(Eloquentでクエリを投げる)



▼マイグレーション

  • カラムの作成・削除
  • 型の指定
  • バージョン管理(過去のテーブルの構造がわかる)
  • 保存場所: app > Models
  • ファイル名はタイムスタンプ & テーブル名
migrationファイルの記述例
public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');    //idカラム
            $table->string('name');    //nameカラム            
            $table->string('email')->unique();   //emailカラム
            $table->timestamps();   //タイムスタンプカラム
        });
    }

マイグレーションファイルに追加したいカラムを記述し、マイグレーションを実行すれば、連携するモデルとDBのテーブルにカラムが追加される。

▼ディレクトリ構造
image.png



▼モデル

  • 取得するデータを指定
  • 取得するデータのフォーマットを指定
  • 保存場所: app > database > migrations
  • ファイル名がテーブルと対応
modelの記述例
class User extends Model
    {
        $user = User::find(1); // id番号1のユーザー情報を取得
        $user->email; // users.email の値を取得
}

▼ディレクトリ構造
image.png


Eloquentとは?

LaravelのModelやMigrationなど、DBについて調べていると必ずEloquent(エロクアント)という用語が出てくる。

Eloquentというのは、LaravelでDBを操作するコマンドのこと。

EloquentにはDB操作するためのメソッドが用意されており、それらをモデルやコントローラに記述することでDB操作が実行できる。



▼使い方

名前空間::Eloquentメソッド名

Eloquentメソッドの例
use App\Models\User;  //対象のテーブルのモデルのuse宣言
$user = User::all()->toArray(); 

usersテーブルからすべてのデータを抽出し配列化したものを、変数userに格納。

主なEloquentのメソッド

実例はusersテーブル(Userモデル)に対して操作する場合。

use App\Models\User; 
メソッド 内容 実例
all() すべてのデータを抽出 $names = User::all()
find(int) 指定したid番号のレコードを抽出 $user1 = User::find([10, 20, 30]);
get() 結果を取得する $data = User::orderBy('created_at')->get();
where('フィールド名', 条件) 指定したフィールド名のカラムから条件に一致するものを抽出 $data = User::where('id',1)->get()
where('フィールド名', '不等号' ,条件) 指定フィールドで条件を満たすものを抽出 $data = User::where('id','>=', 10)->get()
toArray() 配列に変換する $arr = User::all()->toArray()
findOrFail 条件に一致しない場合、例外処理をする User::findOrFial(1)
count() 数を数える $count = User::::where('active', 1)->count();
max('フィールド名') 最大値を取得する $maxNum = User::max('id');
sum('フィールド名') 合計値を取得する $totalPrice = User::sum('price');

基本的に一般に使えるメソッドは、Eloquentでも使える。


Eloquentでも使えるメソッド一覧

image.png

Laravel公式 Eloquentコレクション
Laravel公式 Eloquent実例


クエリビルダとは?

LaravelでDBを操作するコードは、Eloquent以外にクエリビルダという方法もある。

▼クエリビルダの使い方

use Illuminate\Support\Facades\DB;
$変数名 = DB::table('フィールド名')->メソッド->get();

クエリビルダを使うには、DBファサードのtableメソッドを使う。
これはEloquentのuse 名前空間と同じ。

実際、Eloquentはクエリビルダで使えるすべてのメソッドを使用できる

Eloquentモデルはクエリビルダですから、クエリビルダで使用できる全メソッドを確認しておくべきでしょう。Eloquentクエリでどんなメソッドも使用できます。

Laravel公式 Eloquent
Laravel公式 クエリビルダ

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

Docker for MacでLaravelを速くする方法

皆さんこんにちは。tyamahoriです。Docker for Mac使って開発してますか?遅くてキレ散らかしてませんか。。?

そんなあなたに朗報です。
2021年1月、tyamahoriはDocker for Mac が遅い問題に立ち向かいました。LaravelのサンプルプロジェクトをGitHubにあげておりますので見てください。

vendorディレクトリをそのままマウントしない!

composer install したら、vendorディレクトリができます。これをコンテナにマウントするさいに一工夫必要です。

じゃあどうするか?

ローカル開発だと、 docker-composeをほとんどの場合使うと思います。その際には、volumesを使うようにして、Macローカルにファイルを置かないようにします。

落とし穴。。

ただ、ローカルにvendorディレクトリがないと、PhpStormなどで補完が効きません。。いくらスピードが速くなるといえ、補完が聞かないと意味ないですよね。。。?

さらなる一工夫

コンテナ内でcomposerインストールをしたあとに、vendorディレクトリをMacのローカルに持ってきます。docker cp のコマンドがあるので、それを使って、コンテナないから、Macローカルにディレクトリをコピーします!

細かいところ

じゃあ、いつのタイミングでdocker cpやるのか? 新しくcomposer install でなにか追加した場合どうするのか。。などなどあります。そういうときは、スクリプトを組んで、色々と試行錯誤をしましょう。サンプルプロジェクトにスクリプトを置いてありますので、参考にしてみてください。

我慢するところ

docker cpでvendorディレクトリをMacローカルに持ってきたら、PhpStormはvendorディレクトリを読み込みます。その際にMacのファンがブンブン回るので、そこだけは我慢する必要があります。。

結論

本当に速くなるかはまず試してもらえればと思います。サンプルプロジェクトをクローンして、Docker for Macを使って、立ち上げて見てください!皆様のご感想お待ちしております!

GitHubでのプロジェクト

https://github.com/tyamahori/laravel8-sample

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