チャットアプリで、1グループのメッセージ数上限を50件にする(Laravel)
はじめに
初心者による初心者向けの記事です。
陥りやすい様々な苦手分野も交えて書いてみました。
「collectionと配列の違い」「モデルインスタンスってなんやねん!」「クエリビルダとかメソッドとかわからん!」「ネットでcount()
関数について調べてから使ったのに、エラーになる!」など。
このように実装しようと思った背景
実用的なチャットアプリを作りたいため、今回の実装をしました。
テーブル関係はgroups hasmany messagesの1対多です。
私はAjax通信のリアルタイムチャットアプリを作成しています。LINEのグループチャット的なものです。
トークルームのAjaxは、では5秒おき(setTimeout("get_messageC()",5000);
)にそのグループの全メッセージを取得し、表示してあるメッセージを全部消して(.remove();
)全部書き足す(.append(html);
)という実装をしています。
しかしこれでは、メッセージが1000,2000と増えるごとに動作が重くなってしまいます。よって、1グループメッセージは50件までしか保存されないような設計にしました。そうすれば最大でも50件しか書き換えと表示が行われません。
やること
★メッセージ送信アクション時に、そのgroup_idと関連づいたmessageの数を数える(ここでcollectionと配列の違いを理解しとく必要がある)→
★50件以上あるなら、上位50件以外のメッセージは削除する(ここでモデルインスタンスなのかDBインスタンスなのか把握しておく必要がある)
下図messageテーブルです。ターミナルにてmysqlで出しました。見づらいですが、messagesテーブルのカラムにgroup_idがあります。user_idはグループ作成者です。いざという時の拡張性を考えて入れときました。
collectionと配列の違い
collectionはLaravelが提供する高機能な配列です。一方で配列はみなさんがよく見かけるphpの「the・普通の配列」です。
データをインスタンス化した時はcollectionであることが多いです。例えば下記のようにモデルをインスタンス化した時。
例:$apple = new Apple;
下記のように自分で配列を作った時は、紛れもなくphpの配列です。
例:$apple = array('iphone','macbook' ,'ipad');
違いを理解すべき瞬間
厄介なのは、「配列の要素数を数えるcount関数」1つとっても、collectionと配列で文法が異なることです。先ほどの$apple
を例に取りましょう。
collectionの場合$count = $apple->count();
配列の場合$count = count($apple);
ちなみに配列関数count()
をcollectionに適用すると以下のようなエラーが出ます。
ErrorException (E_WARNING)
count(): Parameter must be an array or an object that implements Countable
「count()関数は引数は配列かオブジェクトじゃないとダメですよ〜」ということですね。collectionを配列とみなしていないようです。
ちなみに僕もなんのインスタンスがcollectionになるのか、というのは把握していません。エラー文見てその都度判断してます。
書いたコード
先にクラスをuseしちゃいましょう。自分のコントローラーにあるものをコピペします。
今回使用するクラス
注目すべき箇所は「★」をつけてます。今回は★をuseしておけば問題ないと思います。
<?php
namespace App\Http\Controllers\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB; //★
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Auth;
use Illuminate\Support\Facades\Hash;
use App\User;
use App\Follow;
use Abraham\TwitterOAuth\TwitterOAuth;
use App\Group;
use App\Message; //★
use Illuminate\Support\Facades\Log;
use Storage;
///まず現在チャットしているgroupのメッセージ数を全て取得します。
$count = $message->where('group_id',$_POST['group_id'])->count();
///その数が50を超えているなら、
if ($count > 50) {
///現在チャットしてるグループがhasするmessageのidを取得するためにやはりまずメッセージを取得します
$deleteid = DB::table('messages')
->where('group_id', $_POST['group_id'])
///それの並び順を古い順から新しい順に変えます。
->orderBy('id','desc')
///messageデータを50件のみ取得します(新しい順なので最新50件)。
->take(50)
///idのみ抽出します(必要ないけど、動作軽くなるかなーと思って)
->pluck('id')
//最新50件のなかで最も古いメッセージのidを取得。これで$deleteidに最も古いメッセージのidを入れました。
->min();
Message::where('group_id',$_POST['group_id'])
//$deleteidより古いメッセージは全て削除。
->where('id','<',$deleteid)->delete();
}
このコードより前で$message = new Message;
しました。つまり$message
は、Messageモデルのインスタンスです。group_id
はAjaxのtype: "POST",
で送信しているので、$_POST['group_id']
で受け取ります。type: "GET",
の場合やそもそもtype指定してない場合は$_GET['group_id']
で受け取ってください。type指定しないと自動でtype: "GET",
になるので。
tips
なぜ$message
があるにもかかわらずif(){}
内でわざわざDB::table('messages');
しているのか。なぜ$message
を使用しないのか。
それは、$message
はcollectionだからです。Message
モデルのインスタンスなのでcollectionになります。
クエリビルダのメソッドを使いたいです。->orderBy()
と->take()
と->pluck()
を使いたいです。DBのインスタンスじゃないとクエリビルダメソッドは使えません。
ちなみにuse Illuminate\Support\Facades\DB; //★
クラスをインスタンス化してます。
また、$message
にクエリメソッドをしようすると、Object of class Illuminate\Database\Eloquent\Builder could not be converted to string
エラーが出ます。
一番下でまたクラス呼んでいますが、なぜそうしたか自分でもわかりません。昨日の自分に問い質したいです。
Message::where('group_id',$_POST['group_id'])
->where('id','<',$deleteid)->delete();
最後に
よく「ドキュメント読め」とか「オブジェクト指向を理解しろ」と言われますが、それが全てだと僕は思いません。
ドキュメントが理解できるようになったのは学習開始5ヶ月目とかですし、平均1日6時間とか勉強した挙句のそれです。
僕が要領悪いだけかもしれませんが、是非僕のような初心者の方の役に立てたら幸いです。
Author And Source
この問題について(チャットアプリで、1グループのメッセージ数上限を50件にする(Laravel)), 我々は、より多くの情報をここで見つけました https://qiita.com/u_rin/items/c5c7776345154aa89982著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .