Created
May 3, 2011 15:43
-
-
Save mix3/953572 to your computer and use it in GitHub Desktop.
Mojolicious::Lite + Teng + SNBinder + Xslate (+ SQLite/OnMemory) でCRUDアプリ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package Message; | |
use parent 'Teng'; | |
__PACKAGE__->load_plugin('Pager'); | |
use Class::Method::Modifiers; | |
around delete => sub { | |
my ($orig, $self, $table_name, $delete_condition) = @_; | |
my $update_row_data = { | |
deleted_at => DateTime->now->set_time_zone('Asia/Tokyo'), | |
}; | |
$self->update($table_name, $update_row_data, $delete_condition); | |
}; | |
before update => sub { | |
my ($self, $table_name, $update_row_data, $update_condition) = @_; | |
if (!$update_row_data->{deleted_at}) { | |
$update_row_data->{updated_at} = DateTime->now->set_time_zone('Asia/Tokyo'); | |
} | |
}; | |
before insert => sub { | |
my ($self, $table_name, $row_data) = @_; | |
$row_data->{created_at} = DateTime->now->set_time_zone('Asia/Tokyo'); | |
$row_data->{updated_at} = DateTime->now->set_time_zone('Asia/Tokyo'); | |
}; | |
before fast_insert => sub { | |
my ($self, $table_name, $row_data) = @_; | |
$row_data->{created_at} = DateTime->now->set_time_zone('Asia/Tokyo'); | |
$row_data->{updated_at} = DateTime->now->set_time_zone('Asia/Tokyo'); | |
}; | |
before search => sub { | |
my ($self, $table_name, $search_condition, $search_attr) = @_; | |
$search_condition->{deleted_at} = \'IS NULL'; | |
}; | |
before search_with_pager => sub { | |
my ($self, $table_name, $where, $opts) = @_; | |
$where->{deleted_at} = \'IS NULL'; | |
}; | |
1; | |
package Message::Schema; | |
use Teng::Schema::Declare; | |
use DateTime::Format::MySQL; | |
table { | |
name 'message', | |
pk 'id', | |
columns qw( | |
id | |
message | |
created_at | |
updated_at | |
deleted_at | |
); | |
deflate qr/_at$/ => sub { | |
DateTime::Format::MySQL->format_datetime(shift); | |
}; | |
inflate qr/_at$/ => sub { | |
DateTime::Format::MySQL->parse_datetime(shift); | |
}; | |
}; | |
1; | |
package main; | |
use utf8; | |
use Mojolicious::Lite; | |
plugin 'xslate_renderer'; | |
use Devel::KYTProf; | |
my $model = Message->new( | |
dbh => DBI->connect( | |
'dbi:SQLite:dbname=:memory:', '', '', | |
{ | |
RaiseError => 1, | |
PrintError => 0, | |
AutoCommit => 1, | |
sqlite_unicode => 1, | |
} | |
) | |
); | |
$model->do(q{ | |
CREATE TABLE IF NOT EXISTS message ( | |
id INTEGER PRIMARY KEY AUTOINCREMENT, | |
message TEXT NOT NULL, | |
created_at DATETIME NOT NULL, | |
updated_at DATETIME NOT NULL, | |
deleted_at DATETIME | |
) | |
}); | |
get '/' => sub{ | |
my $self = shift; | |
$self->render( | |
handler => 'tx', | |
); | |
} => 'index'; | |
get '/edit/:id' => sub { | |
my $self = shift; | |
my $result = $model->single('message', { | |
id => $self->param('id') | |
}); | |
return $self->render( | |
handler => 'tx', | |
template => 'error', | |
message => '該当メッセージが見つからないか、既に削除されています' | |
) if !$result; | |
$self->render( | |
handler => 'tx', | |
id => $result->get_column('id'), | |
message => $result->get_column('message') | |
); | |
} => 'edit'; | |
post '/create' => sub { | |
my $self = shift; | |
return $self->render( | |
handler => 'tx', | |
template => 'error', | |
message => 'メッセージを入力してください' | |
) if !$self->param('message'); | |
$model->fast_insert('message', { | |
message => $self->param('message'), | |
}); | |
$self->redirect_to('index'); | |
}; | |
post '/update' => sub { | |
my $self = shift; | |
return $self->render( | |
handler => 'tx', | |
template => 'error', | |
message => 'メッセージを入力してください' | |
) if !$self->param('message'); | |
$model->update('message', | |
{ | |
message => $self->param('message'), | |
}, | |
{ | |
id => $self->param('id'), | |
} | |
); | |
$self->redirect_to('index'); | |
}; | |
get '/delete/:id' => sub { | |
my $self = shift; | |
$model->delete('message', { | |
id => $self->param('id'), | |
}); | |
$self->redirect_to('index'); | |
}; | |
get '/show/:id' => sub { | |
my $self = shift; | |
my $row = $model->single('message', { | |
id => $self->param('id'), | |
}); | |
my $result = !$row ? {} : $row->get_columns; | |
$self->render('json' => $result); | |
}; | |
get '/list' => sub { | |
my $self = shift; | |
my $page = $self->param('page') || 1; | |
my ($rows, $pager) = $model->search_with_pager( | |
'message', | |
{ | |
}, | |
{ | |
order_by => 'id DESC', | |
page => $page, | |
rows => 3, | |
} | |
); | |
my $messages = []; | |
foreach my $row (@$rows) { | |
push @$messages, $row->get_columns; | |
} | |
my $result = { | |
messages => $messages, | |
entries_per_page => $pager->entries_per_page(), | |
current_page => $pager->current_page(), | |
has_next => $pager->has_next(), | |
entries_on_this_page => $pager->entries_on_this_page(), | |
next_page => $pager->next_page(), | |
prev_page => $pager->prev_page(), | |
}; | |
$self->render('json' => $result); | |
}; | |
get '/templates' => sub { | |
my $self = shift; | |
$self->render( | |
template => 'templates' | |
); | |
} => 'templates'; | |
app->start; | |
__DATA__ | |
@@ base.tx | |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> | |
<script src="http://www.google.com/jsapi" type="text/javascript"></script> | |
<script type="text/javascript">//<![CDATA[ | |
google.load('jquery', '1.4.4'); | |
//]]></script> | |
<script src="https://github.com/snakajima/SNBinder/raw/master/snbinder-0.5.3.js" type="text/javascript"></script> | |
: include main_js | |
<title>Mojolicious::Lite + Teng + SNBinder + Xslate (+ SQLite/OnMemory)</title> | |
</head> | |
<body> | |
: block content -> { } | |
</body> | |
</html> | |
@@ main_js.tx | |
<script type="text/javascript">//<![CDATA[ | |
var page = 1; | |
var templates = null; | |
var main = (function(){ | |
return { | |
init: function(){ | |
SNBinder.flush_all(); | |
SNBinder.get_named_sections("/templates", null, function(sections) { | |
templates = sections; | |
$('div#main').show().html(templates['main']); | |
main.reload(); | |
$('#prev').click(function(){ | |
page--; | |
main.reload(); | |
}); | |
$('#next').click(function(){ | |
page++; | |
main.reload(); | |
}); | |
}); | |
}, | |
reload: function() { | |
$.get('/list', {"page": page}, function(json){ | |
main.list(json); | |
main.pager(json); | |
}); | |
}, | |
list: function(json){ | |
$('#list').fadeOut('fast', function(){ | |
$(this).html(SNBinder.bind_rowset(templates['content'], json.messages)); | |
$(this).show('fast'); | |
}); | |
}, | |
pager: function (json){ | |
$('#pager').fadeOut('fast', function(){ | |
if(json.prev_page != null){ | |
$('#prev').attr('href', '#'); | |
}else{ | |
$('#prev').removeAttr('href'); | |
} | |
if(json.next_page != null){ | |
$('#next').attr('href', '#'); | |
}else{ | |
$('#next').removeAttr('href'); | |
} | |
$(this).show('fast'); | |
}); | |
}, | |
}; | |
})(); | |
$(document).ready(function(){ | |
SNBinder.init(); | |
main.init(); | |
}); | |
//]]></script> | |
@@ templates.html.tx | |
{%}main{%} | |
<div id="list" style="display:none;" /> | |
<div id="pager" style="display:none;"><a id="prev"><</a>|<a id="next">></a></div> | |
{%}content{%} | |
<hr /><p>$(.message)</p><p>[<a href=\"/edit/$(.id)\">編集</a>][<a href=\"/delete/$(.id)\">削除</a>]</p> | |
@@ form.tx | |
<form method="post" action="<: $path :>"> | |
: if ($id) { | |
<input type="hidden" name="id" value="<: $id :>"> | |
: } | |
<p><textarea name="message" cols="50" rows="10" ><: $message :></textarea></p> | |
<p><input type="submit" /></p> | |
</form> | |
@@ index.html.tx | |
: cascade base | |
: override content -> { | |
: include form { path => "/create" } | |
<div id="main" style="display:none;"> | |
<p>Accessing server ...</p> | |
</div> | |
: } | |
@@ edit.html.tx | |
: cascade base | |
: override content -> { | |
: include form { path => "/update", message => $message } | |
: } | |
@@ error.html.tx | |
: cascade base | |
: override content -> { | |
ERROR: <: $message :> | |
: } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment