Laravel5.6 DBアクセス

公開日:2018-06-16

1. 概要

Laravel5.6 で MySQL による DB アクセスを行います。
プロジェクトは前回作成したものを使用します。

2. データベースの作成

以前作成した cmd_for_php.bat でコマンドプロンプトを開き、以下のコマンドを実行して DB を作成します。
コマンドプロンプト
mysql -u roor -p
CREATE DATABASE db_laravel DEFAULT CHARACTER SET utf8mb4;

3. .env の修正

.env を環境に合わせて変更します。
.env抜粋
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db_larave
DB_USERNAME=root
DB_PASSWORD=root

4. テーブルの作成

以下のコマンドを実行します。
コマンドプロンプト
cd C:\pleiades\xampp\htdocs\laravel_test
php artisan make:migration create_articles_table
実行すると、laravel_test/database/migrations 配下に、ファイルが作成されます。
今回は、2018_06_15_023558_create_articles_table.php と言うファイルが作成されました。
この段階では、まだ DB にテーブルは作成されていません。
migrations 配下には、作成されたファイル以外に create_users_table.php、create_password_resets_table.php と言うファイルも入っています。
create_users_table.php のソースを見てみます。
create_users_table.php抜粋
public function up()
{
  Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
  });
}
up() でテーブル定義をしています。

create_articles_table.php には id とタイムスタンプしか項目がないため、data を追加します。
create_articles_table.php抜粋
public function up()
{
  Schema::create('articles', function (Blueprint $table) {
    $table->increments('id');
    $table->string('data1');   //追加
    $table->string('data2');   //追加
    $table->timestamps();
  });
}

up() を動かすには、以下のコマンドを実行します。
コマンドプロンプト
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 `users` add unique `users_email_unique`(`email`))
email を unique にしようしたが、サイズが大きすぎるためエラーとなったようです。

テーブルを確認します。
テーブル
MariaDB [db_laravel]> desc users;
+----------------+------------------+------+-----+---------+----------------+
| Field          | Type             | Null | Key | Default | Extra          |
+----------------+------------------+------+-----+---------+----------------+
| id             | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name           | varchar(255)     | NO   |     | NULL    |                |
| email          | varchar(255)     | NO   |     | NULL    |                |
| password       | varchar(255)     | NO   |     | NULL    |                |
| remember_token | varchar(100)     | YES  |     | NULL    |                |
| created_at     | timestamp        | YES  |     | NULL    |                |
| updated_at     | timestamp        | YES  |     | NULL    |                |
+----------------+------------------+------+-----+---------+----------------+
email は varchar(255) となっています。
DB のエンコーディングを utf8mb4 にしたため、255文字 * 4 = 1020バイトとなり、767バイトを越えています。
「$table->string('email')->unique();」が email の項目に該当しますが、ここで文字数が指定できないか調べます。
$table は Blueprint で、use より vendor/laravel/framework/src/Illuminate/Database/Schema/Blueprint.php だとわかります。
string() の定義は、
Blueprint.php抜粋
public function string($column, $length = null)
となっているため、2番目の引数に文字列長を指定できそうです。
以下のように191(191 * 4 = 764 で 767以下)を指定します。
create_users_table.php抜粋
$table->string('email', 191)->unique();
テーブルが作成されているため、テーブルを削除してもう1度以下のコマンドを実行します。
コマンドプロンプト
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 `password_resets` add index `password_resets_email_index`(`email`))
最初に出たエラーと似ていますが、今度は他の項目が文字数の制限に引っかかっているようです。
create_password_resets_table.php の email も同様に 191 を指定します。
テーブルを削除して、もう1度 migrate を実行します。

エラーが出なくなりました。
テーブルを確認すると、migrations、articles、password_resets、users の4つのテーブルが作成されました。
articles テーブルは以下のようになります。
articlesテーブル
MariaDB [db_laravel]> desc articles;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| data1      | varchar(255)     | NO   |     | NULL    |                |
| data2      | varchar(255)     | NO   |     | NULL    |                |
| created_at | timestamp        | YES  |     | NULL    |                |
| updated_at | timestamp        | YES  |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+
追加した data が入っています。
また、timestamps() は、created_at と updated_at になるようです。

migrations テーブルには、migrate したファイル名の一部が入っています。
ここに入っているものは、次回 migrate した時に、対象外となります。
試しに migrations はそのままにして、articles テーブルを削除して migrate すると、
「Nothing to migrate.」と表示され、テーブルが作成されなくなります。
また、migrations テーブルから articles のレコードを削除して、migrate すると、
今度は articles テーブルが作成されます。

なお、以下のコマンドを実行すると、全て再作成してくれます。
コマンドプロンプト
php artisan migrate:refresh

3. データの追加

1. シーダーの作成

以下のコマンドを実行します。
コマンドプロンプト
php artisan make:seeder ArticlesTableSeeder
実行すると、database/seeds/ArticlesTableSeeder.php が作成されます。

ArticlesTableSeeder.php を以下のように修正します。
ArticlesTableSeeder.php
<?php
use Illuminate\Database\Seeder;

