Events and Listeners
Chamilo uses Symfony's event system for decoupled communication between components.
Event Listeners
Chamilo uses two listener locations:
src/CoreBundle/EventListener/— Symfony kernel/HTTP listeners (request, response, exception, login/logout, course/session access, etc.). Examples:CidReqListener,CourseAccessListener,LoginSuccessHandler,LogoutListener,ExceptionListener,ResourceDoctrineListener.src/CoreBundle/Entity/Listener/— Doctrine entity listeners attached to specific entities. Examples:ResourceNodeListener,CourseListener,SessionListener,LanguageListener,UserListener,MessageListener.
Pick the location that matches what you need to react to: HTTP-pipeline events go in EventListener/; entity lifecycle hooks go in Entity/Listener/.
Event Subscribers
Located in src/CoreBundle/EventSubscriber/:
Event subscribers can listen to multiple events:
Security subscribers — Handle login/logout events, track login attempts
API subscribers — Pre/post processing for API requests
Doctrine subscribers — React to entity lifecycle events
Doctrine Lifecycle Events
Entities use #[ORM\HasLifecycleCallbacks] for database-level events:
Creating Custom Listeners
To add custom behavior:
Create a listener/subscriber class in the appropriate bundle
Tag it as an event listener or subscriber in the service configuration
Implement the handler method
Key Events
kernel.request
Every HTTP request
kernel.response
Before sending the HTTP response
security.interactive_login
User logs in
doctrine.prePersist
Before an entity is first saved
doctrine.postUpdate
After an entity is updated
Chamilo-Specific Events
These events are dispatched by Chamilo's own code and are the primary integration points for plugins. Constants are defined in Chamilo\CoreBundle\Event\Events.
Events::COURSE_CREATED
chamilo.event.course_created
After a course is created
Events::COURSE_ACCESS_CHECK
chamilo.course_access_check
Before a user accesses a course
Events::COURSE_USER_SUBSCRIPTION_CHECK
chamilo.event.course_user_subscription_check
Before a user enrols in a course
Events::SESSION_RESUBSCRIPTION
chamilo.event.session_resubscription
When a user attempts to resubscribe to a session
Events::LOGIN_CREDENTIALS_CHECKED
chamilo.event.login_credentials_checked
After login credentials are validated
Events::LOGIN_CONDITION_CHECKED
chamilo.event.login_condition_checked
After additional login conditions are checked
Events::DOCUMENT_ACTION
chamilo.event.document_action
When the document tool toolbar is rendered
Events::DOCUMENT_ITEM_ACTION
chamilo.event.document_item_action
When per-file action buttons are rendered
Events::DOCUMENT_ITEM_VIEW
chamilo.event.document_item_view
When a document is opened for viewing
Events::EXERCISE_REPORT_ACTION
chamilo.event.exercise_report_action
When the exercise report page renders its action links
Events::EXERCISE_ENDED
chamilo.event.exercise_ended
After a learner submits an exercise
Events::EXERCISE_QUESTION_ANSWERED
chamilo.event.question_answered
After each question is answered
Events::LP_CREATED
chamilo.event.learning_path_created
After a learning path is created
Events::LP_ITEM_VIEWED
chamilo.event.learning_path_item_viewed
When a learner opens an LP item
Events::LP_ENDED
chamilo.event.learning_path_ended
After a learner completes a learning path
Events::ADMIN_BLOCK_DISPLAYED
chamilo.event.admin_block_displayed
When the admin dashboard builds its block list
Events::USER_CREATED
chamilo.event.user_created
After a user account is created
Events::USER_UPDATED
chamilo.event.user_updated
After a user account is updated
Events::USER_DELETED
chamilo.event.user_deleted
After a user account is deleted
Events::PORTFOLIO_ITEM_ADDED
chamilo.event.portfolio_item_added
After a portfolio item is created
Events::NOTIFICATION_CONTENT_FORMATTED
chamilo_hook_event.notification_content
When a notification body is formatted
Plugin Example: Adding a Button to the Document Viewer
This section walks through how a plugin uses an event subscriber to inject a button into an existing Chamilo page — no core-code modification required.
Scenario
A plugin called MyViewer wants to add an "Open in MyViewer" button next to every document in the course file manager. The relevant event is Events::DOCUMENT_ITEM_VIEW, dispatched by Chamilo whenever a document is about to be displayed, carrying the CDocument entity and a mutable list of links.
Plugin directory layout
Main plugin class (src/MyViewerPlugin.php)
src/MyViewerPlugin.php)The Plugin base class provides isEnabled(), get($settingKey), and helpers for installing course tools and settings. The singleton pattern (static $instance) is the standard Chamilo convention because the plugin class is also instantiated outside the Symfony container (in legacy PHP pages).
Event subscriber (src/EventSubscriber/MyViewerEventSubscriber.php)
src/EventSubscriber/MyViewerEventSubscriber.php)addLink() appends HTML to the array that Chamilo's document view template renders alongside the built-in "Download" and "Preview" actions. The subscriber never modifies Chamilo core files.
Registration
No manual service registration is needed. Chamilo's config/services.yaml enables Symfony's autoconfigure flag globally, which automatically tags any class implementing EventSubscriberInterface as a kernel.event_subscriber. As long as the plugin directory is loaded (via Composer's classmap or PSR-4 autoload), Symfony picks up the subscriber on the next cache clear.
How the event data flows
Multiple plugins can subscribe to the same event independently; each appends to the shared data without knowing about the others. The order of execution follows Symfony's priority system — pass a priority integer as the second element of the handler tuple in getSubscribedEvents() if ordering matters:
Last updated
Was this helpful?