🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

2回答

1351閲覧

【Laravel】テーブルのデータ操作方法について

YO14

総合スコア45

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2019/11/04 13:37

開発環境

Laravel 5.6

分からないこと

Laravelを使用した掲示板プログラムを、こちらのサイトを参考にして作成しているのですが、
そこで行われている、テーブルのデータ操作方法が、ぼんやりと理解できるのですが明確に自分の中で言語化できません。
その方法を流用して機能を追加したいと考えているため、処理の流れを自分の中できちんと理解したいです。

具体的には、postsとcommentsという2つのテーブルがあり、
モデルであるPost.phpでは、

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

Comment.phpでは、

public function post() { return $this->belongsTo('App\Post'); }

という記述があります(「postsテーブルとcommentsテーブルが1対多の関係である」と定義していると思っています)

その上で、Controllerにて、postテーブルの値を取得し全件表示するために、

public function show($post_id) { $post = Post::findOrFail($post_id); return view('posts.show', [ 'post' => $post, ]); }

とやっています。
この時、$postの中には、postsテーブルの中身とcommentsテーブルの中身が全て格納されるのだろうと思うのですが、
なぜ2つのテーブルから一気にデータを取得できるのか、が上手く言語化できません。

$post = Post::findOrFail($post_id);

で、Postモデルを使用してpostsテーブルの値を取得している一方、Commentモデルを使用している様子がないのは、
先述のhasMany('App\Comment'); によって、PostモデルとCommentモデルが紐づいているのでCommentモデルをわざわざ使うことなくcommentsテーブルの値を取得できる、という理解で正しいでしょうか。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーー
また、postsテーブルの値を削除する関数が、

public function destroy($post_id) { $post = Post::findOrFail($post_id); \DB::transaction(function () use ($post) { $post->comments()->delete(); $post->delete(); }); return redirect()->route('top'); }

と定義されており、結果として、投稿データとそれに紐づくコメント全てがテーブルからdeleteされるのですが、

$post->comments()->delete();

の、comments()とは、Postモデルで定義されているcommentsメソッドのことでしょうか。
$postの値をcomments関数に渡して、deleteを実行している、ということでしょうか。ここが上手く言語化できません。
変数->関数 というアロー演算子の使い方は、公式ドキュメントでも見当たらず、他にサンプルがないので処理内容が分かりません。

長文になってしまい恐縮ですが、どなたかお時間のある方、サイトをご参照のうえ上記内容について、合っている/そうじゃない・正しくはこう、といったアドバイスいただけないでしょうか。
宜しくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

変数->関数 というアロー演算子の使い方は、公式ドキュメントでも見当たらず、他にサンプルがないので> 処理内容が分かりません。

変数->関数という考え方だと余計に混乱すると思います。ここはPHPにおける、オブジェクト指向のインスタンスとメソッドの関係です。LaravelはあくまでPHPを使ったフレームワークなので、公式マニュアルもPHPの記述ルールを熟知している前提での補足説明にとどまっています。したがって、この辺りはPHPのオブジェクト指向を参照した方がいいでしょう。公式ページもありますが、自分はこのページで勉強しました。

PHPのオブジェクト指向入門

なぜ2つのテーブルから一気にデータを取得できるのか、が上手く言語化できません。

ここはリンク先のページのDBテーブル設計を見たらわかると思いますが、postsマスタのidとcommentsトランザクションのuser_idが双方紐付いているからです。hasMany()は1対多の関係、対してbelongsToは多対1の関係になっています。これをわかりやすく言えば

一つの投稿(posts)には複数の記事(comments)を持っているということです。そのidを紐付けておかないと、記事はバラバラになってしまい、うまく整理することができないですね。

、comments()とは、Postモデルで定義されているcommentsメソッドのことでしょうか。

$postの値をcomments関数に渡して、deleteを実行している、ということでしょうか。ここが上手く言語化できません。

