質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

91.87%

  • CakePHP

    1691questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

[CakePHP 2.X]Search Pluginを用いたつぶやき検索で、ヒットしたつぶやきを持つuse_idの他のつぶやきを表示

解決済

回答 1

投稿 2015/12/20 15:53 ・編集 2015/12/21 18:36

  • 評価
  • クリップ 0
  • VIEW 507

hiro_87g

score 13

ユーザー情報を管理するUserテーブルと、つぶやき情報を管理するTweetテーブルがあります。

UserはhasmanyでTweetを持っています。
TweetはbelongsToでUserに属しています。

Search Pluginで検索した時に、ヒットした「つぶやき」を持つuser_idの他の「つぶやき」も参考として表示させたいと思っているのですが、方法が分かりません。

・Tweetの方からSearch pluginを使うことで、検索に該当したつぶやきのみは表示できていますが、同userの他のつぶやきを表示する方法が分かりません。(参考までに下記にソースを記載しています)

・Userの方からSearch pluginが使えればいける気もしましたが、hasmanyで持っているテーブル内を検索対象にする方法が分かりませんでした。

Tweet内でSearch pluginを使用 or User内でSearch pluginを使用、
実現したいことができれば、このどちらでも(もしくは他の方法でも)構わないのですが
良い方法がありましたらお教えいただけますと助かります。

何卒よろしくお願いします。

■cakeのバージョン:2.7

■データベース
Userテーブル(ユーザー)
~~~~~~~~~~~~~~~
ID|username
1  太郎
2  花子

Tweetテーブル(つぶやき)
~~~~~~~~~~~~~~~
ID | tweet | user_id   
1  暑いなー     1
2  お腹いっぱい   1
3  楽しい!     1
4  お腹空いた    2
5  いい天気     2
6  風邪ひいた    2
7  嬉しい      2

■現状
現状


■完成イメージ(画像編集ソフトで作成しました)
完成イメージ

■現状のソース(Tweetの方からSearch pluginを使用)

//Model/User.php
<?php
App::uses('AuthComponent', 'Controller/Component');
class User extends AppModel {
    public $hasMany = array('Tweet');
?>
//Model/Tweet.php
<?php
class Tweet extends AppModel {
    public $belongsTo = 'User';
    public $actsAs = array('Search.Searchable');
    public $filterArgs = array(
        'tweet' => array('type' => 'like')
    );
}
?>
//Controller/TweetsController
<?php

class TweetsController extends AppController {

    public $components = array('Search.Prg');
    public $presetVars = true;
    public $paginate = array();

    public function search() {
        $this->paginate = array(
            'limit' => 100,
            );
        $this->Prg->commonProcess();
        $this->paginate['conditions'] = $this->Tweet->parseCriteria($this->passedArgs);
        $tweetLists = $this->paginate();
        $this->set(compact('tweetLists'));
    }
}
?>
//View/Tweets/search.ctp
<div>
    <?php echo $this->Form->create('Tweet',array(
        'novalidate' => true,
        'url' => array_merge(array('action' => 'search'),
            $this->params['pass'])
        ));
        ?>
        <?php echo $this->Form->input('tweet', array(
            'type' => 'text',
            'placeholder' => '検索ワードを入力してください',
            'label' => false
            )); ?>
            <?php echo $this->Form->submit('検索'); ?>
            <?php echo $this->Form->end(); ?>
        </div>

        <div>
            <h2>検索結果</h2>
            <table>
                <tr>
                    <th><?php echo $this->Paginator->sort('User.username', 'ユーザー名'); ?></th>
                    <th><?php echo $this->Paginator->sort('tweet', 'つぶやき'); ?></th>
                </tr>

                <?php foreach($tweetLists as $tweetList): ?>

                    <tr>
                        <td><?php echo $this->Html->link($tweetList['User']['username'],'/users/view/'.$tweetList['User']['id']) ?></td>
                        <td><?php echo h($tweetList['Tweet']['tweet']); ?></td>
                    </tr>

                <?php endforeach; ?>

            </table>
        </div>

        <div>
            <?php echo $this->Paginator->prev(); ?>&nbsp;
            <?php echo $this->Paginator->numbers(); ?>&nbsp;
            <?php echo $this->Paginator->next(); ?>
        </div>
  • 気になる質問をクリップする

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

    クリップした質問はマイページの「クリップ」タブからいつでも見ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

おそらく取得したい情報を1回のSQLで取得しようとすると、以下のようなSQLになると思います

SELECT 
  Tweet.user_id,
  User.username, 
  group_concat(Tweet.tweet SEPARATOR ' | ') 
FROM 
  tweets AS Tweet 
  LEFT JOIN users AS User ON (tweet.user_id = User.user_id)
where
  Tweet.user_id IN (select DISTINCT user_id from tweets where tweets.tweet like '%お腹%')
group by Tweet.user_id

このまま1回のSQLで実現するのは難しいと判断したので、サブクエリでのuser_idの取得部分とそれをパラメータとしたtweetの取得部分の二つに分けて実装してみました

//Controller/TweetsController
<?php
class TweetsController extends AppController {

    public $components = array('Search.Prg');
    public $presetVars = true;
    public $paginate = array();
    public $userid = array();
    public $uses = array('Tweet','user','wkTweet');

    public function search() {
        $this->paginate = array(
                'limit' => 100,
        );

        $this->Prg->commonProcess();
                // 最初につぶやきを検索して対象のuser_idを取得
        $this->userid['conditions'] = $this->Tweet->parseCriteria($this->passedArgs);
        $this->userid['fields'] = array('DISTINCT Tweet.user_id');

        $array_user_id = $this->Tweet->find('all', $this->userid);

        $user_ids = array();
        foreach ($array_user_id as $wkTweet) {
            $user_ids[] = $wkTweet['Tweet']['user_id'];
        }

        $user_id['user_id'] = implode(',', $user_ids);

                // そのユーザIDで対象の全つぶやきを取得して編集
        $this->paginate['conditions'] = $this->Tweet->parseCriteria($user_id);
        $this->paginate['fields'] = array('Tweet.user_id','User.username', 'group_concat(tweet SEPARATOR "|") as tweets');
        $this->paginate['group'] = array('Tweet.user_id'); 
        $tweetLists = $this->paginate();
        $this->set(compact('tweetLists'));
    }
}
?>
//Model/Tweet.php
class Tweet extends AppModel {
    public $belongsTo = 'User';
    public $actsAs = array('Search.Searchable');
    public $filterArgs = array(
            'tweet' => array('type' => 'like'),
            'user_id' => array('type' => 'subquery','method' => 'searchIn', 'field' => 'Tweet.user_id')
    );

    function searchIn($data = array()) {
        $query = $data['user_id'];
        return $query;
    }
}
//View/Tweets/search.ctp
    <?php echo $this->Form->create('Tweet',array(
        'novalidate' => true,
        'url' => array_merge(array('action' => 'search'),
            $this->params['pass'])
        ));
        ?>
        <?php echo $this->Form->input('tweet', array(
            'type' => 'text',
            'placeholder' => '検索ワードを入力してください',
            'label' => false
            )); ?>
            <?php echo $this->Form->submit('検索'); ?>
            <?php echo $this->Form->end(); ?>
        </div>

        <div>
            <h2>検索結果</h2>
            <table>
                <tr>
                    <th><?php echo $this->Paginator->sort('User.username', 'ユーザー名'); ?></th>
                    <th><?php echo $this->Paginator->sort('tweet', 'つぶやき'); ?></th>
                </tr>

                <?php foreach($tweetLists as $tweetList): ?>

                    <tr>
                        <td><?php echo $this->Html->link($tweetList['User']['username'],'/users/view/'.$tweetList['Tweet']['user_id']) ?></td>
                        <td><?php echo h($tweetList[0]['tweets']); ?></td>
                    </tr>

                <?php endforeach; ?>

            </table>
        </div>

        <div>
            <?php echo $this->Paginator->prev(); ?>&nbsp;
            <?php echo $this->Paginator->numbers(); ?>&nbsp;
            <?php echo $this->Paginator->next(); ?>
        </div>


Model/User.phpについては、変更はありません
また、Group Byを使用しているので、ページネート処理が上手く行くかまでは検証していません
おそらくですが、このままではレコード総数の取得が上手く行かないため、ページ処理ではエラーが出ると思います・・・

投稿 2015/12/25 15:22

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    以下のような回答は評価を下げられます

    • 間違っている回答
    • 質問の回答になっていない投稿
    • 不快な投稿

    評価を下げる際はその理由をコメントに書き込んでください。

  • 2015/12/28 18:49

    大変丁寧なご回答、ありがとうございました。

    おかげさまで希望の動作を実装することが出来ました。
    ページネートも、正しく動作しているように見えます。

    回答いただいたソースも理解できるように勉強していこうと思います。

    キャンセル

teratailには29人のエキスパートがいます

今すぐはじめる

もっと詳しく

関連した質問

同じタグがついた質問を見る

  • CakePHP

    1691questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

閲覧数の多いCakePHPの質問

  • トップ
  • CakePHPに関する質問
  • [CakePHP 2.X]Search Pluginを用いたつぶやき検索で、ヒットしたつぶやきを持つuse_idの他のつぶやきを表示