Laravel5.7でClass ${class_name} does not exist

コマンドラインでシーダーを実行しようとすると、Class ${class_name} does not existのエラーが出た時の対処法。

[vagrant@localhost zeus]$ php artisan db:seed
Seeding: AccountTableSeeder

   ReflectionException  : Class AccountTableSeeder does not exist

  at /home/vagrant/local/zeus/vendor/laravel/framework/src/Illuminate/Container/Container.php:779
    775|         if ($concrete instanceof Closure) {
    776|             return $concrete($this, $this->getLastParameterOverride());
    777|         }
    778|
  > 779|         $reflector = new ReflectionClass($concrete);
    780|
    781|         // If the type is not instantiable, the developer is attempting to resolve
    782|         // an abstract type such as an Interface of Abstract Class and there is
    783|         // no binding registered for the abstractions so we need to bail out.

  Exception trace:

  1   ReflectionClass::__construct("AccountTableSeeder")
      /home/vagrant/local/zeus/vendor/laravel/framework/src/Illuminate/Container/Container.php:779

  2   Illuminate\Container\Container::build("AccountTableSeeder")
      /home/vagrant/local/zeus/vendor/laravel/framework/src/Illuminate/Container/Container.php:658

  Please use the argument -v to see more details.

1.DatabaseSeeder.phpと読み込むclassが存在するか確認する

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
		AccountTableSeeder::class,
	 ]);
    }
}
use Illuminate\Database\Seeder;

class AccountTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
        DB::table('account')->insert([
            'login_id' => str_random(10),
            'company_id' => '001',
        ]);
        //
    }
}

問題ない。何故だ?

composer dump-autoload で直る
コマンドラインでたたきます。

[vagrant@localhost zeus]$ php composer.phar dump-autoload
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.

改めてphp artisan db:seedとすると、今度は上手くいくのがわかります。

[vagrant@localhost zeus]$ php artisan db:seed
Seeding: AccountTableSeeder
Database seeding completed successfully.

Good Job!

Laravel5.7のseeder

シーダー?
シーザーサラダのことでしょうか? シャキシャキした機能?

とりあえず公式ドキュメントを見てみます。
https://readouble.com/laravel/5.7/ja/seeding.html
「テストデーターをデーターベースに設定するシンプルな方法」と記載があります。なるほど、seed(種)から派生しているのです。それならseedと言ってくれればいいのに。。

それはさておき、/database/seeds/ 配下に設置されます。

シーダークラスの定義
make:seeder tablenameでAccountTableをつくります。

$ php artisan make:seeder AccountTableSeeder
Seeder created successfully.

make:seederでAccountTableSeeder.phpが作られたので、中のソースコードを見てみます。

runの部分で挿入するテーブルを指定して、レコードをinsertしてきます。

use Illuminate\Database\Seeder;
class AccountTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}

thinkerもあるので、seederを使うメリットがイマイチわかりません。

public function run()
    {
    	DB:table('account')->insert([
    		'login_id' => str_random(10),
    		'company_id' => ''

    	]);
        //
    }

シーダの実行
[vagrant@localhost zeus]$ php artisan db:seed
Database seeding completed successfully.

mysqlでデータを見てみます。

select * from account で見ても、empty set。何故だ?

Laravel5.7でモデル(model)を使ったデータベース操作

Laravel5.7でモデル(model)を使ったデータベース操作をやりたいと思います。Laravelではモデルを通してDBのデータ操作を行います。なお、DBとモデルオブジェクトを対応付ける機能をEloquentという。

php artisan make:model によるmodelの作成
ドキュメントを斜め読みしていましたが、一向に理解が深まらないので、まずmodelを作ってみます。Accountというモデルを作成します。

php artisan make:model ${model_name}

[vagrant@localhost zeus]$ php artisan make:model Account
Model created successfully.

すると、appディレクトリ配下に${model_name}.phpが作られます。

Laravel5.7でviolation: 1071 Specified key was too long; max key length is 767 bytes

Laravel5.7でphp artisan migrateしようとしたら、以下のようなエラー文が吐き出された時。

 Illuminate\Database\QueryException  : SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `account` add unique `account_login_id_unique`(`login_id`))

  at /home/vagrant/local/zeus/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664
    660|         // If an exception occurs when attempting to run a query, we'll format the error
    661|         // message to include the bindings with SQL, which will make this exception a
    662|         // lot more helpful to the developer instead of just the database's errors.
    663|         catch (Exception $e) {
  > 664|             throw new QueryException(
    665|                 $query, $this->prepareBindings($bindings), $e
    666|             );
    667|         }
    668|

  Exception trace:

  1   PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes")
      /home/vagrant/local/zeus/vendor/laravel/framework/src/Illuminate/Database/Connection.php:458

  2   PDOStatement::execute()
      /home/vagrant/local/zeus/vendor/laravel/framework/src/Illuminate/Database/Connection.php:458

  Please use the argument -v to see more details.