destoryメソッドにある\DB::transaction(function () use ($post) {…}はPHPにおけるクロージャの記述です。クロージャは説明するとややこしくなりますが、平たく言えば同じidを持つデータに対し、同じ処理を繰り返す仕組みです。したがって、特定の投稿idを持つ記事全部に対して、記事がなくなるまでDBにおけるdelete文処理を繰り返すことになります。

投稿2019/11/05 00:36

FKM

総合スコア3647

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YO14

2019/11/06 00:56 編集

ご回答ありがとうございます。 >ここはPHPにおける、オブジェクト指向のインスタンスとメソッドの関係です。 こちらですが、ご提示いただいたサイトを見たりして推測したのですが、 $post = Post::findOrFail($post_id); の$postには、Post.phpで定義したメソッドもインスタンス化されているのでしょうか。 つまり、 $post = new Post; と同じことをやっている、ということでしょうか。 もしそうだとすると、 $post->comments()->delete(); は、Postクラスで定義されたcommentsメソッドによって取得されたCommentsテーブルのレコードについて、 deleteメソッドを実行している、だからコメントを削除できる、ということになりますでしょうか。 私はPost::findOrFail($post_id)とあるので、てっきり、 Postモデルが使用するテーブル(とそれに紐づくCommentsテーブル)から、 where 'post_id' = '1'; という条件句で取得したデータが$postに入っているだけと思っていました。
FKM

2019/11/05 23:48

> $postには、Post.phpで定義したメソッドもインスタンス化されているのでしょうか。 定義したメソッドがインスタンス化されているのではなく、$postにはコンストラクタによって処理されたデータを持ったインスタンスPostによってメソッド実行した後のデータベースオブジェクトが入ります。 findといった名前のつく関数はクエリを抽出するものなので、findOrFailはつまり、クエリ処理か失敗かを返すものですね。
YO14

2019/11/06 00:57 編集

ご回答ありがとうございます。 > 定義したメソッドがインスタンス化されているのではなく、$postにはコンストラクタによって処理された > データを持ったインスタンスPostによってメソッド実行した後のデータベースオブジェクトが入ります。 こちら、もう少し細かくご説明いただけると有難いです。 ・コンストラクタによって処理されたデータ ・インスタンスPostによってメソッド実行 ・データベースオブジェクト という3つの要素が出てきたと認識しており、それぞれを理解したいです。 ・コンストラクタによって処理されたデータ コンストラクタというのは、クラスがインスタンス化された瞬間に実行される何かしらの処理だという認識なのですが、 Post.phpにて定義されたPostクラスのどれがコンストラクタに該当するのでしょうか。public function commentsでしょうか。 また、それによって処理されたデータというのは…?? ・インスタンスPostによってメソッド実行 インスタンスPostとなると、 public function comments() { return $this->hasMany('App\Comment'); } なので、commentsメソッドが実行された、ということで合っていますでしょうか。 ・データベースオブジェクト データベースオブジェクトという言葉を初めて聞きました…。 select * from posts where post_id =1; の実行結果が、オブジェクトとして入っている、という理解で合っていますでしょうか。 >findといった名前のつく関数はクエリを抽出するものなので、findOrFailはつまり、クエリ処理か失敗かを返すものですね。 「クエリ処理」というのは、 >Postモデルが使用するテーブル(とそれに紐づくCommentsテーブル)から、 >where 'post_id' = '1'; >という条件句で取得したデータ ということで合っていますでしょうか。それとも >Postモデルが使用するテーブル(とそれに紐づくCommentsテーブル)から、 >where 'post_id' = '1'; >という条件句 までのことでしょうか。
FKM

2019/11/06 01:16 編集

ちょっと抽象的な説明だったので、もっと具体的な説明をします(自分も少しこんがらがってたので) POSTというのがややこしさを増長してますね。ここのPOSTはリンク先を見てもらったらわかるように、投稿マスタテーブルの名前です。そして、そのマスタテーブルからfindメソッドを使って、$post_idというグローバル変数によって返された記事番号($post_id)にしたがい、クエリ結果を$post(データベースオブジェクト)に格納します。$postには検索結果のデータが入ります。それをviewメソッドで、テンプレートファイルに値を返しているという処理になります。 コンストラクタはあまり難しく考えず、要はメソッドで処理するときに最初から投稿マスタと記事トランザクションを紐付けたテーブル(これをビューといいます)を作り、すぐに検索できる準備がされているものと考えるといいでしょう。なぜそうなっているかは、hasManyとbelongToで記事番号を紐付けてあるからです。
YO14

2019/11/06 13:58 編集

ご回答ありがとうございます。 前半、Postテーブルからのデータ取得の流れは概ね考えていたものと一致していてほっとしました。詳細にご説明いただきありがとうございます。 コンストラクタについては、ビューを作成してそこからデータを取得しているものだ、というご説明でおおよそ理解できました。 繰り返しの質問になって恐縮なのですが、 public function destroy($post_id) { $post = Post::findOrFail($post_id); \DB::transaction(function () use ($post) { $post->comments()->delete(); $post->delete(); }); return redirect()->route('top'); } の、 $post->comments()->delete(); についてはいかがでしょうか・・・。 改めて自分なりに考えてみたのですが、$post->comments()をdeleteする、という処理の流れですので、 $post->commentという記述によってやはり、postsテーブルと紐づくcommentsテーブルからデータを取得し、それをdeleteしている、ということなのではないかという同じ答えに行き着いてしまいました。 ただそうなると、なぜnewもしていないのに、$postでPostクラスのインスタンスが使えるようになるのかが、分かりません(もうひと押しのような気がするのですが) $post->comments() って書くとcommentsテーブルから値を取ってこれるんだよ、というのはわかったのですが・・・・。
FKM

2019/11/07 08:44 編集

インスタンス = new クラス;の呪縛から離れた方がいいですね。 ここでは クラス::メソッド になっているので、静的メソッドです。静的メソッド(上記リンク参照)の場合は作る必要ないですよ。なぜなら、一度作ったビューは変更をかける必要がなく、ただ、既製データを参照しているだけだからです。 http://raichel.hatenablog.com/entry/2015/01/17/205954 流れとしては ●投稿マスタと記事トランザクションを紐付けたビューを静的メソッドで準備 ●メソッドには紐付けられた投稿トランザクションの記事id番号を取得 ●その記事id番号を元に、ビューからクエリ操作を行い、対象データをデータベースオブジェクトに格納 ●データをテンプレートに返す こうなります。
YO14

2019/11/07 06:15

ご回答ありがとうございます。 ご提示いただいたサイトの、 >「ダブルコロン」は、トークンのひとつです。 static, 定数 およびオーバーライドされたクラスのプロパティやメソッドにアクセスすることができます。これらの要素をクラス定義の外から参照する際には、 クラスの名前を使用してください。 を、Post::findOrFail($post_id); でやっている、ということでしょうか。 それによって、Postクラスのプロパティやメソッドにアクセスして、その結果を$postに格納しているので、 $post->comments()と実行できる、という理解で合っていますでしょうか。 クラス名::メソッド という書き方をする際、メソッドは、定義する際staticと書かれていなければならない(public function comments()だけではダメ)と思っていたのですが、それは関係なくアクセスし使用できる、ということでしょうか。
FKM

2019/11/07 08:18

認識はそれで間違いないと思います。 親子クラスの関係なのでそこは大丈夫です。スコープ演算子はもっと参考になるサイトもあったはずなので、調べてみてください。
guest

0

一部にのみ回答する形になります。

前提として
利用者が頑張って言語化しようとしなくても、書いたとおりに動くだけです。動いている結果が全てということですね。

もしドキュメントを読んでも納得しないのであればコアソースをしっかり追ってみることです。そのほうが他人に説明を受けるよりも何倍も理解が深まりますし、より効果的な使い方ができます。

$postの中には、postsテーブルの中身とcommentsテーブルの中身が全て格納されるのだろうと思うのですが、

なぜ2つのテーブルから一気にデータを取得できるのか、が上手く言語化できません

findOrFail()およびfind()の仕様をドキュメントで確認してください。

$post->comments()->delete();

の、comments()とは、Postモデルで定義されているcommentsメソッドのことでしょうか。
$postの値をcomments関数に渡して、deleteを実行している、ということでしょうか。ここが上手く言語化できません。
変数->関数 というアロー演算子の使い方は、公式ドキュメントでも見当たらず、他にサンプルがないので処理内容が分かりません。

ここで見るべきは「変数が保持しいている情報」となります。
おそらくどこかしらでnewなりしているのでしょうが(そのコードが提示されてないので私にはわかりません)、実際に持っているのはオブジェクトになります。
dd()なりdump()なりで確認してみると保持している情報を確認することができます。
オブジェクトが保持しているメソッドなりプロパティは利用可能です。
アロー演算子が更に重ねてあるのは「その結果をもって更に実行する」ことになります。
つまり、$postもオブジェクトだし$post->comments()もオブジェクトを返しているということになります。

LaravelというよりPHPのオブジェクト指向部分になるので、確認すべきはPHPマニュアルと思います。

投稿2019/11/04 22:06

編集2019/11/05 00:35
m.ts10806

総合スコア80875

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YO14

2019/11/06 14:17

ご回答ありがとうございます。 仰る通り、こう書けばこう動く、というのは分かったのですが、「なぜこう書けばこう動くんだ」という、裏側では何が行われているんだ、が分からない状態になっており、 機能を流用するにあたってそれでは良くない、と考えた次第です。 findOrFail()については、引数の変数の値を条件にしてテーブルに対して何らかのクエリ処理を指示するか、できなかったらできなかったということを返すか、という事は分かりました。 ただ、無事クエリ処理を実行できた結果は、配列で返ってくるのか別な形で返ってくるのか、という所は公式ドキュメントにも載っておらず、理解はふわっとした状態です。 dd($post)とやると、Collectionなるものに様々な情報が配列の形で格納されていました。該当の投稿にはコメントが2つ付いている状態なのですが、それぞれのコメントのID、本文、作成日なども格納されていることが確認できました。 これは、$postというオブジェクトの詳細を見ている、という行為になるのでしょうか? $post = Post::findOrFail($post_id); \DB::transaction(function () use ($post) { $post->comments()->delete(); については、 delete()の使い方が、以下のように公式ドキュメントに記述されておりまして、 $flight = App\Flight::find(1); $flight->delete(); 取得した値のうち、postsテーブルと紐づくcommentsテーブル上の値をdeleteする処理だ、ということだと考えています。 ただ、 $post->comments()->delete(); は、$post = new Post; とやっていないのにも関わらずpostクラスで定義されたcommentsメソッドを使用しているように見えるのがどうにもモヤモヤします!なぜなのでしょうか・・・? 何か、ご教示いただけることがありましたらぜひ、よろしくお願いいたします。
m.ts10806

2019/11/06 14:24

> 「なぜこう書けばこう動くんだ」という、裏側では何が行われているんだ、が分からない状態になっており、 となると、やはり他人の説明を受けたところで他人ごとになってしまうので、自身でコアソースを読み進めた方が良いでしょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問