- パターンごとにイベントを生成する機能が必要でした。
- ライブラリのインターフェイスは視覚的に好かれていませんでした。
もちろん、私はライブラリを完成させて「自分用に」コームすることにしました。
パターンによるイベント生成
テンプレートを使用して、名前が階層キー(
foo.bar.baz
)である必要なイベントを生成する機能が必要でした。
たとえば、このようなイベントのリストの場合:
-
some.event
-
another.event
-
yet.another.event
-
something.new
「イベント」で終わるすべてのイベントを生成する必要があります。 または、「まだ」で始まり「イベント」で終わるので、中間にあるかどうかは関係ありません。
イベント可能
少し考えてから、以前に見つかったEvenementに基づいて、ライブラリの実装に取りかかりました。
イベントディスパッチャ
インターフェースについて考えると、jQueryと、イベントを操作するそのメソッド
on()
、
one()
、
off()
、
trigger()
off()
に
trigger()
。 このアプローチは、その簡潔さと簡潔さのおかげで、大部分が好きでした。
結果は次のインターフェースです。
Dispatcher { public Dispatcher on(string $event, callable $listener) public Dispatcher once(string $event, callable $listener) public Dispatcher off([string $event [, callable $listener ]]) public Dispatcher trigger(string $event [, array $args ]) public Dispatcher fire(string $event [, array $args ]) }
したがって、
off()
メソッドは2つのパラメーターを取ることができ、指定されたイベントの特定のハンドラーは削除されます。 1つのパラメーター-この場合、すべてのイベントハンドラーが削除されます。 または、パラメータを受け入れないでください。つまり、サブスクライブしているすべてのイベントとハンドラを削除します。
trigger()
はイベントキーパターンを取り、一致するすべてのイベントを発生させます。
fire()
は、単一の特定のイベントを発生させます。
ハンドラーを1回実行する必要がある場合は、
once()
メソッドを使用してイベントでハングします
Dispatcher.php
namespace Yowsa\Eventable; class Dispatcher { protected $events = []; public function on($event, callable $listener) { if (!KeysResolver::isValidKey($event)) { throw new \InvalidArgumentException('Invalid event name given'); } if (!isset($this->events[$event])) { $this->events[$event] = []; } $this->events[$event][] = $listener; return $this; } public function once($event, callable $listener) { $onceClosure = function () use (&$onceClosure, $event, $listener) { $this->off($event, $onceClosure); call_user_func_array($listener, func_get_args()); }; $this->on($event, $onceClosure); return $this; } public function off($event = null, callable $listener = null) { if (empty($event)) { $this->events = []; } elseif (empty($listener)) { $this->events[$event] = []; } elseif (!empty($this->events[$event])) { $index = array_search($listener, $this->events[$event], true); if (false !== $index) { unset($this->events[$event][$index]); } } return $this; } public function trigger($event, array $args = []) { $matchedEvents = KeysResolver::filterKeys($event, array_keys($this->events)); if (!empty($matchedEvents)) { if (is_array($matchedEvents)) { foreach ($matchedEvents as $eventName) { $this->fire($eventName, $args); } } else { $this->fire($matchedEvents, $args); } } return $this; } public function fire($event, array $args = []) { foreach ($this->events[$event] as $listener) { call_user_func_array($listener, $args); } return $this; } }
解析キー
作業の半分が完了しました-ディスパッチャーが実装され、動作しています。 次のステップでは、テンプレートによるイベントフィルタリングを追加します。
テンプレートはすべて同じキーですが、フィルタリング用のラベルが付いています。
-
*
-区切り記号の前の1つのセグメント。 -
**
-任意の数のセグメント。
キー
application.user.signin.error
について、次の正しいテンプレートを作成できます。
-
application.**.error
-
**.error
-
application.user.*.error
-
application.user.**
このフィルタリングを実装するには、3つの方法が必要でした。
KeysResolver { public static int isValidKey(string $key) public static string getKeyRegexPattern(string $key) public static mixed filterKeys(string $pattern [, array $keys ]) }
軍事的なものは何もありません。キーの検証、パターンの正規表現への変換、キー配列のフィルタリング。
KeysResolver.php
namespace Yowsa\Eventable; class KeysResolver { public static function isValidKey($key) { return preg_match('/^(([\w\d\-]+)\.?)+[^\.]$/', $key); } public static function getKeyRegexPattern($key) { $pattern = ('*' === $key) ? '([^\.]+)' : (('**' === $key) ? '(.*)' : str_replace( array('\*\*', '\*'), array('(.+)', '([^.]*)'), preg_quote($key) ) ); return '/^' . $pattern . '$/i'; } public static function filterKeys($pattern, array $keys = array()) { $matched = preg_grep(self::getKeyRegexPattern($pattern), $keys); if (empty($matched)) { return null; } if (1 === count($matched)) { return array_shift($matched); } return array_values($matched); } }
パッケージ全体は2つの単純なクラスに収まり、テストが容易で、コンポーザパッケージが設計されています。
動作しますか
Eventableがどのように機能し、どの場合に役立つかを示すために、以下に簡単な例を示します。
require_once __DIR__ . '/../vendor/autoload.php'; $dispatcher = new Yowsa\Eventable\Dispatcher(); $teacher = 'Mrs. Teacher'; $children = ['Mildred', 'Nicholas', 'Kevin', 'Bobby', 'Anna', 'Kelly', 'Howard', 'Christopher', 'Maria', 'Alan']; // teacher comes in the classroom // and children welcome her once $dispatcher->once('teacher.comes', function($teacher) use ($children) { foreach ($children as $kid) { printf("%-12s- Hello, %s!\n", $kid, $teacher); } }); // every kid answers to teacher once foreach ($children as $kid) { $dispatcher->once("children.{$kid}.says", function() use ($kid) { echo "Hi {$kid}!\n"; }); } // boddy cannot stop to talk $dispatcher->on('children.Bobby.says', function() { echo "\tBobby: I want pee\n"; }); // trigger events echo "{$teacher} is entering the classroom.\n\n"; $dispatcher->trigger('teacher.comes', [$teacher]); echo "\n\n{$teacher} welcomes everyone personally\n\n"; $dispatcher->trigger('children.*.says'); for ($i = 0; $i < 5; $i++) { $dispatcher->trigger('children.Bobby.says'); }
結果
Mrs. Teacher is entering the classroom. Mildred — Hello, Mrs. Teacher! Nicholas — Hello, Mrs. Teacher! Kevin — Hello, Mrs. Teacher! Bobby — Hello, Mrs. Teacher! Anna — Hello, Mrs. Teacher! Kelly — Hello, Mrs. Teacher! Howard — Hello, Mrs. Teacher! Christopher — Hello, Mrs. Teacher! Maria — Hello, Mrs. Teacher! Alan — Hello, Mrs. Teacher! Mrs. Teacher welcomes everyone personally Hi Mildred! Hi Nicholas! Hi Kevin! Hi Bobby! Bobby: I want pee Hi Anna! Hi Kelly! Hi Howard! Hi Christopher! Hi Maria! Hi Alan! Bobby: I want pee Bobby: I want pee Bobby: I want pee Bobby: I want pee Bobby: I want pee
おそらく便利なリンク
インスピレーション:
それは判明した: