概要
例えば、製品やユーザなどのデータに画像ファイルを関連付けたい時、OctoberCMSでは簡単にそのデータの管理ページに画像ファイルのアップロード・表示・管理機能が追加できる。意外にもドキュメントではまとまった説明がなかったのでここに記載する。
ステップ
- Configを設定
- モデルにリレーションを定義
- CRUD画面にファイルアップロードウィジェットを追加
前提
テーブル、モデル、CRUD画面は既に作成済み。
Configを設定する
まだ設定していない場合は config/filesystem.php にdisks
を設定する。デフォルトで存在するが、下記に注意。
-
local
を使用する場合、指定ディレクトリにweb serverユーザの書き込み権限がある。 -
s3
などクラウドを使用する場合はクラウドサーバへの書き込みが可能な状態。
下記の例ではenv()
を使用しているが、直書きでも問題ない。
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_REGION'),
'bucket' => env('AWS_S3_BUCKET'),
'visibility' => 'public',
],
],
そして、ファイルアップロード関連の設定は config/cms.php のstorage.uploads
で行う。
'storage' => [
'uploads' => [
'disk' => 'local',
'folder' => 'uploads',
'path' => '/storage/app/uploads',
],
// S3へを指定する場合は`path`はバケットへのURLを指定する必要がある
// 'uploads' => [
// 'disk' => 's3',
// 'folder' => 'uploads',
// 'path' => 'https://s3-ap-southeast-1.amazonaws.com/my-bucket/uploads',
// ],
...
],
対象データのモデルにリレーションを定義する
OctoberCMSでは添付ファイルの情報は別のテーブルに保存される。ここで説明するようにOctoberCMSの添付ファイルのドキュメントに従えば、添付ファイルの情報は既存のsystem_files
テーブルに保存されるので、新たにテーブルを作成したり修正したりする必要はない。
対象のモデルクラスにattachOne
またはattachMany
を追加する。下記の例ではProduct
というモデルクラスに$attachMany
フィールドを設けてattachManyリレーションを定義している。リレーション名がimage
でリレーションのモデルクラスをSystem\Models\File
としている。
public $attachMany = [
'images' => 'System\Models\File'
];
CRUD画面にファイルアップロードウィジェットを追加する
BuilderプラグインのCRUD画面作成画面からでFileUpload controlを追加する。
追加したウィジェットの設定でField nameをモデルクラスで定義したリレーション名に設定する。上記の場合、images
になる。
ファイルが画像の場合は、Builderで生成されたyamlファイル(デフォルトでは<plugin_name>/models/<model_name>/fields.yaml
)を開いて追加したフィールドのmode
をimage
にすると、サムネイルを表示してくれる。
fields:
name:
label: 'cocci.utility::backend.common.field.name.label'
oc.commentPosition: ''
span: auto
required: true
type: text
display_name:
label: 'cocci.utility::backend.common.field.display_name.label'
oc.commentPosition: ''
span: auto
required: true
type: text
description:
label: 'cocci.utility::backend.common.field.description.label'
size: large
oc.commentPosition: ''
span: auto
type: textarea
images:
label: Images
oc.commentPosition: ''
mode: image
useCaption: true
thumbOptions:
mode: crop
extension: auto
span: auto
type: fileupload
アップロードしたファイルの使用方法
データに添付したファイルの使用方法も非常に簡単だ。
例えば上の例だと、下記のようにアップロードしたファイルのURLを取得できる。
$product->images[0]->getPath();
また、attachOne
のリレーションの場合は単純に配列ではなくなる。
$product->image->getPath();
Twigテンプレートからは単純にこうだ。
<img src='{{ product.images[0].getPath() }}'>
バグ対処方法
2018/1/1現在(build 431)、OctoberCMSにバグらしきものがあり、storage.uploads.disk
が効かない。代わりにfilesystem.phpのdefault
が適用されてしまっている。が、修正されるまで比較的簡単・安全な方法で回避できる。
上記の説明ではSystem\Models\File
をリレーションモデルに使用しているが、このクラスを拡張して修正を仕込む。1行目のnamespaceだけ適宜変更すれば下記を丸コピーでよい。
<?php namespace Pikanji\Myplugin\Models;
use Config;
use File as FileHelper;
use Storage;
class File extends \System\Models\File
{
/**
* Returns true if storage.uploads.disk in config/cms.php is "local".
* @return bool
*/
protected function isLocalStorage()
{
return Config::get('cms.storage.uploads.disk') == 'local';
}
/**
* Copy the local file to Storage
* @return bool True on success, false on failure.
*/
protected function copyLocalToStorage($localPath, $storagePath)
{
$disk = Storage::disk(Config::get('cms.storage.uploads.disk'));
return $disk->put($storagePath, FileHelper::get($localPath), ($this->isPublic()) ? 'public' : null);
}
}
そして、このクラスをattachOne/Manyで指定したSystem\Models\File
の代わりに指定する。これで、storage.uploads.disk
で指定した先にアップロードしたファイルが保存されるはずだ。
この修正は、System\Models\File
のベースクラスOctober\Rain\Database\Attach\File
のメソッドisLocalStorage
とcopyLocalToStorage
をオーバーライドしている。元のメソッドはcms.storage.uploads.disk
ではなくfilesystem.default
を見てしまっているからだ。
この問題はこのissueで報告しており、pull requestも出しているので、早く取り込んでもらいたい。