どうしてーー?

よくみると、SQL: alter table `account` add unique `account_login_id_unique`(`login_id`)とあり、login_idがおかしいと書いています。

$table->string('login_id')->unique();

原因
MySQLのver5.7.7以前の場合、テーブルのindexに指定できるデータ長は最大767byteで超えてしまっているからのようです。
laravelのデフォルトcharsetは”utf8mb4″で、1文字あたり4byteの領域が必要な為、varchar(255)で格納する列を作った場合255*4=1020byteになるからです。

varchar(string)のデータ長を191byteにすれば、191*4=764で767byteに収まるようになります。

app/Providers/AppServiceProvider.phpを開きます。

function boot()の中に以下の一文を追加します。
\Illuminate\Support\Facades\Schema::defaultStringLength(191);

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
        \Illuminate\Support\Facades\Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

もう一度php artisan migrateします。
[vagrant@localhost zeus]$ php artisan migrate:fresh
Dropped all tables successfully.
Migration table created successfully.
Migrating: 2018_11_18_195714_create_account_tables
Migrated: 2018_11_18_195714_create_account_tables
Migrating: 2018_11_18_204842_create_password_history_tables
Migrated: 2018_11_18_204842_create_password_history_tables

できたー

Laravel5.7でmigrationによるテーブル作成手順

おおまかな流れです。
1. データベース設計(Excel、ER図など)
2. MySQLでデータベースを作成(create database ${database name})
3. .envファイルの編集
4. migrationファイルの作成(php artisan make:migration)
5. エディターでyyyy_mm_dd_hhmmss_{table name}_table.phpの編集
5-1. 作成するカラムを書く
5-2. 必要に応じてカラム修飾子をつける
5-3. 必要に応じてインデックスをカラムに貼る

6. migrateの実行(php artisan migrate)

さあやってごらん。

えー そういわれても。。。
ということで、1.データベース設計、2.Mysqlのデータベース作成、3. .envファイルの編集はできている前提で、4以降のmigrationファイルの作成から、5.カラムの追加、6.migrationの実行まで細かく見ていきたいと思います。

サンプルとして、”exam”というテーブルを作りたいと思います。
sqlだとこうなります。

create table exam(
  id INT AUTO_INCREMENT,
  manu_id INT,
  judge CHAR(1),
  created_by INT,
  created_at DATETIME,
);

Lets go!

1. migrationファイルの作成
–create=${table name}として、オプションでtable名を指定します。

[vagrant@localhost zeus]$ php artisan make:migration create_exam_tables --create=exam
Created Migration: 2018_11_18_112643_create_exam_tables

2. エディターでyyyy_mm_dd_hhmmss_create_exam_table.phpの編集
/database/migrations のディレクトリ配下にmake:migrateで以下のようなファイルが生成されています。この中で、16行目のSchema::createのfunction(Blueprint $table){}の中にカラムを指定していきます。

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

class CreateExamTables extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('exam', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

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

3. 作成するカラムを書く
使用するカラムは公式ドキュメントを見ながら編集していきます。
https://readouble.com/laravel/5.7/ja/migrations.html
今回はINT->integer, CHAR->char, DATETIME->timestampsで記載していきます。

public function up()
    {
        Schema::create('exam', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('manu_id');
            $table->char('judge');
            $table->timestamps('');
        });
    }

4. 必要に応じてカラム修飾子をつける
‘id’にAUTO_INCREMENTを付けます。
こちらも、公式ドキュメントを参考にします。
https://readouble.com/laravel/5.7/ja/migrations.html

public function up()
    {
        Schema::create('exam', function (Blueprint $table) {
            $table->increments('id')->autoIncrement();
            $table->integer('manu_id');
            $table->char('judge');
            $table->timestamps('');
        });
    }

5. 必要に応じてインデックスをカラムに貼る
今回はナシ

6. migrateの実行(php artisan migrate)
[vagrant@localhost zeus]$ php artisan migrate
Migrating: 2018_11_18_112643_create_exam_tables
Migrated: 2018_11_18_112643_create_exam_tables

7. MySQLで確認
期待したテーブル、カラムが作成されたかmysqlのdescribe examで確認

