Registering and Executing Your Own Events

If you're building an add-on that other developers might want to extend, it might help you to create custom events within your add-on. For example, let's say this code is in an eCommerce add-on, and is executed when a product is added.

class Product
{

    public static function add($productName)
    {
        $product = new Product();
        $product->setName($productName);
        return $product;
    }

}

The add product routine in a controller might look like this:

public function add_product()
{
    $product = Product::add($this->request->request->get('productName'));
}

Now, let's add an on_product_add event to this code:

public static function add($productName)
{
    $product = new Product();
    $product->setName($productName);

    $event = new \Symfony\Component\EventDispatcher\GenericEvent();
    $event->setArgument('product', $product);
    \Events::dispatch('on_product_add', $event);
    return $product;
}

That's it! Now you can hook into the event like this from anywhere:

Events::addListener('on_product_add', function($event) {
    $product = $event->getArgument('product');
    // Do custom stuff here with the product object.
});

Custom Event Objects

Notice how we use the Symfony\Component\EventDispatcher\GenericEvent object in this example? That's because it's a simple event object for us to use. It lets us pass arbitrary variables in using the getArgument() and setArgument() methods. But if we want something more strongly typed like our Concrete\Core\User\Event\UserInfoWithPassword class, we simply need to instantiate it, and make sure it extends the Symfony\Component\EventDispatcher\Event abstract event: Noted that, for version 9 you need to use Symfony\Contracts\EventDispatcher\Event.

namespace My\Application;
use Symfony\Component\EventDispatcher\Event as AbstractEvent;
class ProductEvent extends AbstractEvent
{

    protected $product;

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

    public function setProduct(Product $product)
    {
        $this->product = $product;
    }

    public function __construct(Product $product)
    {
        $this->setProduct($product);
    }

}

Then, use this object in place of the generic event object:

public static function add($productName)
{
    $product = new Product();
    $product->setName($productName);

    $event = new ProductEvent($product);
    \Events::dispatch('on_product_add', $event);
    return $product;
}

And retrieve it with:

Events::addListener('on_product_add', function($event) {
    $product = $event->getProduct();
    // Do custom stuff here with the product object.
});