Events and Event Listeners
General
Pimcore provides an extensive number of events that are fired during execution of Pimcore functions. These events can be used to hook into many Pimcore functions such as saving an object, asset or document and can be used to change or extend the default behavior of Pimcore.
The most common use-case for events is using them in a bundle/extension, but
of course you can use them also anywhere in your code or in your dependency injection configuration (config/services.yaml
).
Pimcore implements the standard Symfony framework event dispatcher and just adds some pimcore specific events, so you can also subscribe to all Symfony core eventsand events triggered by arbitrary Symfony bundles.
For that reason it's recommended to have a look into the Symfony Events and Event Listeners documentation first, which covers all basics in that matter.
Available Events
All Pimcore events are defined and documented as a constant on component specific classes:
- Assets
- Documents
- Data Objects
- Versions
- Data Object Class Definition
- Object Brick Definition
- Data Object Classification Store
- Data Object Custom Layouts
- Data Object Import
- Data Object Quantity Value Unit
- Users / Roles
- Workflows
- Elements
- Notifications
- Redirect
- Admin
- Frontend
- Cache
- Full-Page Cache
- Search
- System
- Tags
- Target Group
- Targeting
- Tests
- Translation
- Bundle Manager for injecting js/css files to Pimcore backend or editmode
Examples
Hook into the pre-update event of assets, documents and objects
The following example shows how to register events for assets, documents and objects
in your config/services.yaml
:
services:
App\EventListener\TestListener:
tags:
- { name: kernel.event_listener, event: pimcore.asset.preUpdate, method: onPreUpdate }
- { name: kernel.event_listener, event: pimcore.document.preUpdate, method: onPreUpdate }
- { name: kernel.event_listener, event: pimcore.dataobject.preUpdate, method: onPreUpdate }
in your listener class src/EventListener/TestListener
<?php
namespace App\EventListener;
use Pimcore\Event\Model\ElementEventInterface;
use Pimcore\Event\Model\DataObjectEvent;
use Pimcore\Event\Model\AssetEvent;
use Pimcore\Event\Model\DocumentEvent;
class TestListener
{
public function onPreUpdate(ElementEventInterface $e): void
{
if ($e instanceof AssetEvent) {
// do something with the asset
$foo = $e->getAsset();
} else if ($e instanceof DocumentEvent) {
// do something with the document
$foo = $e->getDocument();
} else if ($e instanceof DataObjectEvent) {
// do something with the object
$foo = $e->getObject();
$foo->setMyValue(microtime(true));
// we don't have to call save here as we are in the pre-update event anyway ;-)
}
}
}
Hook into the list of objects in the tree, the grid list and the search panel
There are some global events having effect on several places. One of those is pimcore.admin.object.list.beforeListLoad
.
The object list can be modified (changing condition for instance) before being loaded. This global event will apply to the tree, the grid list, the search panel and everywhere objects are listed in the Pimcore GUI.
This way, it is possible to create custom permission rules to decide if the object should or not be listed (for instance, the user must be the owner of the object, ...).
It extends the possibility further than just limiting list permissions folder by folder depending the user/role object workspace. To ensure maximum security, it is advisable to combine this with an object DI to overload isAllowed method with the same custom permission rules. This way proper permission is ensuring all the way (rest services, ...).
Hook into the Open Document|Asset|Data Object dialog
By the default, Pimcore tries to a resolve an element by its ID or path. You can change this behavior by handling the AdminEvents::RESOLVE_ELEMENT event and implement your own logic.
\Pimcore::getEventDispatcher()->addListener(AdminEvents::RESOLVE_ELEMENT, function(ResolveElementEvent $event) {
$id = $event->getId();
if ($event->getType() == "object") {
if (is_numeric($event->getId())) {
return;
}
$listing = new News\Listing();
$listing->setLocale('en');
$listing->setLimit(1);
$listing->setCondition('title LIKE ' . $listing->quote('%' . $id . '%'));
$listing = $listing->load();
if ($listing) {
$id = ($listing[0])->getId();
$event->setId($id);
}
}
Asset Upload Path
Certain data types (like image, relations, etc ...) allow you to specify a dedicated upload path which defaults to '/_default_upload_bucket' if not otherwise specified in the config yml file or in the class definition.
The AssetEvents::RESOLVE_UPLOAD_TARGET event allows you to dynamically modify the target path depending on the object it will be assigned to. Additional contextual information (like fieldname, fieldcollection index number, etc... ) could be utilized to support the decision.
The contextual info provided is the same as described here:
Example Code: For the demo instance, this sample code would place an image which is dragged onto the image_1 field of object 6 (in-enim-justo_2) into the /news/in-enim-justo_2/image_1 asset folder.
\Pimcore::getEventDispatcher()->addListener(AssetEvents::RESOLVE_UPLOAD_TARGET,
function(\Pimcore\Event\Model\Asset\ResolveUploadTargetEvent $event) {
$context = $event->getContext();
if ($context["containerType"] == "object") {
$objectId = $context["objectId"];
$newsObject = News::getById($objectId);
if ($newsObject) {
$fieldname = $context["fieldname"];
$targetPath = $newsObject->getPath() . $newsObject->getKey() . "/" . $fieldname;
$parent = \Pimcore\Model\Asset\Service::createFolderByPath($targetPath);
if ($parent) {
$event->setParentId($parent->getId());
}
}
}
});