--

--

コメント

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

01

06

コメント

地元のボランティアやシゴト情報を探せる「ciitii」リニューアルしました!その2

地元のボランティアやシゴト情報を探せる「ciitii」リニューアルしました!
昨年の2月にも同じことつぶやいてますので、3回目のリニューアルになります。


ciitii

https://ciitii.net/



今回はbootstrapを使用してはいますが、明るいコンセプトで緑色にしてみました。

ciitii20140106.jpg

シゴトを探している皆さん!

どうぞご覧あれ!

ワーイヽ(゚∀゚)メ(゚∀゚)メ(゚∀゚)ノワーイ


スポンサーサイト

01

06

コメント

レスポンス速度の改善とバッチ処理

今CakePHPで作っているERPモドキなんですが、DBが

* 顧客
* 売上
** 伝票(着席して販売)
** 伝票無し販売(レシートのみ)

って感じになっている。

んで、各店舗での売り上げや顧客ごとの売上なんかを1日、1ヵ月、1年単位でまとめていく。

SQLでsumしてやれば、とある店舗の1ヵ月の売上は算出できる。
だけど遅い。

そのため、毎月の売上用のテーブルを用意する。
そうすると、SQLでは単純なselectになるので処理は早い。メモリも食わない。
だけど登録の時に統計データを更新していると登録が遅い。

んじゃーバッチでやろうか。←イマココ

「バッチでやる」というのは、"通常のリクエスト→レスポンス時間に影響を与えないで処理したい"っていう意味で使うものだと私は思うのだけど、果たしてそれでいいのか。

リクエスト→レスポンスの流れの外に毎日、毎月、毎年の売上の統計処理を入れることができればバッチは必要ない。登録処理が終わった段階で全ての統計処理が(ある程度タイムラグはあるかもしれないけど)終わっていることになる。そう考えると、マルチスレッドがいいのではないか...という発想が出てくる。

ここで、マルチスレッドにした場合には"ほぼリアルタイム"という言葉が脳内に浮かんでくると思う。
処理Aの最中に処理B、処理Cを実行すれば、Apache君はきっとABCを素早く終わらせるために頑張ってくれると思う。
ただ、やっぱりPHPでマルチスレッドは限界があると思う。PHPのソースは、先頭から順番に読んでいけば処理が全部理解できるのがやっぱりいいところだからだ。MVC?そんなの方便だ。開発内容を分離したい人たちが作った仕組みの一つにすぎない。
そうすると、"ほぼリアルタイム"が何ミリ秒の世界だとしたら、"ほぼリアルタイム"を何秒くらいまで我慢できればよいのか想像すればよいのではないだろうか。

1分?

ほら、やっぱりバッチでいいじゃないか。

よし、バッチでいこう。

なに?1秒以内がいいだって?

それならCakePHPは使うのをやめよう。そして、たぶんnode.jsを使ったほうが優秀だ。
ただもしあなたが1秒以内の情報を毎日1440回以上見ないのであれば、私は現段階ではCakePHPで作成することをお勧めする。

開発コストを上げることができないだって?

1分我慢できないんだったら、机の上のいらない紙をシュレッドするか、お客様の空いたお皿の一つでも下げれば1分なんてあっという間さ。

よし、バッチでいこう。←イマココマデキタ


バッチ処理をやるにしてもやらないにしても、リソースのことを常に考えることは重要なことだと思う。
毎日、毎月、毎年のデータを作成するのであれば、「店舗aの毎日売上データを更新せよ!」っていう指示があってから動くのが理想的だと思う。
cronの設定が分単位までしか対応していないので、もし統計処理が終わっていないようだったら「ただいま処理中のデータがあります。しばらくしてから再表示してください」というメッセージでも出そう。
cronで毎分、更新指示を確認して、更新すればいいと思う。

更新指示あるかなー→無い→1分後、更新指示あるかなー→ある→キタ――(゚∀゚)――!!

これでバッチ設計は問題無い。

さてこれで統計処理は完全にバッチ化する方針で決まった。

んで、毎日、毎月、毎年のデータについては、

* 毎日のデータの更新後に毎月のデータを更新する指示を出す
* 毎月のデータを更新後に毎年のデータを更新する指示を出す

これでバッチ処理が無駄にならずに済む。

ただこの流れだと、もしかしたら10分くらいタイムラグがあるかもしれない。
だけど考えてみてほしい。1年単位のデータを作成するのに10分のタイムラグが果たして影響するかどうか。