class ArticlesTableSeeder extends Seeder
{
  public function run()
  {
    DB::table('articles')->truncate(); //全データの削除
    
    DB::table('articles')->insert([
      [
        'data1'    => 'aaa1',
        'data2'    => 'aaa2'
      ],
      [
        'data1'    => 'bbb1',
        'data2'    => 'bbb2'
      ],
      [
        'data1'    => 'ccc1',
        'data2'    => 'ccc2'
      ],
    ]);
  }
}

次に、ArticlesTableSeeder.php と同じ階層にある database/seeds/DatabaseSeeder.php を修正します。
ArticlesTableSeeder.php
public function run()
{
  // $this->call(UsersTableSeeder::class);
  $this->call(ArticlesTableSeeder::class); //追加
}

2. シーダーの実行

以下のコマンドを実行します。
コマンドプロンプト
php artisan db:seed

以下のエラーが出ました。
エラー
ReflectionException  : Class ArticlesTableSeeder does not exist

クラス名、ファイル名、パスに問題がなくても上記エラーが出る場合は、以下のコマンドを実行します。
コマンドプロンプト
composer dump-autoload
これで vendor/composer 配下の autoload_classmap.php と autoload_static.php にクラスが登録されて、オートロードできるようになります。

もう1度以下のコマンドを実行します。
コマンドプロンプト
php artisan db:seed

エラーが出なければ、articles テーブルにデータが追加されています。
コマンドプロンプト
MariaDB [db_laravel]> select * from articles;
+----+-------+-------+------------+------------+
| id | data1 | data2 | created_at | updated_at |
+----+-------+-------+------------+------------+
|  1 | aaa1  | aaa2  | NULL       | NULL       |
|  2 | bbb1  | bbb2  | NULL       | NULL       |
|  3 | ccc1  | ccc2  | NULL       | NULL       |
+----+-------+-------+------------+------------+

3. DBアクセス

1. モデムの作成

以下のコマンドを実行します。
コマンドプロンプト
php artisan make:model Article
実行すると、app/Article.php が作成されます。
初めから User.php と言うファイルも入っています。

2. データの取得

app/Http/Controllers/TestController.php を以下のように修正します。
TestController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

use App\Article;
use App\User;

class TestController extends Controller
{
	protected $article;
	public function __construct(Article $article)
	{
		$this->article = $article;
	}
	
	public function test() {
		$list = $this->article->all();
		var_dump($list[0]->id);
		var_dump($list[0]->data1);
		var_dump($list[0]->data2);
		
		//$a = "Hello";
		//return view('test')->with(compact('a'));
	}
}
routes/web.php抜粋
Route::get('/test/',  'TestController@test');
http://localhost/laravel_test/public/test/ にアクセスします。
出力されたHTMLのソースを確認すると、articles テーブルのデータが取得できていることがわかります。

Users テーブルでも試してみます。今回はシーダーを使わずに直接SQLでデータを入れます。
SQL
insert into users (name, email, password) values ('aaa', 'aaa@aaa', 'pass1');
insert into users (name, email, password) values ('bbb', 'bbb@bbb', 'pass2');

コンストラクタの型の Article を User にして以下のようにすると、users テーブルの値が取得できます。
TestController.php抜粋
var_dump($list[0]->id);
var_dump($list[0]->name);
var_dump($list[0]->email);
var_dump($list[0]->password);

どうやら、コンストラクタの引数の型で、入ってくるデータが変わるようです(コンストラクタインジェクション)。
以下のように、引数を複数入れることも可能です。
TestController.php抜粋
public function __construct(Article $article, User $user)

また、メソッドでも同様に行えます(メソッドインジェクション)。
TestController.php抜粋
public function test(Article $article, User $user) {
  $list1 = $article->all();
  $list2 = $user->all();
  var_dump($list1[0]->data1);
  var_dump($list2[0]->name);
}
Laravel の DI コンテナとしての機能だそうです。

以下のようにすると、引数で取得しなくてもデータが取得できます。
TestController.php抜粋
use DB;
   :
public function test() {
  $articles = DB::table('articles')->get();
  var_dump($articles[0]->data1);
}

3. データの取得

最初の1レコードを取得します。
TestController.php抜粋
public function test() {
  $article = DB::table('articles')->first();
  var_dump($article->data1);
}

条件を指定して取得します。
TestController.php抜粋
public function test() {
  $article = DB::table('articles')->where('data1', 'aaa1')->first();
  var_dump($article->data1);
}

指定した項目の値だけ取得します。
TestController.php抜粋
$data2 = DB::table('articles')->where('data1', 'aaa1')->value('data2');
var_dump($data2);
などなど。

4. データの更新

データを追加します。
TestController.php抜粋
$data = [
  'data1' => 'abc',
  'data2' => 'def'
];
$article->insert($data);

データを追加します。
これは、database/seeds/ArticlesTableSeeder.php のデータ追加方法と同じです。
TestController.php抜粋
$data = [
  'data1' => 'xxx',
  'data2' => 'yyy'
];
DB::table('articles')->insert($data);

データを更新します。
TestController.php抜粋
DB::table('articles')->where('data1', 'xxx')->update(['data1' => 'zzz']);

データを削除します。
TestController.php抜粋
DB::table('articles')->where('data1', 'zzz')->delete();
などなど。