PHPackages                             epa/epa - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. epa/epa

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

epa/epa
=======

Event-based Plugin Architecture

0.5.0(7y ago)02115BSD-2-ClausePHPPHP &gt;=7.2

Since Apr 18Pushed 7y ago1 watchersCompare

[ Source](https://github.com/koenhoeymans/Epa)[ Packagist](https://packagist.org/packages/epa/epa)[ RSS](/packages/epa-epa/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (1)Versions (10)Used By (5)

EPA
===

[](#epa)

What is it?
-----------

[](#what-is-it)

EPA stands for Event-based Plugin Architecture. These are some simple classes and interfaces that together form a whole that can be used to let plugins enhance your code. The plugins can register themselves for certain events and are notified of and passed the event when it occures.

Using it
--------

[](#using-it)

### Events and the observer pattern

[](#events-and-the-observer-pattern)

An event can be anything you like, it just needs to implement `Epa\Event` which is an interface with no defined methods. This can be an event:

```
use Epa\Api\Event;

class FailedLogin implements Event
{
	private $username;
	private $loginSucceeded;

	public function __construct($username, $loginSucceeded)
	{
		$this->username = $username;
		$this->loginSucceeded = $loginSucceeded;
	}

	public function getUserName()
	{
		return $this->username;
	}

	public function loginSucceeded()
	{
		return $this->loginSucceeded;
	}
}

```

A plugin that logs failed logins could make use of this. Another event might allow a plugin to change the content of a post:

```
use Epa\Api\Event;

class BeforePublishPostEvent implements Event
{
	private $postContent;

	public function __construct($postContent)
	{
		$this->postContent = $postContent;
	}

	public function getPostContent()
	{
		return $this->postContent;
	}

	public function setPostContent($postContent)
	{
		$this->postContent = $postContent;
	}
}

```

For each class that you allow a plugin to change or notify of something you use the interface `Epa\Api\Observable` and the trait `Epa\Api\ObserverStore`to implement it.

```
use Epa\Api\Observable;
use Epa\Api\ObserverStore;

class MyClass implements Observable
{
	use ObserverStore;
}

```

Observers implement `\Epa\Api\Observer`. It has one method `notify`.

```
class SampleObserver implements \Epa\Api\Observer
{
	public function notify(\Epa\Api\Event $event)
	{
		echo 'following event observed: ' . get_class($event);
	}
}

$myClass = new MyClass();
$myClass->addObserver($new SampleObserver());

```

When your class has something interesting for observers you can notify them of the event by using the `ObserverStore::notify` method using the event as an argument.

```
use Epa\Api\Observable;
use Epa\Api\ObserverStore;

class BlogPostDisplay implements Observable
{
	use ObserverStore;

	public function display($postContent)
	{
		$event = new EditPostContentEvent($postContent);
		// ...
		$this->notify(new BeforePublishPostEvent($event));
		// ...
	}
}

```

Now all observers will be notified and be able to do something with the post content. This is the classic observer pattern in action.

### Plugins And the EventDispatcher

[](#plugins-and-the-eventdispatcher)

The `EventDispatcher`, which implements `\Epa\Api\Observer`, is used to dispatch events to callbacks that register for them. An instance can be created using a factory:

```
$eventDispatcher = \Epa\Api\EventDispatcherFactory::create();

```

A `Plugin` registers callbacks for certain events. You can create one by implementing the `\Epa\Api\Plugin` interface.

```
use Epa\Api\Plugin;
use Epa\Api\EventDispatcher

class FailedLoginLogger implements Plugin
{
	public function registerHandlers(EventDispatcher $mapper)
	{
		$mapper->registerForEvent('FailedLogin', function(FailedLogin $event) {
			$this->handleFailedLoginEvent($event);
		});
	}

	private function handleFailedLoginEvent(FailedLogin $event)
	{
		// $event->getUserName();
		// write to log etc
	}
{

```

You can see that the plugin calls the `registerForEvent` method on the `EventDispatcher`to register the callbacks for a certain event. Every time the `EventDispatcher` is notified of an event it activates the callbacks that registered for the event.

Since a plugin can register more than one callback it is possible to use `EventDispatcher::addPlugin`. This will in its turn call `Plugin::registerHandlers`so the plugin can register the callbacks.

```
$eventDispatcher->addPlugin(new FailedLoginLogger());

```

The event names the `EventDispatcher` uses are the class names of the event that is 'thrown' by the observable classes.

The `EventDispatcher` can be passed to your classes by constructor injection or by using the observer pattern mentioned above and pass it as an observer.

```
class LoginChecker
{
	private $eventDispatcher;

	public function __construct(\Epa\Api\EventDispatcher $eventDispatcher)
	{
		$this->eventDispatcher = $eventDispatcher;
	}

	public function check($username, $password)
	{
		$loginAttempt = new LoginAttemp($username, $password);
		$this->eventDispatcher->notify($loginAttempt);

		// do more stuff
	}
}

$loginChecker = new LoginChecker($eventDispatcher);

```

Versus

```
class LoginChecker implements \Epa\Api\Observable
{
	use \Epa\Api\ObserverStore;

	public function check($username, $password)
	{
		$loginAttempt = new LoginAttemp($username, $password);
		$this->eventDispatcher->notify($loginAttempt);

		// do more stuff
	}
}

$loginChecker = new LoginChecker();
$loginChecker->addObserver($eventDispatcher);

```

Advantages and disadvantages
----------------------------

[](#advantages-and-disadvantages)

One advantage is that your plugin api is simple and the events are easy to document. If you choose to put all your events in one directory all your api is in one place and easy to inspect.

Another advantage is that you can start using plugins right away by using the trait `ObserverStore` and throw an event. It is very simple to implement.

A third advantage is that loading plugins is simple by adding them to the `EventDispatcher`.

A disadvantage of this approach is that the `EventDispatcher` needs to be added as an observer to every class that is observable or passed as a constructor dependency. That is why I prefer to use it together with [Fjor](http://koenhoeymans.github.com/Fjor/index.html). While Fjor creates the objectgraph it can be told to add the `EventDispatcher`instance to every instance of a class that implements `Observable` or upon construction. This means that you actually don't have to do any work in adding the `EventDispatcher`and can forget about it while Fjor does the work for you.

###  Health Score

26

—

LowBetter than 41% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity11

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~242 days

Recently: every ~477 days

Total

9

Last Release

2884d ago

PHP version history (2 changes)0.1.0PHP &gt;=5.4.6

0.5.0PHP &gt;=7.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/433513?v=4)[koenhoeymans](/maintainers/koenhoeymans)[@koenhoeymans](https://github.com/koenhoeymans)

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/epa-epa/health.svg)

```
[![Health](https://phpackages.com/badges/epa-epa/health.svg)](https://phpackages.com/packages/epa-epa)
```

###  Alternatives

[halfpastfouram/phpchartjs

PHP library for ChartJS

2512.3k](/packages/halfpastfouram-phpchartjs)[freemius/php-sdk

Freemius PHP SDK

346.1k](/packages/freemius-php-sdk)[thefair/hyperf-rocketmq

The PHP library for hyperf rocketmq

1510.9k](/packages/thefair-hyperf-rocketmq)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