よし、ぜんぜん大丈夫。これで行こう。

こうなってくると、連動しているデータは全部バッチ処理で大丈夫なんじゃないかって気がしてきた。
Webシステムはとにかくレスポンス時間が重要だから、ほとんどバッチ処理化して単純化することは、いいことのような気がしてきた。
ただそうするとバッチが動いてるかどうかの確認が必要だな...

よし、バッチの最終起動時刻を保存するテーブルを作ろう。
んで、バッチの最終起動時刻が相当過ぎていた場合(1分ごとのバッチなんだから、10分くらい動いてなければアラート出そう)、管理者に連絡せよとエラーメッセージを表示すればいいだろう。

うん、これでバッチ設計完了。
あとは細かい統計情報の作成処理を既存の処理から抜き出してその部分にバッチ実行指示を設定。
統計処理をバッチに外出しすればいいだろう。

\(^o^)/オワタ!


CakePHP2系のShellについて少し触れておくことにしたい。


bakeについて

CakePHPは「超絶速度で開発作業を進める」という目的を持って開発されています。
そのため、データベースに対して、CRUD(登録、検索、更新、削除)を行う画面を速攻で開発するためのツールがbakeです。
マスタデータの作成あたりに大変効果的であり、弊社の開発案件ではほとんどのモジュールのおおもとはbakeから自動生成されています。

CakePHPの格納されているディレクトリをCAKEとして

> cd CAKE/app/Console/

して

> ./cake [コマンド]

で実行したときの処理がバッチ処理になります

> ./cake bake

で各パーツ

> ./cake bake all

でMVCの全部を出力します。

ただし、1テーブルにつき1回コマンドが必要です


shellについて

CakePHPは、「超絶速度で開発作業を進める」ということの他に、「SQLをあんまりわからなくても実装できる」という点も気を使っています。
ただしそうするとアクセス時の速度を犠牲にする可能性があります。
そうした場合に大量処理をする補助を行うのがshellになります。

CAKE/app/Console/Commandに格納されている
~Shell.phpが実行対象です

実行方法は、

> cd CAKE/app/Console/

して、

> ./cake [シェルの名前]

で実行できます。
例えば

> ./cake SummarySale

と実行すると CAKE/app/Command/Console/SummarySaleShell.php が実行されます。
開発の観点で言うと、SummarySaleShell.phpのfunction mainが実行されますので、function mainは必須になります。

04

20

コメント

CakePHP2にFullcalendar対応させてみたよ!

Fullclendar


超時間かかってしまった\(^o^)/
でも使えるようになるとすごくいいかもしれない。

Fullcalendarとは、GoogleカレンダーのようなUIを実現するjavascriptライブラリです。

http://arshaw.com/fullcalendar/

FullCalendar is a jQuery plugin that provides a full-sized, drag & drop calendar like the one below. It uses AJAX to fetch events on-the-fly for each month and is easily configured to use your own feed format (an extension is provided for Google Calendar). It is visually customizable and exposes hooks for user-triggered events (like clicking or dragging an event). It is open source licensed under an MIT license.



今回のCakePHPは確認したら2.2.9でした。
http://cakephp.jp/

さて、適当なscheduleテーブルをbakeしてからがスタートになります。

以下、構想

* 通常アクセスのindexではカレンダー表示のフィールドとjavascriptを設定し、ajaxアクセスの時にリストを返す。
* 登録と変更と削除はbootstrapのモーダルダイアログで表示する。
* 祝日はgoogle先生から引っ張ってくる。

作業開始です。

作業開始なのですが、もうすでにレイアウトにはjsとcssとかいろいろ設定済みという前提で行きたいと思います!!
あと説明は省略しまくり!
本当はもっとたくさんコーディングしてあるんですが、さすがにそれはお客様向けの設定なので割愛しました。
なのでもしかしたらコピペじゃ動かないかも!というのを前提でお願いします<(_ _)>

CakephpのTwitterBootstrapプラグインを使用しているので、BootstrapFormとかBootstrapHtmlとかありますが、使用していない方は、その辺は通常のFormとHtmlに直して対応してください。

まずはDBですが、こちらはFullcalendarに合わせて、start、end、allDay、titleって感じでいいと思います。
ユーザ情報とか必要な方は、それも追加してくださいね!

まずはコントローラです。

SchedulesController.php


/**
* index method
*
* @return void
*/
public function index() {
if($this->request->is('ajax')) {
$this->Schedule->recursive = 0;


$target_start = $this->request->query['start'];
$target_end = $this->request->query['end'];

$schedules = $this->paginate(array(
'OR' => array(
'Schedule.start between ? and ?' => array($target_start_time, $target_end_time),
'Schedule.end between ? and ?' => array($target_start_time, $target_end_time),
),
));

$this->set('schedules', $schedules);

$this->render('jsonlist');
}
}

/**
* add method
*
* @return void
*/
public function add() {
if ($this->request->is('post')) {
$this->Schedule->create();

if ($this->Schedule->save($this->request->data)) {

$this->Session->setFlash(
__('The %s has been saved', __('schedule')),
'alert',
array(
'plugin' => 'TwitterBootstrap',
'class' => 'alert-success'
)
);

if(!$this->request->is('ajax')) {
$this->redirect(array('action' => 'index'));
} else {
$this->autoRender = false;
return $this->Schedule->id;
}
} else {
$this->Session->setFlash(
__('The %s could not be saved. Please, try again.', __('schedule')),
'alert',
array(
'plugin' => 'TwitterBootstrap',
'class' => 'alert-error'
)
);
}
} else {
if(!empty($this->request->query['start'])) {
$this->request->data['Schedule']['start'] = strtotime($this->request->query['start']);
}
if(!empty($this->request->query['end'])) {
$this->request->data['Schedule']['end'] = strtotime($this->request->query['end']);
}
if(!empty($this->request->query['allDay'])) {
$this->request->data['Schedule']['allDay'] = strtotime($this->request->query['allDay']);
}
}

if($this->request->is('ajax')) {
$this->render('modal_add');
}
}

/**
* edit method
*
* @param string $id
* @return void
*/
public function edit($id = null) {
$this->Schedule->id = $id;
if (!$this->Schedule->exists()) {
throw new NotFoundException(__('Invalid %s', __('schedule')));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->Schedule->save($this->request->data)) {
$this->Session->setFlash(
__('The %s has been saved', __('schedule')),
'alert',
array(
'plugin' => 'TwitterBootstrap',
'class' => 'alert-success'
)
);
if(!$this->request->is('ajax')) {
$this->redirect(array('action' => 'index'));
} else {
$this->autoRender = false;
return true;
}
} else {
$this->Session->setFlash(
__('The %s could not be saved. Please, try again.', __('schedule')),
'alert',
array(
'plugin' => 'TwitterBootstrap',
'class' => 'alert-error'
)
);
}
} else {
$this->request->data = $this->Schedule->find('first', array(
'conditions' => array(
'Schedule.id' => $id
),
'contain' => false
));
}

if($this->request->is('ajax')) {
$this->render('modal_edit');
}
}

/**
* change method
*
* @param string $id
* @return void
*/
public function change($id, $start, $end, $allDay = false) {
$this->Schedule->id = $id;
if (!$this->Schedule->exists()) {
throw new NotFoundException(__('Invalid %s', __('schedule')));
}

$schedule = $this->Schedule->getMiniData($id);

$schedule['Schedule']['start'] = $start;
$schedule['Schedule']['end'] = $end;
$schedule['Schedule']['allDay'] = $allDay;
$schedule['Schedule']['modified'] = null;

$this->autoRender = false;

if ($this->Schedule->save($schedule)) {
return true;
} else {
return false;
}
}

/**
* delete method
*
* @param string $id
* @return void
*/
public function delete($id = null) {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException();
}
$this->Schedule->id = $id;
if (!$this->Schedule->exists()) {
throw new NotFoundException(__('Invalid %s', __('schedule')));
}
if ($this->Schedule->delete()) {
$this->Session->setFlash(
__('The %s deleted', __('schedule')),
'alert',
array(
'plugin' => 'TwitterBootstrap',
'class' => 'alert-success'
)
);
if(!$this->request->is('ajax')) {
$this->redirect(array('action' => 'index'));
} else {
$this->autoRender = false;
return true;
}
}
$this->Session->setFlash(
__('The %s was not deleted', __('schedule')),
'alert',
array(
'plugin' => 'TwitterBootstrap',
'class' => 'alert-error'
)
);
$this->redirect(array('action' => 'index'));
}



