疎通させてみる
Bancha使ってみたくてcakeをざっと流し読みしたけど、
まだ疎通できてないので疎通させてみようと思います。
お題はBanchaのサンプルをMVCに再配置、と、
テスト的にコンポーネントからイベント発火させて
Mainコントローラでディスパッチするようにしてみました。
A.View(何らかの操作)
↓
Aコントローラ(ビューをコンポーネントクエリで引っ掛けて)
Ext既存イベントの処理→A.fireEventで独自イベント発行
↓
Mainコントローラ(ビューをコンポーネントクエリで引っ掛けて)
独自インベントのディスパッチ
AコントローラをgetControllerで取得してAコントローラ.実装処理を呼び出し
なかんじで複数コントローラ時な感じを想定して見ました。
アプリの作成
ここからはExtJS4の話になります。xframeworkであればwebapp下にsrcとか掘ってアプリを設置するんですが、
Cakeで言うところだと、、、
webroot/js/srcとかになるのでしょうかね。
あとは株式会社ゼノフィさんの技術ページ(code:x)か@martini3ozさんの
ページを見ながら実践開発ガイドのクラスローダ部分を読み返せばスタートアップ設置はOKです。
大掛かりな設置をすると大変なので
ビューポートにGridのみ入れて
Banchaのサンプルを切り出しながら再整形して
CRUDの確認だけしてみます。
example.htmlについて
やることは- extのロード
- Banchaの準備
<head>
<title>Bancha Example</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" type="text/css" href="./ext/resources/css/ext-all.css" />
<script type="text/javascript" src="./ext/ext-all-debug.js"></script>
<script type="text/javascript" src="./ext/locale/ext-lang-ja.js"></script>
<!-- include Bancha and the remote API -->
<script type="text/javascript" src="./Bancha/js/Bancha.js"></script>
<!-- for the github version use /Bancha/js/Bancha.js -->
<script type="text/javascript" src="./bancha-api/models/all.js"></script>
<!-- ExampleApp の設置 -->
<script type="text/javascript" src="./js/src/app.js"></script>
</head>
<body>
</body>
</html>
こんな感じになるのでしょうか。
404帰ってきてないこと確認しておきます。app.jsとviwportの設置
- addProviderの関係上、先行してExt.OnReadyが走る必要があり、
これはBancha.OnModelReady内でExt.OnRadyしている。
してみました。
設置については、、
* snippetsでひな形配置して
* namespace決めて
* app名決めて
* launchにalertとか設置して動作確認。
* 最初はcontrollersプロパティをコメントアウトして表示される
のを確認してもいいかもしれないです(ブランク開くと表示すら躓くのでひとつづ表示させながら)
で、
こんなかんじになると思います。
- app.js
これは実践開発ガイドの77ページ目のローダの説明を見ると理解が深まります。
Ext.ns('BE');
// Ext.Loader有効化
Ext.Loader.setConfig({
enabled: true,
paths: {
'Ext': './ext/src',
'BE': './js/src'
}
});
//Bancha 初期化
Bancha.onModelReady('User',function(){
//alert('hoge');
// アプリケーション設定
Ext.application({
// Viewport自動生成
autoCreateViewport: true,
// アプリケーション名
name: 'BE',
// アプリケーションフォルダパス
appFolder: './js/src/app',
// 使用コントローラー定義
controllers: [
'Main',
'Usergrid'
],
// アプリケーション起動時イベントハンドラ
launch: function() {
//alert('fuga');
}
});
});
サーバサイドのモデルが増えたら、、onModelReadyの第一パラメタも増やしていきます。
Bancha.onModelReady(['User','hoge1','hoge2'],function(){
みたいにね。- viewport.js
// {{{ BE.view.Viewport
Ext.define('BE.view.Viewport', {
// {{{ requires
requires: [
'BE.view.Usergrid'
],
// }}}
// {{{ extend
extend: 'Ext.container.Viewport',
// }}}
// {{{ layout
layout: {
type: 'border',
padding: 5
},
// }}}
// {{{ items
items: [{
region: 'center',
//html: 'hoge'
xtype: 'usergrid'
}]
// }}}
});
// }}}
Controllerの設置
上記のcontrollersをコメントインして(最初はコメントアウトしてhogeだけ表示させてた)Main,Usergridのコントローラを作成。* MainControllerの設置をします。
* UsergridControllerの設置をします。
* これもスニペットで作成。設置のみ。ほとんどコメントアウト状態。以下、例。
- Main.js
// {{{ 'BE.controller.Main',
/**
* @class BE.controller.Main
* メインコントローラ
*/
Ext.define('BE.controller.Main', {
// {{{ extend
extend : 'Ext.app.Controller',
// }}}
// {{{ refs インスタンス化されたViewへの参照提供 get([R]efname)
/*
refs: [{
selector: 'xtype..',ref: 'localname'
}],
*/
/*
// }}}
// {{{ views クラスへの参照提供 get(Xxxx)View
views:[
'Views'
],
// }}}
// {{{ models クラスへの参照提供 get(Xxxx)Model
models:[
'Models'
],
// }}}
// {{{ stores インスタンスへの参照提供 get(Xxxx)Store
stores: [
'Store'
],
// }}}*/
// {{{ init
//アプリケーション起動時にコールされる特別なメソッド
//ApplicationのLaunch前にコールされる
init: function() {
//alert('hoge');
var me = this;
me.control(me.bindItem);
},
// {{{ bindItem
bindItem: {
// 作成
'usergrid' : {
create: function(){
var me = this;
alert('create dispatch');
me.getController('Usergrid').onCreate();
},
reset: function(){
var me = this;
alert('reset dispatch');
me.getController('Usergrid').onReset();
},
save: function(){
var me = this;
alert('save dispatch');
me.getController('Usergrid').onSave();
},
del: function(rowIndex){
var me = this;
alert('save dispatch');
me.getController('Usergrid').onDelete(rowIndex);
}
/*
hoge: function(){
var me = this;
me.getController('Hoge').onHoge();
},*/
}
}
/*
// }}}
// }}}
// {{{ onXXXX
onXXXX: function() {
console.log('hoge');
}
*/
// }}}
});
// }}}
- Usergrid.js
沈み込ませてそれを継承させたらすっきりするかなぁ。とおもってます。
// {{{ 'BE.controller.Usergrid',
/**
* @class BE.controller.Usergrid
* ユーザグリッドコントローラ
*/
Ext.define('BE.controller.Usergrid', {
// {{{ extend
extend : 'Ext.app.Controller',
// }}}
// {{{ refs インスタンス化されたViewへの参照提供 get([R]efname)
refs: [{
selector: 'usergrid',ref: 'crudgrid'
}],
// }}}
// {{{ views クラスへの参照提供 get(Xxxx)View
views:[
],
// }}}
// {{{ models クラスへの参照提供 get(Xxxx)Model
// }}}
// {{{ stores インスタンスへの参照提供 get(Xxxx)Store
stores: [
'User'
],
// }}}
// {{{ init
//アプリケーション起動時にコールされる特別なメソッド
//ApplicationのLaunch前にコールされる
init: function() {
var me = this;
me.control(me.bindItem);
},
// }}}
// {{{ bindItem
bindItem: {
// 作成
'usergrid button[action=create]' : {
click: function(){
var me = this;
alert('create');
me.getCrudgrid().fireEvent('create');
}
},
// リセット
'usergrid button[action=reset]' : {
click: function(){
var me = this;
alert('reset');
me.getCrudgrid().fireEvent('reset');
}
},
// 保存
'usergrid button[action=save]' : {
click: function(){
var me = this;
alert('save');
me.getCrudgrid().fireEvent('save');
}
},
// 削除
'usergrid actioncolumn' : {
click: function(view,cell,row,col,e){
var me = this;
alert('delete');
me.getCrudgrid().fireEvent('del',row);
}
}
},
// }}}
// {{{
onCreate: function() {
var me = this;
me.create();
},
onSave: function() {
var me = this;
me.save();
},
onDelete: function(rowIndex) {
var me = this;
me.del(rowIndex);
},
onReset: function() {
var me = this;
me.reset();
},
// }}}
// {{{
create: function() { // scope is a config object
var me = this,
grid = me.getCrudgrid(),
edit = grid.getPlugin('cellplugin'),
store = grid.getStore(),
model = store.getProxy().getModel(),
rec;
// Cancel any active editing.
edit.cancelEdit();
// create new entry
rec = Ext.create(Ext.ClassManager.getName(model),{});
// add entry
store.insert(0, rec);
// start editing
edit.startEditByPosition({
row: 0,
column: 0
});
},
save: function() { // scope is the store
var me = this,
valid = true,
msg = "",
name,
grid = me.getCrudgrid(),
store = grid.getStore();
// check if all changes are valid
store.each(function(el) {
if(!el.isValid()) {
valid = false;
name = el.get('name') || el.get('title') || (el.phantom ? "New entry" : el.getId());
msg += "<br><br><b>"+name+":</b>";
el.validate().each(function(error) {
msg += "<br> "+error.field+" "+error.message;
});
}
});
if(!valid) {
Ext.MessageBox.show({
title: 'Invalid Data',
msg: '<div style="text-align:left; padding-left:50px;">There are errors in your data:'+msg+"</div>",
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
} else {
// commit create and update
store.sync();
}
},
del: function (rowIndex) {
var me = this,
grid = me.getCrudgrid(),
store = grid.getStore();
rec = store.getAt(rowIndex),
name = Ext.getClassName(rec);
// instantly remove vom ui
store.remove(rec);
// sync to server
// for before-ExtJS 4.1 the callbacks will be ignored,
// since they were added in 4.1
store.sync({
success: function(record,operation) {
Ext.MessageBox.show({
title: name + ' record deleted',
msg: name + ' record was successfully deleted.',
icon: Ext.MessageBox.INFO,
buttons: Ext.Msg.OK
});
},
failure: function(record,operation) {
// since it couldn't be deleted, add again
store.add(rec);
// inform user
Ext.MessageBox.show({
title: name + ' record could not be deleted',
msg: operation.getError() || (name + ' record could not be deleted.'),
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
}
}); //eo store sync
},
reset: function() { // scope is the store
// reject all changes
var me = this,
grid = me.getCrudgrid(),
store = grid.getStore();
store.each(function(rec) {
if (rec.modified) {
rec.reject();
}
if(rec.phantom) {
store.remove(rec);
}
});
}
});
// }}}
storeの設置
ストアの設置です。 で、いままでProxyの設定はStoreでやってたんですけど、、 Banchaが提供するModelにはすでにCakeにあわせたProxyの設定が 盛り込まれたModelを返却するのでストアはBanchaの提供するモデルを 設置するのみです。// {{{ 'BE.store.User',
/**
* @class BE.store.User
* desctription
*/
Ext.define('BE.store.User', {
// {{{ extend
extend : 'Ext.data.Store',
// }}}
// {{{ model
model: Bancha.getModel('User'),
autoLoad: true
// }}}
});
// }}}
modelの設置
モデルは要らないっす。 ModelはBanchaが提供してくれますので。 Bancha.getModel(‘モデル名’); で取得可能です。または、Bancha.model.モデル名ですかね。。。
これで全部載せたかな。。。
all.jsからの返却
rpc用のメソッド一覧等の情報がちゃんとできているか見てみます。 all.jsのレスポスンスをJavaScriptBeautifierで整形してみました。 よさそうです。Ext.ns('Bancha');
Bancha.REMOTE_API = {
"url": "\/~banchatest\/bancha.php",
"namespace": "Bancha.RemoteStubs",
"type": "remoting",
"metadata": {
"User": {
"idProperty": "id",
"fields": [{
"name": "id",
"type": "int"
}, {
"name": "username",
"type": "string"
}, {
"name": "password",
"type": "string"
}, {
"name": "first_name",
"type": "string"
}, {
"name": "last_name",
"type": "string"
}, {
"name": "created",
"type": "date",
"dateFormat": "Y-m-d H:i:s"
}, {
"name": "modified",
"type": "date",
"dateFormat": "Y-m-d H:i:s"
}],
"validations": [],
"associations": [],
"sorters": []
},
"_UID": "5030537f74c0a675541393"
},
"actions": {
"User": [{
"name": "getAll",
"len": 0
}, {
"name": "read",
"len": 1
}, {
"name": "create",
"len": 1
}, {
"name": "update",
"len": 1
}, {
"name": "destroy",
"len": 1
}, {
"name": "submit",
"len": 1,
"formHandler": true
}],
"Bancha": [{
"name": "loadMetaData",
"len": 1
}]
}
}
※注目すべきはxframeworkでもハマった"formHandler": true
これ。これは.formのAPIに設定する用のハンドラにはこれをつけます。
xframeworkの時はドキュメントコメントに記載すると
フレームワークがパースしてこのフラグを立ててくれてました。
超ハマったのでよく覚えてます。実行してみる。
まとめ
で、、 プロトタイプを作成しよう!となると、- UserDirの設置
- cake2.1.5の設置
- htaccessの変更
- Bancha0.9.5の設置(cake配下のPlugin下)
- bake実施(モデルとコントローラ)
- bakeで生成したモデルに追記
public $actsAs = array(‘Bancha.BanchaRemotable’); - Extjsの設置(cake配下app/webroot/js/配下)
- ExtJsMVCの設置
cake→banchaと夜な夜な帰宅後にやったわりには理解は思ったより早くてすっきりしてきた。 これを業務にフィードバックできればいいんだけど、
あとは、banchascaffoldだね。
感想
久々のMVCの設置、スニペットがあるのと無いのでは雲泥の差だし、何より先の技術サイトのように一気通貫で説明があると助かるなぁ。。
と思いこのエントリも自分用に再度まとめ直したし、サンプルも作り替えた。
疲れた。。。
0 件のコメント:
コメントを投稿