FuelPHPに独自の設定ファイルを追加する

設定ファイルを新たに追加するには、fuel/app/config/に Arrayを返すPHPファイルを置きます。

以下、ページングの件数の共通設定を追加してみた例です。

fuel/app/config/paging.php
[php]
<?php
return array(
‘per_page’ => 20,
);
[/php]

設定の読み込みは Config::load メソッドを呼び出す必要があります。
[php]
Config::load(‘paging’);
[/php]
全体で利用する設定の場合は fuel/app/bootstrap.php に追加してしまって良い気がします。

設定値の読み込みは Config::get メソッドを使います。
[php]
Config::get(‘paging.per_page’)
[/php]

公式ドキュメント: Config Class

Eclipse Java開発でよく使うショートカットめとめ

私は普段英語版を使っているのでウィンドウ/パースペクティブの名前は英語で記述しています。

ナビゲーション

Open Resource (Ctrl + Shift + R)

Javaクラスに限らずワークスペース上の任意の種類のファイルを対象に検索したいときには Open Resource が便利です。
ワークスペース上のファイルを開く

Open Type (Ctrl + Shift + T)

Java SDK ライブラリやビルドパスに含まれるライブラリも含めてJavaのクラス/インタフェースを検索したいときには Open Type を使います。
クラス/インタフェースを検索 width=

任意のメンバーにジャンプ (Ctrl + O / Command + O)

現在開いているクラスのアウトラインを表示して、メンバー(メソッド/フィールド)にジャンプできます。
アウトラインを表示

関連するショートカット

  • 前のメンバーにジャンプ (Ctrl + Shift + Up / Ctrl + Alt + Up)
  • 次のメンバーへジャンプ (Ctrl + Shift + Down / Ctrl + Alt + Down)

クラス階層を表示 (Ctrl + T / Command + T)

現在開いているクラスのクラス階層を表示します。
クラス階層の表示
関連するショートカット

  • Type Hierarchy パースペクティブを開く (F4 / Fn + F4)

Call Hierarchy パースペクティブを開く (Alt + Shift + H)

現在選択されているクラス/フィールド/メソッドの呼び出し階層を Call Hierarchy パースペクティブに表示します。

指定行にジャンプ (Command + L)

メニュー

Refactor メニューを開く (Alt + Shift + T / Alt + Command + T)

Source メニューを開く (Alt + Shift + S / Alt + Command + S)

エディター編用

コメントアウト (Ctrl + / / Command + /)

現在の行を削除 (Ctrl + D / Command + D)

実行 / デバッグ

Run (Ctrl + F11 / Shift + Command + Fn + F11)

Debug (F11 / Shift + Command + Fn + F11)

参考リンク

10 Eclipse Navigation Shortcuts Every Java Programmer Should Know
“Right Click” keyboard short cut for Eclipse?

Hello FuelPHP

FuelPHPは、PHPのメジャーなMVCフレームワークの一つです。

規約よりも設定というRuby on Rails的なMVCフレームワークとは逆行するコンセプトですが、非常に柔軟にアプリケーションを実装できとても使い勝手の良いフレームワークです。

また機能についても、データベースアクセスにクエリービルダー形式とORMのサポートがあり、ORMは関連も含めて複合キーも使えたりと、他のフレームワークで意外と困ることを難なくこなしてくれます。

ただ、FuelPHPは、MySQLでしかまともに動きません。Postgresqlの場合は、1.7でもシーケンスの扱いなどそれなりに修正が必要となります。
また、PHP系のフレームワークだとどれもそうですがユニットテストのサポートがイマイチなので、その辺りは割り切りがある程度必要そうではあります。

チュートリアル
Fuel Crash Course

セットアップ

公式ドキュメントのインストール方法に掲載されている「コマンドラインからインストール」の手順に従ってプロジェクトを作成します。
[bash]
$ cd /var/www
$ curl get.fuelphp.com/oil | sh
$ oil create blog
[/bash]
oil は、CakePHPの bake、 Railsの rails コマンドに当たります。

Apacheに設定を追加

[text]
<VirtualHost *:80>
ServerName www.blog.net
DocumentRoot /var/www/blog/public
</VirtualHost>
[/text]
/etc/hosts にwww.blog.netとそのIPアドレスを追加します。
[text]
127.0.0.1 www.blog.net
[/text]
http://www.blog.net にアクセスして以下の画面が表示されればセットアップは成功です。
fuelphp_welcome

Scaffold

データベースを作成

