CakePHPとVue-cli2でSPA②コントローラーからVueに変数を渡す

CakePHPとVue-cli2でSPA②コントローラーからVueに変数を渡す

70 回閲覧されました

みなさんこんにちは、jonioです。

前回はCakePHPとVue-cliの連携をしました。

今回はCakePHPのコントローラーからVueに変数を渡してブラウザに表示します。

CakePHPの4系をベースに解説しますが3系は一部書き方が違うのでその部分にも触れます。

コントローラーからVueに渡す変数

テーブルの中身の情報を渡します、使うテーブル名はdemoです。

カラムは以下になりますが自分で用意したテーブルを使っても問題ないです。

default.phpの編集

下記のコードに変更してください。

<?php
/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @since         0.10.0
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 * @var \App\View\AppView $this
 */

$cakeDescription = 'CakePHP: the rapid development php framework';
?>
<!DOCTYPE html>
<html>
<head>
    <?= $this->Html->charset() ?>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>
        <?= $cakeDescription ?>:
        <?= $this->fetch('title') ?>
    </title>

    <?= $this->Html->css(['normalize.min', 'milligram.min', 'cake']) ?>

    <?= $this->fetch('meta') ?>
    <?= $this->fetch('css') ?>
    <?= $this->fetch('script') ?>

  <?= $this->AssetMix->script('main') ?>

</head>
<body>
    <nav class="top-nav">
        <div class="top-nav-title">
            <a href="<?= $this->Url->build('/') ?>"><span>Cake</span>PHP</a>
        </div>
        <div class="top-nav-links">
            <a target="_blank" rel="noopener" href="https://book.cakephp.org/4/">Documentation</a>
            <a target="_blank" rel="noopener" href="https://api.cakephp.org/4/">API</a>
        </div>
    </nav>
    <main class="main">
        <div class="container">
            <?= $this->fetch('content') ?>
        </div>
    </main>
    <footer>
    </footer>
</body>
</html>

50行目がないとVue.jsが表示できないです。

CakePHPの設定

今回はDemoコントローラーのindexアクションでブラウザ(http://localhost/demo/index)を表示します。

コントローラーのindexアクションのコードを下記にします。

public function index()
{
  $demos = $this->Demo->find('all')->toArray();

  $this->set(compact('demos')); 

  $this->viewBuilder()->setOption('serialize', ['demos']);

}

7行目はCakePHPのバージョンが4の場合の書き方で3の場合の書き方は下記になります。

$this->set('_serialize', 'demos');

話を戻して、7行目の「demos」は5行目の「demos」と同じにします。

次はindex.phpです、コードを下記にします。

<div id="app"></div>

今回は「http://localhost/demo/index」でVue.jsを表示したいので上記のコードをこのファイルに持ってきました。

routes.php

「CakePHPのプロジェクト > config > routes.php」の編集をします。

<?php
/**
 * Routes configuration.
 *
 * In this file, you set up routes to your controllers and their actions.
 * Routes are very important mechanism that allows you to freely connect
 * different URLs to chosen controllers and their actions (functions).
 *
 * It's loaded within the context of `Application::routes()` method which
 * receives a `RouteBuilder` instance `$routes` as method argument.
 *
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 */


//ここから追加
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;
//ここまで追加


/*
 * The default class to use for all routes
 *
 * The following route classes are supplied with CakePHP and are appropriate
 * to set as the default:
 *
 * - Route
 * - InflectedRoute
 * - DashedRoute
 *
 * If no call is made to `Router::defaultRouteClass()`, the class used is
 * `Route` (`Cake\Routing\Route\Route`)
 *
 * Note that `Route` does not do any inflections on URLs which will result in
 * inconsistently cased URLs when used with `:plugin`, `:controller` and
 * `:action` markers.
 */
/** @var \Cake\Routing\RouteBuilder $routes */
// $routes->setRouteClass(DashedRoute::class);


//ここから追加
$routes->setExtensions(['json']);
$routes->resources('Demo');
//ここまで追加


$routes->scope('/', function (RouteBuilder $builder) {
  /*
  Here, we are connecting '/' (base path) to a controller called 'Pages',
  * its action called 'display', and we pass a param to select the view file
  * to use (in this case, templates/Pages/home.php)...
  */
  $builder->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);

  /*
  * ...and connect the rest of 'Pages' controller's URLs.
  */
  $builder->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);

  $builder->connect('/demo/index', ['controller' => 'Demo', 'action' => 'index'])->setExtensions(['json']);      //この行を追加

  /*
  * Connect catchall routes for all controllers.
  *
  * The `fallbacks` method is a shortcut for
  *
  * ```
  * $builder->connect('/:controller', ['action' => 'index']);
  * $builder->connect('/:controller/:action/*', []);
  * ```
  *
  * You can remove these routes once you've connected the
  * routes you want in your application.
  */
  $builder->fallbacks();
});

/*
 * If you need a different set of middleware or none at all,
 * open new scope and define routes there.
 *
 * ```
 * $routes->scope('/api', function (RouteBuilder $builder) {
 *     // No $builder->applyMiddleware() here.
 *     // Connect API actions here.
 * });
 * ```
 */

54行目の「Demo」はコントローラー名です、今回はDemoコントローラーを使うのでDemoを指定しています。

53行目は71行目に使う為にあります、「->setExtensions([‘json’])」でDemoコントローラーの「$demos」をjsonに変換します。

public function index()
{
  $demos = $this->Demo->find('all')->toArray();       //←これ

  $this->set(compact('demos')); 

  $this->viewBuilder()->setOption('serialize', ['demos']);

}

これで「http://localhost/demo/index.json」にアクセスすると下記の表示になりdemoテーブルの内容をjsonで表示されているのが確認できます。

{
  demos: [
    {
      id: 1,
      title: "title1",
      content: "content1",
      like_flag: true,
      created: null,
      modified: null
    },
    {
      id: 2,
      title: "title2",
      content: "content2",
      like_flag: false,
      created: null,
      modified: null
    },
    {
      id: 3,
      title: "title3",
      content: "content3",
      like_flag: true,
      created: null,
      modified: null
    }
  ]
}

このデータをVueで使えるようにします。

Vue.jsの設定

まずはmain.jsの設定をします。

main.js

エントリーポイントの設定をします。

「CakePHPのプロジェクト > resources > vue_demo > src > App.vue」を最初に呼び出すVueファイルにする為に「CakePHPのプロジェクト > resources > vue_demo > src > main.js」のコードを下記にします。

import Vue from 'vue';
import  App from './App';

Vue.config.productionTip = false;

new Vue({
  render: h => h(App),
}).$mount('#app')

App.vue

「CakePHPのプロジェクト > resources > vue_demo > src > App.vue」のコードを下記にします。

<template>
  <entry></entry>
</template>

<script>
import Entry from './components/Entry.vue'

export default {
  name: 'App',
  components: {
    Entry
  }
}
</script>

Entry.vueはまだ作成していないので作成します。

Entry.vue

「CakePHPのプロジェクト > resources > vue_demo > src > components」の下の階層にEntry.vueを作成して下記のコードを記述します。

<script>
import axios from 'axios';

export default {
  data: function () {
    return {
      demos   : [],  
    }
  },
  mounted: function(){
    axios.get('http://localhost/demo.json')
      .then(response  => {
            this.demos = response.data;

            console.log(this.demos);
      }) 
      .catch(err => {
          this.status = err.message;
      });
  },
};
</script>

11行目の「http://localhost/demo.json」の「http://localhost/demo」はdemoコントローラーのindexアクションという意味です。

.json」は付けないといけないんだと思っていいです。

これで「http://localhost/demo/index」にアクセスしてデベロッパーツールを開くとDemoコントローラーのindexアクションにあった「$demos」を取得できているのが確認できます。

それでは$demosの内容をブラウザに表示します、Entry.vueに追記します。



//ここから追加
<template>
  <div>
    <ul>
      <li 
        v-for="demoList in demos" 
        :key="demoList.id"
      >
        <ul>
          <li 
            v-for="demo in demoList" 
            :key="demo.id"
          >
          {{ demo.title }}</li>
        </ul>
      </li>
    </ul>
  </div>
</template>
//ここまで追加


<script>
import axios from 'axios';

export default {
  data: function () {
    return {
      demos   : [],  
    }
  },
  mounted: function(){
    axios.get('http://localhost/demo.json')
      .then(response  => {
            this.demos = response.data;

            console.log(this.demos);
      }) 
      .catch(err => {
          this.status = err.message;
      });
  },
};
</script>

これで「http://localhost/demo/index」にアクセスすると下記の表示になります。