退職しました
ご報告が遅れましたが、3月末で前職を退職し、株式会社クロコスに入社いたしました。
2008年から丸3年間お世話になったR社の皆様、たくさん可愛がっていただきありがとうございました!
みなさまとの出会いは本当に本当に大切な宝物です。
特に入社後からずっと見守っていてくださった先輩、そしてチームのリーダーには感謝の気持ちでいっぱいです。
現在働いている株式会社クロコスは今年の2月に設立した会社で、
主にfacebook上で動くアプリケーションを専門として開発を行っています。
少し前までは、まさか自分たちで会社を立ち上げるなんて思ってもみなかったのですが、
色々な人とのつながりとか、タイミングとか、運とかが重なってこのような形になりました。
今辞めるのは惜しいような会社を辞めてJoinした子もいますし、
みんなそれなりに覚悟を決めて来ています。
(ちなみにメンバーは数人被ってますがnequalとは関係ないです)
前職ではあまりアプリ開発をしていなかったので、今は毎日が新鮮です^^
まだまだ始まったばかりで、大変なこともあるけれど、今のメンバーとならきっと乗り越えて行けると確信しています。
最後になりましたが、岡元さん、おざーんさん、そして楽しい仲間と一緒に、
これから色々と面白いものをリリースして行きますのでよろしくお願いします!
..え、転職祝い?そんなーいいですよぉ///
でも一応ウィッシュリスト載せとこうかな...
http://www.amazon.co.jp/wishlist/FC1A4685IA96
そういえばRedBullがあと1箱になったような…
エンジニア女子なら一度はやってみたいRedBullネイルをしてきたよ
SymfonyEventDispatcher→Symfony2(PR4)EventDispatcherの変更点
この記事は、Symfony アドベントカレンダー 2010 に参加しています。
Symfony Advent 2010 : ATND
http://www.symfony.gr.jp/adventcalendar/2010
前の記事
先日、Observerパターンから学ぶSymfonyEventDispatcherの実装というエントリでsymfony1.4でのEventDispatcherの実装についてご紹介しました。
今回は、12/01に公開されたSymfony2 PR4のEventDispatcherでの変更点と追加機能についてご紹介します。
クラス図比較
Symfony2でのEventDispatcherは、1系とおおまかな作りは変わっていませんが、メソッド名の変更や細かい機能追加がいくつかあります。
二つをクラス図に落としてみたので比較してみましょう。
変更点
それではまず変更点について説明していきます。
Symfony2では、クラス内の主要なパラメータの取得や設定を行うためのアクセサの名前を、get(), set(), all()などのメソッド名に統一するポリシーとなりました。
http://docs.symfony-reloaded.org/master/contributing/code/conventions.html
このため、Eventクラス内の以下のメソッド名もこのポリシーに従い変更されています。
- getParameters() → all()
- offsetExists(name) → has(name)
- offsetGet(name) → get(name)
- offsetSet(name, value) → set(name, value)
また、1系ではdisconnect時にイベント名+listenerを指定するようになっていましたが、今回からはlistener指定はなくなりイベントを丸ごと削除するようになっています。
以下の機能は廃止されています。
- ArrayAccessのimplements
- offsetUnset(name)メソッドの実装(ArrayAccessのimplementsをなくしたため)
追加機能
次に追加機能についてです。
新しいEventDispatcherでは、priorityの概念が導入されました。
listenerの登録時に、priority(優先度)を指定することが出来ます。
優先度はデフォルト値が0となっていて、-10〜10の間で指定することが出来ます(この範囲外の値も使えますが目安としては-10〜10みたいです)。登録されたlistenerは、このpriorityの順でソートされ、値の低い方から実行されます。
getListeners()メソッドでは、優先度順に並び替えられたlistenerを得ることが出来ます。
サンプルプログラム
前回のエントリで紹介したサンプルプログラムと同じ物を、今回も実装してみます。
<?php require_once "EventDispatcher/Event.php"; require_once "EventDispatcher/EventDispatcher.php"; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; class greetingListener { public function __construct() {} public function update(Event $event) { $hour = $event->get("hour"); if ($hour >= 5 && $hour < 11) { echo "おはよう",PHP_EOL; } elseif ($hour >= 11 && $hour < 19) { echo "こんにちは",PHP_EOL; } else { echo "こんばんは",PHP_EOL; } } } class FacemarkListener { public $facemarks = array("\(^o^)/", "(・∀・)", "(´・ω・`)"); public function __construct() {} public function update(Event $event) { $key = array_rand($this->facemarks, 1); echo $this->facemarks[$key]; } } $dispatcher = new EventDispatcher(); $grListener = new GreetingListener(); $fmListener = new FacemarkListener(); $dispatcher->connect("test.greeting", array($grListener, "update"), 5); // test.greetingというイベントに対してGreetingListenerのupdate処理をpriority=5で登録 ・・・1 $dispatcher->connect("test.greeting", array($fmListener, "update"), -10); // test.greetingというイベントに対してFacemarkListenerのupdate処理をpriority=-10で登録 ・・・1 // 状態変化をイベントとしてdispatcherに通知 ・・・2、3 $dispatcher->notify(new Event(null, "test.greeting", array("hour"=>7))); $dispatcher->notify(new Event(null, "test.greeting", array("hour"=>12))); $dispatcher->disconnect("test.greeting"); // test.greetingというイベントの登録を解除 ・・・4 $dispatcher->notify(new Event(null, "test.greeting", array("hour"=>23))); // イベントの登録が解除されたので何も起こらない ・・・5
実行結果
\(^o^)/おはよう (´・ω・`)こんにちは
前回と同様、dispatcherにはあらかじめイベント名とListenerの処理を2つ登録しておきます(1)。このとき、priorityを指定します。時刻が変化するとそれをイベントとしてdispatcherに通知します。(2、3)
dispatcherでは、通知を受けると、受け取ったイベント名に対して登録されているLitenerの処理を呼び出します。
今回はFacemarkListenerを優先するようpriorityをつけたので、登録順は逆ですが顔文字の方が先に出力されています。
test.greetingイベントの登録を解除(4)すると、次の通知から出力はされません(5)。
その他
リクエスト情報のプロファイリングを行うSymfony Profilerからイベントの一覧を見ることが出来るようになりました。
これは便利!
まだ簡単なサンプルでしか確認できていませんが、実装も以前よりシンプルになり、より使いやすくなった印象を受けました。
少し長くなりましたが、本日のエントリは以上です。Symfony2の本リリースが待ち遠しいですね。
Symfonyアドベントカレンダー、明日の担当はid:Fivestarです!
symfonyでデータベースの接続情報を扱う
symfonyでデータベースを利用する際、config/databases.ymlに以下のように接続設定を記述します。
all: # 環境 doctrine: # 設定名 class: sfDoctrineDatabase # 接続クラス param: # パラメータ dsn: mysql:host=localhost;dbname=hoge username: root password:
今回は、この設定がsymfony内部でどのようなオブジェクトに保持されているのかと、その利用方法について簡単にまとめてみます。(symfony1.4のソースコードを基にしています)
はじめに
このエントリで取り上げる主なクラスは以下の二つです
- database/sfDatabase
- データベースの接続設定の保持と、接続/切断の機能を提供する基底クラス
- database/sfDatabaseManager
- sfDatabaseのオブジェクトを設定名と対応させて保持するクラス
sfDatabase
sfDatabaseは、プロジェクトで扱う様々なデータベースとの接続機能を提供するための抽象基底クラスです。
databases.ymlで設定されたパラメータはこの中に保持されます。
sfDatabaseの持つ機能:
- initialize()
- オブジェクトの初期化をする
- connect()
- 抽象メソッド。データベースとの接続を行う
- shutdown()
- 抽象メソッド。データベースとの接続を切断する。
- getConnection()
- データベースの接続情報を返す
- getResource()
- getConnection()と同じ。接続リソースを返す。
- getParameterHolder()
- オブジェクトが保持しているパラメータを返す
- getParameter($name, $default = null)
- 指定されたパラメータの値を返す
- hasParameter($name)
- 指定されたパラメータの有無を返す
- setParameter($name, $value)
- パラメータをセットする
connect()とshutdown()はデータベースによってロジックの異なる部分なので、実装はこのクラスを継承して作られるハンドラクラスに委ねられています。
ハンドラクラス
symfony内部にはあらかじめ、よく利用されるデータベースとの接続を行うためのハンドラクラスが用意されています。いずれもsfDatabaseのサブクラスです。
- sfMySQLDatabase
- sfMySQLiDatabase
- sfPDODatabase
- sfPostgreSQLDatabase
- sfDoctrineDatabase(plugins/sfDoctrinePlugin以下)
- sfPropelDatabase(plugins/sfProlepPlugin以下)
databases.ymlのclass:パスにはこのクラスの名前を指定します。
この他のデータベースとの接続を行う場合は、同様にsfDatabaseを継承したサブクラスを作成し、接続周りの実装を行います。(プラグインなどで提供されているものが既にたくさんあるので、自分で実装することはあまりないかもしれませんが)
sfDatabaseManager
sfDatabaseManagerは、databases.ymlで指定された設定名と、対応するsfDatabaseのオブジェクトを保持するクラスです。
sfDatabaseManagerの持つ機能:
サンプルプログラム
sfDatabaseManagerにはdatabases.ymlで設定した全ての接続情報が入っているので、コントローラ等から取得することが出来ます。
databases.yml
all: doctrine: class: sfDoctrineDatabase param: dsn: mysql:host=localhost;dbname=hoge username: root password: pass test: class: TestDatabase param: dsn: mysql:host=localhost;dbname=test username: hoge password: piyo
コントローラ
<?php class testActions extends sfActions { public function executeIndex(sfWebRequest $request) { // アプリケーションの設定情報 $config = ProjectConfiguration::getApplicationConfiguration('frontend', 'test', true); $dbManager = new sfDatabaseManager($config); // databases.ymlの設定名を取得 $names = $dbManager->getNames(); echo "<pre>"; foreach ($names as $name) { $db = $dbManager->getDatabase($name); echo "class: ".get_class($db),PHP_EOL; echo "dsn: ".$db->getParameter("dsn"),PHP_EOL; echo "username: ".$db->getParameter("username"),PHP_EOL; echo "password: ".$db->getParameter("password"),PHP_EOL,PHP_EOL; } echo "</pre>"; } }
実行結果
class: sfDoctrineDatabase dsn: mysql:host=localhost;dbname=hoge username: root password: pass class: TestDatabase dsn: mysql:host=localhost;dbname=test username: hoge password: piyo
sfDatabaseにはパラメータを上書きしたりする機能もあるので、プログラム中でユーザ名を変更して接続し直す等の使い方もできそうですね。
ちなみにsfDatabaseのgetResource()はgetConnection()と全く同じものを返すと思うのですが、これがなんのためにあるのか謎です・・・
誰か教えて!(>_<)
Observerパターンから学ぶSymfonyEventDispatcherの実装
SymfonyEventDispatcherは、デザインパターンの一種であるObserverパターンで実装されたライブラリです。
symfonyではこのライブラリを介してフレームワーク内の様々な処理を行っています。
Observerパターン
SymfonyEventDispatcherを理解する上で前提となるのが、このObserverパターンについての知識です。まずこちらの説明から。
Observerパターンとは?
オブジェクトの状態を他のオブジェクトから観察し、状態が変化した場合に観察者側にそれが通知される仕組みです。
このパターンは、主に以下のようなクラスから構成されます。
観察者(オブザーバ/Observer)
- リスナー/Listener、ハンドラとも呼ばれる
- Subjectの状態変化を観察し、変化が通知されると登録されている処理を行う。
観察対象(サブジェクト/Subject)
- 自分を観察しているObserverのリストを保持している。
- 自分の状態が変化すると、それをObserverに通知する
ここで注意しておきたいのが、観察者/観察対象とありますが実際に「観察者が観察対象を監視している」訳ではありません。状態変化があった際は「観察対象が観察者に通知」します。観察者は報告を受けて初めて状態変化に気づきます。
クラス図
- Observerパターンをクラス図にすると以下のようになります。
Observer, Subjectにはそれぞれインターフェイスが定義されていて、具体的な実装はConcreteObserver, ConcreteSubjectにされています。(Concreteは"具体的な"って意味ですね)
こうすることにより、ConcreteObserverとConcreteSubjectの間に依存関係を作ることなく、処理を実装することができます。
サンプルコード
簡単なObserverパターンのサンプルを作ってみます。
セットされた時間帯にあった挨拶とランダムな顔文字を出力するプログラムです。(全然このパターンで書く必要ないのですがまぁ簡単な例ということで。。)
<?php /** * Subjectインターフェイス */ interface Subject { public function attach(Observer $observer); public function detach(Observer $observer); public function notify(); } /** * Observerインターフェイス */ interface Observer { public function update(Subject $subject); } /** * ConcreteSubjectクラス */ class ConcreteSubject implements Subject { private $observers = array(); // 登録されたObserverを保持 private $hour = 0; // 時間帯 public function __construct() {} // Observerを登録 public function attach(Observer $observer) { $this->observers[get_class($observer)] = $observer; } // Observerの登録を解除 public function detach(Observer $observer) { unset($this->observers[get_class($observer)]); } // 通知を受け、登録されたObserverの処理を実行 public function notify() { foreach ($this->observers as $observer) { $observer->update($this); } } public function setHour($hour) { $this->hour = $hour; } public function getHour() { return $this->hour; } } /** * ConcreteObserverクラス1 */ class GreetingObserver implements Observer { public function __construct() {} public function update(Subject $subject) { $hour = $subject->getHour(); if ($hour >= 5 && $hour < 11) { echo "おはよう"; } elseif ($hour >= 11 && $hour < 19) { echo "こんにちは"; } else { echo "こんばんは"; } } } /** * ConcreteObserverクラス2 */ class FacemarkObserver implements Observer { public $facemarks = array("\(^o^)/", "(・∀・)", "(´・ω・`)"); public function __construct() {} public function update(Subject $subject) { $key = array_rand($this->facemarks, 1); echo $this->facemarks[$key],PHP_EOL; } } // クライアント側 $subject = new ConcreteSubject(); $grObserver = new GreetingObserver(); $fmObserver = new FacemarkObserver(); // Observerを登録 $subject->attach($grObserver); // GreetingObserverを登録 ・・・1 $subject->attach($fmObserver); // FacemarkObserverを登録 ・・・1 $subject->setHour(7); // 状態変化 ・・・2 $subject->notify(); // 通知 ・・・3 $subject->setHour(12); $subject->notify(); $subject->detach($fmObserver); // FacemarkObserverの登録を解除 ・・・4 $subject->setHour(23); $subject->notify();
実行結果
おはよう\(^o^)/ こんにちは(・∀・) こんばんは
時刻をプロパティに持つとあるクラス(Subject)が1つと、このSubjectの状態が変化した際に通知を受けるクラス(Observer)が2種類用意されています。
SubjectにはあらかじめこのObserverを2つ登録しておき(1)、時刻が変化(2)するとそれを通知(3)します。
Subjectでは通知を受けると、登録されたObserverの処理を行います。1つ目に登録されたGreetingObserverでは時間に合わせたテキストを出力し、2つ目のFacemarkObserverではランダムに顔文字を出力します。
FacemarkObserverの登録を解除(4)すると、次の通知からは顔文字の出力はされません。
このように、Observerを登録したり解除したりすることで、Subjectの中身を書き換えることなく、状態変化があった際の処理を変えることが出来ます。
SymfonyEventDispatcher
次に、このObserverパターンで実装されているSymfonyEventDispatcherについてです。
柔軟性を持たせるために、シンプルなObserverパターンとは少し違う形で作られています。
SymfonyEventDispatcherとは?
SymfonyEventDispatcherでは、複数のSubjectとObserverをsfEventDispatcherというクラスで管理するようになっています。また、状態の変化はイベント(sfEvent)を用いて通知されます。
先ほどのような通常のObserverパターンでは、SubjectのインスタンスがなければObserverを登録することが出来ませんが、symfonyではObserverはSubjectに対してではなくイベント名に対して登録されるため、SubjectがなくてもObserverを登録することが出来ます。
SymfonyEventDispatcherは以下のようなクラスから構成されます。
sfEvent
イベントに関する情報(観察対象(Subject)のインスタンスや、イベント名、イベントの状態など)を保持するクラスです。
sfEventDispatcher
イベント名とObserverの結びつけの保持や、Observerへの通知を行うクラスです。
サンプルコード
SymfonyEventDispatcherを使って、先ほどと同じプログラムを書いてみます。
(Listenerの部分は、Observerと読み替えてください)
<?php class greetingListener { public function __construct() {} public function update(sfEvent $event) { $hour = $event["hour"]; if ($hour >= 5 && $hour < 11) { echo "おはよう"; } elseif ($hour >= 11 && $hour < 19) { echo "こんにちは"; } else { echo "こんばんは"; } } } class FacemarkListener { public $facemarks = array("\(^o^)/", "(・∀・)", "(´・ω・`)"); public function __construct() {} public function update(sfEvent $event) { $key = array_rand($this->facemarks, 1); echo $this->facemarks[$key],PHP_EOL; } } $dispatcher = new sfEventDispatcher(); $grListener = new GreetingListener(); $fmListener = new FacemarkListener(); $dispatcher->connect("test.greeting", array($grListener, "update")); // test.greetingというイベントに対してGreetingListenerのupdate処理を登録 ・・・1 $dispatcher->connect("test.greeting", array($fmListener, "update")); // test.greetingというイベントに対してFacemarkListenerのupdate処理を登録 ・・・1 // 状態変化をイベントとしてdispatcherに通知 ・・・2、3 $dispatcher->notify(new sfEvent(null, "test.greeting", array("hour"=>7))); $dispatcher->notify(new sfEvent(null, "test.greeting", array("hour"=>12))); $dispatcher->disconnect("test.greeting", array($fmListener, "update")); // test.greetingというイベントに対するFacemarkListenerの登録を解除 ・・・4 $dispatcher->notify(new sfEvent(null, "test.greeting", array("hour"=>23)));
実行結果
おはよう(´・ω・`) こんにちは\(^o^)/ こんばんは
dispatcherにはあらかじめイベント名とListenerの処理を2つ登録しておき(1)、時刻が変化するとそれをイベントとしてdispatcherに通知します。(2、3)
dispatcherでは、通知を受けると、受け取ったイベント名に対して登録されているLitenerの処理を呼び出します。
FacemarkListenerの登録を解除(4)すると、次の通知からは顔文字の出力はされません。
間にdispatcherが挟まっていますが、行っている処理としては最初に出したサンプルと同じですよね。
このように、symfonyではdispatcherを用いることでフレームワーク内のどこからでも柔軟にイベントの管理を行うことが出来ます。
今回は通知するイベントの種類としてnotify()しか載せていませんが、他にもnotifyUntil()、filter()といったものもありますので、マニュアル等参考に使い分けてみてください。
24日に24歳になるので
ひとつの区切りとして、この1年の振り返りなどしてみようと思います。
23歳のわたし
出会いの年
この1年間を一言で表すと、「出会いの年」でした。
PHPとかのコミュニティに顔を出すようになったのはちょうど1年半くらい前なのですが、それまではホントに仕事関係の人しかこの業界に知り合いはいませんでした。
それが、先輩に勉強会とか連れて行ってもらうようになって、だんだん話せる人が増えて、楽しく感じるようになったのが1年ちょっと前。
そこから自然と知り合いが増えていきました。
大げさだけど、20歳くらいまでに知り合った人数と同じくらいの人数、この1年で出会ったんじゃないかな、とか。少なくとも濃さは負けてないと思うw
nequal
そして多分1番大きかったのが、nequalのみんなとの出会いでした。
今年のはじめくらいにid:sotarokとかが誘ってくれてnequalに入ったのですが、同年代で同じ業界で頑張ってるみんなといるとすごく刺激になるし、楽しい。信頼できる仲間がいるってすごく幸せなことなんだなということも気づきました。
あとnequal関係ではid:Yudoufuやid:cocoitiさんには特にお世話になってる。ありがとう!
ドラ娘のお仕事
去年のPHPカンファレンスをきっかけにドラ娘関係のお仕事をいただくようになりました。
7月にはid:yoshioriさまと元祖ドラ娘であるid:ngtykさまの結婚カンファレンスで「ドラ娘LT」をさせていただいたり、LLTigerではid:ngtykさまとの競演が実現したりと夢のようなこと続きでした(*>_<*)
あと9月のPHPカンファレンス2010でチャイナとか着てしまった気がしますがみなさんもう忘れていいですよ^^
お引っ越しした!
あと大きな変化としては引っ越しがあるかな...
6月に横浜→都内に引っ越ししました。
前に住んでたとこが駅から徒歩20分の丘の上にあって通勤とかが結構大変だったのと、割と頻繁に変質者的な人が出たりして怖かったので友達も多い総武線沿いにお引っ越ししました。
駅から近くなったし安心できる環境になったので、すごく快適に過ごせてます!
Redbull
中毒です\(^o^)/
24歳のわたし
24歳の1年間は、とにかくエンジニアとしてのスキルを伸ばす年にしたいと思います。
今年はドラ鳴らしてばっかりでしたが、鳴らされる側になりますw
ちなみにお祝いも受付中です!^ω^♡
http://www.amazon.co.jp/wishlist/FC1A4685IA96
という訳で、みなさまこれからもよろしくお願いします!
23++;
sotarokを勝手に祝う会を全力で開催した
なんというか、燃え尽きて(?)眠れないので忘れないうちに書いておこう。
無事「sotarokを勝手に祝う会」を開催することができました。
今考えると、思いついてから2週間でよくここまでできたなと。
開催日時が某Waveの追悼式と被ったり、調子に乗りすぎてイベントの公式アカウント(@sotarok_wedding)がbanされたりと色々アクシデントはありましたが、いい思い出です。
パーティには全部で48名の方にご出席いただきました。(わーいっぱい!)
人数もさることながら、メンツの豪華さも半端なかったです。さすがid:sotarok。
最高でした。
今回のパーティに祝電を贈ってくださった方々をご紹介いたします。
お祝いの花束を贈ってくださった方々をご紹介いたします。
- グリー株式会社さま
- 株式会社プリファードインフラストラクチャーさま
- アシアル株式会社さま
- Webcore株式会社 柴田さま
- nequal
祝辞LTをご披露いただいた方々をご紹介いたします。
- @yuunyan_m さま:sotarokとの出会いについて
- @tsuyoshikawa さま:silly love songs
- @masaki_fujimoto さま:「♥」オペレータの実装
- @moriyoshi さま:オリジナルApacheモジュールの実装
パーティの予算もギリギリ(というかちょいマイナス)で運営していたので、先輩方の援助大変助かりました。
この場を借りてお礼申し上げます。
nequalのみんな、おつかれ!楽しかったね。
そしてなにより、@sotarok、@mikko、結婚おめでとう。
幸せになってね。