Posts Tagged ‘CakePHP3’

[CakePHP3]2つのファイルアップロードのうちどちらか一方を必須にしたい

複数のファイルアップロードフィールドを配置し、それら全てではなく、そのうち一つが入力されることを保証するバリデーションを行いたいというケースがある。

https://book.cakephp.org/3.0/ja/core-libraries/validation.html#id9
ここにあるように条件付きバリデーションで実装しようとしてnotEmpty()メソッドに on オプションをつけてみたが、$this->Form->file()でレンダリングされた時点で全てのファイルアップロードフィールドに required 属性が付与されてしまって全てが必須になってしまう。

こういう時は時間があればバリデーションクラスを実装する方が美しいが、余裕がなければ標準から外れてしまうが思い切ってバリデータの使用は諦めて、コントローラーで実装してしまった方が早い。

その場合、エラーメッセージはEntityクラスのsetError()メソッドを使って、

1
2
3
4
5
6
7
8
9
10
11
12
$foo = $this->Foos->patchEntity($foo, $this->request->getData());
if ($foo->getErrors()) {
    // 入力チェックエラー
}
else if (!isset($this->request->getData('file1')['name'])
        && !isset($this->request->getData('file2')['name'])) {
    // 独自のバリデーションエラー
    $foo->setError('file1', 'ここにエラーメッセージを書く');
}
else {
    // 保存処理など
}

のような形でセットしてやれば、画面の方で他のバリデーションエラーと同様に表示ができる。

—-

[CakePHP3]ファイルを持つエンティティにpatchEntityメソッドでファイルアップロードフィールドをコピーしたい

Webサイトであれば、アップロードしたファイルをストレージに保存し、ファイルのパスまたはURLをデータベースで管理するといったケースはよく行われるだろう。

とあるBlogエンティティに画像のファイルパスを複数持っているとする。例えばこんな感じ。

  • blog_title
  • blog_image_path_1
  • blog_image_path_2

これを愚直にこのようなフォームにしてしまうとする。

1
2
3
4
5
<?= $this->Form->create($blog, ['enctype' => 'multipart/form-data']) ?>
  <?= $this->Form->text('blog_title') ?>
  <?= $this->Form->file('blog_image_path_1') ?>
  <?= $this->Form->file('blog_image_path_2') ?>
<?= $this->Form->end() ?>

このフォームのリクエストを受け取って

1
2
3
$blog = $this->Blogs->get($id); // DBから取得
$blog = $this->Blogs->patchEntity($blog, $this->request->getData()); // 画面の入力を反映
$this->Blogs->save($blog); // DBに保存

としてしまうのは、2つのファイルが両方とも必須項目であればともかく、片方だけ変更するといったケースでは、指定しなかった方のファイルパスがブランクになってしまって都合が悪い。

そういう場合は、イレギュラーな対応かもしれないが、直接コピーすることをせずに、エンティティにはない項目を一時的に使用して、最終的にエンティティに格納するようにする。そもそもファイルアップロードフィールドには初期値は設定できないのだ。

1
2
3
4
5
<?= $this->Form->create($blog, ['enctype' => 'multipart/form-data']) ?>
  <?= $this->Form->text('blog_title') ?>
  <?= $this->Form->file('blog_image_file_1') ?>
  <?= $this->Form->file('blog_image_file_2') ?>
<?= $this->Form->end() ?>
1
2
3
4
5
6
7
8
9
10
11
$blog = $this->Blogs->get($id);
$blog = $this->Blogs->patchEntity($blog, $this->request->getData());
// 1つ目のファイルが指定されていたら反映
if (isset($this->request->getData('blog_image_file_1')['name'])) {
    $blog->blog_image_path_1 = $this->request->getData('blog_image_file_1')['name'];
}
// 2つ目のファイルが指定されていたら反映
if (isset($this->request->getData('blog_image_file_2')['name'])) {
    $blog->blog_image_path_2 = $this->request->getData('blog_image_file_2')['name'];
}
$this->Blogs->save($blog);

尚、入力チェックや、基本ディレクトリ名の合成などは省略しているので、各々の状況に合わせてアレンジして欲しい。

ファイルアップロードフォームから渡ってくる項目の詳細については以下を参照のこと。
https://secure.php.net/manual/ja/features.file-upload.post-method.php

—-

アーカイブ