[bash]
$ mysql -uroot -p
mysql> CREATE DATABASE blog DEFAULT CHARACTER SET utf8;
[/bash]
fuel/app/config/development/db.phpに作成したデータベースを設定
[php]
return array(
‘default’ => array(
‘connection’ => array(
‘dsn’ => ‘mysql:host=localhost;dbname=blog’,
‘username’ => ‘root’,
‘password’ => ‘root’,
),
),
);
[/php]
参照: PDO_MYSQL DSN

ORMパッケージを有効にする

fuel/app/config/config.phpの257行目からのAlways Load セクションの該当箇所をコメントアウトして設定します。
[php]

/**************************************************************************/
/* Always Load */
/**************************************************************************/
‘always_load’ => array(

‘packages’ => array(
‘orm’,
),

),

[/php]
これで、scafoldを実行する準備が整いました。
scaffoldを実行して、生成されるマイグレーションを実行してデータベースに適用します。
[bash]
$ php oil generate scaffold posts name:string message:text

$ php oil refine migrate
Performed migrations for app:default:
001_create_posts
[/bash]
http://www.blog.net/posts にアクセスすると以下のようなPostの一覧画面が表示されます。
fuel_php_posts

CentOS 6.3でRsyslog ommailを利用してシステムアラートを送信するには

ommail はrsyslogで特定のエラーが発生した場合、メールアラートを送信するモジュールです。
CentOS 5系でommailを使用する場合は、rsyslogをコンパイル・インストールし直す必要がありましたが、CentOS 6以降では、デフォルトでommail.soを含むrsyslogがインストールされていますので設定だけで利用することができます。

/etc/rsyslog.d/ommail.conf

[text]
$ModLoad ommail

$ActionMailSMTPServer 192.168.1.2
$ActionMailFrom alert@example.com
$ActionMailTo admin@example.com
$template mail_subject,"Syslog Warning"
$template mail_body,"%fromhost%\r\n%msg%"
$ActionMailSubject mail_subject
$ActionExecOnlyOnceEveryInterval 15

*.error :ommail:;mail_body
[/text]
主な設定は以下のとおり

  • $ActionMailSMTPServer: SMTPサーバーのホスト名/IPアドレス
  • $ActionMailFrom: アラートメールの送信者アドレス
  • $ActionMailTo: アラートメールの送信先アドレス
  • $ActionMailSubject: メールタイトル
  • $template mail_subject: メールタイトルのテンプレート
  • $template mail_body: メール本文のテンプレート
    ール本文のテンプレート
  • ActionExecOnlyOnceEveryInterval: メール送信間隔

SELinuxの設定

SELinuxが有効な場合は、rsyslogからメールを送信できないように制限されています。
setseboolコマンドでlogging_syslogd_can_sendmailを有効にします。
[bash]
setsebool -P logging_syslogd_can_sendmail 1
[/bash]
getseboolで確認
[bash]
# getsebool -a | grep logging
logging_syslogd_can_sendmail –> on
[/bash]

AppEngin (Python) でメール受信

app.yaml
[text]
– url: /_ah/mail/.+
script: handle_incoming_email.app
login: admin

inbound_services:
– mail
[/text]

handle_incoming_email.app
[python]
import logging
import webapp2
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler

class ReceiveEmail(InboundMailHandler):
def receive(self,message):
logging.info("Received email from %s" % message.sender)
plaintext = message.bodies(content_type=’text/plain’)
for text in plaintext:
txtmsg = ""
txtmsg = text[1].decode()
logging.info("Body is %s" % txtmsg)
self.response.out.write(txtmsg)

app = webapp2.WSGIApplication([
ReceiveEmail.mapping()
], debug=True)
[/python]

GWT Remote Loggingで出力されるログを読みやすくする

Google Web Toolkit にはJavaのLoggingインタフェースを利用したロギング機構が用意されています。

中でも強力なのはRemote Loggingが標準でサポートされていることです。
クライアントのエラーをサーバーに集められるため迅速なトラブルシューティングが可能になります。

