File events
File events split into two phases: upload (when the file enters the system) and serve (when a user downloads it). Three additional stats events fire during a serve and are consumed by the Stats registry.
Upload events
| Event | Signature | When |
|---|---|---|
mc_dm_file_pre_upload | (DownloadFile $file) | Before processors run, after the upload has been received to a temp path. |
mc_dm_file_post_upload | (DownloadFile $file) | After all processors have run and the row has been persisted. |
Processors (hash, mime, magic-byte, decompression-bomb) run between these two events. A pre_upload listener that throws aborts the upload. A post_upload listener firing means the file passed every processor.
Serve events
| Event | Signature | When |
|---|---|---|
mc_dm_file_pre_serve | (DownloadFile $file, GateContext $context) | Before gate evaluation. |
mc_dm_file_post_serve | (DownloadFile $file, GateContext $context) | After bytes have been streamed. |
pre_serve runs before any gate (see Gate registry). Listeners here can short-circuit by throwing. post_serve only fires on successful serves.
Stats events
These fire from Pub\Controller\Downloads around the file serve:
| Event | Signature | When |
|---|---|---|
mc_dm_download_started | (Download $download, Version $version, File $file) | At the top of a serve, after gates pass. |
mc_dm_download_completed | (Download $download, Version $version, File $file) | After bytes have been fully streamed (or, for external/magnet links, after handoff). |
mc_dm_download_failed | (Download $download, Version $version, ?File $file, string $reason) | On serve error: gate fail, storage error, missing file row, client disconnect. $file is null when the failure happens before a specific file is resolved. $reason is a short identifier (e.g. missing_object, storage_unreadable). |
The webhook payload for download_failed carries reason, file_id, and version_id as top-level fields alongside the Download entity. See Webhook payloads.
Example
public static function filePreServe(
\MC\DownloadsManager\Entity\DownloadFile $file,
\MC\DownloadsManager\Gate\GateContext $context
)
{
if ($context->visitor->is_banned)
{
throw new \XF\PrintableException(\XF::phraseDeferred('your_addon.banned_from_downloads'));
}
}