Hatena::ブログ(Diary)

* yuchimiriのにっき *

2011-05-22

退職しました

ご報告が遅れましたが、3月末で前職を退職し、株式会社クロコス入社いたしました。


2008年から丸3年間お世話になったR社の皆様、たくさん可愛がっていただきありがとうございました!

みなさまとの出会いは本当に本当に大切な宝物です。


特に入社後からずっと見守っていてくださった先輩、そしてチームのリーダーには感謝の気持ちでいっぱいです。



現在働いている株式会社クロコスは今年の2月に設立した会社で、

主にfacebook上で動くアプリケーションを専門として開発を行っています。


少し前までは、まさか自分たちで会社を立ち上げるなんて思ってもみなかったのですが、

色々な人とのつながりとか、タイミングとか、運とかが重なってこのような形になりました。


今辞めるのは惜しいような会社を辞めてJoinした子もいますし、

みんなそれなりに覚悟を決めて来ています。

(ちなみにメンバーは数人被ってますがnequalとは関係ないです)


前職ではあまりアプリ開発をしていなかったので、今は毎日が新鮮です^^



まだまだ始まったばかりで、大変なこともあるけれど、今のメンバーとならきっと乗り越えて行けると確信しています。


最後になりましたが、岡元さん、おざーんさん、そして楽しい仲間と一緒に、

これから色々と面白いものをリリースして行きますのでよろしくお願いします!




..え、転職祝い?そんなーいいですよぉ///

でも一応ウィッシュリスト載せとこうかな...

http://www.amazon.co.jp/wishlist/FC1A4685IA96


そういえばRedBullがあと1箱になったような…

2011-05-17

エンジニア女子なら一度はやってみたいRedBullネイルをしてきたよ

先日twitterで、次のネイルのデザインを募集した所、



というリプライをもらったので

@(@の妻)と一緒にRedBullネイルやってきたよ!


会社のすぐ近くのネイルサロンだったので、手ぶら+RedBull持参という不審な姿で行ったんだけどネイリストさんはいつも通り暖かく迎えてくださいました^ω^


ほぼネタのつもりでやってみたけど、意外とブルー×シルバーがマッチして可愛い感じになった!


キリッ

f:id:yuchimiri:20110518001452g:image:w400


この牛クオリティ...

f:id:yuchimiri:20110518001453g:image:w400


Bull×2

f:id:yuchimiri:20110518001454g:image:w440


女子2人のわがままに付き合ってくれたネイリストさんありがとうございました><


楽しかった!!


(次回のリクエストは@ まで!)

2010-12-07

SymfonyEventDispatcher→Symfony2(PR4)EventDispatcherの変更点

この記事は、Symfony アドベントカレンダー 2010 に参加しています。

Symfony Advent 2010 : ATND

Symfonyアドベントカレンダー 2010 | 日本Symfonyユーザー会

前の記事


先日、Observerパターンから学ぶSymfonyEventDispatcherの実装というエントリでsymfony1.4でのEventDispatcherの実装についてご紹介しました。

今回は、12/01に公開されたSymfony2 PR4のEventDispatcherでの変更点と追加機能についてご紹介します。

クラス図比較

Symfony2でのEventDispatcherは、1系とおおまかな作りは変わっていませんが、メソッド名の変更や細かい機能追加がいくつかあります。

二つをクラス図に落としてみたので比較してみましょう。

f:id:yuchimiri:20101205173331p:image

f:id:yuchimiri:20101205173330p:image



変更点

それではまず変更点について説明していきます。

Symfony2では、クラス内の主要なパラメータの取得や設定を行うためのアクセサの名前を、get(), set(), all()などのメソッド名に統一するポリシーとなりました。

Learn Symfony - Symfony

このため、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からイベントの一覧を見ることが出来るようになりました。

f:id:yuchimiri:20101207004204p:image

これは便利!


まだ簡単なサンプルでしか確認できていませんが、実装も以前よりシンプルになり、より使いやすくなった印象を受けました。

少し長くなりましたが、本日のエントリは以上です。Symfony2の本リリースが待ち遠しいですね。

Symfonyアドベントカレンダー、明日の担当はid:Fivestarです!


Symfony Advent 2010であなたの記事を公開してみませんか?

Symfony Advent 2010では12月1日から12月24日までを使って日替わりでsymfonyでイイなと思った小さなtipsから内部構造まで迫った解説などをブログ記事にして公開していくイベントです。

参加についてはATNDで参加表明の上、Google

GroupのSymfony Advent 2010に追加リクエストを送信ください。

Symfony Advent 2010チーム一同、あなたの参加をお待ちしております。

日本Symfonyユーザー会

Symfony アドベントカレンダー2010

2010-12-04

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は、プロジェクトで扱う様々なデータベースとの接続機能を提供するための抽象基底クラスです。

databases.ymlで設定されたパラメータはこの中に保持されます。

sfDatabaseの持つ機能:

connect()とshutdown()はデータベースによってロジックの異なる部分なので、実装はこのクラスを継承して作られるハンドラクラスに委ねられています。

ハンドラクラス

symfony内部にはあらかじめ、よく利用されるデータベースとの接続を行うためのハンドラクラスが用意されています。いずれもsfDatabaseのサブクラスです。

  • sfMySQLDatabase
  • sfMySQLiDatabase
  • sfPDODatabase
  • sfPostgreSQLDatabase
  • sfDoctrineDatabase(plugins/sfDoctrinePlugin以下)
  • sfPropelDatabase(plugins/sfProlepPlugin以下)

databases.ymlのclass:パスにはこのクラスの名前を指定します。

この他のデータベースとの接続を行う場合は、同様にsfDatabaseを継承したサブクラスを作成し、接続周りの実装を行います。(プラグインなどで提供されているものが既にたくさんあるので、自分で実装することはあまりないかもしれませんが)

sfDatabaseManager

sfDatabaseManagerは、databases.ymlで指定された設定名と、対応するsfDatabaseのオブジェクトを保持するクラスです。

sfDatabaseManagerの持つ機能:

  • initialize(sfProjectConfiguration $configuration)
  • loadConfiguration()
    • databases.ymlの設定を読み込む
  • setDatabase($name, sfDatabase $database)
  • getDatabase($name = 'default')
  • getNames()
  • shutdown()
    • すべての接続を切断する

サンプルプログラム

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()と全く同じものを返すと思うのですが、これがなんのためにあるのか謎です・・・

誰か教えて!(>_<)

htairahtaira 2010/12/05 00:19 抽象化されたデータベースの実装ではない対象に対して、
実行する時にはデータベース接続リソースを返すとコメントが書いてあった。

sfDatabaseクラスを継承する実装クラスのコードを見ると、
各実装クラスの connect() メソッドの中で最後に
$this->resource = $this->connection;
と代入処理を行っているので、実装クラスを書く人がコードを忘れると、
$this->resource は常に null になる場合もあります。

一般的なコードで利用する場合には、getResource() メソッドを使わず、
getConnection() メソッドを使った方がよいでしょう。

2010-11-28

Observerパターンから学ぶSymfonyEventDispatcherの実装

SymfonyEventDispatcherは、デザインパターンの一種であるObserverパターンで実装されたライブラリです。

symfonyではこのライブラリを介してフレームワーク内の様々な処理を行っています。

Observerパターン

SymfonyEventDispatcherを理解する上で前提となるのが、このObserverパターンについての知識です。まずこちらの説明から。

Observerパターンとは?

オブジェクトの状態を他のオブジェクトから観察し、状態が変化した場合に観察者側にそれが通知される仕組みです。

このパターンは、主に以下のようなクラスから構成されます。

観察者(オブザーバ/Observer)
  • リスナー/Listener、ハンドラとも呼ばれる
  • Subjectの状態変化を観察し、変化が通知されると登録されている処理を行う。
観察対象(サブジェクト/Subject)
  • 自分を観察しているObserverのリストを保持している。
  • 自分の状態が変化すると、それをObserverに通知する

ここで注意しておきたいのが、観察者/観察対象とありますが実際に「観察者が観察対象を監視している」訳ではありません。状態変化があった際は「観察対象が観察者に通知」します。観察者は報告を受けて初めて状態変化に気づきます。

クラス図

  • Observerパターンをクラス図にすると以下のようになります。

f:id:yuchimiri:20101205173709p:image

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()といったものもありますので、マニュアル等参考に使い分けてみてください。