20190828のlaravelに関する記事は5件です。

Laravel5.8 MAMPを利用した開発環境構築

内容

  • MacでのMAMPを使用したLaravel5.8開発環境を構築
  • 環境構築と言っても必要なものをインストールし、プロジェクトを作成するだけのシンプルな手順解説

環境

  • OS macOS Mojave 10.14.6
  • MAMP 5.3
  • PHP 7.3.1
  • MySQL 5.7.25
  • Composer 1.8.6

MAMPの導入

入っていることを想定して省略

Composerのインストール

LaravelなどのPHPのフレームワークを使用する際にComposerというPHPのパッケージ管理ソフトを利用する。

# Composerのインストール
$ curl -sS https://getcomposer.org/installer | php

# ファイルをusr/local/binへ移動
$ sudo mv composer.phar /usr/local/bin/composer

# パーミッションの変更
# aは全てという意味、xは実行権、この場合全ての項目で実行権を与えるということ
$ chmod a+x /usr/local/bin/composer

これでComposerがインストールされ、Laravelをインストールする準備完了

# 確認
$ composer -V

Laravelのインストール

Composerを使ってLaravelをインストールする

$ composer global require "laravel/installer"

Laravelインストール後は環境変数PATHを設定する

$ export PATH="$PATH:~/.composer/vendor/bin"

# パスをsourceコマンドで有効にする
$ source ~/.bash_profile

※ PATHの通し方についての説明
https://qiita.com/KZ-taran/items/0cb2cfa64625ec1b58a9

プロジェクトの作成

/Application/MAMP/htdocs/laravel_sampleというプロジェクトを作成することとする
/Application/MAMP/htdocs/に移動し、下記コマンド入力

/Application/MAMP/htdocs/
# /Application/MAMP/htdocs/に移動
$ cd /Application/MAMP/htdocs/

# Laravelコマンドを使ってプロジェクトの作成
$ laravel new {プロジェクト名}
# laravel_sampleというプロジェクトを作成する場合
$ laravel new laravel_sample

コマンド実行後、成功すればプロジェクトが生成される。
laravelのフレームワークのversionを確認する場合

/Application/MAMP/htdocs/laravel_sample/
# プロジェクトまで移動
$ cd /Application/MAMP/htdocs/laravel_sample/

# Laravelフレームワークのバージョン確認
php artisan --version

# (補足)単にLaravelインストーラーのバージョン確認
$ laravel -V

MySQLを使用する場合

MySQLへのログイン(PATHを通していない場合)

# PATHを通さないmysqlログイン手順
# MAMPのmysqlmコマンドが入っているディレクトリに移動する
$ cd /Applications/MAMP/Library/bin/

# DBへログイン
$ ./mysql -u root -p

MySQLへのログイン(PATHを通す場合)

# エディタviで~/.bash_profileを編集する
$ vim ~/.bash_profile

# 下記内容を追加
# テキスト挿入の際にはiを押してから
$ export PATH=/Applications/MAMP/Library/bin:$PATH

# 書き込み終了の際はescで抜けてから:wqで保存し、次のコードで変更を反映させる
$ source ~/.bash_profile

これにより、どのディレクトリからでも次のコマンドでmysqlログイン可能になる

$ mysql -u root -p

プロジェクトのenvファイルの修正

DB設定値を使用するMySQLの情報へ変更していく

/Application/MAMP/htdocs/laravel_sample/.env
// 変更前
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

// 変更後
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_sample  // (使用するDB名)
DB_USERNAME=root  // (DBのユーザー名(仮にrootとする))
DB_PASSWORD=root  // (DBのPW(仮にrootとする))

DBのコネクションの設定

/config/databases.phpの変更

/Application/MAMP/htdocs/laravel_sample/config/databases.php
// 変更箇所 デフォルト
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),

// 今回の修正
'database' => env('DB_DATABASE', 'laravel_sample(.envで設定したDB名)'),
'username' => env('DB_USERNAME', 'root(.envで設定したユーザー名)'),
'password' => env('DB_PASSWORD', 'root(.envで設定したPASS)'),
'unix_socket' => env('DB_SOCKET', '/Applications/MAMP/tmp/mysql/mysql.sock'),

