mediaプラグイン導入(1) 基本的な導入

画像など、アップロードファイルを保存・表示するプラグイン「Media Plugin for CakePHP」を導入してみました。

個人的に、実際に使うには、若干機能追加が欲しい感じですが、まずは基本機能の導入から。


今回の目標

  1. 「ユーザのイメージ画像アップロード&表示」機能を追加
  2. 1ユーザが設定できるイメージ画像は、1種類
  3. アップロード画面は、users/edit(ユーザ情報編集画面)とは別アクション(usersの項目を編集しない)。
  4. CakePHPのバージョンは1.2.5

手間取った点

  1. Formにtype => 'file'の設定ミス
  2. user_idの設定(usersの項目を編集しない画像設定アクションに設定したため)

導入作業

  1. GitHubからソース取得。

バージョンは0.6.0。

  1. app/plugins/media を作成し、取得したソースを全てアップロード
[cake@cake cake-frame]$ mkdir app/plugins/media
(アップロードは省略)
  1. attachmentsテーブルの作成
[cake@cake cake-frame]$ ./cake/console/cake schema run create media -path app/plugins/media/config/sql/


Welcome to CakePHP v1.2.4.8284 Console
---------------------------------------------------------------
App : app
Path: /var/www/html/cake-frame/app
---------------------------------------------------------------
Cake Schema Shell
---------------------------------------------------------------

The following table(s) will be dropped.
attachments

Are you sure you want to drop the table(s)? (y/n)
[n] > y
Dropping table(s).
attachments updated.

The following table(s) will be created.
attachments

Are you sure you want to create the table(s)? (y/n)
[y] > y
Creating table(s).
attachments updated.
End create.
1. DROP TABLE IF EXISTS `attachments`;

2. CREATE TABLE `attachments` (
        `id` int(10) NOT NULL AUTO_INCREMENT,
        `model` varchar(255) NOT NULL,
        `foreign_key` int(10) NOT NULL,
        `dirname` varchar(255) DEFAULT NULL,
        `basename` varchar(255) NOT NULL,
        `checksum` varchar(255) NOT NULL,
        `group` varchar(255) DEFAULT NULL,
        `alternative` varchar(50) DEFAULT NULL,
        `created` datetime DEFAULT NULL,
        `modified` datetime DEFAULT NULL,       PRIMARY KEY  (`id`));
  1. app/webroot/mediaの作成とパーミッション設定

ver0.6では、cakeコマンドからインタラクティブに作成できます。
transfer/.htaccessの作成も、自動でできています。

[cake@cake cake-frame]$ ./cake/console/cake media

--------------------------------------------------------------------------------
Media Shell
--------------------------------------------------------------------------------
[I]nitialize Media Directory
[P]rotect Transfer Directory
[S]ynchronize
[M]ake
[C]ollect
[H]elp
[Q]uit
What would you like to do? (I/P/S/M/C/H/Q)
[q] > I

Do you want to create missing media directories now?
[n] > y
/app/webroot/media/                                [SKIP]
/app/webroot/media/static/                         [OK  ]
/app/webroot/media/static/aud                      [OK  ]
/app/webroot/media/static/css                      [OK  ]
/app/webroot/media/static/doc                      [OK  ]
/app/webroot/media/static/gen                      [OK  ]
/app/webroot/media/static/ico                      [OK  ]
/app/webroot/media/static/img                      [OK  ]
/app/webroot/media/static/js                       [OK  ]
/app/webroot/media/static/txt                      [OK  ]
/app/webroot/media/static/vid                      [OK  ]
/app/webroot/media/transfer/                       [OK  ]
/app/webroot/media/transfer/aud                    [OK  ]
/app/webroot/media/transfer/css                    [OK  ]
/app/webroot/media/transfer/doc                    [OK  ]
/app/webroot/media/transfer/gen                    [OK  ]
/app/webroot/media/transfer/ico                    [OK  ]
/app/webroot/media/transfer/img                    [OK  ]
/app/webroot/media/transfer/js                     [OK  ]
/app/webroot/media/transfer/txt                    [OK  ]
/app/webroot/media/transfer/vid                    [OK  ]
/app/webroot/media/filter/                         [OK  ]

Your transfer directory is missing a htaccess file to block requests.
Do you want to create it now?
[n] > y
/app/webroot/media/transfer/.htaccess created.

Remember to set the correct permissions on transfer and filter directory.
--------------------------------------------------------------------------------
Media Shell
--------------------------------------------------------------------------------
[I]nitialize Media Directory
[P]rotect Transfer Directory
[S]ynchronize
[M]ake
[C]ollect
[H]elp
[Q]uit
What would you like to do? (I/P/S/M/C/H/Q)
[q] > Q

Quitting.

[cake@cake cake-frame]$ chmod -R 777 app/webroot/media/transfer/
[cake@cake cake-frame]$ chmod -R 777 app/webroot/media/filter/
[cake@cake cake-frame]$ ls -l  app/webroot/media/
合計 24
drwxrwxrwx  2 cake cake 4096  2月 15 23:14 filter
drwxr-xr-x 11 cake cake 4096  2月 15 23:14 static
drwxrwxrwx 11 cake cake 4096  2月 15 23:14 transfer


アップロードファイルについて、.gitignoreの設定追加も忘れずに。

--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@
 app/tmp/*
 app/config/core.php
 app/config/database.php
+app/webroot/media/*
  1. ファイルの移動

こちらも、cakeコマンドから実施。
webroot/js/とwebroot/css/にしかファイルを追加してないので、実質この2ディレクトリからのファイル移動になります。

でもこれは、mediaプラグイン経由でファイルを呼び出す場合のみ移動が必要のようなので、通常通り呼び出すなら不要のようです。

--------------------------------------------------------------------------------
Media Shell
--------------------------------------------------------------------------------
[I]nitialize Media Directory
[P]rotect Transfer Directory
[S]ynchronize
[M]ake
[C]ollect
[H]elp
[Q]uit
What would you like to do? (I/P/S/M/C/H/Q)
[q] > C

Would you like to collect files from /app/vendors/?
[y] > y
Would you like to collect files from /vendors/?
[y] > y
Would you like to collect files from /app/webroot/?
[y] > y
Would you like to collect files from /app/plugins/cakeplus/vendors/?
[y] > y
Would you like to collect files from /app/plugins/media/vendors/?
[y] > y
Would you like to add another path?
[n] > n
Would you like to link (instead of copy) the files?
[n] > n

Mapping
--------------------------------------------------------------------------------
/app/webroot/favicon.ico               -> /app/webroot/media/static/img/favicon.ico
/app/webroot/js/jquery-1.3.2.min.js    -> /app/webroot/media/static/gen/jquery-1.3.2.min.js
(以下、移動するファイルが列記)

Looks OK?
[y] > y

Collecting
--------------------------------------------------------------------------------
  2.94% [OK    ] /app/webroot/favicon.ico
  5.88% [OK    ] /app/webroot/js/jquery-1.3.2.min.js
(以下、移動処理列記)

[I]nitialize Media Directory
[P]rotect Transfer Directory
[S]ynchronize
[M]ake
[C]ollect
[H]elp
[Q]uit
What would you like to do? (I/P/S/M/C/H/Q)
[q] > q

Quitting.
  1. media plugin設定の読み込み追加

app/config/bootstrap.php 差分

--- a/app/config/bootstrap.php
+++ b/app/config/bootstrap.php
@@ -45,5 +45,8 @@
 require_once ('init.php');
 require_once ('config.php');

+/* media plugin */
+require_once(APP.'plugins'.DS.'media'.DS.'config'.DS.'core.php');
+

init.php、およびconfig.phpは独自に追加した設定ファイル。
media plugin設定の上書きを考慮して、これらのファイルの後にmedia pluginの設定を読み込む事にしました。

  1. ファイルをアップロードするモデルに、Associationを追加

対象モデルはUserなので、以下の通りに設定を追加。

app/models/user.php 差分

       //The Associations below have been created with all possible keys, those that are not needed can be removed
       var $hasMany = array(
+               'Attachment' => array(
+                       'className' => 'Media.Attachment',
+                       'foreignKey' => 'foreign_key',
+                       'conditions' => array('model' => 'User'),
+                       'dependent' => true,
+               )
       );


ここから、画像編集画面を別作成したため、参考サイトと違う点が出てきます。

  1. コントローラ編集

app/controllers/users_controller.php

--- a/app/controllers/users_controller.php
+++ b/app/controllers/users_controller.php
@@ -10,6 +10,7 @@ class UsersController extends ModuleController {
        var $actionMapPlus = array(
                'listview' => 'read',
                'change_password' => 'update',
+               'edit_image' => 'update',
        );

        var $disableTokenActions = array('add','mobile_add');
@@ -73,6 +74,31 @@ class UsersController extends ModuleController {
                self::_edit($id);
        }

+       function edit_image() {
+               $id = $this->AuthPlus->user("id");
+
+               if (!empty($this->data)) {
+                       $this->data['User']['id'] = $id;
+
+                       if ($this->User->saveAll($this->data, array('validate' => 'first'))) {
+                               $this->Session->setFlash(__('The User has been saved', true));
+                               $this->redirect(array('action'=>'index'));
+                       } else {
+                               $this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
+                               $this->data['User']['id'] = $id;
+                       }
+               }
+
+               $this->data = $this->User->read(null, $id);
+       }
+


いろいろ書いてますが、

$this->data['User']['id'] = $id;

if ($this->User->saveAll($this->data, array('validate' => 'first'))) {

この2つが要です。

  1. 追加テンプレート

app/views/users/edit_image.ctp

<div class="users form">
<?php echo $form->create('User', array(
	'url' => array(
		'controller' => 'users',
		'action' => 'edit_image',
	),
	'type' => 'file',
));?>
<fieldset>
<legend><?php __('Edit Image');?></legend>
<?php
	echo $this->element('attachments', array('plugin' => 'media'));

	echo $token->create();
?>
</fieldset>
<?php echo $form->end('Submit');?>
</div>

<div class="backButton">
<?php
echo $form->create('', array('url' => array(
	'action' => 'view', $this->data['User']['id']),
	'type' => 'GET',
));
echo $form->end('Cancel');
?>
</div>


users/edit_image/edit_imageから、アップロードする画像を選択、Textual replacementという項目に、適当な文字列を入力して送信すると、
アクションで受信する$this->dataは、以下のようになっています。

array(2) {
	["Attachment"]=>  array(1) {
		[0]=>  array(4) {
			["model"]=>  string(4) "User"
			["group"]=>  string(10) "attachment" 
			["alternative"]=>  string(4) "another name" 
			["file"]=>  array(5) {
				["name"]=>  string(11) "tooMuch.jpg" 
				["type"]=>  string(10) "image/jpeg" 
				["tmp_name"]=>  string(14) "/tmp/phplHK1t1" 
				["error"]=>  int(0) 
				["size"]=>  int(32702)
			}
		}
	} 
	["User"]=>  array(1) { ["__Token"]=>  string(32) "a5f4435546a39b8dcd462ada229a9eb9"} 
} 

そして、attachmentsには以下のデータが保存されます。

mysql> SELECT * FROM attachments\G
*************************** 1. row ***************************
         id: 1
      model: User
foreign_key: 1
    dirname: transfer/img
   basename: toomuch.jpg
   checksum: e5c689305d1dfb481a3d098280034e21
      group: attachment
alternative: another name
    created: 2010-02-16 00:34:40
   modified: 2010-02-16 00:34:40
1 row in set (0.00 sec)

そして実画像データは、dirname/basenameである以下に保存されていました。

[cake@cake cake-frame]$ ls -l app/webroot/media/transfer/img/
合計 36
-rw-r--r-- 1 apache apache 32702  2月 16 00:34 toomuch.jpg