Application Events

Improvements?

Let us know by posting here.

Application Events Overview

Concrete CMS events let you add functionality to existing processes without altering the core.

Examples

  • Deleting a Page Type with Extra Information: Instead of modifying Page::delete() in Concrete\Core\Page\Page, use Concrete's delete page event to also remove associated information from an extra database table.

  • Integrating with Third Party Authentication: For actions like adding a user, instead of altering the codebase, hook into Concrete's "Add User" event to trigger custom code in your third-party system through an API.

Use Concrete's Events System to implement such custom functionalities.

Hooking into Application Events

Application-Level

Add custom code to application/bootstrap/app.php for use on the current website without packaging.

In a Package

In a Package, add event hooking code to the on_start() method in controller.php. This integrates the event early in Concrete's bootstrapping and ensures it's active only when the package is installed.

Import the Events Class

In a package controller, import the Events class:

use Concrete\Core\Support\Facade\Events;

At the application level, importing Events is not needed.

Code Example

Example to log when a user is added:

Events::addListener('on_user_add', function($event) {
    $user = $event->getUserInfoObject();
    \Log::info(sprintf('Added user %s', $user->getUserName()));
});

Pass the event and a closure to Events::addListener. The closure receives an Event object, whose type varies based on the event. For on_user_add, it works with Concrete\Core\User\Event\UserInfoWithPassword.

Example: Changing a Page's Location Based on its Date

Automatically structure blog post URLs based on date, like /blog/2016/03/hello-world instead of /blog/hello-world, using page events.

Create a custom handler class instance to place posts correctly:

$handler = new \Path\To\My\Custom\PageHandler();

Hook into three events:

  1. On Page Type Publish: When a page type is published.

    \Concrete\Core\Support\Facade\Events::addListener('on_page_type_publish', function($event) use ($handler) {
       $page = $event->getPageObject();
       if ($page->getPageTypeHandle() == 'blog_entry') {
           $handler->placePost($page);
       }
    });
    
  2. On Page Version Approve: When a new page version is approved, possibly with a new URL slug.

    \Concrete\Core\Support\Facade\Events::addListener('on_page_version_approve', function($event) use ($handler) {
       $page = $event->getPageObject();
       if ($page->getPageTypeHandle() == 'blog_entry' && $page->isPageDraft()) {
           $handler->placePost($page);
       }
    });
    
  3. On Page Move: To recalculate paths when a blog entry is moved.

    \Concrete\Core\Support\Facade\Events::addListener('on_page_move', function($event) use ($handler) {
       $page = $event->getPageObject();
       if ($page->getPageTypeHandle() == 'blog_entry') {
           $parent = $event->getOldParentPageObject();
           $handler->cleanPostParent($parent);
       }
    });
    

Registering and Executing Your Own Events

Create custom events in your add-on to allow extension by other developers. For instance, in an eCommerce add-on, when a product is added:

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

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

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;
}

Hook into the event like this:

Events::addListener('on_product_add', function($event) {
    $product = $event->getArgument('product');
    // Custom operations with product object
});

Custom Event Objects

You can use the Symfony\Component\EventDispatcher\GenericEvent for simplicity, but for more specific needs, create a custom event object extending Symfony\Component\EventDispatcher\Event (use Symfony\Contracts\EventDispatcher\Event for version 9):

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 custom 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;
}

Events::addListener('on_product_add', function($event) {
    $product = $event->getProduct();
    // Custom operations with product object
});

Halting Execution Based on Events

You can stop further execution in Concrete CMS using event objects. For instance, the on_before_user_add event allows you to halt user addition:

Events::addListener('on_before_user_add', function($event) {
    $data = $event->getData();
    if ($data['uName'] == 'andrew') {
        $event->cancelAdd(); // Prevents adding users named 'andrew'
    }
});

The cancelAdd() method in the Concrete\Core\User\Event\AddUser event sets $proceed to false. If $proceed is false, Concrete's core code stops the add operation.

Full List of Events

Application Level

Event Description Event Class Argument
on_start Run when a Concrete rendering session is started Generic Event
on_before_dispatch Runs aofter Concrete starts, but before the current request is dispatched None
on_before_render Run right before a view is to be rendered Generic Event
on_render_complete Run when a render is complete Generic Event
on_shutdown Run when Concrete shuts down None
on_cache_flush Run when the cache is cleared None
on_before_console_run Run when Concrete is run from the command line None
on_after_console_run Run after Concrete is run from the command line None
on_entity_manager_configure Runs when the entity manager is first created by the database connection Generic Event
on_locale_load Runs when an active locale is set Generic Event
on_locale_add Runs when a locale is added Generic Event
on_locale_delete Runs when a locale is deleted Generic Event
on_locale_change Runs when a locale is changed Generic Event
on_logger_create Runs when the logger is created Concrete\Core\Logging\Event
on_header_required_ready Runs when the header is rendered Generic Event

Pages

Event Description Event Class Argument
on_page_view Run when a user visits a page Concrete\Core\Page\Event
on_get_page_wrapper_class Run when a page is rendered (9.1.2+) Generic Event
on_page_output Run when a page is output to a visitor Generic Event
on_page_add Run when a page is added Concrete\Core\Page\Event
on_page_get_icon Run when an icon is retrieved for a page in the sitemap Concrete\Core\Page\Event
on_page_update Run when a page is updated Concrete\Core\Page\Event
on_page_delete Run when a page is about to be deleted Concrete\Core\Page\DeletePageEvent
on_page_move Run when a page is moved Concrete\Core\Page\MovePageEvent
on_page_display_order_update Run when the display order of a page changes (8.5.0+) Concrete\Core\Page\DisplayOrderUpdateEvent
on_page_duplicate Run when a page is duplicated Concrete\Core\Page\DuplicatePageEvent
on_page_move_to_trash Run when a page is moved to the trash but not yet deleted Concrete\Core\Page\Event
on_page_not_found Run when a page is not found None
on_compute_canonical_page_path Run when a page's canonical path is computed Concrete\Core\Page\PagePathEvent
on_multilingual_page_relate Run when a multilingual page is related to another Concrete\Core\Multilingual\Page\Section\Event

Page Types

Event Description Event Class Argument
on_page_type_publish Run when a page of a certain type is published Concrete\Core\Page\Type\Event
on_page_type_save_composer_form Run when a page type composer form is saved Concrete\Core\Page\Type\Event

Page Version

Event Description Event Class Argument
on_page_version_add Run when a new page version is created Concrete\Core\Page\Collection\Version\Event
on_page_version_approve Run when a particular page version is approved Concrete\Core\Page\Collection\Version\Event
on_page_version_submit_approve Run when a particular page version is submitted for approval Concrete\Core\Page\Collection\Version\Event
on_page_version_deny Run when a page version is denied approval Concrete\Core\Page\Collection\Version\Event

Files

Event Description Event Class Argument
on_file_add Run when a file is added Concrete\Core\File\Event\FileVersion
on_file_set_password Run when a file password is set Concrete\Core\File\Event\FileWithPassword
on_file_download Run when a file is downloaded Concrete\Core\File\Event\FileAccess
on_file_delete Run when a file is deleted fully Concrete\Core\File\Event\DeleteFile
on_file_duplicate Run when a file is duplicated Concrete\Core\File\Event\DuplicateFile

File Versions

Event Description Event Class Argument
on_file_version_add Run when a file version is added Concrete\Core\File\Event\FileVersion
on_file_version_deny Run when a file version is denied Concrete\Core\File\Event\FileVersion
on_file_version_approve Run when a file version is approved Concrete\Core\File\Event\FileVersion
on_file_version_duplicate Run when a file version is duplicated Concrete\Core\File\Event\FileVersion
on_file_version_update_title Run when a file version's title is updated Concrete\Core\File\Event\FileVersion
on_file_version_update_tags Run when a file version's tags are updated Concrete\Core\File\Event\FileVersion
on_file_version_update_description Run when a file version's description is updated Concrete\Core\File\Event\FileVersion
on_file_version_update_contents Run when a file version's contents are updated Concrete\Core\File\Event\FileVersion

File Sets