出来たぞー

idはちゃんとprimary key, autincrementになってます。
これを応用して、テーブルを作っていきましょう♪ (私はこれから10個位テーブルを作ります)

laravelのmigrationでindexを作成する

mysqlでインデックスを追加するケースが多々あるかと思います。例えば以下のように、UNIQUEなど。

create table account(
  id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
  login_id VARCHAR(256) UNIQUE,
)

laravelではuniqueは以下のように書きます。

$table->string('login_id', 256)->unique();

簡単じゃーん!

Laravelで使用できるIndex
$table->primary(‘id’); 主キー追加
$table->primary([‘id’], ‘parent_id’);
$table->unique(’email’); uniqueキー追加
$table->index(‘state’); 基本的なインデックス
$table->spatialIndex(‘location’); 空間インデックス追加


primary、uniqueは必須でしょうね。

Laravelでカラム指定する場合のColumn modifiers

laravelでColumn Modifiersと言われるカラム修飾子があります。
MySQLでカラムをセットする際につけるafterなどのことです。
ドキュメントにどのようなカラム修飾子があるか掲載されているので、よく使うものを整理しておきましょう。私は見たことないカラムもかなりありました。

なお、Laravelのドキュメントに詳しく乗っています。英語版も見ておくとよいでしょう。
https://readouble.com/laravel/5.7/ja/migrations.html

サービスによって差があるかと思いますが、autoIncrementの頻度は高いです。


よく使用するカラム修飾子
->autoIncrement() 自動増分ID(主キー)
->after(‘column’) 指定カラムの次に他のカラム
->default($value) 予め値を設定
->nullable($value = true) NULL値をカラムに挿入


あまり使わなそうなカラム修飾子

->charset(‘utf8’) charsetを指定
->collation(‘utf8_unicode_ci’) コロケーションを指定
->comment(‘my comment’) カラムにコメント追加
->first() カラムをテーブルの最初に設置
->storedAs($expression) stored generatedカラムを生成
->unsigned() 整数カラムを符号なしに設定
->useCurrent TIMESTAMPカラムのデフォルト値を指定
->virtualAs($expression) virtual generatedカラムを生成
->generatedAs($expression) 指定のシーケンスオプションで、識別カラムを生成
->always() 識別カラムの入力を上書きするシーケンス値を定義

Laravel5.7のmigrationでカラムを作成・追加・変更

Laravelで使用できるカラムは公式ドキュメントに記載があります。
https://readouble.com/laravel/5.7/ja/migrations.html


こちらを見ながら使用していけば問題ないでしょう。
公式ドキュメントを見るのに抵抗がある方は、一度ドキュメント全部見ておいた方がいいです。ざっと見るのであれば、4~5日もあれば十分でしょう。もちろんQitaの投稿記事などで必要な情報が出てきますが、Qiitaの場合、Laravaleのバージョンが使用しているバージョンと異なっていたら、間違ってしまう可能性がありますが、公式ドキュメントの場合は、間違いはありません。

では、公式ドキュメント記載の使用できるカラムタイプを見ていきます。
Laravel migrationのカラムコマンド


良く使いそうなコマンド
increment(‘id’); 符号なしINTを使用した自動増分ID(主キー)
integer(‘votes’);
boolean(‘confirm’); BOOLEAN
string(‘name’, 100); VARCHARカラム
char(‘name’, 100); CHARカラム
text(‘description’); TEXTカラム
dateTime(‘created_at’); DATETIMEカラム
timestamps(); NULL値可能なcreated_atとupdated_atカラム