syntaxhighlightしてなくてすいません。
コピペしてテキストエディタで詳細確認してください(^_^;)

続いてViewです。

modal_add.ctpとmodal_edit.ctpは、bakeで出てきたaddとeditの見出しとかを削除しただけなので割愛します!

/View/Schedules/index.ctp


<?php
echo $this->Html->div(null, '', array('id' => 'FullCalendar'));
echo $this->Html->div('hidden_field', $this->Html->image('loader.gif', array('width' => 96, 'height' => 96, 'alt' => 'Now Loading...')), array('id' => 'schedule_loader'));
echo $this->Html->div('hidden_field', '', array('id' => 'schedule_fade'));
?>

<!-- Modal -->
<div id="schedule_add_dialog_area" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="scheduleAddModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="scheduleAddModalLabel">スケジュールの登録</h3>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">キャンセル</button>
<button class="btn btn-primary" id="schedule_add_save">登録</button>
</div>
</div>
<div id="schedule_edit_dialog_area" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="scheduleEditModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="scheduleEditModalLabel">スケジュールの編集</h3>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">キャンセル</button>
<button class="btn btn-warning" id="schedule_delete"><i class="icon-trash"></i></button>
<button class="btn btn-primary" id="schedule_edit_save">登録</button>
</div>
</div>

<script type="text/javascript">
function showLoader() {
$("#schedule_fade").css("top", window.scrollY+"px");

$("#schedule_fade").fadeIn("fast");
$("#schedule_loader").fadeIn("fast");
}
function hideLoader() {
$("#schedule_fade").delay(600).fadeOut(300);
$("#schedule_loader").delay(600).fadeOut(300);
}

