I’m hooking to the media events Introduction - October CMS - 3.x to update the fields in my models when a file is renamed or moved, and it’s working ok. But I’d like to be able to also prevent the files to be deleted if they are used in a model: if the user tries to delete a file that is used in a model, I’d like to show an error message saying “This file is being used in X models and cannot be deleted”. I think that I can’t do this right now because the media.file.delete event is launched after the file has been deleted. Is there any workaround that I can use to achieve this?
how about to disable media deletion through permissions?
There is mediaDelete
permission and is checked before any other actions in MediaManager.php
(in function onDeleteItem
).
This my solution to your question. Add the code below to your plugin boot method. This prohibits deleting by default.
public function boot()
{
\Media\Widgets\MediaManager::extend(function($manager) {
$manager->addDynamicMethod('__onDeleteItem', function() use($manager) {
if(!$manager->customFilter()) {
throw new ForbiddenException;
}
return $manager->onDeleteItem();
});
$manager->addDynamicMethod('customFilter', function() {
// Add you logic here to check if the file is being used by your model.
// Return true to allow deletion.
return false;
});
});
\Media\Controllers\Index::extend(function($controller) {
$controller->addDynamicMethod('runMediaDeleteChecks', function(string $handler) use($controller) {
if(strpos($handler, '::')) {
if ($handler === 'manager::onDeleteItem') {
[$widgetName, $handlerName] = explode('::', $handler);
if ($controller->fatalError) {
throw new SystemException($controller->fatalError);
}
if (!isset($controller->widget->{$widgetName})) {
throw new SystemException(Lang::get('backend::lang.widget.not_bound', ['name'=>$widgetName]));
}
if (($widget = $controller->widget->{$widgetName}) && $widget->methodExists($handlerName)) {
$result = $controller->runAjaxHandlerForWidget($widget, '__'.$handlerName);
return $result ?: true;
}
}
}
});
$controller->addDynamicMethod('runAjaxHandlerForWidget', function($widget, $handler) use($controller) {
$controller->addViewPath($widget->getViewPaths());
$dependancyResolver = new \System\Classes\DependencyResolver;
$resolvedParams = $dependancyResolver->resolve($widget, $handler, $controller->params?:[]);
$result = $widget->$handler(...$resolvedParams);
$controller->vars = $widget->vars + $controller->vars;
return $result;
});
});
Event::listen('backend.ajax.beforeRunHandler', function($controller, string $handler) {
if($controller instanceof \Media\Controllers\Index) {
return $controller->runMediaDeleteChecks($handler);
}
});
}
You need to update the customFilter method to check if the is being used by your model.
$manager->addDynamicMethod('customFilter', function() {
// Add you logic here to check if the file is being used by your model.
// Return true to allow deletion.
return true;
});
I hope this solves your issue.