// 'DB_SOCKET'はmysqlで次のコマンドで確認できる
SHOW VARIABLES LIKE '%sock%';

デバッグ設定の有効

Laravelではエラーや例外処理はすでに設定されているためtry, catchを書く必要はなく、アプリケーションエラー発生時にどの程度の情報を表示させるかconfig/app.php設定ファイルのdebug設定オプションで設定する

/Application/MAMP/htdocs/laravel_sample/config/app.php
// 変更前
// デバッグを有効にする際には'APP_DEBUG'をtrueにし、リリースするときには必ずfalseにする
'debug' => env('APP_DEBUG', false),  

// 変更後
'debug' => env('APP_DEBUG', true),

サーバーの起動

LaravelにはWebサーバー機能が備わっている

# サーバー起動方法
$ php artisan serve

以上で完了
http://localhost:8000で確認できる

(補足) Laravel よく使うディレクトリ構成

https://readouble.com/laravel/5.8/ja/structure.html

app   // ModelやContoller
└─ Http
    └─ Controllers  // Controller

config  // 各種設定ファイル

database  // マイグレーションと初期設定(シーディング)
├─ factories
├─ migrations  // マイグレーションファイル
└─ seeds  // シーディングファイル

public  // アセット(画像, JavaScript, CSSなど)

resources  // Viewやアセットのビルド前のファイル
└─ views  // View

routes
└─ web.php  // ルーティング設定

storage  // コンパイルされたBladeテンプレート、ファイルベースのセッション、ファイルキャッシュなどのフレーム
└─ logs  // ログ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel 5.8 任意に設定したカラムを外部キーとする場合のリレーション

変則的なテーブル設計のリレーションを定義する機会があり、調べるのに時間がかかったためメモります。

今回使うテーブルの設計

1つのwork(仕事)に対して複数のapplicaiton(応募)が存在する一対多の関係。これら2つのテーブルをwork_idでリレーションして簡単に呼び出せるようにする。

特筆すべき点
・workテーブルの主キーがidではなくwork_id
・work_idには32桁のuuidが入る。typeはstring

スクリーンショット 2019-08-28 22.03.24.png

環境

OS : macOS Mojave 10.14.5
PHP : 7.3.1
mysql : Ver 14.14 Distrib 5.6.42, for osx10.14 (x86_64) using EditLine wrapper
Laravel : 5.7.6

手順

・migration
・Workの主キーの設定
・リレーションの設定をモデルに記述

migration

workテーブル

create_works_table.php
public function up()
    {
        Schema::create('works', function (Blueprint $table) {
            $table->char('work_id',32);
            $table->primary('work_id');
            //work_idを主キーに設定
            $table->string('catch_copy',50);
            $table->string('place',50);
            $table->string('description',500);
            $table->timestamps();

        });
    }

applicationテーブル

create_applications_table.php
public function up()
    {
        Schema::create('applications', function (Blueprint $table) {
            $table->bigIncrements('id');

            $table->char('work_id',32);
            $table->foreign('work_id')->references('work_id')->on('works');
            // このテーブルのwork_idを、worksテーブルのwork_idを参照する外部キーにする

            $table->string('message',500);
            $table->timestamps();
        });
    }

Workの主キーの設定

workの主キーの名前はidではなく、かつuuidであります。laravel標準のものとは違うため少し設定が必要となります。

Work.php
class Work extends Model
{
    protected $primaryKey = 'work_id';
    // 主キーをオーバーライド
    public $incrementing = false;
    // IDが自動増分されない場合
    protected $keyType = 'string'
    // 主キーが整数でない場合
}

