!目的 mmt.pmをmojoliciousで書き直す。 *apache無しでmojoliciousたけで動かす。(apache,psgi,等々で動かしても良いが…) *utf-8をデフォルトにする。 *prototype.jsからjQueryに移行する。 !github https://github.com/john-smith-7701/mmt に登録した。 *インストール $ git clone https://github.com/john-smith-7701/mmt.git !memo *https://github.com/kraih/mojo/wiki/Hypnotoad-prefork-web-server *http://www.perlmonks.org/?node_id=1078222 *http://search.cpan.org/~kimoto/Mojolicious-Plugin-DBViewer-0.28/lib/Mojolicious/Plugin/DBViewer.pm *[Mojoliciousのモデル構成例|http://qiita.com/nakayama_yasuhiro/items/f085ca4d8521cd72d98b] *[morboとhypnotoadの違いとハマりどころ|http://qiita.com/xtetsuji/items/1227e40bea05b09684e0] *[Mojoliciousを使ってみたよ|http://sasakure.hatenablog.com/entry/20121113/1352803904] !初めの一歩 $ mojo generate app Tool::mmt $ tree toolmmt toolmmt ├── lib │ └── Tool │ ├── mmt │ │ └── Example.pm │ └── mmt.pm ├── log ├── public │ └── index.html ├── script │ └── toolmmt ├── t │ └── basic.t └── templates ├── example │ └── welcome.html.ep └── layouts └── default.html.ep 10 directories, 7 files $ svn import toolmmt svn+ssh://userId@localhost/usr/local/svn/repos/toolmmt -m "Initial Import." $ svn co svn+ssh://userId@www21051ue.sakura.ne.jp/usr/local/svn/repos/toolmmt !2015/11/10現在 $ tree -f |perl -alne '@x=split /\s+/,`wc -l $F[-1] 2>/dev/null`;$l=sprintf("%5d %s",$x[0],$_);$l=~ s/ 0 / /;$l=~ s{\..*/}{};print $l' . ├── lib │ └── Tool │ ├── mmt 13 │ │ ├── Example.pm 512 │ │ └── Mmt.pm 25 │ ├── mmt.pm │ ├── Model 46 │ │ └── Webdb.pm 7 │ └── Model.pm ├── log 3979 │ └── development.log ├── public 11 │ └── index.html ├── script 11 │ └── toolmmt 4 ├── svn-commit.tmp ├── t 9 │ └── basic.t └── templates ├── example 7 │ └── welcome.html.ep ├── layouts 5 │ └── default.html.ep └── mmt 27 ├── datalist.html.ep 5 ├── desc.html.ep 29 └── mainform.html.ep 12 directories, 15 files $ !2015/11/21 とりあえず素のメンテ作成。cssも == JavaScript == (12/9) も無し。 *[商品|http://www21051ue.sakura.ne.jp:3003/mmt/%E5%95%86%E5%93%81] *[user_tbl|http://www21051ue.sakura.ne.jp:3003/mmt/user_tbl] *[chatdata|http://www21051ue.sakura.ne.jp:3003/mmt/chatdata] *[commodity(商品)|http://www21051ue.sakura.ne.jp:3003/mmtx/commodity] Mmtを継承し商品テーブルメンテを作成 *http://www21051ue.sakura.ne.jp:3003/mmtx/commodity?_action=get_name&n=item5&p=001&p=002 [2017/04/09]帳票悪性ツール(rwt)追加 *[分類マスタリスト|http://www21051ue.sakura.ne.jp:3003/rwt/list001] -- https access *[commodity(商品)|https://qweer.info/mmtx/commodity] Mmtを継承 [2016/01/11] . ├── lib │ └── Tool │ ├── Model │ │ ├── Webdb 29 │ │ │ └── constant.pm 210 │ │ └── Webdb.pm 7 │ ├── Model.pm │ ├── mmt 35 │ │ ├── Commodity.pm 13 │ │ ├── Example.pm 759 │ │ ├── Mmt.pm 19 │ │ └── Usertbl.pm 28 │ └── mmt.pm ├── log ├── public │ ├── css 121 │ │ └── default.css 11 │ ├── index.html │ └── js ├── script 11 │ └── toolmmt 4 ├── svn-commit.tmp ├── t 9 │ └── basic.t └── templates ├── example 7 │ └── welcome.html.ep ├── layouts 33 │ ├── default.html.ep 32 │ └── defsubwin.html.ep └── mmt 36 ├── datalist.html.ep 9 ├── desc.html.ep 4 ├── dumper.html.ep 53 ├── mainform.html.ep 32 └── subwin.html.ep 15 directories, 21 files !2017/4/9 帳票作成ツールを追加 !!構成 !script/toolmmt # アプリケーションスクリプト #!/usr/bin/env perl use strict; use warnings; use FindBin; BEGIN { unshift @INC, "$FindBin::Bin/../lib" } # Start command line interface for application require Mojolicious::Commands; Mojolicious::Commands->start_app('Tool::mmt'); !lib/Tool/mmt.pm # アプリケーションクラス(ルーター等) package Tool::mmt; use Mojo::Base 'Mojolicious'; use Tool::Model; has 'model' => sub {Tool::Model->new}; # modelを追加 has 'controller' => "mmt"; # This method will run once at server start sub startup { my $self = shift; # Documentation browser under "/perldoc" $self->plugin('PODRenderer'); $self->plugin('TagHelpers'); # Router my $r = $self->routes; # Normal route to controller $r->get('/')->to('example#welcome'); $r->get('/mmt/:_table/desc')->to('mmt#desc'); $r->get('/mmt/:_table')->to(controller => $self->controller,action =>'mainform'); $r->post('/mmt/:_table')->to(controller => $self->controller,action => 'registry'); $r->get('/mmtx/:controller')->to(controller => $self->controller,action =>'mainform'); # 特別なプレースフォルダ :controllerと:action 柔軟なルーティングの構築が可能になる $r->post('/mmtx/:controller')->to(controller => $self->controller,action => 'registry'); } 1; !lib/Tool/Model.pm package Tool::Model; use Mojo::Base 'Mojolicious'; use Tool::Model::Webdb; has 'webdb' => sub { Tool::Model::Webdb->new }; # 自作モデルとか 1; !lib/Tool/Model/Webdb.pm #モデル (DB CONNECT とか…) package Tool::Model::Webdb; use Mojo::Base 'Mojolicious'; use DBI; use utf8; use Data::Dumper; use Tool::Model::Webdb::constant; has const => sub { my $s = shift; return Webdb::constant->new(); # constant dataを読み込む }; has dbh => sub { my $self = shift; my $data_source = $self->const->{data_source}; my $user = $self->const->{user}; my $password = $self->const->{password}; my $dbh = DBI->connect( $data_source, $user, $password, {RaiseError => 1, mysql_enable_utf8 =>1, mysql_auto_reconnect =>1, # 再接続させる } ); $dbh->do("set names UTF8"); return $dbh; }; sub desc_table{ my $s = shift; my $m = shift || 'm'; my $f; $s->{'m'}->{key} = []; $s->{'m'}->{item} = []; my $dbh = $s->dbh; my $sth = $dbh->prepare($s->desc_param($m)); $sth->execute(); my $flag = 0; while(my $ref = $sth->fetchrow_hashref()){ $f = $ref->{Field}; $s->{'m'}->{$f}->{Type} = $ref->{Type}; $s->{'m'}->{$f}->{Null} = $ref->{Null}; $s->{'m'}->{$f}->{Key} = $ref->{Key}; $s->{'m'}->{$f}->{Default} = $ref->{Default}; $s->{'m'}->{$f}->{Extra} = $ref->{Extra}; $s->{'m'}->{$f}->{Size} = $s->size($ref->{Type}); if($ref->{Key} eq 'PRI'){ push @{$s->{'m'}->{key}},$f; }elsif($ref->{Type} =~ /timestamp/){ $s->{'m'}->{timestamp} = $f; }else{ push @{$s->{'m'}->{item}},$f; } $flag = 1; } $sth->finish(); return $s->{'m'}; } sub size { . . . } . . 1; !lib/Tool/Model/Webdb/constant.pm # コンスタントデータ package Webdb::constant; use utf8; sub new { my $class = shift; my $self = bless {},$class; $self->_initalize; return $self; } sub _initalize{ my $s = shift; $s->{data_source} = "DBI:mysql:database=YourDB;host=localhost"; $s->{user} = "YourName"; $s->{password} = "YourPassword"; $s->{explan} = { # DB項目の説明 '担当者' => { # TABLE NAME 'ID' => 'admin:管理者,0〜999', # FIELD NAME => COMMENT }, '商品' => { '商品区分' => '0:課税,1:非課税,2:軽減課税', }, }; } 1; !lib/Tool/mmt/Mmt.pm # controller package Tool::mmt::Mmt; use Mojo::Base 'Mojolicious::Controller'; use Mojo::Log; use utf8; use Encode; use Text::CSV::Encoded; has 'mmtForm' => 'mmt/mainform'; has 'mmtDataList' => 'mmt/datalist'; # This action will render a template sub mainform { my $self = shift; $self->{'m'} = $self->app->model->webdb->desc_table($self->param('_table')); # model 呼び出し $self->{'m'}->{'table'} = $self->param('_table'); $self->set_input_names(); $self->action_set(); $self->my_render($self->mmtForm); } sub my_render{ my $s = shift; my $render = shift; $s->stash->{_title} = join('',$s->param('_table')); $s->render($render); } sub registry{ my $self = shift; $self->action_set(); my $log = Mojo::Log->new(); $log->debug( "IN registry" ); for my $action (@{$self->{'_action'}}) { if($action->{'name'} eq $self->param('_action')){ return $action->{action}(); } } $self->stash->{'_dumper'} = $self->dumper ($self->param()) . $self->param('_action'); $self->render('mmt/dumper'); } . . . !templates/mmt/mainform.html.ep # データメンテナンス画面 *$selfでコントローラのメソッドが使える % layout 'default'; % title "mmt - $_title " ;

