LoginSignup
2
1

More than 3 years have passed since last update.

CommandBox+ColdBoxでCRUDアプリを作ってみる

Last updated at Posted at 2020-03-16

CommandBox+ColdBoxでCRUDアプリを作ってみる

普段仕事ではフレームワークをあまり使わない環境なんですが、モダンな開発環境が構築できそうなColdBoxを勉強してみることにしました。英語アレルギーの体に鞭打ちつつ(Google翻訳に頼りつつ)。

HMVCフレームワークについて右も左もわからないので、とりあえずユーザー一覧をCRUDするアプリを作ってみようと思います。

ColdBoxってなに?

ColdBoxは、ColdFusion(CFML)用の規約ベースのHMVC開発フレームワークです。

ColdBox公式ドキュメントより引用

まずCommandBoxをインストール

CommandBoxというCLIを導入します。
https://www.ortussolutions.com/products/commandbox

導入編→CommandBoxを使ってみる

アプリのベースを作る

適当なフォルダを作って、その中にMyAppというアプリを作成します。

CommandBox
> mkdir study --cd
> install coldbox
> coldbox create app MyApp
> server start --rewritesEnable

「Welcome to ColdBox!」と書かれたアプリがブラウザで立ち上がったと思います。

ハンドラーを作成

usersハンドラーにアクションindex,list,detail,add,edit,removeを作成します。

CommandBox
> coldbox create handler name="users" actions="index,list,detail,add,edit,remove"

ブラウザを更新すると、「Registered Event Handlers」にusersというリンクができていると思います。クリックしてもまだタイトルしか表示されません。これから作っていきます。

モデルを作成

UserServiceサービスにメソッドgetAll,getUser,addUser,editUser,removeUserを作成します。

CommandBox
> coldbox create model name="UserService" methods="getAll,getUser,addUser,editUser,removeUser" persistence="singleton"

UserServiceをハンドラーのプロパティに追加

handlers/users.cfc
component{ 
  property name="userService" inject="UserService";

コンストラクタにデータのモックを作成

おためしなので今回データベースは使いません。

models/UserService.cfc
UserService function init(){
  variables.data = [
    { id=1, name="Taro Suzuki" },
    { id=2, name="Ichiro Tanaka" },
    { id=3, name="Hanako Yamada" }
  ];
  return this;
}

一覧画面を作成します

メソッド getAll()を編集

データ全件を取得するメソッドを用意します。

models/UserService.cfc
function getAll(){
  return variables.data;
}

ハンドラーのindexアクションを編集

indexはlistに飛ばすだけにします。

handlers/users.cfc
function index( event, rc, prc ){
  // list画面に飛ばします
  setNextEvent( "users/list" );
}

listアクションを編集

getAll()で取得した配列をrc構造体に格納します。使用するビューはusers/listです。

handlers/users.cfc
function list( event, rc, prc ){
  rc.aUsers = userService.getAll();
  event.setView( "users/list" );
}

ビュー list.cfmを編集

rcに格納されたユーザー一覧のデータを表示します。
event.buildLink(to="users.detail",queryString="id=#user.id#")/users/detail?id={id}の意味で、detailアクションは後ほど作ります。
表の3列目が空ですが、後で作る削除ボタン用です。

views/users/list.cfm
<cfoutput>
<h1>users.list</h1>
<table class="table table-striped">
  <thead>
    <tr>
      <th>ID</th>
      <th>Name</th>
      <th>#html.nbs()#</th>
    </tr>
  </thead>
  <tbody>
    <cfloop array="#rc.aUsers#" index="user">
      <tr>
        <td>#html.href( href=event.buildLink(to="users.detail",queryString="id=#user.id#"), text=user.id, noBaseURL=true )#</td>
        <td>#encodeForHTML(user.name)#</td>
        <td></td>
      </tr>
    </cfloop>
  </tbody>
</table>
</cfoutput>

画面を見てみよう

まずhttp://127.0.0.1:{port}/の下のほうにあるExecuteボタンを押して、編集したUserServiceサービスを再読み込みします。この作業はUserServiceを書き換えるたびに行ってください。
2020-03-16_231314.png

次に、画面上のほうにあるusersリンクをクリックします。
2020-03-16_231618.png

ユーザー一覧が表示されました。
2020-03-16_232023.png

詳細画面を作成します

detailアクションを編集

一覧画面の番号リンクをクリックするとdetailアクションにパラメータidが渡ってきますので、当該IDのユーザーデータを取得するコードを書きます。

handlers/users.cfc
function detail( event, rc, prc ){
  rc.User = userService.getUser( event.getValue("id","") );
  event.setView( "users/detail" );
}

メソッド getUser()を編集

上で呼び出したgetUser()の中身を書きます。データをIDで検索し、当該ユーザーのデータを返します。

models/UserService.cfc
function getUser(id){
  var n = arrayFind(variables.data, (x)=>{ return (x.id == id) ? true : false ; });
  return variables.data[n];
}

ビュー detail.cfmを編集

rc構造体に入れたユーザーデータを表示します。フォームのpost先はusers/editです。

views/users/detail.cfm
<cfoutput>
<h1>users.detail</h1>
<form action="#event.buildLink(to="users.edit")#" method="POST">
  <div class="form-group row">
    <label for="staticID" class="col-sm-2 col-form-label">ID</label>
    <div class="col-sm-10">
      <input type="text" readonly class="form-control-plaintext" id="staticID" value="#encodeForHTMLAttribute(rc.User.id)#">
    </div>
  </div>
  <div class="form-group row">
    <label for="username" class="col-sm-2 col-form-label">Name</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="username" value="#encodeForHTMLAttribute(rc.User.name)#">
    </div>
  </div>
  <div class="form-group row">
    <div class="col-sm-12">
      <input type="submit" class="btn btn-primary float-right" value="submit">
    </div>
  </div>
</form>
</cfoutput>

list画面で番号リンクをクリックし、detail画面を確認します。当該ユーザーのIDとNameが表示されました。
2020-03-16_233227.png

更新処理を作成します

editアクションを編集

フォームに入力された値をeditUser()に渡します。エラーの場合はdetail画面に戻るようにしています。

handlers/users.cfc
function edit( event, rc, prc ){
  rc.User.id = event.getValue("staticID","");
  rc.User.name = event.getValue("username","");
  if( userService.editUser( rc.User.id, rc.User.name ) ){
    event.setView( "users/edit" );
  }else{
    event.setView( "users/detail" );
  }
}

メソッド editUser()を編集

上で呼び出したeditUser()の中身を書きます。データをIDで検索し、当該ユーザーのデータを書き換えます。

models/UserService.cfc
function editUser(id, name){
  var n = arrayFind(variables.data, (x)=>{ return (x.id == id) ? true : false ; });
  if( n != 0 ){
    variables.data[n].name = name;
    return true;
  }else{
    return false;
  }
}

ビュー edit.cfmを編集

更新完了の画面です。

views/users/edit.cfm
<cfoutput>
<h1>users.edit</h1>
#html.meta( name="Refresh", content="3;URL=#event.buildLink(to="users.list")#", type="equiv" )#
<div class="alert alert-success" role="alert"><strong>success</strong> - Updated!</div>
</cfoutput>

新規登録処理を作成します

listアクションを編集

新規登録フォームを作る前に、nameフィールドの値を用意しておきます。

handlers/users.cfc
function list( event, rc, prc ){
  rc.aUsers = userService.getAll();
  rc.User.name = event.getValue("username",""); // 追加
  event.setView( "users/list" );
}

ビュー list.cfmを編集

一覧の下に新規登録フォームを追加します。フォームのpost先はusers/addです。

views/users/list.cfm
<!--- tableの下にフォームを追加 --->
<form action="#event.buildLink(to="users.add")#" method="POST">
  <div class="form-group row">
    <label for="username" class="col-sm-2 col-form-label">Name</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="username" name="username" value="#encodeForHTMLAttribute(rc.User.name)#">
    </div>
  </div>
  <div class="form-group row">
    <div class="col-sm-12">
      <input type="submit" class="btn btn-primary float-right" value="add">
    </div>
  </div>
</form>
</cfoutput>

こんな感じ。
2020-03-16_235801.png

addアクションを編集

フォームに入力された値をaddUser()に渡します。エラーの場合はlist画面に戻るようにしています。

handlers/users.cfc
function add( event, rc, prc ){
  rc.User.name = event.getValue("username","");
  if( userService.addUser( rc.User.name ) ){
    event.setView( "users/add" );
  }else{
    event.setView( "users/list" );
  }
}

メソッド addUser()を編集

上で呼び出したaddUser()の中身を書きます。IDを採番し、ユーザーデータを追加します。

models/UserService.cfc
function addUser(name){
  if(arrayLen(variables.data) == 0){
    var id = 1;
  }else{
    var id = arrayLast(variables.data).id + 1;
  }
  arrayAppend(variables.data, { id=id, name=name })
  return true;
}

ビュー add.cfmを編集

登録完了の画面です。

views/users/add.cfm
<cfoutput>
<h1>users.add</h1>
#html.meta( name="Refresh", content="3;URL=#event.buildLink(to="users.list")#", type="equiv" )#
<div class="alert alert-success" role="alert"><strong>success</strong> - Added!</div>
</cfoutput>

削除処理を作成します

ビュー list.cfmを編集

空欄だった3列目に、削除ボタンを追加します。リンク先はusers/removeで、パラメータidを渡します。

views/users/list.cfm
<!--- tbodyの3列目を以下のように変更 --->
<td>#html.href( href=event.buildLink(to="users.remove",queryString="id=#user.id#"), text="remove", noBaseURL=true, class="btn btn-danger btn-sm" )#</td>

こんな感じ。
2020-03-16_235916.png

removeアクションを編集

パラメータのIDをremoveUser()に渡します。エラーの場合はlist画面に戻るようにしています。

handlers/users.cfc
function remove( event, rc, prc ){
  if( userService.removeUser( event.getValue("id","") ) ){
    event.setView( "users/remove" );
  }else{
    event.setView( "users/list" );
  }
}

メソッド removeUser()を編集

上で呼び出したremoveUser()の中身を書きます。当該IDのユーザーデータを削除します。

models/UserService.cfc
function removeUser(id){
  var n = arrayFind(variables.data, (x)=>{ return (x.id == id) ? true : false ; });
  if( n != 0 ){
    arrayDeleteAt(variables.data, n);
    return true;
  }else{
    return false;
  }
}

ビュー remove.cfmを編集

削除完了の画面です。

views/users/remove.cfm
<cfoutput>
<h1>users.remove</h1>
#html.meta( name="Refresh", content="3;URL=#event.buildLink(to="users.list")#", type="equiv" )#
<div class="alert alert-success" role="alert"><strong>success</strong> - Removed!</div>
</cfoutput>

日本語が文字化けする場合

コンポーネントの場合は

cfprocessingdirective(pageencoding="utf-8");

ビューやレイアウトの場合は

<cfprocessingdirective pageencoding="utf-8">

を書いておくと文字化けしません。

あと、layouts/Main.cfmのhtmlタグのlang属性も"ja"に変えておくとよいでしょう。

おわりに

エラー処理なんかは全く入れていませんが、CRUDの流れだけはなんとかつかめた感じです。

coldbox createでモデルやハンドラーを作成するとTestBoxのモジュールも作成されますが、今回無視してしまいました。近いうちBDDについてもちゃんと勉強したいと思います。。。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1