Laravelの主キーについての設定についてはドキュメントの以下のページに記載されています。
Eloquentの準備(https://readouble.com/laravel/5.8/ja/eloquent.html)

$primaryKey

各モデルの親クラスであるModel.phpを確認すると以下のように'id'がデフォルトとなっています。

Model.php
protected $primaryKey = 'id';

$primaryKeyをWork.phpでオーバーライドしてあげることで、Workの主キーをwork_idに設定することができます。

$incrementing

$incrementingは、IDが自動増分されるかどうかのプロパティです。Model.phpではtrueとなっています。
今回はuuidゆえ自動増分されないので、falseにしてあげます。

$keyType

$keyTypeは、主キーtypeについてのプロパティです。
Model.phpではintとなっています。整数ではない場合、stringに設定します。

(incrementing、keyTypeの設定はなくても動きました。書かないとどんな時に困るのか教えて欲しいです。)

リレーションの設定をモデルに記述

まずは先ほどのWork.phpに書き加えます

Work.php
class Work extends Model
{
    protected $primaryKey = 'work_id';
    public $incrementing = false;
    protected $keyType = 'string';

    public function applications(){
        return $this->hasMany('App\Application', 'work_id');
        // 第二引数にforeign_keyを設定する。
    }
}

次はApplication.phpです。

Application.php
class Application extends Model
{
    public function work(){
        return $this->belongsTo('App\Work','work_id');
        // 第二引数にforeign_keyを設定する。
    }
}

ドキュメントは以下になります。
リレーション(https://readouble.com/laravel/5.8/ja/eloquent-relationships.html)

foreign_key

foreign_keyは引数で指定しない場合、モデル名 +_+ $primary_keyという形になります。

先ほど、workの$primary_keyをオーバーライドしたため、'work_work_id'となってしまっています。これではエラーが起きてしまうため、今度はforeign_keyをオーバーライドしてあげましょう。

参考

hasMany,hasOne,belongsToなどのリレーション関連のメソッドは
Illuminate\Database\Eloquent\Concerns\HasRelationships.phpに記述されています。

HasRelationships.php
public function hasOne($related, $foreignKey = null, $localKey = null)
    {
        $instance = $this->newRelatedInstance($related);
        $foreignKey = $foreignKey ?: $this->getForeignKey();
        $localKey = $localKey ?: $this->getKeyName();

        return $this->newHasOne($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);
    }

local_key

今回は指定しませんでしたが、foreign_keyだけではなく、local_keyも指定することができます。

local_keyはデフォルトだと、primary_keyになります。今回はもうすでに$primary_keyをwork_idとオーバーライドしたため新たな設定は必要ありませんでした。

もし、Work.phpで$primary_keyをオーバーライドしなかった場合は、local_keyつまり第三引数にwork_idを入れてあげると動きました。

終わりに

ネットでもググってもあんま情報探せなかったけど、ドキュメントを見たら書いてあった。いい経験になった気がする。
変なところあったら優しく教えてください。お願いします。

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

Vagrant+VirtualBoxで作った仮想環境(CentOS)にLaravel環境構築

はじめに

以前参画していたプロジェクトにて、コンテナ内のLaravelログをCloudWatch Logsに出力したいという要望があった。
参画しておきながら、あまり開発環境構成などの理解が浅く、この機会にLinux環境にLaravel環境を構築する手順を身につける。

目次

  • Vagrant、VirtualBoxのインストール
  • 仮想環境(CentOS)の構築
  • PHPのインストール
  • composerのインストール
  • Laravelのインストール

Vagrant、VirtualBoxのインストール

仮想環境(CentOS)の構築

コマンドプロンプトを起動し、適当なフォルダへ移動します。

> d:
> cd d:\work

CentOSのイメージをダウンロードします。(これ、結構かかります)

> vagrant box add centos/7

CentOS起動用のVagrantfileの雛形を作成します。

> vagrant init centos/7

作成したVagrantfileの雛形をカスタマイズします。
D:\work フォルダに Vagrantfileファイルが出来ているので、テキストエディタで開いて、以下の編集を行います。
以下の行のコメントアウトを解除するだけです。

Vagrantfile
35|  config.vm.network "private_network", ip: "192.168.33.10"
  • 35行目の編集は、後ほどCentOS上で起動されたLaravelのビルドインWebサーバーへ接続する為に必要になります。

さあ、Vagrantを起動しましょう。

> vagrant up

カレントフォルダのvagrantfileを参照して、そこに記載してある仮想環境を構築、起動します。

仮想環境(CentOS)が起動しているので、仮想環境にSSHで接続しましょう。

> vagrant ssh

PHPのインストール

最新のLaravel 5.8 では、PHP 7.1.3 以上が必要なので、ここでは PHP 7.2をインストールすることにします。
通常なら、yum install でphpを指定すればよいのですが、既定のリポジトリには PHP7.2系が配布されていない為、リポジトリを追加する必要があります。

今回はPHP7.2を配布しているRemiリポジトリを追加しますが、Remiリポジトリを追加する為に、EPELリポジトリを追加する必要があります。
このあたりの手順は、RemiさんのWebサイトの設定ウィザードで対象OSなどを選択して、確認するのが一番かと思います。

以下で行う yum install コマンドには全て -y オプションをつけていますが、これは途中の確認を全てYESで答えるオプションです。

では、EPELリポジトリの追加から行っていきます。

$ sudo yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

Remiリポジトリを追加します。

$ sudo yum -y install https://rpms.remirepo.net/enterprise/remi-release-7.rpm

yum-config-managerコマンド用にyum-utilsをインストールします。

$ sudo yum -y install yum-utils

remiリポジトリの有効化を行います。

$ sudo yum-config-manager --enable remi-php72

PHP 7.2 と関連パッケージをインストールします。

$ sudo yum -y install php php-devel php-mbstring php-pdo php-gd php-xml php-mcrypt php-zip php-unzip

インストールを確認します。

$ rpm -qa | grep php
$ php -v
PHP 7.2.21 (cli) (built: Jul 30 2019 14:46:08) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

無事 PHP 7.2.21 がインストールできました。

余談(Software Collections(SCL)リポジトリ)

こちらの記事によると、PHP 7.xを配布する公式のリポジトリ Software Collections(SCL) もあるそうですが、これで配布されたPHPを利用するには、ログイン毎、ソフトウェア毎に'scl enable'コマンドでSCLを有効化する必要があり、後々面倒になりそうなので、今回の手順ではRemiリポジトリからインストールしました。

PHPの設定

PHPの設定ファイル、/etc/php.ini をviで編集します。

$ sudo vi /etc/php.ini

編集箇所は以下の通りです。

php.ini
date.timezone = "Asia/Tokyo"
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.http_input = UTF-8
mbstring.http_output = pass
mbstring.encoding_translation = On
mbstring.detect_order = auto
mbstring.substitute_character = none 

composerをインストール

composerは、PHPのライブラリ管理ツールです。
今回はLaravelのインストールに使いますが、このLaravelのインストール時に必要なPHPライブラリを自動でインストールしてくれます。

参考:PHP開発でComposerを使わないなんてありえない!基礎編

PHPのインストールほど面倒ではないです。

# curl -sS https://getcomposer.org/installer | php

curlでダウンロードしてきたインストーラをPHPで実行しています。

ダウンロードとインストールが完了すると、カレントディレクトリにcomposer.pharというファイルができます。
これが実行ファイルなので、パスの通ったディレクトリに移動します。

$ mv composer.phar /usr/local/bin/composer

これで、composerコマンドが使えます。
早速バージョン確認してみましょう。

$ composer -v
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.9.0 2019-08-02 20:55:32

インストール完了です。

Laravelのインストール

composerを使ってインストールします。

$ composer global require "laravel/installer"

今回は /var/www 配下にプロジェクトを作成していこうと思います。
Laravelの新規プロジェクトを作成する際のコマンドcomposerは、一般ユーザー権限で実行されますが、/var/wwwディレクトリの書き込み権限が無いので、このディレクトリの所有者変更と書き込み権限付与を行います。

$ ls -al /var/www
total 0
drwxr-xr-x.  4 root root  33 Aug 28 09:31 .
drwxr-xr-x. 19 root root 265 Aug 28 09:31 ..
drwxr-xr-x.  2 root root   6 Jul 29 17:19 cgi-bin
drwxr-xr-x.  2 root root   6 Jul 29 17:19 html
$ cd /var/www
$ sudo chown -Rv root:$USER .
changed ownership of ‘./cgi-bin’ from root:root to root:vagrant
changed ownership of ‘./html’ from root:root to root:vagrant
changed ownership of ‘.’ from root:root to root:vagrant
$ sudo chmod -Rv g+rw .
mode of ‘.’ changed from 0755 (rwxr-xr-x) to 0775 (rwxrwxr-x)
mode of ‘./cgi-bin’ changed from 0755 (rwxr-xr-x) to 0775 (rwxrwxr-x)
mode of ‘./html’ changed from 0755 (rwxr-xr-x) to 0775 (rwxrwxr-x)

では、新しいLaravelプロジェクトを作成します。

$ composer create-project --prefer-dist laravel/laravel blog "5.6.*"

※プロジェクトが作成されると、最後にキーが同時に作成されるので、残しておきましょう。

動作確認します。

$ cd blog
$ php artisan --version
Laravel Framework 5.6.39

Laravelのバージョンが表示されればプロジェクトの作成は無事完了です。

あとは、PHPのビルドインWebサーバーを使用して動作確認するだけですが、CentOSにはSELinuxが導入されており、これが動作確認の邪魔になります。
一時的にアクセス制御を無効化して、動作確認をします。(恒久的に無効化する方法もありますが、ここでは割愛します)

$ sudo setenforce 0
$ php -S 0.0.0.0:8000 -t public
PHP 7.2.21 Development Server started at Wed Aug 28 11:04:35 2019
Listening on http://0.0.0.0:8000
Document root is /var/www/blog/public
Press Ctrl-C to quit.

この状態で、ホストOSのブラウザで、http://192.168.33.10:8000 にアクセスしてください。
laravel_success.png

おわりに

次は、Laravelの環境をBuildしてコンテナ化する手順を身につけたい

参考

https://qiita.com/inexp_eng4432/items/ec818f151b8ad516988b
https://qiita.com/ozawan/items/caf6e7ddec7c6b31f01e
https://qiita.com/takeshi_nozawa/items/ee01981b4fc338209437
https://rpms.remirepo.net/wizard/
https://eng-entrance.com/linux-selinux

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

Laravelで.env が読み込めなくなった

ほんとにメモ程度に。

他の人がenvファイルに更新をしたので
そのまま加筆したら反映されなかったので

qiita.rb
php artisan config:cache
php artisan view:clear

を実行したところenvファイル自体読み込めなくなり
Undefined index:エラーに、、、

結局

bootstrap/cache/config.php
を削除したら正常に読み込めた。

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

LaravelにおけるN対Nリレーションをやってみた

目的

Laravel上でN対Nリレーションのものを何か実装してみる。

前提

下記の環境で実装した。

  • PHP7.1.x
  • Laravel5.8.x
  • PostgreSQL11.4

上記環境にてN対Nのリレーションを用いたものを実装してみた。

サンプル仕様

本とその著者について考える。

本には著者が必ずいるが一人とは限らない。また著者は本を複数冊出す。

よって本と著者の関係はN対Nになる。

そこで、下記のようなテーブル構造とする。

img1.png

サンプルのために簡略化のため本はタイトルと内容のみ、著者は名前のみとする。  

画面構成は

  • 書籍一覧

    img2.png

  • 書籍詳細
    img3.png

の2画面とする。  
また簡略化のため、authorsテーブルには既に3人の著者を登録済みとする。

実装手順

下記の手順で実装した。

  • モデル作成
  • コントローラー作成
  • ビューの作成

モデル作成

まず、books(書籍データ)のモデルを作成する。Laravelなのでartisanで雛形作成する。

% php artisan make:model book --migration

以上でBook.phpとbooksのミグレーションファイルが作成される。
同様にauthors(著者データ)のモデルも作成する。

% php artisan make:model author --migration

まず、ミグレーションを片付けてしまおう。

****_create_books_table.php
<?php
 省略  

class CreateBooksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('books', function (Blueprint $table) {
            $table->bigIncrements('id'); // ここから
            $table->string("title");
            $table->text("memo");
            $table->timestamps();        // ここまでを追加記述
        });
    }

 省略  
}
****_create_authors_table.php
<?php
 省略  

class CreateAuthorsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('authors', function (Blueprint $table) {
            $table->bigIncrements('id'); // ここから
            $table->string("name");
            $table->timestamps();        // ここまでを追加記述
        });
    }
 省略  
}

また、リンクテーブルを作成する必要があるので、モデルは作成する必要がないため、ミグレーションのみ作成する。

% php artisan make:migration author_book
****_create_author_book_table.php
<?php
 省略  
class CreateBookAuthor extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('book_author', function (Blueprint $table) {
            $table->bigIncrements('id');  // ここから
            $table->integer("book_id");
            $table->integer("author_id"); // ここまでを追加記述
        });
    }
 省略  
}

ここでまずテーブルを作成してしまう。

% php artisan migrate

これでデータベースの準備は整ったので、モデルのリレーション設定を行う。

まずbookモデル

Book.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    public function authors() {
      return $this->belongsToMany(Author::class);
    }
}

authorsとリンクするので、authors()メソッドを作成して、belongsToMany()を上記のように記述する。

同様にauthorsモデル

Book.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Author extends Model
{
    public function books() {
      return $this->belongsToMany(Book::class);
    }
}

以上で、モデルの作成は終了である。

コントローラ

booksのコントローラーを作成する。

例によってartisanにて雛形を作成する。

% php artisan make:controller BookController --resource --model=Book

