CakePHP(v3.x)、投稿画面に確認画面を追加する。

今回は外部からCSVファイルをインポートして、CSVファイル内のデータを一旦確認してからデータベースに保存するという処理を書いていきたいと思います。

Controllerの設定

ArticlesController.php

class ArticlesCpntroller extends AppController{



    public function csvImport(){
        $article = $this->Articles->newEntity();

        if ($this->request->is('post')) {
            $connection = ConnectionManager::get('default');
            // トランザクション開始
            $connection->begin();
            try {
                $postData = $this->request->getData();
                $action = $postData['action'];
                switch($action){
                    case 'preview':
                        $tmp_file_name = $_FILES["csv"]["tmp_name"];
                        $data = array();
                        if (is_uploaded_file($tmp_file_name)){
                            $csv_contents = fopen($tmp_file_name, "r");
                            while(($csv_content = fgetcsv($csv_contents, 0, ",")) !==FALSE){
                                $datas = mb_convert_encoding($csv_content, 'UTF-8', "auto");  // エンコード
                                $temp['title'] = $datas[0];
                                $temp['contents'] = $datas[0];
                                $data[] = $temp;
                            }
                        }
                        $article = $this->Articles->patchEntity($article, $data);
                        break;
                    case 'save':
                        $article = $this->Articles->patchEntity($article, $postData);
                        if($this->Articles->save($article)){
                            $connection->commit();
                            $this->Flash->success(__('CSVファイルを追加しました'));
                            return $this->redirect(['action' => 'index']);
                        }
                        $this->log(print_r($deposits->getErrors(), true), LOG_DEBUG);
                        $this->Flash->error(__('CSVファイルを追加できませんでした'));
                        break;
                }
            } catch (Exception $e) {
                $this->log($e);
                //ロールバック
                $connection->rollback();
            }
        }

        if($action == 'preview' || $action == 'save'){
            $this->set(compact('article'));
            $this->render('csv_preview', 'single');
        } else {
            $this->set(compact('article'));
            $this->render('csv_import', 'single');
        }
    }
}

前回のCSVを読み込む内容を含んでいます。 postDataのなかの’action’という連想配列の値がによって表示させる画面を変えます。 previewのときはタイトルとコンテンツをアップロードされたCSVファイルから読みだしてプレビュー画面(csv_preview.ctp)に遷移します。 saveのときはpostDataをデータベースに保存して保存が失敗したら再びアップロード画面(csv_import.ctp)に戻ります。

アップロード画面(csv_import.ctp)

<?= $this->Form->create($article, array('type' => 'file')) ?>
<?= $this->Form->file('csv',[ 'accept'=>'.csv', 'id'=>'elmFile']) ?>
<?= $this->Form->button('プレビューへ', [ 'name' => 'action', 'value' => 'preview', 'id' => 'btnUpload', 'disabled']); ?>
<?= $this->Form->end() ?>

<script>
  document.getElementById("elmFile").addEventListener('change', selectFile, {passive: true});
  window.onload = function() {
    selectFile();
  };
  function selectFile() {
    if (document.getElementById("elmFile").value === "") {
      document.getElementById("btnUpload").disabled = true;
    }
    else {
      document.getElementById("btnUpload").disabled = false;
    }
  }
</script>

csvがきちんとセットされれば「プレビューへ」と書かれたボタンが有効になります。 このボタンに「’name’ => ‘action’, ‘value’ => ‘preview’」としてやることで、コントローラ側で画面の遷移ができます

プレビュー画面(csv_preview.ctp)

<?= $this->Form->create($deposit) ?>
<?= $this->Form->control('title') ?>
<?= $this->Form->control('contents') ?>
<?= $this->Form->button('インポート', [ 'name' => 'action', 'value' => 'save']); ?>
<?= $this->Form->end() ?>

同様にボタンに「’name’ => ‘action’, ‘value’ => ‘save’」としてやることで、コントローラ側でデータベースへの値の保存が実行されます。