こんにちはjunです。Concrete5にVueCLIを使ってUIを構築する。1【環境構築編】の記事の続きを書いていきます。
今回の記事では
どんなフォームを作成するのか。 テキストインプットを用いたフォームの簡易実装 データの保存のバックエンド実装 を行いたいと思います。ファイルマネージャー、リッチテキストエディタをvueでレンダリングする方法は追加・編集・一覧化が終わった後に書きたいと思います。まずは簡単なフォーム(テキスト)とデータの保存をvueとともに実装していきましょう。
「アルバム管理」たるものを作成しようと思います。インスタグラム的な物で、機能は以下の通りです。
db.xmlを用いて以下のようなテーブルを作成しておきます。
<?xml version="1.0" encoding="UTF-8"?>
<schema
xmlns="http://www.concrete5.org/doctrine-xml/0.5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.concrete5.org/doctrine-xml/0.5 http://concrete5.github.io/doctrine-xml/doctrine-xml-0.5.xsd">
<table name="album">
<field name="id" type="integer">
<autoincrement/>
<key/>
</field>
<field name="title" type="string" size="255"/>
<field name="created" type="datetime">
<default value="1000-01-01 00:00:00"/>
<notnull/>
</field>
<field name="modified" type="timestamp">
<deftimestamp/>
<notnull/>
</field>
</table>
<table name="albumPics">
<field name="id" type="integer">
<autoincrement/>
<key/>
</field>
<field name="albumID" type="integer">
<unsigned/>
</field>
<field name="fID" type="integer">
<unsigned/>
</field>
<field name="html" type="text" size="65535"/>
<field name="created" type="datetime">
<default value="1000-01-01 00:00:00"/>
<notnull/>
</field>
<field name="modified" type="timestamp">
<deftimestamp/>
<notnull/>
</field>
</table>
</schema>
1アルバムに対して不定数の画像が登録されるので上記の様なDBになっています。
それではアルバムののフォームを作っていきましょう。前回インストールした「vuetest」にてフォーム用のシングルページを作成します。
vuetest
├── controller.php //これはパッケージのcontroller
├── controllers
│ └── single_page
│ └── dashboard
│ └── vuetest.php
└── single_pages
└── dashboard
└── vuetest
├── add.php //追加画面シングルページ
├── edit.php //編集画面シングルページ
└── view.php
そしてシングルページのコントローラーであるvuetest.php
で以下の様に入力
class Vuetest extends DashboardPageController
{
public $packageHandle = 'vuetest';
//vuetest のシングルページでvueのjsファイルを読み込む様にする。
public function on_start() {
$this->requireAsset('package-vue-production');
}
public function view() {
}
// /dashboard/vuetest/ に /add というURLを追加できる
public function add(){
$this->render('/dashboard/vuetest/add');
}
}
すると/dashboard/vuetest/add というURLを叩くとadd.phpが表示されます。
<?php
defined('C5_EXECUTE') or die('Access Denied.');
?>
<p>add用のページだよ</p>
↓
ページの表示が確認できたら、add.phpに以下の様に変更しておきます。
<?php
defined('C5_EXECUTE') or die('Access Denied.');
?>
<div id="add"></div>
この<div id=”app></div>
としたところがvueコンポーネントを流し込むエントリーになります。フォームのビューファイルであるadd.phpはこれだけでおしまいです。
ではvue側も作っていきましょう。src配下は以下の様に構成します。
├── src
├── add.vue
├── components
│ └── form.vue
├── edit.vue
├── index.vue
└── main.js
index.vue、add.vue、edit.vueそれぞれが一覧・追加・編集ページのUIを構築します。しかしedit.vueとadd.vueは入力項目が同じで、初期値があるかないかの違いだけです。そのため共通のコンポーネントform.vueを作成します。
form.vueはひとまず以下の様に設定しておきます。
<template>
<div class="ccm-dashboard-content-inner">
<p>vueレンダリングテスト</p>
<div class="ccm-dashboard-form-actions-wrapper">
<div class="ccm-dashboard-form-actions">
<button class="pull-left btn btn-primary">
一覧へ戻る
</button>
<a href="#" class="pull-right btn btn-primary">
登録
</a>
</div>
</div>
</div>
</template>
<script>
export default {
name:'albumForm',
props:['isEdit']
}
</script>
そしてadd.vueでこのform.vueを読み込んで
<template>
<AlbumForm :isEdit="false"/>
</template>
<script>
import AlbumForm from './components/form';
export default {
name:'add',
components:{AlbumForm}
}
</script>
main.js
にてid="app"
の要素にマウントする様にします。
import Vue from 'vue'
import Add from './add.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(Add),
}).$mount('#add')
こうしてビルドをしてみましょう。そして/dashboard/vuetest/add
へ移動してみると
しっかりとid="app"
にform.vue
がレンダリングされました。ではこのform.vue
にガシガシとフォームUIを作っていきましょう!
最終的なフォームにはリッチテキストエディタとファイルセレクターなど、concrete5で用いられているフォームをvueで実装したいと思います。しかし、その2つはなかなか曲者で今回の記事で説明すると長くなるので次回に話します。
まずはvueとPHP(concrete5)でどう連携させてDBにデータを挿入するかの全体的な流れについて説明するとともに、タイトル部分(プレーンテキスト)を追加できる様にしていきましょう。
vueで構築したUIで入力された値はどうやってバックに渡すか?簡単です。フォームを作る時の様にinput
を<form method="post"></form>
で囲んであげて、送信用のsubmitボタンを作るだけです。今回のパッケージではPOSTの値をAjaxとかで送るのでなく、普通にsubmitでサーバーに送信する様にしました。以下の様にform.vue
を変えます。
<template>
<div class="ccm-dashboard-content-inner">
<h3>アルバム新規追加</h3>
<hr>
<form method="post">
<label for="title" class="control-label">アルバムタイトル</label>
<input type="text" name="title" class="form-control ccm-input-text" v-model="title">
<div class="ccm-dashboard-form-actions-wrapper">
<div class="ccm-dashboard-form-actions">
<button class="pull-left btn btn-primary">
一覧へ戻る
</button>
<input value="登録" type="submit" class="pull-right btn btn-primary">
</div>
</div>
</form>
</div>
</template>
<script>
export default {
name:'albumForm',
props:['isEdit'],
data(){
return{
title:''
}
}
}
</script>
フォームから入力された値をバリデーションチェックします。しかし今回はせっかくvueを使っているのでフロントでバリデーションをしてあげましょう。例えばtitleが空でないかをチェックする場合以下の様にします。
<template>
<div class="ccm-dashboard-content-inner">
<h3>アルバム新規追加</h3>
<hr>
<form method="post" @submit="checkForm">
<label for="title" class="control-label">アルバムタイトル</label>
<input type="text" name="title" class="form-control ccm-input-text" v-model="title">
<p class="text-danger" v-if="errTitle.length>0">{{errTitle}}</p>
<div class="ccm-dashboard-form-actions-wrapper">
<div class="ccm-dashboard-form-actions">
<button class="pull-left btn btn-primary">
一覧へ戻る
</button>
<input value="登録" type="submit" class="pull-right btn btn-primary">
</div>
</div>
</form>
</div>
</template>
<script>
export default {
name:'albumForm',
props:['isEdit'],
data(){
return{
title:'',
errTitle:''
}
},
methods:{
checkForm($event){
if(this.title.length >0){
return true;
}else{
$event.preventDefault();
ConcreteAlert.error({
title:'入力項目に誤りがあります。',
message:'アルバムタイトルが入力されていません。',
delay:5000
})
this.errTitle = "タイトルを入力してください。"
}
}
}
}
</script>
form
の箇所に@submit="checkForm"
というイベントを作成。これはこのformがsubmitされた際にcheckForm
というメソッドを発火させるという意味です。そしてcheckForm
ではtitleの値が空かどうかを判断しています。
もし空でない場合はreturn true
となってsubmit
が通って、サーバーへ値が送信されます。からの場合は$event.preventDefault();
が実行されてsubmitされません。そしてConcreteAlert.error
という8.4系から使用できるconcrete5のフラッシュメッセージのjsを出しています。(ConcreteAlert.error
は特に何も読み込まないでも使える)
空で「登録」を押すと以下の様になります。
$event.preventDefault();
によってサーバーにデータは送信されず、ユーザーに対してエラーを表示できました。
ConcreteAlert
はconcrete5が用意してくれた便利なフラッシュメッセージです。しかし、ESLint付きのvueCLI内で使用ようとすると、ビルド時にこの様に怒られます。
ERROR Failed to compile with 1 errors 23:50:16
error in ./src/components/form.vue
Module Error (from ./node_modules/eslint-loader/index.js):
/Applications/MAMP/htdocs/c5test/packages/vuetest/js/packageui/src/components/form.vue
40:17 error 'ConcreteAlert' is not defined no-undef
✖ 1 problem (1 error, 0 warnings)
そうです。vueプロジェクト内にはConcreteAlert
を定義したjsファイルがない、というかconcreteが用意したjsを読み込めないのでこの様に怒られます。これだとビルドできないのでpackage.json
のeslintの設定に以下の記述をします。
"eslintConfig": {
"globals":{
"ConcreteAlert": true,
}
},
こうするとESLintは「ConcreteAlertってのはグローバルな奴なんだな〜。」と認識してくれて、実際にvueプロジェクト外にあるConcreteAlert
に対して怒らなくなります。
vueを用いてまずはアルバムのタイトルだけを入力できるフォームを作りました。そしてこのタイトルをDBに挿入するまで行います。と言ってもシングルページコントローラーを以下の様に記述します。
<?php
namespace Concrete\Package\Vuetest\Controller\SinglePage\Dashboard;
defined('C5_EXECUTE') or die('Access Denied.');
use \Concrete\Core\Page\Controller\DashboardPageController;
use Concrete\Core\Routing\Redirect;
use Concrete\Core\Http\Request;
use Core;
use Database;
class Vuetest extends DashboardPageController
{
public $packageHandle = 'vuetest';
public function on_start()
{
$this->requireAsset('package-vue-production');
}
public function view() {
}
public function add(){
if(Request::isPost() == true){
$title = $this->post('title');
if(empty($title)==false){
$db = Database::connection();
$db->executeQuery("START TRANSACTION");
$db->executeQuery(
'INSERT album SET `title`=?, `created`=now(), `modified`=now()',
array($title)
);
$db->executeQuery("COMMIT");
Redirect::to('/dashboard/vuetest')->send();
}else{
Redirect::to('/dashboard/vuetest')->send();
}
}else{
$this->render('/dashboard/vuetest/add');
}
}
}
/dashboard/vuetest/add
でpostを送るとadd()
にて処理が行われます。Request::isPost()
というメソッドを用いてリクエストがpostかどうかをチェックします。postであれば値をDBへ挿入するスクリプトを実行し、そうでなければ新規追加の画面を表示します。
DashboardPageController
配下では$this->post('name')
というメソッドで対応するname属性のinputの値を取得することができます!先ほどのフォームではタイトルの値をname="title"
としていたので$title = $this->post('title');
で取得します
よくみると下記の様にタイトルの値を検査しています。
if(empty($title)==false){
...
}
vueで行っているバリデーションはあくまでユーザー補助、UX的な物でありセキュリティの観点からは言えばガバガバです。エンドユーザーが偽造ができないバックエンドであれば確実にバリデーションをすることができます。
dashbord配下は基本的にサイト管理者が触る物なので、不正な値を入れようとする人はいないと思いますが、フロントからpostされた値は基本的に信用しないスタイルを貫いた方が無難です。
では早速使ってみましょう。/dashboard/vuetest/add
にアクセスするとタイトル入力フォームが出てきました。仮に「テスト」と入力。そして「登録」を押します。
一覧のページにリダイレクトされました。ちゃんと挿入されたか、phpmyadminでみてみましょう。
いましたね。titleが「テスト」となっているので、正しくデータが入力されました。
以上がvueとバックエンド部分の一通りの実装でした。
¥以上を意識すればconcrete5のシングルページに自由にvueを用いてUIを構築できます。あとはvueの使い方とバックエンドの設計を頑張るだけです。そして次回は編集画面と一覧画面の作成をしていきます。
コメント
コメント読み込み中..