LoginSignup
3
3

More than 5 years have passed since last update.

CakePHP3:関連するテーブルにデータを保存(画像アップロード)

Last updated at Posted at 2017-06-04

本投稿は、こちらの記事の復習といいますか、応用編です:
http://qiita.com/uedatakeshi/items/fd3de8e2b770798aacfc
@uedatakeshi様、ありがとうございます)

仮に、postsというテーブルとpost_imagesというテーブルがあるとします。
postsにはブログの記事を、post_imagesには記事に関連する画像を格納するとします。

postgresで恐縮ですが、テーブルはこんな感じです:

\d posts
                                  テーブル "public.posts"
     列      |           型           |                       修飾語
-------------+------------------------+----------------------------------------------------
 id          | integer                | not null default nextval('posts_id_seq'::regclass)
 title       | character varying(255) | not null default 'title'::character varying
 description | text                   | not null default 'no description'::text

\d post_images
                                テーブル "public.post_images"
    列    |           型           |                          修飾語
----------+------------------------+----------------------------------------------------------
 id       | integer                | not null default nextval('post_images_id_seq'::regclass)
 filename | character varying(255) | not null default 'name'::character varying
 post_id  | integer                | not null

これをbakeします。Modelはこちらのように生成されます:

Model/Table/PostsTable.php
class PostsTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('posts');
        $this->setDisplayField('title');
        $this->setPrimaryKey('id');

        $this->hasMany('PostImages', [
            'foreignKey' => 'post_id'
        ]);
    }
Model/Table/PostImagesTable.php
class PostImagesTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('post_images');
        $this->setDisplayField('name');
        $this->setPrimaryKey('id');

        $this->belongsTo('Posts', [
            'foreignKey' => 'post_id',
            'joinType' => 'INNER'
        ]);
    }

さて、ユーザがpostsをaddした際に画像をアップロードし、その画像のファイル名をpost_images.filenameに格納したいとします。

コントローラでは次のように書きます:

PostsController.php
    public function add()
    {
        $post = $this->Posts->newEntity();
        if ($this->request->is('post')) {
            //$post = $this->Posts->patchEntity($post, $this->request->getData()); この行はbakeすると自動的にできる
            $post = $this->Posts->patchEntity($post, $this->request->getData(), ['associated' => ['PostImages']]); // associatedの記述がキモ

            //アップロードデータ
            $tmp      = $this->request->data['image']['tmp_name'];

            //ファイル名
            $filename = $this->request->data['post_images'][0]['filename'];

            //エラー処理等、かなり端折ってますがファイルシステムの希望の場所に移動
            if( is_uploaded_file($tmp) ) {
               $dir = "/var/www/html/app/webroot/images";
               move_uploaded_file($tmp, $dir . DS . $filename);
            }

            if ($this->Posts->save($post)) {
                $this->Flash->success(__('The post has been saved.'));
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error(__('The post could not be saved. Please, try again.'));
        }
        $this->set(compact('post'));
        $this->set('_serialize', ['post']);
    }

そしてビューでは次のように書きます:

Posts/add.ctp
<div class="posts form large-9 medium-8 columns content">
    <?= $this->Form->create($post, ['type' => 'file']) ?>
    <fieldset>
        <legend><?= __('Add Post') ?></legend>
        <?php
            echo $this->Form->control('title');
            echo $this->Form->control('description');
            echo $this->Form->input('post_images.0.filename', ['label' => 'filename']);
            echo $this->Form->file('image');
        ?>
    </fieldset>
    <?= $this->Form->button(__('Submit')) ?>
    <?= $this->Form->end() ?>
</div>
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3