速習Larave3(その14)、タグNo.3

タグ: Laravel3  

いよいよ、これで最後の記事です。タグ機能の追加処理、最後はPostモデルです。

<?php

class Tag extends Eloquent
{
    public static $timestamps = true;

    public function posts()
    {
        return $this->has_many_and_belongs_to('Post');
    }

    public static function get_by_string($post_id)
    {
        $post = Post::with('tags')->find($post_id);

        if ( $post == null )
        {
            return false;
        }

        $string = "";

        // タグをスペースで区切り連結
        foreach ( $post->tags as $tag ) {
            $string .= $tag->name." ";
        }

        return $string;
    }

    public static function put_by_string($post_id, $string)
    {
        $post = Post::find($post_id);

        if ( $post == null )
        {
            return false;
        }

        // テーブルに保存されているタグを配列に変換

        $reg_tags = array( );

        foreach ( Tag::get() as $reg_tag ) {
            $reg_tags[$reg_tag->id] = $reg_tag->name;
        }

        // 引数をカンマ、半角空白、全角空白を区切りに、配列に変換

        $new_tags = explode(' ', str_replace(array(' ', ','), ' ', $string));

        // 新しく入力されたタグが、既にテーブルに存在するかチェックし
        // 存在していない場合は追加する。

        $exist_ids = array( );

        foreach ( $new_tags as $new_tag ) {
            if ( $new_tag != "" ) // $stringに空白が続いている場合の対策
            {
                $key = array_search($new_tag, $reg_tags);
                if ( $key === false )
                {
                    // 入力されたタグがテーブルに存在しない
                    $tag = new Tag(array(
                            'name' => $new_tag,
                        ));
                    $tag->save();

                    $exist_ids[] = $tag->id;
                }
                else
                {
                    // 入力されたタグがテーブルに存在している
                    $exist_ids[] = $key;
                }
            }
        }

        // 中間テーブルを更新

        $post->tags()->sync($exist_ids);

        return true;
    }

}

関係の定義はPostモデルもTagモデルも同じコードです。指定するクラスが違うだけです。

$this->has_many_and_belongs_to('Post')は「このタグモデルは多くのPostモデルを持ち、かつ所属している」というわけです。

Tagモデルにはタグを文字列で取得するメソッドと、文字列のタグを保存するメソッドが入っています。

今回学ぶ新しい事柄はこの2つのメソッドの中に全部入っています。

get_by_string()

ポストIDを引数で渡し、その記事に対するタグを空白区切りの文字列でリターンするメソッドです。

この中で学ぶことはただひとつです。$post = Post::with('tags')->find($post_id);をご覧ください。

実際は中間テーブルをセレクトし、その結果でタグテーブルを引いていますが、そんな面倒な記述はしていません。1:多の関係と同様に、シンプルに記述できています。実際、今まで学んだ書き方と全く同じですね。

put_by_string()

ここは、多少複雑に見えますが、コメントで一つ一つ説明しております。ですから、読んでいただければ理解していただけるでしょう。

引数でポストIDとタブのページ入力を受け取り、それをテーブルに書き戻す処理です。

全タグを取得し配列に変換します。その配列に入力されたタグ一つ一つが存在するか確認し、存在していなければ、新しいタグとしてテーブルに追加します。

既に存在する場合も、新しく追加した場合も、入力されたタブのIDを配列で保持しておきます。

そして最後にsyncで一気に中間テーブルを書き換えます。このsyncの使い方が分からないという投稿をどこかで見ましたが、このように中間テーブルをシンプルに書き換えるために使用します。これを中間テーブルを一つ一つ更新し、削除しとやっているとコードも煩雑になりがちですが、一気に更新がかけられるsyncは大変便利なメソッドです。

これで、今回のチュートリアルは終了です。ご苦労様でした。

今の時点で、ここまで読まれている方はほとんどいません。数名の方でしょう。:D

今回のチュートリアルは、考えながら作成したため、このサイトのコードより、まともなコードになっています。このサイトのコードは半分スパゲティーです。まあ、胃にもたれるほどしつこい味ではありまえんけどね。あっさり和風醤油味くらいです。

実際に動作させていただければ分かりますが、タグ分けされた記事を表示したり、タグを更新/削除する管理画面は実装されていません。このサイトのサイドナビにあるようなタグの一覧も表示されていません。

もし、実用的なサイトを目指しているのでしたら、改造すべきことはたくさんあります。後は皆さんにお任せします。このまま改造を続けても良し、最初から作り直すも良しです。