<%= $_title %>

%= form_for url_for('_table'=> param('_table')) => (method => 'POST') => begin <%= hidden_field timestamp => param('timestamp') %> <%= hidden_field _table => param('_table') %> % for my $item (@{$self->{'m'}->{'key'}}){ % }
<%= $self->Label($item) %>
<%== $self->input_field($item) %> <%== $self->get_explan(param('_table'),$item) %>
%= submit_button $self->{'_action'}[0]->{'name'} ,id => '_action',name => '_action' <%== $self->serch_input_field() %> %= submit_button $self->{'_action'}[4]->{'name'} ,id => '_action',name => '_action' %= submit_button $self->{'_action'}[6]->{'name'} ,id => '_action',name => '_action'
INFO:<%= $self->{errstr} %>
% my $i = 0; % for my $item (@{$self->{'m'}->{'item'}}){ % }
<%= $self->Label($item) %>
<%== $self->input_field($item) %> <%== $self->get_explan(param('_table'),$item) %>
% for my $item (@{$self->{'_action'}}[1..3]){ %= submit_button $item->{'name'} ,id => '_action',name => '_action' % } % end
<%= hidden_field _table => param('_table') %>
Mojolicious::Controllerのrenderメソッドを呼び出すことで、レンダラを手動で起動できます。しかし、通常は必要ありません。なぜならルータの処理が終わったとき、何もレンダリングされていない場合はレンダラが自動的に呼び出されるからです。これは、何もアクションを実行しない、テンプレートだけを指し示すルーティングを作成できるということです。 $c->render; ただし、大きな違いがひとつあります。renderを手動で呼ぶことによって、テンプレートが現在のコントローラオブジェクトを使用し、アプリケーションクラスのMojoliciousのcontroller_class属性で指定されたデフォルトコントローラを使用しないことを保証できます。 [templateからcontrollerのmethodを実行する為にcontrollerの最後にrenderを追加|https://github.com/john-smith-7701/mmt/commit/264f72ab025fc1bfb5d9694654a3f5c7874cb778] $ git diff eafe8b7b1b21773dcf4726a0c7ee1a944eb55be5 diff --git a/toolmmt/lib/Tool/mmt/Controller/Json.pm b/toolmmt/lib/Tool/mmt/Controller/Json.pm index ba51f87..ab00b7a 100644 --- a/toolmmt/lib/Tool/mmt/Controller/Json.pm +++ b/toolmmt/lib/Tool/mmt/Controller/Json.pm @@ -27,8 +27,13 @@ sub json{ my $s = shift; - $s->render(json => $s->req->json) if($s->req->json); + if($s->req->json){ + $s->render(json => $s->req->json); + }else{ + $s->render('json/json'); + } } + sub json_or_jsonp{ my $s = shift; my $json = shift; diff --git a/toolmmt/lib/Tool/mmt/Controller/Menu.pm b/toolmmt/lib/Tool/mmt/Controller/Menu.pm index 69da8cb..ef1ca1f 100644 --- a/toolmmt/lib/Tool/mmt/Controller/Menu.pm +++ b/toolmmt/lib/Tool/mmt/Controller/Menu.pm @@ -7,6 +7,7 @@ my $s = shift; my $data = $s->menu_get(); $s->stash(_data=> $data); + $s->render('menu/menu'); } sub menu_get{ my $s = shift; !templates/mmt/datalist.html.ep # 一覧表示画面 % layout 'default'; % title "mmt - $_title";

<%= $_title %>

% for my $item (@{$self->{'m'}->{'key'}},@{$self->{'m'}->{'item'}}){ % } % my $count = 0; % while (my $ref = $self->{'sth'}->fetchrow_hashref()){ % $count++; % last if $count > 2000; %= form_for url_for('_table'=> param('_table')) => (method => 'POST') => begin <%= hidden_field _table => param('_table') %> % for my $name (@{$self->{'m'}->{key}}){ % } % for my $name (@{$self->{'m'}->{item}}){ % } % end % }
<%= $self->Label($item) %>
%= submit_button $self->{'_action'}[0]->{'name'} ,id => '_action',name => '_action' <%= $ref->{Encode::encode("utf8",$name)} %> <%= hidden_field $self->{'n'}->{$name} => $ref->{Encode::encode("utf8",$name)} %> <%= $ref->{Encode::encode("utf8",$name)} %>
%= "* No Data *" if ($count == 0); %= "* Max over * " if ($count > 2000); !templates/mmt/Commodity.pm # Mmtを継承したアプリケーション package Tool::mmt::Commodity; use Mojo::Base 'Tool::mmt::Mmt'; has 'mmtDataList' => 'mmt/datalist'; sub init_set { my $s = shift; $s->mmtForm('mmt/mainform'); $s->param('_table','商品'); } sub look_up_set{ my $s = shift; $s->{'m'}->{LOOK_UP}->{ref $s}->{$s->{'n'}->{'大分類'}} = ["select 略称 from 分類名称 where 中分類 = '' and 小分類 = '' and 大分類 = ? ", [$s->{'n'}->{'大分類'}] ]; $s->{'m'}->{SUBWIN}->{ref $s}->{$s->{'n'}->{'大分類'}} = ["select 大分類,略称 from 分類名称 where 中分類 = '' and 小分類 = ''", []]; $s->{'m'}->{LOOK_UP}->{ref $s}->{$s->{'n'}->{'中分類'}} = ["select 略称 from 分類名称 where 大分類 = ? and 中分類 = ? and 小分類 = '' ", [$s->{'n'}->{'大分類'},$s->{'n'}->{'中分類'}] ]; $s->{'m'}->{SUBWIN}->{ref $s}->{$s->{'n'}->{'中分類'}} = ["select 中分類,略称 from 分類名称 where 大分類 = ? and 中分類 <> '' and 小分類 = ''", [$s->{'n'}->{'大分類'}] ]; $s->{'m'}->{LOOK_UP}->{ref $s}->{$s->{'n'}->{'小分類'}} = ["select 略称 from 分類名称 where 大分類 = ? and 中分類 = ? and 小分類 = ? ", [$s->{'n'}->{'大分類'},$s->{'n'}->{'中分類'},$s->{'n'}->{'小分類'}] ]; $s->{'m'}->{SUBWIN}->{ref $s}->{$s->{'n'}->{'小分類'}} = ["select 小分類,略称 from 分類名称 where 大分類 = ? and 中分類 = ? and 小分類 <> ''", [$s->{'n'}->{'大分類'},$s->{'n'}->{'中分類'}] ]; } 1; !TODO *validation * == 検索SUB画面 == (1/7) *綺麗な画面 * == ENTERで項目移動 == (12/9) * == セッション管理 == (2019/11/19) * == login処理 == (2019/11/19) * == メニュー作成 == (2020/01) [メニュー|https://qweer.info/menu/menu] * == レポートライターツール == (2017/04/09) !ENTERで項目移動 (12/9) [toolmmt/templates/layouts/toolmmt/templates/layouts] <%= title %> <%= content %> !ajaxにてテーブル参照とサブウインドを開く sub make_ajax{ my $s = shift; my $p = ''; my $onload = ''; # # マスタ参照ajax(LOOK_UPをサーチ) # for (keys %{$s->{'m'}->{LOOK_UP}->{ref $s}}){ next unless ($_ =~ /^(\D)+(\d)+$/); $p .= $s->new_updater($_); $onload .= "\$('#$_').change();\n"; } # # マスタ参照ウインド(WUBWINをサーチ) # for (keys %{$s->{'m'}->{SUBWIN}->{ref $s}}){ next unless ($_ =~ /^(\D)+(\d)+$/); $p .= $s->new_subwin($_); } return $p . $onload; } # # マスタ参照(http://www21051ue.sakura.ne.jp:3003/mmtx/commodity?_action=get_name&n=item5&p=001&p=002) # sub get_name{ my $s = shift; my @names = qw/未登録/; #eval { @names = $s->app->model->webdb->dbh->selectrow_array( $s->{'m'}->{LOOK_UP}->{ref $s}->{$s->param('n')}->[0],undef,$s->param('p')); #}; if ($@){ $s->render(json=>$@); } else{ my $json = {rec=>@names}; $s->render(json=>$json); # JSONを描画する } } sub subwin{ my $s = shift; my $subwin = $s->{'m'}->{SUBWIN}->{ref $s}->{$s->param('n')}; my $sql = $subwin->[0]; my $render = $subwin->[2] || 'mmt/subwin'; my $param = $s->param('p'); my $dbh = $s->app->model->webdb->dbh; $s->{'sth'} = $dbh->prepare($sql); $s->{'sth'}->execute($s->param('p')); $s->stash->{_title} = '検索'; $s->stash->{_sql} = $sql; $s->stash->{_controller} = ref $s; $s->render($render); } sub new_updater{ my $s = shift; my $n = shift; my $p = '"'; $p .= join '',map{qq{ + "&p=" + \$('#$_').val()}} @{$s->{'m'}->{'LOOK_UP'}->{ref $s}->{$n}->[1]}; return <Label($s->get_input_name($n))]}>"); }); jQuery('#l_$n').click( function (){ // SUB WINDOWを開く window.open("@{[$s->url_for->query( _action=>'subwin' ,n=>$n ) ]}$p,'_blank','$win_para'); return false; }); End_Script } 1; !SUB WINDOW [layouts/defsubwin.html.ep] <%= title %> <%= stylesheet '/css/default.css' %>
<%= content %>
[mmt/subwin.html.ep] % layout 'defsubwin'; % title "mmt - $_title";

<%= $_title %>

<%= $_sql %>
[<%= $_controller %>][<%= param('n') %>][<%= join '|',param('p') %>] % for my $item (@{$self->{'sth'}->{'NAME'}}){ % } % my $count = 0; % while (my $ref = $self->{'sth'}->fetchrow_arrayref()){ % $count++; % last if $count > 2000; % my $i = 0; % for my $item (@{$ref}){ % $i++; % } % }
<%= Encode::decode('UTF-8',$item) %>
% if($i == 1){ % } <%= $item %>
%= "* No Data *" if ($count == 0); %= "* Max over * " if ($count > 2000);