以上でコントローラーの雛形が作成される。

ルーティングは下記のように設定した。

routes/web.php
Route::resource("books","BookController");

コントローラーの中身を埋めていこう。

index(書籍一覧)

indexは特に説明することはないが、Bookモデルでリレーションの設定をしているため、
Authorを取得するコードを記述する必要はない。

BookController.php
public function index()
{
    $books = Book::get();
    return view("books.index",["books"=>$books]);
}

create(書籍登録画面)

新規登録画面である。Authorのチェックボックスを作成するため、Authorのリストが必要になる。

BookController.php
public function create()
{
    $authors = Author::pluck("name","id")->toArray();
    return view("books.create",compact('authors'));
}

store(書籍登録実行)

bookレコード作成とauthorとのリンク(author_book)レコードの作成を行う。

BookController.php
public function store(Request $request)
{
    // フォーム値からauthor_idの配列を抜き出す。
   $authors = $request->input("author_id",[]);
   unset($request["author_id"]);

   // bookの登録
   $book = new Book();
   $book->title = $request->title;
   $book->memo = $request->memo;
   $book->save();

    // authorとのリレーションレコードを登録    
   $book->authors()->attach($authors);

    return redirect(
            route("books.edit",$book->id))
        ->with("flash_message","保存しました");
}
$book->authors()->attach($authors);

