phossa2/event

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# phossa2/event [ABANDONED]

**PLEASE USE [phoole/event](https://github.com/phoole/event) library instead**

[![Build Status](https://travis-ci.org/phossa2/event.svg?branch=master)](https://travis-ci.org/phossa2/event)
[![Code Quality](https://scrutinizer-ci.com/g/phossa2/event/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/phossa2/event/)
[![Code Climate](https://codeclimate.com/github/phossa2/event/badges/gpa.svg)](https://codeclimate.com/github/phossa2/event)
[![PHP 7 ready](http://php7ready.timesplinter.ch/phossa2/event/master/badge.svg)](https://travis-ci.org/phossa2/event)
[![HHVM](https://img.shields.io/hhvm/phossa2/event.svg?style=flat)](http://hhvm.h4cc.de/package/phossa2/event)
[![Latest Stable Version](https://img.shields.io/packagist/vpre/phossa2/event.svg?style=flat)](https://packagist.org/packages/phossa2/event)
[![License](https://img.shields.io/:license-mit-blue.svg)](http://mit-license.org/)

**phossa2/event** is a PSR-14 event manager library for PHP.

It requires PHP 5.4, supports PHP 7.0+ and HHVM. It is compliant with
[PSR-1][PSR-1], [PSR-2][PSR-2], [PSR-4][PSR-4] and the upcoming [PSR-14][PSR-14]

[PSR-1]: http://www.php-fig.org/psr/psr-1/ "PSR-1: Basic Coding Standard"
[PSR-2]: http://www.php-fig.org/psr/psr-2/ "PSR-2: Coding Style Guide"
[PSR-4]: http://www.php-fig.org/psr/psr-4/ "PSR-4: Autoloader"
[PSR-14]: https://github.com/php-fig/fig-standards/blob/master/proposed/event-manager.md "Event Manager"

Installation
---
Install via the `composer` utility.

```
composer require "phossa2/event=2.1.*"
```

or add the following lines to your `composer.json`

```json
{
    "require": {
       "phossa2/event": "^2.1.0"
    }
}
```

Features
---

- Event name [globbing](#glob).

- Built-in *multiple* [shared event managers](#shared) support.

- [Attach and detach](#attach) listeners.

- [Static event manager](#static) support.

- Built-in [class level](#class) events support.

- Able to [limit](#limit) number of times of an event callable executed.

Usage
---

- <a name="start"></a>Quick start

  ```php
  use Phossa2\Event\EventDispatcher;

  // event dispatcher
  $events = new EventDispatcher();

  // bind event with a callback
  $events->attach('login.success', function($evt) {
      echo "logged in as ". $evt->getParam('username');
  });

  // bind event with a callable
  $events->attach('login.attempt', [$logger, 'logEvent']);

  // unbind an event
  $events->clearListeners('login.attempt');

  // fire the trigger
  $events->trigger('login.success');
  ```

- <a name="glob"></a>Event name globbing

  Event name globbing means callables of the binding 'login.*' will also be
  triggered when triggering event 'login.success'.

  ```php
  // bind 'login.*' with callables
  $events->attach('login.*', function($evt) {
      echo $evt->getName();
  });

  // trigger 'login.atttempt' will also trigger callables of 'login.*'
  $events->trigger('login.attempt');
  ```

  The globbing rules are similiar to the PHP function `glob()`, where

  - `*` in the string means any chars except the dot.

  - If `*` at the end, will match any chars including the dot. e.g. `login.*`
    will match 'login.attempt.before'.

  - `.` means the dot.

  - one-char-string `*` means match any string (including the dot).

  **Note:** Name globbing **ONLY** happens when event is being triggered.
  Binding or unbinding events only affect the *EXACT* event name.

  ```php
  // unbind the exact 'login.*'
  $events->clearListeners('login.*');
  ```

- <a name="shared"></a>Shared event manager support

  Class `EventDispatcher` implements the `Phossa2\Shared\Shareable\ShareableInterface`.

  `ShareableInterface` is an extended version of singleton pattern. Instead of
  supporting only one shared instance, Classes implements `ShareableInterface`
  may have shared instance for different `scope`.

  ```php
  // global event manager, global scope is ''
  $globalEvents = EventDispatcher::getShareable();

  // shared event manager in scope 'MVC'
  $mvcEvents = EventDispatcher::getShareable('MVC');

  // an event manager instance, which has scope 'MVC'
  $events = new EventDispatcher('MVC');

  // in scope MVC ?
  var_dump($events->hasScope('MVC')); // true

  // in global scope ?
  var_dump($events->hasScope()); // true
  ```

  Callables bound to a shared manager will also be triggered if an event manager
  instance has the same scope.

  ```php
  // shared event manager in scope 'MVC'
  $mvcEvents = EventDispatcher::getShareable('MVC');

  // bind with pirority 100 (highest priority)
  $mvcEvents->attach('*', function($evt) {
      echo "mvc";
  }, 100);

  // create a new instance within the MVC scope
  $events = new EventDispatcher('MVC');

  // bind with default priority 0
  $events->attach('test', function($evt) {
      echo "test";
  });

  // will also trigger matched events in $mvcEvents
  $events->trigger("test");
  ```

  Event manager instance can have multiple scopes, either specified during the
  instantiation or using `addScope()`.

  ```php
  // create an event manager with 2 scopes
  $events = new EventDispatcher(['MVC', 'AnotherScope']);

  // add another scope
  $events->addScope('thirdScope');
  ```

  Couple of helper methods are provided for on/off/trigger events with shared
  managers.

  ```php
  // bind a callable to global event manager
  EventDispatcher::onGlobalEvent('login.success', function() {});

  // use interface name as a scope
  EventDispatcher::onEvent(
      'Psr\\Log\\LoggerInterface', // scope
      'log.error', // event name
      function () {}
  );

  // unbind all callables of event 'log.error' in a scope
  EventDispatcher::offEvent(
      'Psr\\Log\\LoggerInterface',
      'log.error'
  );

  // unbind *ALL* events in global scope
  EventDispatcher::offGlobalEvent();
  ```

- <a name="attach"></a>Attaching a listener

  `Listener` implements the `ListenerInterface`. Or in short, provides a method
  `eventsListening()`.

  ```php
  use Phossa2\Event\Interfaces\ListenerInterface;

  class myListener implements ListenerInterface
  {
      public function eventsListening()
      {
          return [
              // one method of $this
              eventName1 => 'method1',

              // 2 methods
              eventName2 => ['callable1', 'method2'],

              // priority 20 and in a 'mvcScope' scope
              eventName2 => ['method2', 20, 'mvcScope'], // with priority 20

              eventName3 => [
                  ['method3', 50],
                  ['method4', 70, 'anotherScope']
              ]
          ];
      }
  }
  ```

  `EventDispatcher::attachListener()` can be used to bind events defined in
  `eventsListening()` instead of using `EventDispatcher::attach()` to bind each
  event manually.

  ```php
  $events = new EventDispatcher();

  $listener = new \myListener();

  // bind all events defined in $listener->eventsListening()
  $events->attachListener($listener);

  // will call $listener->method1()
  $events->trigger('eventName1');
  ```

- <a name="static"></a>Using event manager statically

  `StaticEventDispatcher` is a static wrapper for an `EventDispatcher` slave.

  ```php
  StaticEventDispatcher::attach('*', function($evt) {
      echo 'event ' . $evt->getName();
  });

  // will print 'event test'
  StaticEventDispatcher::trigger('test');
  ```

  `StaticEventDispatcher` is not the same as global event manager.
  `StaticEventDispatcher` has a default slave which is a shared event manager
  in scope `'__STATIC__'`. While global event manager is the shared event
  manager in global scope `''`.

  User may set another event manager to replace the default slave.

  ```php
  StaticEventDispatcher::setEventManager(new EventDispatcher());
  ```

- `EventCapableAbstract`

  `EventCapableAbstract` implements both `ListenerInterface` and
  `EventCapableInterface`. It will do the following when `triggerEvent()`
  is called,

  - Get the event manager. If it is not set yet, create one default event
    manager with current classname as scope.

  - Attach events defined in `eventsListening()` if not yet.

  - Trigger the event and processed by the event manager and all of the
    shared managers of its scopes.

  ```php
  class LoginController extends EventCapableAbstract
  {
      public function login() {

          // failed
          if (!$this->trigger('login.pre')) {
              return;
          }

          // ...
      }

      public function beforeLogin() {
          // ...
      }

      public function eventsListening()
      {
          return [
              'login.pre' => 'beforeLogin'
          ];
      }
  }
  ```

- `EventableExtensionAbstract` and `EventableExtensionCapableAbstract`

  `EventableExtensionCapableAbstract` is the base class supporting events and
  extensions.

  Detail usage can be found in [phossa2/cache](https://github.com/phossa2/cache)
  `Phossa2\Cache\CachePool` extends `EventableExtensionCapableAbstract` and
  `Phossa2\Cache\Extension\ByPass` extends `EventableExtensionAbstract`.

  Or look at [phossa2/route](https://github.com/phossa2/route).

- <a name="class"></a>Class or interface level events support

  Class or interface name can be used as the `scope`. When events bound to these
  kind of scopes, any events triggered by child class will also search callables
  defined in parent class/interface level shared event managers.

  ```php
  // define event '*' for interface 'MyInterface'
  EventDispatcher::onEvent(
      'MyInterface', '*', function() { echo "MyInterface"; }, 60
  );
  ```

  Extends `EventCapableAbstract`.

  ```php
  class MyClass extends EventCapableAbstract implements MyInterface
  {
      public function myMethod()
      {
          echo "myMethod";
      }

      public function eventsListening()/*# : array */
      {
          return [
              // priority 20
              'afterTest' => ['myMethod', 20]
          ];
      }
  }

  $obj = new MyClass();

  // will trigger callable 'myMethod' and handlers for 'MyInterface'
  $obj->trigger('afterTest');
  ```

- <a name="limit"></a>Execute callable for limited times

  ```php
  // bind a callable for executing only once
  $events->one('user.login', function(Event $evt) {
      // ...
  });

  // 3 times
  $events->many(3, 'user.tag', function(Event $evt) {
      // ...
  });
  ```

Change log
---

Please see [CHANGELOG](CHANGELOG.md) from more information.

Testing
---

```bash
$ composer test
```

Contributing
---

Please see [CONTRIBUTE](CONTRIBUTE.md) for more information.

Dependencies
---

- PHP >= 5.4.0

- phossa2/shared >= 2.0.21

License
---

[MIT License](http://mit-license.org/)