しかし、GWTのデフォルトのコンパイルスタイル OBFUSCATED だとスタックトレースは以下のように、最も難読化されたモードのまま出力されてしまいます。
例えば、GWT2.5.0のsamplesに含まれるLogExampleを実行して、”Trigger Exception”ボタンをクリックして出力されるスタックトレースは以下のようになります。
[text]
Sat Nov 02 10:15:15 GMT+900 2013 SEVERE: Fake Null Exception Hit
java.lang.NullPointerException: null
at Unknown.Ec(StackTraceCreator.java:174)
at Unknown.jI(StackTraceCreator.java:501)
at Unknown.Rv(OneLoggerController.java:70)
at Unknown.Of(ClickEvent.java:55)
at Unknown.Gh(GwtEvent.java:76)
at Unknown.vh(HandlerManager.java:127)
at Unknown.Sr(Widget.java:129)
at Unknown.Bf(DomEvent.java:116)
at Unknown._r(UIObject.java:557)
at Unknown.ay(DOM.java:1307)
at Unknown.anonymous(DOMImplStandard.java:171)
at Unknown.Xb(Impl.java:189)
at Unknown.$b(Impl.java:242)
at Unknown.anonymous(Impl.java:70)
[/text]
これでは、なかなかエラーを追うのが大変なため、以下のように元のクラス名に変換して出力ように設定していきます。
[text]
2013/11/02 10:15:15 com.google.gwt.logging.server.RemoteLoggingServiceUtil logOnServer
SEVERE: Fake Null Exception Hit
java.lang.Throwable
at com.google.gwt.core.client.impl.StackTraceCreator$CollectorEmulated.$fillInStackTrace(StackTraceCreator.java:174)
at java.lang.NullPointerException.NullPointerException(NullPointerException.java:501)
at com.google.gwt.sample.logexample.client.OneLoggerController_MyUiBinderImpl$Widgets$2.onClick(OneLoggerController_MyUiBinderImpl.java:70)
at com.google.gwt.event.dom.client.ClickEvent.dispatch(ClickEvent.java:55)
at com.google.web.bindery.event.shared.SimpleEventBus.$doFire(SimpleEventBus.java:76)
at com.google.gwt.event.shared.HandlerManager.$fireEvent(HandlerManager.java:127)
at com.google.gwt.user.client.ui.Widget.$fireEvent(Widget.java:129)
at com.google.gwt.event.dom.client.DomEvent.fireNativeEvent(DomEvent.java:116)
at com.google.gwt.user.client.ui.Widget.onBrowserEvent(Widget.java:557)
at com.google.gwt.user.client.DOM.dispatchEvent(DOM.java:1307)
at Unknown.anonymous(DOMImplStandard.java:171)
at com.google.gwt.core.client.impl.Impl.apply(Impl.java:189)
at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:242)
at Unknown.anonymous(Impl.java:70)
[/text]

1. Remote Loggingを有効にする

gwt.xmlで以下のプロパティを設定するとサーバーにログが送信されるようになります。
[xml]
<set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
[/xml]
LogExampleの場合は、既に設定済みですので、samples/LogExample/src/com/google/gwt/sample/logexample/LogExample.gwt.xml を確認してください。

2. コンパイル時にsymbolMapsをwarに含める

symbolMapsは、コンパイルされたJavascriptのメソッド名と実際のクラス/メソッドのマップを保持するファイルを含みます。
デフォルトでは、コンパイル時に -war に指定されたディレクトリの WEB-INF/deplay/<モジュール名>/symbolMaps ディレクトリに出力されるので、そのままwarファイルに含まれます。

3. symbolMapsを読み込むRemoteLoggingServiceを実装する

サーバーでクライアントのログを受けるためには、RemoteLoggingServiceImpl を web.xml に追加します。
samples/LogExample/war/WEB-INF/web.xml で確認できます。

いくつかのブログや掲示板では、この RemoteLoggingServiceImpl の init-param に symbolMaps のパスを渡すとスタックトレースが実際のJavaのクラス/メソッドに変換されて出力される記述されていますが RemoteLoggingServiceImp はinit-paramをハンドリングしません。

そのため、RemoteLoggingServiceImp を拡張するクラスを実装する必要があります。
Removing obfuscation from a stack trace.

LogExampleを用いて確認するために、src/com/google/gwt/sample/logexample/server/MyRemoteLoggingService.java を以下のように記述しました。
[java]
package com.google.gwt.sample.logexample.server;

import com.google.gwt.logging.server.RemoteLoggingServiceImpl;
import javax.servlet.*;
public class MyRemoteLoggingService extends RemoteLoggingServiceImpl {

@Override
public void init() throws ServletException {
super.init();
setSymbolMapsDirectory(getServletContext().getRealPath("/WEB-INF/deploy/logexample/symbolMaps"));
}

}
[/java]
web.xml のサーブレット設定も RemoteLoggingServiceImpl から MyRemoteLoggingService へ変更します。
[xml]
<servlet>
<servlet-name>remoteLoggingServlet</servlet-name>
<servlet-class>com.google.gwt.sample.logexample.server.MyRemoteLoggingService</servlet-class>
<init-param>
<param-name>symbolMaps</param-name>
<param-value>WEB-INF/deploy/logexample/symbolMaps</param-value>
</init-param>
</servlet>
[/xml]

