a-blog cmsの拡張アプリを掘り起こしてみた
Posted: Updated:
a-blog cms Advent Calendar 2013
この記事は、a-blog cms Advent Calendar 2013 - Adventarの13日の金曜です。
@ahomu http://t.co/bfXGBOt0Np どこか1日よろしくね! #aboogcms
— 山本一道@アップルップル (@kazumich) December 3, 2013
ご無沙汰しております。
かずみちさん、よくみたら aboogcms になってます!!
JSONプロバイダーを生やしてみた
ダイレクト編集の存在はさておき、RESTfulなJSON生成器とすることで、他システムとの連携や使い道が広がるかもしれません。かも。
今回はそんな .json
でエントリー一覧系のデータを返してくれるAPIのようなものを、拡張アプリという仕組みを通してサンプルにしてみました。
拡張アプリって?
ご存じでしょうか。アンドキュメントの壁により合宿のひっそりとした話のネタになってるかもしれませんし、まあなんぞよくわかりませんが掘り起こしてみました。
php/AAPP
以下に所定のフォーマットに従ったphp(gist後述)を配置することで、拡張アプリ画面にアプリが表示されます。
ウロ覚えですが、これでGET/POSTモジュールの名前解決時の候補になるネームスペースが追加されて、 php/AAPP/APPNAME/GET
以下もオートローダーの対象になるとかだったような。
2.0かっこいいですね。コードネームはNewYorkなのだろうか...。
拡張アプリに使用したPHP
以下のgistがJSONプロバイダーのサンプルとして利用したPHPです。ほとんどパッケージに同梱されているサンプル通りです。
ACMS_APP
は abstract
クラスであり、各メソッドもすべて abstract
として定義されています。拡張アプリ側では、中身からっぽでもメソッドを実装してください。
拡張領域としては User
のネームスペースも存在しますが、ここではよりポータブルに"よく使う拡張"をモジュール化する意図が強い・・・はず・・・です。
<?php | |
class AAPP_JSONProvider extends ACMS_APP | |
{ | |
public $version = '0.1'; | |
public $name = 'ACMS JSON Provider'; | |
public $author = 'mu.aho'; | |
public $desc = 'a-blog cms のデータをJSON APIとして扱うための拡張です'; | |
/** | |
* インストールする前の環境チェック処理 | |
* @return bool | |
*/ | |
public function checkRequirements() | |
{ | |
return true; | |
} | |
/** | |
* インストールするときの処理 | |
* データベーステーブルの初期化など | |
* @return void | |
*/ | |
public function install() { } | |
/** | |
* アンインストールするときの処理 | |
* データベーステーブルの始末など | |
* @return void | |
*/ | |
public function uninstall() { } | |
/** | |
* アップデートするときの処理 | |
* @return bool | |
*/ | |
public function update() { return true; } | |
/** | |
* 有効化するときの処理 | |
* @return bool | |
*/ | |
public function activate() { return true; } | |
/** | |
* 無効化するときの処理 | |
* @return bool | |
*/ | |
public function deactivate() { return true; } | |
} |
<?php | |
class AAPP_JSONProvider_GET_Entries extends ACMS_GET | |
{ | |
var $_axis = array( | |
'bid' => 'self', | |
'cid' => 'self', | |
); | |
function get() | |
{ | |
$DB = DB::singleton(dsn()); | |
$SQL = SQL::newSelect('entry'); | |
$limit = !!LIMIT ? LIMIT : 10; | |
$page = !!PAGE ? PAGE : 1; | |
if ( $uid = intval($this->uid) ) { | |
$SQL->addWhereOpr('entry_user_id', $uid); | |
} | |
if ( empty($this->cid) and null !== $this->cid ) { | |
$SQL->addWhereOpr('entry_category_id', null); | |
} | |
if ( !empty($this->eid) ) { | |
$SQL->addWhereOpr('entry_id', $this->eid); | |
} | |
ACMS_Filter::entrySession($SQL); | |
ACMS_Filter::entrySpan($SQL, $this->start, $this->end); | |
if ( !empty($this->tags) ) { | |
ACMS_Filter::entryTag($SQL, $this->tags); | |
} | |
if ( !empty($this->keyword) ) { | |
ACMS_Filter::entryKeyword($SQL, $this->keyword); | |
} | |
if ( !empty($this->Field) ) { | |
ACMS_Filter::entryField($SQL, $this->Field); | |
} | |
$Amount = new SQL_Select($SQL); | |
$Amount->setSelect('*', 'entry_amount', null, 'count'); | |
if ( !$itemsAmount = intval($DB->query($Amount->get(dsn()), 'one')) ) { | |
return json_encode(array('entries' => array())); | |
} | |
ACMS_Filter::entryOrder($SQL, $this->order, $this->uid, $this->cid); | |
$from = ($page - 1) * $limit; | |
$limit = ((($from + $limit) > $itemsAmount) ? ($itemsAmount - $from) : $limit); | |
if ( 1 > $limit ) return ''; | |
$SQL->setLimit($limit, ($from)); | |
$q = $SQL->get(dsn()); | |
$rows = $DB->query($q, 'all'); | |
return json_encode(array('entries' => array_map(function($row) { | |
$row['entry_url'] = acmsLink(array( | |
'bid' => $row['entry_blog_id'], | |
'cid' => $row['entry_category_id'], | |
'eid' => $row['entry_id'] | |
), false); | |
return $row; | |
}, $rows))); | |
} | |
} |
%{callback}(<!-- BEGIN_MODULE Entries --><!-- END_MODULE Entries -->) |
一番下のはjsonのサンプルです。これを例えば、使っているテーマディレクトリ内の api/entry.json
として保存すると、http://example.com/api/entry.json?callback=JSON_CALLBACK
のようにリクエストすればJSONPとして利用できます。
%{callback}
のくだりは、GETパラメータのグローバル変数利用を使ってるだけですね。
ここで利用しているGETモジュール(サンプル2段目)は、Entry_Summaryの公開ソースをベースにいらないものを消して、json_encode
しただけなので割愛します。
コンテンツストレージとしてのCMS
やや斜め方向の話になりますが、普段からa-blog cmsを使い慣れているプログラマの方でしたら、管理ページつきのデータプロバイダーとしてa-blog cmsを使い回すのは面白いかもしれません。
ライトライセンスを見る限り、商用利用も可能でモジュールIDとルール、あとカスタムフィールドあたりを使うことができれば、一般的なAPIっぽいものを作るのは容易なはずです。
もちろん、普通にWebサイトとして運用中のところで、コンテンツ資源を流用するというのもアリですよね。MySQL直でデータ抜いてくるというアプローチは前からありますが、a-blog cmsのオフィシャルな機能で完結できるのであれば、それはそれでスマートではないでしょうか。
オマケAngularJSしてみた
_人人人人人人人人人_
> 突然のAngularJS <
 ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