$(function() {
var now_edit_event = null;

$("#schedule_delete").click(function() {
$.ajax({
type: "POST",
url: "/schedules/delete/"+$("#ScheduleId").val(),
timeout: (30 * 1000), // タイムアウト30秒
success: function(html) {
$("#FullCalendar").fullCalendar("removeEvents", now_edit_event.id);
$("#schedule_edit_dialog_area").modal("hide");
$(".modal-body", "#schedule_edit_dialog_area").html("");
}
});
});

$("#schedule_add_save").click(function() {
// フォームの内容をsubmitする
$.ajax({
type: "POST",
url: "/schedules/add",
dataType: "json",
data: $("#ScheduleAddForm").serializeArray(),
timeout: (30 * 1000), // タイムアウト30秒
beforeSend: function(XMLHttpRequest){
showLoader(); // ローディング呼出
},
success: function(html) {
// カレンダーの更新
var title = $("#ScheduleTitle", "#ScheduleAddForm").val();
var start = $("#ScheduleStart", "#ScheduleAddForm").val();;
var end = $("#ScheduleEnd", "#ScheduleAddForm").val();;
var allDay = $("#ScheduleAllDay", "#ScheduleAddForm").val();;

$("#FullCalendar").fullCalendar("addEventSource", [{
id: html,
title: title,
start: start,
end: end,
allDay: allDay
}]);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("通信に失敗しました。しばらくたってからもう一度お試しください。");
hideLoader(); // ローディング隠す
},
complete: function(XMLHttpRequest, textStatus) {
$("#schedule_add_dialog_area").modal("hide");
$(".modal-body", "#schedule_add_dialog_area").html("");
hideLoader(); // ローディング隠す
},
});
});
$("#schedule_edit_save").click(function() {
// フォームの内容をsubmitする
$.ajax({
type: "POST",
url: "/schedules/edit",
dataType: "json",
data: $("#ScheduleEditForm").serializeArray(),
timeout: (30 * 1000), // タイムアウト30秒
beforeSend: function(XMLHttpRequest){
showLoader(); // ローディング呼出
},
success: function(html) {
// カレンダーの更新
var title = $("#ScheduleTitle", "#ScheduleEditForm").val();
var start = $("#ScheduleStart", "#ScheduleEditForm").val();;
var end = $("#ScheduleEnd", "#ScheduleEditForm").val();;
var allDay = $("#ScheduleAllDay", "#ScheduleEditForm").val();;

event.title = title;
event.start = start;
event.end = end;
event.allDay = allDay;

$("#FullCalendar").fullCalendar("updateEvent", event);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("通信に失敗しました。しばらくたってからもう一度お試しください。");
hideLoader(); // ローディング隠す
},
complete: function(XMLHttpRequest, textStatus) {
$("#schedule_edit_dialog_area").modal("hide");
$(".modal-body", "#schedule_edit_dialog_area").html("");
hideLoader(); // ローディング隠す
},
});
});

$("#FullCalendar").fullCalendar({
editable: true,
header: { left: "today prev,next title", right: "month,agendaWeek,agendaDay" },
axisFormat: "H:mm",
timeFormat: { agenda: "H:mm{ - H:mm}", "": "H:mm" },
columnFormat: { month: "ddd", week: "M月d日 ddd", day: "M月d日 dddd" },
buttonText: { today: "今日", month: "月", week: "週", day: "日" },
titleFormat: { month: "yyyy年 M月", week: "yyyy年 M月 d日{ - [ M月] d日}", day: "yyyy年 M月 d日 dddd" },
monthNames: [ "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月" ],
dayNamesShort: [ "日", "月", "火", "水", "木", "金", "土" ],
dayNames: [ "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日" ],
selectable: true,
// 登録済みデータの呼び出し
events: "/schedules/index",
// Google先生から祝日情報の呼び出し
eventSources: [ { url: "https://www.google.com/calendar/feeds/ja.japanese%23holiday%40group.v.calendar.google.com/public/full/", color: "red" } ],
// カレンダーのどこかをクリックしたらイベントを作る
select: function(start, end, allDay, jsEvent, view) {
start = $.fullCalendar.parseDate(start);
end = $.fullCalendar.parseDate(end);

// 選択されたstartとendからスケジュール登録画面呼出
$.ajax({
type: "GET",
url: "/schedules/add?start="+start.toLocaleString()+"&end="+end.toLocaleString()+"&allDay="+allDay,
timeout: (30 * 1000), // タイムアウト30秒
beforeSend: function(XMLHttpRequest){
showLoader(); // ローディング呼出
},
success: function(html) {
$(".modal-body", "#schedule_add_dialog_area").html(html);
$("#schedule_add_dialog_area").modal();
hideLoader(); // ローディング隠す
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("通信に失敗しました。しばらくたってからもう一度お試しください。");
hideLoader(); // ローディング隠す
},
complete: function(XMLHttpRequest, textStatus) {
hideLoader(); // ローディング隠す
}
});
},
// イベントをクリックしたら予定変更する
eventClick: function(event, jsEvent){
// 選択されたstartとendからスケジュール登録画面呼出
$.ajax({
type: "GET",
url: "/schedules/edit/"+event.id,
timeout: (30 * 1000), // タイムアウト30秒
beforeSend: function(XMLHttpRequest){
// イベントの保持
now_edit_event = event;
showLoader(); // ローディング呼出
},
success: function(html) {
$(".modal-body", "#schedule_edit_dialog_area").html(html);
$("#schedule_edit_dialog_area").modal();
hideLoader(); // ローディング隠す
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("通信に失敗しました。しばらくたってからもう一度お試しください。");
hideLoader(); // ローディング隠す
},
complete: function(XMLHttpRequest, textStatus) {
hideLoader(); // ローディング隠す
}
});
},
// ドロップ時のイベント(更新)
eventDrop: function( event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view ) {
// ドロップ時のイベントについては失敗してもそのまま放置
schedule_id = event.id;
start = $.fullCalendar.parseDate(start);
end = $.fullCalendar.parseDate(end);

// 更新処理
$.ajax({
type: "GET",
url: "/schedules/change/"+schedule_id+"/"+start+"/"+end+"/"+allDay,
timeout: (30 * 1000), // タイムアウト30秒
});
},
// 日付と時間の再設定
eventResize: function(event,dayDelta,minuteDelta,revertFunc) {
// ドロップ時のイベントについては失敗してもそのまま放置
schedule_id = event.id;
start = $.fullCalendar.parseDate(start);
end = $.fullCalendar.parseDate(end);

// 更新処理
$.ajax({
type: "GET",
url: "/schedules/change/"+schedule_id+"/"+start+"/"+end+"/"+allDay,
timeout: (30 * 1000), // タイムアウト30秒
});
}
});
});
</script>



/View/Schedules/jsonlist.ctp