の一行でリンクテーブルのレコードを作成してくれる。

edit(書籍更新画面)

更新画面である。これもAuthorのチェックボックスを作成するため、Authorのリストが必要になる。

BookController.php
public function edit(Book $book)
{
   $authors = Author::pluck("name","id")->toArray();
   return view("books.edit",["book"=>$book,"authors"=>$authors]);
}

update(書籍更新実行)

bookレコード更新とauthorとのリンク(author_book)レコードの更新を行う。

BookController.php
public function update(Request $request, Book $book)
{
    // bookの更新
   $book->title = $request->title;
   $book->memo = $request->memo;
   $book->save();

   // authorとのリレーションレコードの更新 
   $book->authors()->sync($request->input('author_id',[]));

   return redirect(
            route("books.edit",$book->id))
        ->with("flash_message","保存しました");
}

これもリンクテーブルの更新は1行で済む。

$book->authors()->sync($request->input('author_id',[]));

delete(書籍削除)

bookレコード削除とauthorとのリンク(author_book)レコードの削除を行う。

BookController.php
public function destroy(Book $book)
{
    // authorとのリレーションレコードの削除
    $book->authors()->detach();

    // bookの削除
    $book->delete();

    return redirect(
            route("books.index"))
        ->with("flash_message","削除しました");
}

これもリンクテーブルの削除は1行で済む。

$book->authors()->detach();

ビューの作成

最後にビューである。

index(書籍一覧)

一覧表示部分のみ抜粋する。

<table class="table table-stripe">
  <tr>
    <th>ID</th>
    <th>タイトル</th>
    <th>著者</th>
  </tr>
  @foreach($books as $book)
  <tr>
    <td>{{ $book->id }}</td>
    <td>{{ $book->title }}</td>
    <td>@foreach($book->authors as $author) {{$author->name}} @endforeach</td>
    <td>
      <a href="{{ route('books.edit',$book->id) }}" class="btn btn-primary">更新</a>
      <form action="{{ route('books.destroy',$book->id) }}" id="form_{{ $book->id }}"
        method="post" style="display:inline">
        {{ csrf_field() }}
        {{ method_field('delete') }}
        <a href="#" data-id="{{ $book->id }}" onClick="delAdmin(this);" class="btn btn-danger">削除</a>
      </form>
    </td>
  </tr>
  @endforeach
</table>
<a href="{{ route('books.create') }}" class="btn btn-primary">追加</a>

$book->authorsにリンクされているauthorが入っているため、$author->nameを表示するだけで良い。

create(新規登録)

フォームのみ抜粋する。

  <form method="post" action="{{ route('books.store') }}" enctype="multipart/form-data">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
    <div class="form-group">
      <label for="title">タイトル</label>
      <input type="text" class="form-control" name="title" id="title">
    </div>
    <div class="form-group">
      <label for="memo">内容</label>
      <textarea class="form-control" rows="3" name="memo" id="memo"></textarea>
    </div>
    <div class="form-group">
      <label for="author">著者</label>
      @foreach( $authors as $key => $author)
        <label class="checkbox-inline">
          <input type="checkbox" name="author_id[]" value="{{ $key }}">{{ $author }}
        </label>
      @endforeach
    </div>
    <input type="submit" class="btn btn-primary" value="登録">
    <a href="{{ route('books.index') }}" class="btn btn-default">一覧へ</a>
  </form>

edit(更新画面)

フォームのみ抜粋する。

  <form method="post" action="{{ route('books.update',$book->id) }}" enctype="multipart/form-data">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
    <div class="form-group">
      <label for="title">タイトル</label>
      <input type="text" class="form-control" name="title" id="title" value="{{ old('title',$book->title) }}">
    </div>
    <div class="form-group">
      <label for="memo">内容</label>
      <textarea class="form-control" rows="3" name="memo" id="memo">{{ old('memo',$book->memo) }}</textarea>
    </div>
    <div class="form-group">
      <label for="author">著者</label>
      @foreach( $authors as $key => $author)
      @php
        $bCheck = false;
        if ( isset($book->authors) && $book->authors->contains($key)) {
          $bCheck=true;
        }
      @endphp
        <label class="checkbox-inline">
          <input type="checkbox" name="author_id[]" value="{{ $key }}" @if ($bCheck==true) checked @endif>{{ $author }}
        </label>
      @endforeach
    </div>
    <input type="submit" class="btn btn-primary" value="登録">
    <a href="{{ route('books.index') }}" class="btn btn-default">一覧へ</a>
  </form>

下記のコードで、リンクされているかどうか判定する。

@foreach( $authors as $key => $author)
@php
  $bCheck = false;
  if ( isset($book->authors) && $book->authors->contains($key)) {
    $bCheck=true;
  }
@endphp

考察

以上のようにN対Nのリレーションが相当楽に実装できるのである。  
少し気持ちが悪いところはbookとauthorのリンクテーブルは

 book_author
としたいところであるが、うまく行かなかった。どうやらアルファベット順でないと
ダメなようである。

ソース一式はGithubにアップした。

https://github.com/kingcony/bookauthor_Sample

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