以上を設定して実行すると、上記のJavaのクラス・メソッド名に変換されたスタックトレースが出力されるようになります。

参考:
7 Tips for Exception Handling in GWT
Using the GWT Compiler for Better Builds

MavenでGWTプロジェクトを作成/管理する

[bash]
$ mvn archetype:generate

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 314: gwt-maven-plugin
Choose archetype:
1: remote -> org.codehaus.mojo:gwt-maven-plugin (Maven plugin for the Google Web Toolkit.)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 1
Choose org.codehaus.mojo:gwt-maven-plugin version:
1: 1.1
2: 1.2
3: 2.1.0
4: 2.1.0-1
5: 2.4.0
6: 2.5.0-rc1
7: 2.5.0-rc2
8: 2.5.0
9: 2.5.1-rc1
10: 2.5.1
Choose a number: 10: 10
Downloading: http://repo1.maven.org/maven2/org/codehaus/mojo/gwt-maven-plugin/2.5.1/gwt-maven-plugin-2.5.1.jar
Downloaded: http://repo1.maven.org/maven2/org/codehaus/mojo/gwt-maven-plugin/2.5.1/gwt-maven-plugin-2.5.1.jar (181 KB at 78.2 KB/sec)
Downloading: http://repo1.maven.org/maven2/org/codehaus/mojo/gwt-maven-plugin/2.5.1/gwt-maven-plugin-2.5.1.pom
Downloaded: http://repo1.maven.org/maven2/org/codehaus/mojo/gwt-maven-plugin/2.5.1/gwt-maven-plugin-2.5.1.pom (21 KB at 44.4 KB/sec)
Define value for property ‘groupId’: : com.example
Define value for property ‘artifactId’: : HelloGWT2.5.1
Define value for property ‘version’: 1.0-SNAPSHOT: :
Define value for property ‘package’: com.example: :
Define value for property ‘module’: : helloworld
Confirm properties configuration:
groupId: com.example
artifactId: HelloGWT2.5.1
version: 1.0-SNAPSHOT
package: com.example
module: helloworld
Y: : y
[INFO] —————————————————————————-
[INFO] Using following parameters for creating project from Archetype: gwt-maven-plugin:2.5.1
[INFO] —————————————————————————-
[INFO] Parameter: groupId, Value: com.example
[INFO] Parameter: artifactId, Value: HelloGWT2.5.1
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.example
[INFO] Parameter: packageInPathFormat, Value: com/example
[INFO] Parameter: package, Value: com.example
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: module, Value: helloworld
[INFO] Parameter: groupId, Value: com.example
[INFO] Parameter: artifactId, Value: HelloGWT2.5.1
[INFO] project created from Archetype in dir: /Users/hrendoh/workspace/HelloGWT2.5.1
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 1:29.365s
[INFO] Finished at: Fri Nov 01 16:48:36 JST 2013
[INFO] Final Memory: 7M/81M
[INFO] ————————————————————————
[/bash]

[bash]
$ cd HelloGWT2.5.1
$ mvn gwt:run
[/bash]
ant devmodeした場合と同じく、”GWT Development Mode”が起動します。

参考:
Compile GWT application into JavaScript

MavenでWebアプリケーションプロジェクト HelloWorld jettyプラグインで実行

Mavenは、Rubyで言うところのrakeにあたる、Javaのプロジェクト管理ツールです。
おそらくデファクトスタンダードなはずですが、antから乗り換える動機が無いためあまりちゃんと勉強したことが無かったので改めてまとめてみました。

で、一番良く使うシンプルなWebアプリプロジェクトを作成してみます。

Mavenのインストール

Macだとhomebrewとかmacportsでお手軽にインストールできます。

Mavenプロジェクトの生成

[bash]
$ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

[INFO] Generating project in Interactive mode
Define value for property ‘groupId’: : com.example
Define value for property ‘artifactId’: : HelloMavenWebApp
Define value for property ‘version’: 1.0-SNAPSHOT: :
Define value for property ‘package’: com.example: :
Confirm properties configuration:
groupId: com.example
artifactId: HelloMavenWebApp
version: 1.0-SNAPSHOT
package: com.example
Y: : y
….
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 45.392s
[INFO] Finished at: Fri Nov 01 14:27:49 JST 2013
[INFO] Final Memory: 7M/81M
[INFO] ————————————————————————
[/bash]

