# For developers: events

Fileshelf can be extended with plugins of your own – exactly the way the Pro version does it. Fileshelf loads all plugins of the group `fileshelf` before it fires its events. The classes are in `Graup\Component\Fileshelf\Administrator\Event`.

<div class="callout info" id="bkmrk-the-events-are-files">The events are Fileshelf's public interface. Their names, arguments and public methods only change with a new major version.

</div>## The events

<table class="table" id="bkmrk-eventclasswhenwhat-a"> <thead> <tr><th scope="col">Event</th><th scope="col">Class</th><th scope="col">When</th><th scope="col">What a plugin can do</th></tr> </thead> <tbody> <tr><td><code>onFileshelfResolveToken</code></td><td><code>ResolveTokenEvent</code></td><td>The request carries a token (<code>t</code>).</td><td><code>grant&#40;&#41;</code> skips access level and password, <code>reject&#40;&#41;</code> locks with reason <code>token</code>.</td></tr> <tr><td><code>onFileshelfAccess</code></td><td><code>AccessEvent</code></td><td>After status, token, access level and password; also in lists (context <code>list</code>).</td><td><code>deny&#40;&#36;reason&#44; &#36;message&#44; &#36;redirect&#41;</code> locks. In lists, never count or write.</td></tr> <tr><td><code>onFileshelfBeforeSend</code></td><td><code>BeforeSendEvent</code></td><td>Access granted, before counting.</td><td><code>setFile&#40;&#41;</code> swaps the file; Fileshelf checks it against the storage again.</td></tr> <tr><td><code>onFileshelfAfterCount</code></td><td><code>AfterCountEvent</code></td><td>After counting, before the first byte.</td><td>Notification only; <code>getRequestId&#40;&#41;</code> links it to the next event.</td></tr> <tr><td><code>onFileshelfAfterSend</code></td><td><code>AfterSendEvent</code></td><td>After sending, also when the visitor broke off.</td><td><code>isCompleted&#40;&#41;</code>, <code>getBytesSent&#40;&#41;</code>, <code>getMethod&#40;&#41;</code>.</td></tr> <tr><td><code>onFileshelfDownloadDisplay</code></td><td><code>DownloadDisplayEvent</code></td><td>Download page, per position.</td><td><code>addHtml&#40;&#41;</code> with finished, escaped HTML.</td></tr> <tr><td><code>onFileshelfDashboard</code></td><td><code>DashboardEvent</code></td><td>Backend dashboard.</td><td><code>addTile&#40;&#36;id&#44; &#36;title&#44; &#36;html&#44; &#36;order&#44; &#36;area&#41;</code> (<code>&#36;area</code>: <code>status</code>, <code>content</code>, <code>insight</code> or <code>setup</code>); from 1.8.0 <code>addAttention&#40;&#36;id&#44; &#36;text&#44; &#36;link&#44; &#36;count&#44; &#36;label&#41;</code> for “Needs your attention”, only for a need for action with a way out; check your own right first.</td></tr> <tr><td><code>onFileshelfAdminPages</code></td><td><code>AdminPagesEvent</code></td><td>Dashboard and every plugin page.</td><td><code>addPage&#40;&#36;name&#44; &#36;title&#44; &#36;right&#44; &#36;icon&#41;</code> announces a page <code>view&#61;page&#38;page&#61;…</code>; Fileshelf checks the right.</td></tr> <tr><td><code>onFileshelfAdminPage</code></td><td><code>AdminPageEvent</code></td><td>The plugin page is shown.</td><td><code>addHtml&#40;&#41;</code>, <code>addAction&#40;&#36;action&#44; &#36;label&#44; &#36;icon&#44; &#36;confirm&#41;</code>.</td></tr> <tr><td><code>onFileshelfAdminAction</code></td><td><code>AdminActionEvent</code></td><td>An action of the page runs; token, right and confirmation are checked.</td><td><code>handled&#40;&#36;message&#44; &#36;type&#41;</code>.</td></tr> <tr><td><code>onFileshelfFilesInUse</code></td><td><code>FilesInUseEvent</code></td><td>Tools, download form and media manager ask which files of the storage belong to plugins.</td><td><code>claim&#40;&#36;path&#41;</code> for your own files (e.g. older versions); they never count as unlinked.</td></tr> <tr><td><code>onFileshelfSitePages</code></td><td><code>SitePagesEvent</code></td><td>Menu item “Extension page” and every call of such a page.</td><td><code>addPage&#40;&#36;name&#44; &#36;title&#44; &#36;login&#41;</code> announces a website page; with <code>&#36;login</code> Fileshelf sends guests to the login.</td></tr> <tr><td><code>onFileshelfSitePage</code></td><td><code>SitePageEvent</code></td><td>The page is shown.</td><td><code>addHtml&#40;&#41;</code> with escaped HTML, <code>setTitle&#40;&#41;</code>, <code>getOptions&#40;&#41;</code> (menu item).</td></tr> <tr><td><code>onFileshelfSiteAction</code></td><td><code>SiteActionEvent</code></td><td>A form of the page was sent; token, page and login are checked.</td><td><code>handled&#40;&#36;message&#44; &#36;type&#44; &#36;redirect&#41;</code>; Fileshelf escapes the message.</td></tr> <tr><td><code>onFileshelfCategoryDisplay</code></td><td><code>CategoryDisplayEvent</code></td><td>Category page, positions <code>beforeList</code> and <code>afterList</code>.</td><td><code>addHtml&#40;&#41;</code> with escaped HTML; <code>getTotal&#40;&#41;</code> gives the number of listed downloads.</td></tr> <tr><td><code>onFileshelfActionLog</code></td><td><code>ActionLogEvent</code></td><td>Since 1.3.0: Fileshelf or a plugin reports an action for the action log (password, approval, import).</td><td>Message only: <code>getAction&#40;&#41;</code>, <code>getKind&#40;&#41;</code> (<code>download</code>, <code>category</code>, <code>import</code>), <code>getItemId&#40;&#41;</code>, <code>getTitle&#40;&#41;</code>, <code>getDetails&#40;&#41;</code>. The plugin "Action Log - Fileshelf" writes it.</td></tr> <tr><td><code>onFileshelfImportSources</code></td><td><code>ImportSourcesEvent</code> (Pro)</td><td>Since 1.3.0: the page "Import" collects its sources.</td><td><code>addSource&#40;&#41;</code> with a class implementing <code>SourceInterface</code> of the import plugin (categories, downloads, table check).</td></tr> <tr><td><code>onFileshelfResolveScopes</code></td><td><code>ResolveScopesEvent</code></td><td>Fired by the Pro version (limits) as soon as a limit uses a scope type of another plugin; the Free version does not fire it.</td><td><code>addScope&#40;&#36;type&#44; &#36;id&#41;</code>.</td></tr> </tbody></table>

The download comes as a read-only `DownloadRecord` (without the password hash), never as a table object. Reasons of your own start with `x-<plugin>-`; the website then shows only the message.

## Example

```
final class Example extends CMSPlugin implements SubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return ['onFileshelfAccess' => 'onAccess'];
    }

    public function onAccess(AccessEvent $event): void
    {
        if ($event->getContext() !== 'list' && !$this->allowed($event->getUser())) {
            $event->deny('x-example-hours', 'Downloads are possible on working days only.');
        }
    }
}
```

Plugins add form tabs to the download as with articles, with `onContentPrepareForm` (form `com_fileshelf.download`), and store them in `onContentAfterSave` (context `com_fileshelf.download`).

## Pages on the website

With the menu item type **Fileshelf → Extension page** a plugin gets a page of its own on the website, without a component of its own. Forms of that page send `task=extension.action`, `page`, `action` and the form token to `Route::_('index.php?option=com_fileshelf')` – always build the address with `Route::_()`, a relative address is wrong under search engine friendly URLs. Plugins add tabs to the category form with `onContentPrepareForm` on the form `com_categories.categorycom_fileshelf`; Fileshelf loads the group `fileshelf` for it.

[Deutsche Fassung](https://docs.graup-it.de/link/433)