JS BinでのAnguarJS(バックエンドにa-blog cmsのGETモジュール)サンプル も誰かの参考になる(ことはない気がするけど)と思って軽く書いてみました。
雰囲気抜粋するとHTMLがこんなカンジで...
- {{entry.entry_title}}
JSはこんなカンジ。
var ACMS = angular.module('ACMS', []);
ACMS.controller('Entries', ['$scope', '$http', 'urlBroadcaster', function($scope, $http, urlBroadcaster) {
$http.jsonp('http://havelog.ayumusato.com/api/entry.json?callback=JSON_CALLBACK')
.success(function(response) {
$scope.entries = response.entries;
});
$scope.onClickItem = function() {
urlBroadcaster.prepForBroadcast(this.entry.entry_url);
};
}]);
ACMS.controller('EntryPreview', ['$scope', 'urlBroadcaster', function($scope, urlBroadcaster) {
$scope.url = 'http://aho.mu';
$scope.$on('urlUpdated', function(a) {
$scope.url = urlBroadcaster.url;
});
}]);
Entries
でa-blog cmsからJSONPでデータを取得してリスト表示し、アイテムがクリックされたときに EntryPreview
に渡しています。
ひさびさでした
a-blog cms 2.0のリリース目前というところで、まさかの公式サイトアップデートには驚きました。この2つを同じタイミングにぶつけてくるだなんて、本当にお疲れ様です。
どうでもいいんですけど、bootstrapテーマでインストールしてloginしようとしたら見た目が別サービスすぎてビックリしましたw