CakePHP初心者向け。バージョン3と4でいいねボタンの実装方法

CakePHP初心者向け。バージョン3と4でいいねボタンの実装方法

299 回閲覧されました

みなさんこんにちは、jonioです。

CakePHPでいいねボタンを実装する方法のメモとしてこの記事を残します。

ネットを見るとライブラリを使って実装する記事がありますが記述で簡単にできる印象です。

CakePHPのバージョン

3.1.0と4.5.3で確認しましたが記述方法が廃止になってなければ5系でも実装できるかもしれません。

今回は4.5.3を使います。

用意するテーブル

テーブルは何でもいいですがDemoテーブルを使います、like_flagカラムがあればいいです。

一応マイグレーションファイルの中身を記載します。

<?php
declare(strict_types=1);

use Migrations\AbstractMigration;

class CreateDemo extends AbstractMigration
{
    /**
     * Change Method.
     *
     * More information on this method is available here:
     * https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
     * @return void
     */
    public function change(): void
    {
        $table = $this->table('demo');
        $table
        ->addColumn('title', 'string', [
            'limit' => 255
        ])
        ->addColumn('content', 'string', [
            'limit' => 255
        ])
        ->addColumn('like_flag', 'boolean', [
            'default' => 0
        ])
        ->addColumn('created', 'datetime', [
            'default' => null,
            'null' => true
        ])
        ->addColumn('modified', 'datetime', [
            'default' => null,
            'null' => true
        ])
        ->create();
    }
}

実装方法

Demoテーブルのlike_flagカラムの値は登録せずデフォルト値に0を設定します。

いいねボタンをクリックすることでlike_flagの値を1に切り替えます。

一覧ページを作って1つ1つの投稿の詳細ページにいいねボタンを設置します。

1つ1つは下記の赤枠になります。

詳細ページは下記です。(赤枠がいいねボタンです)

一覧ページ

DemoController.phpのindexアクションは下記です、デフォルトのままだと思います。

public function index()
{
  $demo = $this->paginate($this->Demo);

  $this->set(compact('demo'));
}

index.phpは下記です、デフォルトのままだと思います。

<?php
/**
 * @var \App\View\AppView $this
 * @var iterable<\App\Model\Entity\Demo> $demo
 */
?>
<div class="demo index content">
    <?= $this->Html->link(__('New Demo'), ['action' => 'add'], ['class' => 'button float-right']) ?>
    <h3><?= __('Demo') ?></h3>
    <div class="table-responsive">
        <table>
            <thead>
                <tr>
                    <th><?= $this->Paginator->sort('id') ?></th>
                    <th><?= __('title') ?></th>
                    <th><?= __('content') ?></th>
                    <th><?= __('like_flag') ?></th>
                    <th class="actions"><?= __('Actions') ?></th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($demo as $demo): ?>
                <tr>
                    <td><?= $this->Number->format($demo->id) ?></td>
                    <td><?= $demo->title ?></td>
                    <td><?= $demo->content ?></td>
                    <td><?= $this->Number->format($demo->like_flag) ?></td>
                    <td class="actions">
                        <?= $this->Html->link(__('View'), ['action' => 'view', $demo->id]) ?>
                        <?= $this->Html->link(__('Edit'), ['action' => 'edit', $demo->id]) ?>
                        <?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $demo->id], ['confirm' => __('Are you sure you want to delete # {0}?', $demo->id)]) ?>
                    </td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>
    <div class="paginator">
        <ul class="pagination">
            <?= $this->Paginator->first('<< ' . __('first')) ?>
            <?= $this->Paginator->prev('< ' . __('previous')) ?>
            <?= $this->Paginator->numbers() ?>
            <?= $this->Paginator->next(__('next') . ' >') ?>
            <?= $this->Paginator->last(__('last') . ' >>') ?>
        </ul>
        <p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
    </div>
</div>

詳細ページ

DemoController.phpのviewアクションは下記です、デフォルトのままだと思います。

public function view($id = null)
{
  $demo = $this->Demo->get($id, [
            'contain' => [],
  ]);

  $this->set(compact('demo'));
}

view.phpは下記です、反応しないいいねボタンをとりあえず設置します。

