CakePHPで画像をプロジェクト内にアップロード機能を実装する方法

1077 回閲覧されました
みなさんこんにちは、jonioです。
今回はCakePHPでプロジェクト内に画像をアップロードする方法の解説をします。
CakePHPのバージョン
4.5.4で解説しますが3系では書き方が違うかもしれません。
前提
テーブル名はuploadsテーブルとします。
モデル・コントローラー・ビューはallコマンドで作成してデフォルトのコードを少し変えることで実装しています。
やりたいこと
画像のアップロードをするページで画像をアップロードして登録します。

すると画像登録用のテーブル(uploadsテーブル)のnameカラムに画像名が登録されて「CakePHPのプロジェクト > webroot > img > uploads」の下の階層に画像が登録されます。
それでは実装します。
ビュー
add.phpのコードを下記にします。
<div class="row">
    <aside class="column">
        <div class="side-nav">
            <h4 class="heading"><?= __('Actions') ?></h4>
            <?= $this->Html->link(__('List Uploads'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
        </div>
    </aside>
    <div class="column-responsive column-80">
        <div class="uploads form content">
            <?= $this->Form->create($upload, ['type' => 'file']) ?>
            <fieldset>
                <legend><?= __('Add Upload') ?></legend>
                <?php
                    echo $this->Form->file('file');
                ?>
            </fieldset>
            <?= $this->Form->button(__('Submit')) ?>
            <?= $this->Form->end() ?>
        </div>
    </div>
</div>10行目の「[‘type’ => ‘file’]」と14行目で画像を登録できるようになります。
次はコントローラーのアクションです。
アクション
コードを下記にします。
public function add()
{
  $upload = $this->Uploads->newEmptyEntity();
  if ($this->request->is('post')) {
    
    //ここから追加
    $uploadedFile = $this->request->getData('file');
    if (!empty($uploadedFile)) {
      $uploadedFileName = $uploadedFile->getClientFilename();
      $filePath = WWW_ROOT . 'img/uploads/' . $uploadedFileName;
      $uploadedFile->moveTo($filePath);
      $this->request = $this->request->withData('eyecatch', $uploaded_file_name);
    }
    //ここまで追加
    
    $upload = $this->Uploads->patchEntity($upload, $this->request->getData());
    
    if ($this->Uploads->save($upload)) {
      $this->Flash->success(__('The upload has been saved.'));
      return $this->redirect(['action' => 'index']);
    }
    $this->Flash->error(__('The upload could not be saved. Please, try again.'));
  }
  $this->set(compact('upload'));
}まずは画像名をuploadsテーブルのnameカラムに登録します。
画像名の登録
9行目はビューで登録した画像を受け取る為にあります。
$uploadedFileに何が入っているかを確認する為にdd関数を使います。
                    ・
                    ・
                    ・
$uploadedFile = $this->request->getData('file');
dd($uploadedFile);
                    ・
                    ・
                    ・ビューで画像を登録すると下記の表示になります。
object(Laminas\Diactoros\UploadedFile) id:0 {
  private error => (int) 0
  private file => '/Applications/MAMP/tmp/php/phpZ9Zk3B'
  private moved => false
  private stream => null
  private size => (int) 18068
  private clientFilename => 'demo-image.png'
  private clientMediaType => 'image/png'
}8行目の「demo-image.png」が登録した画像名です。
$uploadedFileから画像名を取得するにはgetClientFilenameメソッドを使います、それが12行目です。
そして$uploadedFileNameをuploadsテーブルのnameカラムに登録するために18行目があります。
次は画像をアップロードします。
画像のアップロード
14行目はCakePHPの中のどこに画像を配置するかの設定をしてます。
「WWW_ROOT」はCakePHPプロジェクトの直下にあるwebrootのことです。
「/img/uploads」のuploads(フォルダ名)はデフォルトでは存在しないのでimgフォルダの下の階層に作成してください。
16行目で画像をアップロードしていますがmoveToメソッドを使えば実現します、引数には画像を配置するパス(14行目)を記述します。
カラムに画像名を登録
22行目は下記でもうまくいきそうな気がします。
$upload->file = $uploadedFileName;しかしこれだと下記のエラーが出ます。
Object of class Laminas\Diactoros\UploadedFile could not be converted to string$uploadedFileNameはオブジェクトなので文字列に変換しないとカラムに値を保存できない為22行目の書き方になります。
これで画像を登録するとuploadsテーブルのnameカラムに画像名が登録されてuploadsフォルダの下の階層に画像が保存されます。