Maven プロジェクトを生成するコマンドは mvn archetype:generate です。
パラメータ archetypeArtifactId に archetype(Mavenプロジェクトのテンプレート)を指定します。
archetypeを指定しない場合は、コマンドライン上で選択できますが、数が膨大なので目的のテンプレートを探すのは困難です。
今回利用した maven-archetype-webapp はMavenの公式archetype(groupIdがorg.apache.maven.archetypes)です。
Introduction to Archetypes で確認できます。

必要なプロパティは、すべてプロプントで聞かれるので簡単にプロジェクトを生成できます。

  • groupId は、Javaでいつも使っているパッケージを指定します(例:com.co-meeting)。groupId は archetype を検索する際に条件にも利用できます。
  • artifactId は、プロジェクトの名前を指定します。
  • version は、今回はデフォルトのまま、Enter。
  • package は、通常groupIdと同じになるので、Enter。

プロジェクトをビルドして実行

[bash]
$ cd HelloMavenWebApp/
$ mvn compile war:war
[/bash]
http://maven.apache.org/plugins/maven-war-plugin/usage.html

pom.xmlのbuildの下にpluginsを追加します。
[xml]
<build>
<finalName>HelloMavenWebApp</finalName>
  <plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
[/xml]

注意: 似た名前の maven-jetty-plugin は古いので Jetty7以上を使う場合は jetty-maven-plugin をしていすること

jettyプラグインを実行
[bash]
$ mvn jetty:run
[/bash]

http://localhost:8080/ にアクセスして “Hello World!” と表示されれば成功です。

Jetty9 を利用する場合は、org.eclipse.jettyのjetty-maven-pluginを利用する必要があります。

ただし、org.eclipse.jettyのプラグインはデフォルトのリポジトリには含まれていないため Maven の settings.xml に追加する必要があります。
settings.xmlについての説明は Settings Reference を参照してください。

.m2/settings.xml を以下のように記述します。
[xml]
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups>
<pluginGroup>org.eclipse.jetty</pluginGroup>
</pluginGroups>
<servers/>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>
[/xml]

pom.xmlのpluginsを以下の用に書き換えます。
[xml]
<build>
<finalName>HelloMavenWebApp</finalName>
  <plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
[/xml]
実行方法は同じです。
[bash]
$ mvn jetty:run
[/bash]

GWT (Google Web Toolkit) 2.5.0 Hello World

1. ダウンロードサイトからgwtを入手する
https://code.google.com/p/google-web-toolkit/downloads/detail?name=gwt-2.5.0.zip
2. 解凍
[bash]
$ unzip gwt-2.5.1.zip
[/bash]
3. webAppCreatorを使ってプロジェクトを生成
[bash]
$ ./webAppCreator -out ../HelloWorldGWT com.example.HelloWorldGWT
[/bash]
以下のパラメータが必須

  • -out: 出力先ディレクトリ
  • プロジェクト名 “fully-qualified” java的なパッケージ名を指定する必要があります。

4. 開発モードで動作確認
GWTはJavaでコードを記述してJavascriptにコンパイルする開発ツールですが、毎回コンパイルしながら開発しなくても良いように開発用ツールが用意されています。まずは開発ツールを利用して動作を確認します。
[bash]
$ cd ../HelloWorldGWT/
$ ant devmode
[/bash]
開発ツール”GWT Development Mode”が開くので Development Mode タブで [Launch Default Browser]をクリックするか、[Copy Clip Board]をクリックしてURLをコピーしてブラウザのアドレスバーにペーストしてテストサーバーにアクセスできます。

この内容は本家サイトで確認できます。
http://www.gwtproject.org/gettingstarted.html

5. コンパイル
次にJavascriptにコンパイルして動作させてみます。
[bash]
$ ant war
[/bash]
生成された、HelloWorldGWT.warをTomcatやJettyにデプロイします。

PHPのインスタンス メソッド・フィールドを動的に呼び出す

rubyのsendのようにPHPでインスタンスのメソッドやフィールドを呼び出す方法についてまとめてみました。

フィールド(メンバー)

インスタンス->{フィールド名}

で呼び出します。

[PHP]
class Hoge
{
public $foo = “foo”;
}
$hoge = new Hoge();
$field_name = “foo”;
echo $hoge->{$field_name};
[/PHP]

少しトピックと異なりますが、PHPクラスのプロパティについて参考になります:
Dynamic Properties in PHP and StdClass

メソッド

メソッドの場合は以下の関数が用意されています。

それぞれの第一引数はコールバックですが、以下のような配列を渡すことができます。

array( インスタンス, メソッド名 )

[PHP]