<?php
/**
 * @var \App\View\AppView $this
 * @var \App\Model\Entity\Demo $demo
 */
?>
<div class="row">
    <aside class="column">
        <div class="side-nav">
            <h4 class="heading"><?= __('Actions') ?></h4>
            <?= $this->Html->link(__('Edit Demo'), ['action' => 'edit', $demo->id], ['class' => 'side-nav-item']) ?>
            <?= $this->Form->postLink(__('Delete Demo'), ['action' => 'delete', $demo->id], ['confirm' => __('Are you sure you want to delete # {0}?', $demo->id), 'class' => 'side-nav-item']) ?>
            <?= $this->Html->link(__('List Demo'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
            <?= $this->Html->link(__('New Demo'), ['action' => 'add'], ['class' => 'side-nav-item']) ?>
        </div>
    </aside>
    <div class="column-responsive column-80">
        <div class="demo view content">
            <h3><?= h($demo->id) ?></h3>
            <table>
                <tr>
                    <th><?= __('Id') ?></th>
                    <td><?= $this->Number->format($demo->id) ?></td>
                </tr>
                <tr>
                    <th><?= __('Title') ?></th>
                    <td><?= $demo->title ?></td>
                </tr>
                <tr>
                    <th><?= __('Content') ?></th>
                    <td><?= $demo->content ?></td>
                </tr>
                <tr>
                    <th><?= __('Like_flag') ?></th>
                    <td><?= $demo->like_flag ?></td>
                </tr>
            </table>


            //ここから追加
            <?= $this->Form->create() ?>
                <?= $this->Form->button(__('いいね'))?>
            <?= $this->Form->end ?>
            //ここまで追加
            
            
        </div>
    </div>
</div>

それではいいねボタンを機能させます。

いいねボタンのアクション

DemoController.phpにlikeアクションを作成しますが少しずつ作成します。

まずは詳細ページの変数(「http://localhost/demo/view/3」の「3」のこと)を取得します。

public function like($id = null)
{
  $demo = $this->Demo->get($id);
}

demoテーブルの「like_flag」カラムを0から1(falseからtrue)に変えます。

public function like($id = null)
{
  $demo = $this->Demo->get($id);
  
  $demo->like_flag = true;                  //この行を追加
}

値を変更した「like_flag」を保存します。

public function like($id = null)
{
  $demo = $this->Demo->get($id);
  
  $demo->like_flag = true;
  
  $like_flag_entity = $this->Demo->patchEntity($demo, $demo->toArray());     //この行を追加
}

7行目の「->toArray()」で5行目の$demo->like_flagがtrueになったのを配列に変換します。

配列に変換する理由はこのあと出てくるsaveメソッドを使う時はデータが配列じゃないといけないからです。

そして「patchEntity」でlike_flagカラムがtrueになったのが適用されます。

最後にデータを保存します。

public function like($id = null)
{
  $demo = $this->Demo->get($id);
  
  $demo->like_flag = true;
  
  $like_flag_entity = $this->Demo->patchEntity($demo, $demo->toArray()); 
  
  $this->Demo->save($like_flag_entity);             //この行を追加 
}

11行目の「saveメソッド」でlike_flagカラムがtrueになったのを保存します。

ボタンを機能させる

一覧ページに設置したいいねボタンを機能させます。

先ほど作成したview.phpのいいねボタンのコードを書きに変更します。

<?= $this->Form->create($demo, ['url' => ['action' => 'like', $demo->id]]) ?>    //この行を修正
  <?= $this->Form->button(__('いいね'))?>
<?= $this->Form->end ?>

「->create()」のカッコの中を修正しています。

1行目の「$demo」は「$モデル名」です、likeアクションはDemoコントローラーを使っているので「$demo」となります。

「[‘action’ => ‘like’, $demo->id]」の意味は「フォームボタンを押した時にlikeアクションに$demo->idのデータが送信される」という意味です。

「$demo->id」は詳細ページのパラメーターのことです。(下記赤枠参照)

よっていいねボタンを押した時にlikeアクションがパラメーターの値に該当する詳細ページでいいねをつけることができます。