Event Description Event Class Argument
on_file_set_add Run when a file set is added Concrete\Core\File\Event\FileSet
on_file_set_delete Run when a file set is deleted (available from version 8.3.3) Concrete\Core\File\Event\FileSet
on_file_added_to_set Run when a file is added to a set Concrete\Core\File\Event\FileSetFile
on_file_removed_from_set Run when a file is removed from a set Concrete\Core\File\Event\FileSetFile

Blocks

Event Description Event Class Argument
on_block_load Run when a block is loaded for display Generic Event
on_block_add Run after a block is added Concrete\Core\Block\Events\BlockAdd
on_block_edit Run after a block is edited Concrete\Core\Block\Events\BlockEdit
on_block_delete Run after a block is deleted Concrete\Core\Block\Events\BlockDelete
on_block_before_render Run before a block is rendered (8.4.0+) Concrete\Core\Block\Events\BlockBeforeRender
on_block_duplicate Run after a block is duplicated (8.4.0+) Concrete\Core\Block\Events\BlockDuplicate
on_block_output Run just before a block is outputted (8.4.1+) Concrete\Core\Block\Events\BlockOutput

Express

Event Description Event Class Argument
on_express_entry_saved Run when an express entry is saved. Concrete\Core\Express\Event\Event

Users

Event Description Event Class Argument
on_before_user_add Run before a user is added Concrete\Core\User\Event\AddUser
on_user_add Run when a user is added Concrete\Core\User\Event\UserInfoWithPassword
on_user_update Run when a user is updated Concrete\Core\User\Event\UserInfo
on_user_change_password Run when a user's password is changed Concrete\Core\User\Event\UserInfoWithPassword
on_user_delete Run before a user delete. Concrete\Core\User\Event\DeleteUser
on_user_deleted Run when a user is deleted fully (From v8.3.0) Concrete\Core\User\Event\UserInfo
on_user_validate Run when a user is validated Concrete\Core\User\Event\UserInfo
on_user_activate Run when a user is activated Concrete\Core\User\Event\UserInfo
on_user_deactivate Run when a user is deactivated Concrete\Core\User\Event\UserInfo
on_user_login Run when a user logs in Concrete\Core\User\Event\User
on_user_logout Run when a user logs out None
on_user_attributes_saved Run when a user's attributes are saved Concrete\Core\User\Event\UserInfoWithAttributes

Private Messages

Event Description Event Class Argument
on_private_message_marked_not_new Run when new status is removed from a mailbox Concrete\Core\User\Event\UserInfo
on_private_message_marked_as_read Run when a user has read a private message Concrete\Core\User\PrivateMessage\Event
on_private_message_delete Run when a user deletes a private message Concrete\Core\User\PrivateMessage\Event
on_private_message_over_limit Run when a user has tripped private message sending limits Concrete\Core\User\Event\UserInfo

User Groups

Event Description Event Class Argument
on_group_add Run when a group is added Concrete\Core\User\Group\Event
on_group_update Run when a group is updated Concrete\Core\User\Group\Event
on_group_delete Run when a group is deleted Concrete\Core\User\Group\DeleteEvent
on_user_enter_group Run when a user enters a group Concrete\Core\User\Event\UserGroup
on_user_exit_group Run when a user exits a group Concrete\Core\User\Event\UserGroup

Conversations

Event Description Event Class Argument
on_new_conversation_message Run when a conversation message is added Concrete\Core\Conversation\Message\MessageEvent

Jobs

Event Description Event Class Argument
on_job_install Run when a job is installed Concrete\Core\Job\Event
on_job_uninstall Run when a job is uninstalled Concrete\Core\Job\Event
on_before_job_execute Runs before a job is executed Concrete\Core\Job\Event
on_job_execute Runs when a job is executed Concrete\Core\Job\Event

Miscellaneous

Event Description Event Class Argument
on_get_countries_list Runs when the country list is retrieved for use Generic Event
on_get_states_provinces_list Runs when the states/provinces are retrieved Generic Event
on_sitemap_xml_ready Runs when the generate sitemap job's XML is ready Concrete\Core\Page\Sitemap\EventXmlReadyEvent
on_sitemap_xml_addingpage Runs when the generate sitemap job adds a page Generic Event
on_page_feed_output Runs when an RSS feed is output Concrete\Core\Page\FeedEvent
on_form_submission Runs when a form block is submitted Generic Event