<?php
if(!empty($schedules)) {
$output_list = array();

foreach ($schedules as $schedule) {
$output_list[] = array(
'id' => $schedule['Schedule']['id'],
'title' => $schedule['Schedule']['title'],
'start' => $schedule['Schedule']['start_time'],
'end' => $schedule['Schedule']['end_time'],
'allDay' => (!empty($schedule['Schedule']['start_time']) && !empty($schedule['Schedule']['end_time']) ? false : true),
'color' => (!empty($schedule['User']['mycolor']) ? $schedule['User']['mycolor'] : '#bce2e8'),
'textColor' => (!empty($schedule['User']['mytxtcolor']) ? $schedule['User']['mytxtcolor'] : '#FFFFFF'),
'borderColor' => (!empty($schedule['User']['mycolor']) ? $schedule['User']['mycolor'] : '#bce2e8'),
'backgroundColor' => (!empty($schedule['User']['mycolor']) ? $schedule['User']['mycolor'] : '#bce2e8'),
);
}

echo json_encode($output_list);
}



うちのシステムではログインユーザにmycolorっていうのを割り当てているのでjsonlistでリスト作成時に色の設定もしています!
スクリプトの設定っていうわけではないのですが、schedules/addしたときに、戻り値にidをセットすることで、そのまま編集や削除ができるようにしてみました。

FullCalendarで取得されるstartとendの日付がなぜか最後に(東京標準時)っていう文字列が入ってしまっていて、最初??????ってなりました。GMTだから、ローカル時間に変換して解決しました。
あとはとにかくFullCalendarのdocsの読むのに時間がかかりましたー。
なんだろう、こういうのってすごく根気がいる作業だと思うんだけど、自分の意図したように動かすのって本当に大変だなーって。
最後になりますが、私も書き方に癖があるほうなので、ちょっとこれよくわかんない!っていうのがありましたら、コメントください(´∀`)

02

17

コメント

地元のボランティアやシゴト情報を探せる「ciitii」リニューアルしました!

地元のボランティアやシゴトが探せる求人サイト「ciitii」をリニューアルしました。

https://ciitii.net/

ciitii


Twitter Bootstrap使ってみましたが、もう少しよくなりそうな...
そんなわけで日々精進しています。

ボランティアの活動は、個人的にはPTAくらいしかやっていませんが、やってみるとすごく新鮮な経験になります!

みなさんの自分の「やりたいこと」が見つかる手段の一つになるといいです!

現在は東京都大田区だけしか掲載できていませんが、これからどんどんエリア拡大していきたいと思いますので、どうぞよろしくお願いします(´∀`)

12

20

コメント

CakePHP 2系はすごいな。速い

CakePHPとTwitter Bootstrapプラグインを使用した開発を現在2件行っていますが、
これは本当にすごいなーーと思う。

メインになるCRUDの部分はbakeで作れば、あっという間に大枠が完成しちゃう。

そろそろエンジニアがいらない時代が....



コネ━━(゚Д゚)━( ゚Д)━(  ゚)━(  )━(  )━(゚  )━(Д゚ )━(゚Д゚)━━!!!!





まだまだ自分の手がモノを作り出してるって感じがする。

bakeの機能はあくまでサポート。
論理削除のフラグまで画面に出力されちゃうし、整形は必要。

いままで何度も作成してきた処理を自動で作成してくれるというのは素晴らしいことだと思う。

あとTwitterBootstrapを使用すれば、見た目も素晴らしいし、bakeで出力される定型の名前やコメントは、全部ローカライズしてくれてるから、日本語用のテキストを書いてやるだけで、本文をいじる必要もないことがすごくたすかる。



CakePHPの2.2.2で作業中ですが、今後はプラグイン開発に一層力が入りそうな、そんな感じがしました。
社内のモジュール、特にコンポーネントとヘルパーについては、全部まとめてプラグイン化しておけば、あとからの使い回しも簡単だー。

とっても得した気分になるし、また開発終わったら公開したいと思います(´∀`)

ようこそ!

ブロとも申請フォーム

ブロ友申請大歓迎です!
一覧に表示されるので自動で相互リンクになります!

>> ブロ友申請はこちら <<

検索フォーム

最近のコメント

メールフォーム

名前:
メール:
件名:
本文:

FC2ブログランキング

人気ブログランキング

人気ブログランキング

ブログ村

アクセスランキング

[ジャンルランキング]
育児
628位
アクセスランキングを見る>>

[サブジャンルランキング]
パパ育児
51位
アクセスランキングを見る>>

やーんは今、

ブロとも一覧

Designed by

Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。