CakePHP3：関連するテーブルにデータを保存（画像アップロード）

本投稿は、こちらの記事の復習といいますか、応用編です：
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>
```