CakePHPでチェックボックスで選択した画像の名前をテーブルに保存

CakePHPでチェックボックスで選択した画像の名前をテーブルに保存

65 回閲覧されました

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

CakePHPのaddアクションで表示するビューで画像の下にチェックボックスをつけて選択された画像の名前をテーブルに保存して選択した画像をビューに表示したかったのですが中々できず苦労しました。

ネットを調べてもやり方を解説している記事は多分ありません。

私と同じ状況になって苦労している人がいるはずなのでそんな人の為にこの記事を残します。

CakePHPのバージョン

3.1.0と4.5.3で動作の確認ができたので2つのバージョンの間なら動作はできるはずです。

デモ

下記の赤枠の部分に画像とチェックボックスを設置します。

画像以外の部分は今回の説明には必要ないので説明しません。

画像を選択して保存するとテーブルの「image」カラムに保存されます。

そして下記の赤枠の部分に画像を表示させます。

それでは実装していきます。

CSS

「CakePHPのプロジェクト > webroot > css > cake.css」に下記を記述して下さい。

img{
    width: 200px;
}

.img-wrap{
    display: flex;
    column-gap:10px;
}

.checkbox{
    text-align: center;
}

マイグレーションファイル

画像名が保存されるカラム名を「image」にします、データ型は下記になります。

$table
  ->addColumn('image', 'string', [
    'limit' => 255,
    'null' => false,
])

addアクション

コードを下記にします。

public function add()
{
  $this->loadModel('Users');
        
  $review = $this->Reviews->newEmptyEntity();

  if ($this->request->is('post')) {
    $review = $this->Reviews->patchEntity($review, $this->request->getData());

    
    $review->image = $this->request->getData('selectedImage');
    

    if ($this->Reviews->save($review)) {
      $this->Flash->success(__('The review has been saved.'));

      return $this->redirect(['action' => 'index']);
    }else{
        $this->Flash->error(__('The review could not be saved. Please, try again.'));
    }
  }

  $selectUser = $this->Users->find('list', ['limit' => 100]);

  $imgPaths = [
    '/img/1.png',
    '/img/2.png',
    '/img/3.png',
  ];

  $this->set(compact('review', 'selectUser', 'imgPaths'));
}

画像をadd.phpで表示するための画像のパスを配列に格納しているのが25行目〜29行目です。

画像自体は「CakePHPのプロジェクト > webroot > img」の下の階層に設置しています。

選択した画像を取得しているのは11行目です。

ビュー

add.phpのコードを下記にします。

<div class="row">
    <aside class="column">
        <div class="side-nav">
            <h4 class="heading"><?= __('Actions') ?></h4>
            <?= $this->Html->link(__('List Reviews'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
        </div>
    </aside>
    <div class="column-responsive column-80">
        <div class="reviews form content">
            <?= $this->Form->create($review) ?>
            <fieldset>
                <legend><?= __('Add Review') ?></legend>
                <?php
                    echo $this->Form->control('customer_sender_id', ['options' => $selectUser]);
                    echo $this->Form->control('shop_receiver_id', ['options' => $selectUser]);
                    echo $this->Form->control('message');
                ?>
                <div class="img-wrap">
                <?php foreach($imgPaths as $imgPath):?>
                    <div>
                        <?php 
                            echo $this->Html->image($imgPath, ['alt' => '', 'class' => 'image']);
                            $imgName = basename($imgPath); 
                        ?>
                        <div class="checkbox"><input type="checkbox" name="selectedImage" value="<?php echo $imgName; ?>"></div>
                    </div>
                <?php endforeach ?>
                </div>
            </fieldset>
            <?= $this->Form->button(__('Submit')) ?>
            <?= $this->Form->end() ?>
        </div>
    </div>
</div>

画像とチェックボックスを表示しているのは19行目〜27行目です。

コントローラーには画像のパスが記述されていますが画像名だけを切り取ってvalue属性に使う為に23行目があります。

画像を選択できる画面のHTMLは下記ですがvalue属性に画像名だけが入っているのが確認できます。

最後にビューに選択した画像を表示します。

indexアクションとindex.php

indexアクションのコードは下記になります。

public function index()
{
  $this->loadModel('Demo');

  $reviews = $this->paginate($this->Reviews->find('all', ['contain' => ['Users', 'CustomerSender', 'ShopReceiver']]));

  $demos = $this->Demo->find();

  $this->set(compact('reviews', 'demos'));
}

index.phpのコードは下記になります。

<div class="reviews index content">
    <?= $this->Html->link(__('New Review'), ['action' => 'add'], ['class' => 'button float-right']) ?>
    <h3><?= __('Reviews') ?></h3>
    <div class="table-responsive">
        <table>
            <thead>
                <tr>
                    <th><?= $this->Paginator->sort('id') ?></th>
                    <th><?= $this->Paginator->sort('customer_id') ?></th>
                    <th><?= $this->Paginator->sort('shop_id') ?></th>
                    <th><?= $this->Paginator->sort('message') ?></th>
                    <th><?= $this->Paginator->sort('image') ?></th>
                    <th><?= $this->Paginator->sort('created') ?></th>
                    <th><?= $this->Paginator->sort('modified') ?></th>
                    <th class="actions"><?= __('Actions') ?></th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($reviews as $review): ?>
                <tr>
                    <td><?= $this->Number->format($review->id) ?></td>
                    <td><?= $review->customer_sender->id ?></td>
                    <td><?= $review->shop_receiver->name ?></td>
                    <td><?= h($review->message) ?></td>
                    <td><?= $this->Html->image($review->image, ['alt' => 'Image']) ?></td>
                    <td><?= h($review->created) ?></td>
                    <td><?= h($review->modified) ?></td>
                    <td class="actions">
                        <?= $this->Html->link(__('View'), ['action' => 'view', $review->id]) ?>
                        <?= $this->Html->link(__('Edit'), ['action' => 'edit', $review->id]) ?>
                        <?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $review->id], ['confirm' => __('Are you sure you want to delete # {0}?', $review->id)]) ?>
                        <!-- <?php foreach($demos as $demo):?>
                        <?= $this->Html->link('リンク', ['controller' => 'Demo', 'action' => 'view', $demo->id ]) ?>
                        <?php endforeach ?> -->
                    </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>

画像を表示しているのは25行目です。

これで完成です。