その他のコマンド
bigIncrements(‘id’); BIGINTを使用した自動増分ID
bigInteger(‘votes’); BIGINTカラム
binary(‘data’); BLOBカラム
dateTimeTz(‘created_at’); タイムゾーン付きDATETIMEカラム
decimal(‘amount’, 8, 2); 有効(全体桁数)/小数点以下桁数指定のDECIMAL
double(‘amount’, 8, 2); 小数点以下桁数指定のDOUBLE
enum(‘level’, [‘easy’, ‘hard’]); ENUMカラム
float(‘amount’, 8, 2); float
geometry(‘positions’); geometryカラム
geometryCollection(‘positions’); Geometrycollectionカラム
ipAddress(‘visitor’); IPアドレス
json(‘options’); JSONフィールド
jsonb(‘options’); JSONBフィールド
lineString(‘positions’); LINESTRINGカラム
longText(‘description’); LONGTEXTカラム
macAddress(‘device’); MACアドレスカラム
mediumIncrements(‘id’); MEDIUMINTを使用した自動増分ID(主キー)
mediumInteger(‘votes’); MEDIUMINTカラム
mediumText(‘description’); MEDIUMTEXTカラム
morphs(‘taggable’); BIGINTのtaggable_idと文字列のtaggable_type
multiLineString(‘positions’); MULTILINESTRINGカラム
multiPoint(‘positions’); MULTIPOINT
multiPolygon(‘positions’); MULTIPOLYGONカラム
nullableMorphs(‘taggable’); morphs()カラム
nullableTimestamps(); timestamps()メソッドの別名
point(‘position’); POINTカラム
polygon(‘positions’); POLYGONカラム
rememberToken(); VARCHAR(100)でNULL値可能なremember_token
smallIncrements(‘id’); 符号なしSMALLINTを使用した自動増分ID
smallInteger(‘votes’); SMALLINTカラム
softDeletes(); ソフトデリートのためにNull値 可能なdeleted_at
softDeletesTz(); ソフトデリートのためにNull値可能なdeleted_atタイムゾーン
time(‘sunrise’); Timeカラム
timeTz(‘sunrise’); タイムゾーン付TIMEカラム
timestampsTz(); タイムゾーン付
tinyIncrements(‘id’); 符号なしTINYINTを使用
tinyInteger(‘votes’); TINYINTカラム
unsignedBigInteger(‘votes’); 符号なしBIGINTカラム
unsignedDecimal(‘amount’, 8, 2); 符号なしDECIMALカラム
unsignedInteger(‘votes’); 符号なしINTカラム
unsignedMediumInteger(‘votes’); 符号なしMEDIUMINTカラム
unsignedSmallInteger(‘votes’); 符号なしSMALLINTカラム
unsignedTinyInteger(‘votes’); 符号なしTINYINTカラム
uuid(‘id’); UUIDカラム
year(‘birth_year’); YEARカラム

Laravel5.7のmigration(マイグレーション)

migrationとは
マイグレーションとはデータベースのversionコントロール
データベースのスキーマ更新を簡単に出来るようになる


Laravel5.7の公式ドキュメント:
https://readouble.com/laravel/5.7/ja/migrations.html

1. migrationファイルの作成
table名の後ろに”_table”をつけてmigrationファイルを作成します。

php artisan make:migration ${tabale name}_table

では試しにコマンドラインでmigrationファイルを作成しましょう。
[vagrant@localhost zeus]$ php artisan make:migration users_table

/database/migrations 配下に yyyy_mm_dd_hhmmss_users_table.phpが作られます。

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

class UsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        //
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}

function upとdownにカラムを書いていきます。

2. migrateの実行

php artisan migrate

databaseにtableが出来ます。ただし、 public function up()が空の場合はなにもできません。

オプションでtable名を指定した場合
[vagrant@localhost zeus]$ php artisan make:migration create_users_tables –create=users
Created Migration: 2018_11_17_154656_create_users_tables
[vagrant@localhost zeus]$ php artisan migrate
Migration table created successfully.
Migrating: 2018_11_17_154656_create_users_tables
Migrated: 2018_11_17_154656_create_users_tables

mysql側
usersのテーブルが出来ているのがわかります。

Laravel 5.7からMySQL 5.6への接続方法

LaravelからMySQLへの接続方法は、
1. MySQLで接続するDBを作成する
2. .envファイルから接続するmysqlのDB Nameなどを指定する です。

1. MySQLで接続するDBを作成する
まずMySQLにログインします。
[vagrant@localhost ~]$ mysql -u root -p

続いて、dbを作成します。既に使用するデータベースがある場合は省略して構わないでしょう。
mysql> create database zeus;

これで、db側の設定は完了です。きちんと作成できたか、show databases;で確認しておくと良いでしょう。

2. .envファイルから接続するmysqlのDB Nameなどを指定する
.envファイルは、laravelをインストールしたディレクトリにあります。この.envを開きます。

.envは設定ファイルで、アプリ(APP_*)、DB(DB_*)、Redis(REDIS_*)、メール(MAIL_*)、Pusher(PUSHER_*)などの設定が書かれています。今回編集するのは
9~14行目のDBの箇所です。

DB_CONNECTION、DB_HOST、DB_PORTはlocalの場合は変更の必要ありません。RDSにつないでいる時などは設定しましょう。主に編集するのは、DB_DATABASE、DB_USERNAME、DB_PASSWORDの箇所です。適時変更ください。

DB_DATABASE=zeus
DB_USERNAME=root
DB_PASSWORD=

これでLaravelの接続設定は完了です。