Skip to content

Instantly share code, notes, and snippets.

@filozofer
Last active August 5, 2020 04:07
Show Gist options
  • Save filozofer/e397a83d44f552bfbcf7f1b325b284c6 to your computer and use it in GitHub Desktop.
Save filozofer/e397a83d44f552bfbcf7f1b325b284c6 to your computer and use it in GitHub Desktop.
Replace CoopTilleulsCKEditorSonataMediaBundle behaviour directly in your app

This gist is related to this issue: coopTilleuls/CoopTilleulsCKEditorSonataMediaBundle#32

You can replace CoopTilleulsCKEditorSonataMediaBundle behaviour directly in your app by including these files in your project. Be aware that I modified the twig file to do what I want in my project and it may be wiser to start from those of the CoopTilleulsCKEditorSonataMediaBundle.

{% extends base_template %}
{% set ckParameters = {'CKEditor': app.request.get('CKEditor'), 'CKEditorFuncNum': app.request.get('CKEditorFuncNum')} %}
{% block javascripts %}
{{ parent() }}
<script>
$(function () {
$(".select").click(function (e) {
e.preventDefault();
window.opener.CKEDITOR.tools.callFunction({{ app.request.get('CKEditorFuncNum')|escape('js') }}, $(this).attr("href"));
window.close();
});
// Set default value
$('#filter_name_type').val(1).trigger('change');
});
</script>
{% endblock %}
{% block preview %}
{# Do not show possible contexts (only dashboard context) #}
{#<div class="box box-primary">
<div class="box-body">
<ul class="nav nav-pills">
<li><a><strong>{{ "label.select_context"|trans({}, 'SonataMediaBundle') }}</strong></a></li>
{% for name, context in media_pool.contexts %}
{% if context.providers|length == 0 %}
{% set urlParams = {'context' : name}|merge(ckParameters) %}
{% else %}
{% set urlParams = {'context' : name, 'provider' : context.providers[0]}|merge(ckParameters) %}
{% endif %}
{% if name == persistent_parameters.context %}
<li class="active"><a href="{{ admin.generateUrl('browser', urlParams) }}">{{ name|trans({}, 'SonataMediaBundle') }}</a></li>
{% else %}
<li><a href="{{ admin.generateUrl('browser', urlParams) }}">{{ name|trans({}, 'SonataMediaBundle') }}</a></li>
{% endif %}
{% endfor %}
</ul>
</div>
{% set providers = media_pool.getProviderNamesByContext(persistent_parameters.context) %}
<div class="box-footer">
<ul class="nav nav-pills">
{% if providers|length > 1 %}
<li><a><strong>{{ "label.select_provider"|trans({}, 'SonataMediaBundle') }}</strong></a></li>
{% if (persistent_parameters.provider is not defined) or (not persistent_parameters.provider) %}
<li class="active"><a href="{{ admin.generateUrl('browser', {'context': persistent_parameters.context, 'provider': null}|merge(ckParameters)) }}">{{ "link.all_providers"|trans({}, 'SonataMediaBundle') }}</a></li>
{% else %}
<li><a href="{{ admin.generateUrl('browser', {'context': persistent_parameters.context, 'provider': null}|merge(ckParameters)) }}">{{ "link.all_providers"|trans({}, 'SonataMediaBundle') }}</a></li>
{% endif %}
{% for provider_name in providers %}
{% if (persistent_parameters.provider is defined) and (persistent_parameters.provider == provider_name) %}
<li class="active"><a href="{{ admin.generateUrl('browser', {'context': persistent_parameters.context, 'provider': provider_name}|merge(ckParameters)) }}">{{ provider_name|trans({}, 'SonataMediaBundle') }}</a></li>
{% else %}
<li><a href="{{ admin.generateUrl('browser', {'context': persistent_parameters.context, 'provider': provider_name}|merge(ckParameters)) }}">{{ provider_name|trans({}, 'SonataMediaBundle') }}</a></li>
{% endif %}
{% endfor %}
{% endif %}
</ul>
</div>
</div>#}
{% endblock %}
{# Media table #}
{% block list_table %}
<div class="box box-primary">
{% set batchactions = admin.batchactions %}
{% if admin.datagrid.results|length > 0 %}
<table class="table table-bordered table-striped">
{% block table_header %}
<thead>
<tr class="sonata-ba-list-field-header">
{% for field_description in admin.list.elements %}
{% if field_description.getOption('code') == '_batch' or field_description.name == '_action' %}
{# Disable batch and actions #}
{% else %}
{% set sortable = false %}
{% if field_description.options.sortable is defined and field_description.options.sortable%}
{% set sortable = true %}
{% set current = admin.datagrid.values._sort_by == field_description %}
{% set sort_parameters = admin.modelmanager.sortparameters(field_description, admin.datagrid)|merge(ckParameters) %}
{% set sort_active_class = current ? 'sonata-ba-list-field-order-active' : '' %}
{% set sort_by = current ? admin.datagrid.values._sort_order : field_description.options._sort_order %}
{% endif %}
{% spaceless %}
<th class="sonata-ba-list-field-header-{{ field_description.type}} {% if sortable %} sonata-ba-list-field-header-order-{{ sort_by|lower }} {{ sort_active_class }}{% endif %}">
{% if sortable %}<a href="{{ admin.generateUrl('browser', sort_parameters) }}">{% endif %}
{{ admin.trans(field_description.label) }}
{% if sortable %}</a>{% endif %}
</th>
{% endspaceless %}
{% endif %}
{% endfor %}
</tr>
</thead>
{% endblock %}
{% block table_body %}
<tbody>
{% for object in admin.datagrid.results %}
<tr>
{% for field_description in admin.list.elements %}
{% if field_description.getOption('code') == '_batch' or field_description.name == '_action' %}
{# Disable batch and actions #}
{% elseif field_description.name == 'name' %}
<td>
<div>
<a href="{% path object, 'reference' %}" class="select" style="float: left; margin-right: 6px;">{% thumbnail object, 'admin' with {'width': 75, 'height': 60} %}</a>
<strong><a href="{% path object, 'reference' %}" class="select">{{ object.name }}</a></strong> <br />
{{ object.providerName|trans({}, 'SonataMediaBundle') }}{% if object.width %}: {{ object.width }}{% if object.height %}x{{ object.height }}{% endif %}px{% endif %}
{% if formats[object.id]|length > 0 %}
- {{ 'title.formats'|trans({}, 'SonataMediaBundle') }}:
{% for name, format in formats[object.id] %}
<a href="{% path object, name %}" class="select">{{ name }}</a> {% if format.width %}({{ format.width }}{% if format.height %}x{{ format.height }}{% endif %}px){% endif %}
{% endfor %}
{% endif %}
<br />
</div>
</td>
{% else %}
<td>
{{ object|render_list_element(field_description) }}
</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
{% endblock %}
{% block table_footer %}
<tr>
<th colspan="{{ admin.list.elements|length - 1 }}">
<div class="form-inline">
<div class="pull-right">
{% block pager_results %}
{% block num_pages %}
{{ admin.datagrid.pager.page }} / {{ admin.datagrid.pager.lastpage }}
&nbsp;-&nbsp;
{% endblock %}
{% block num_results %}
{% transchoice admin.datagrid.pager.nbresults with {'%count%': admin.datagrid.pager.nbresults} from 'SonataAdminBundle' %}list_results_count{% endtranschoice %}
&nbsp;-&nbsp;
{% endblock %}
{% block max_per_page %}
<label class="control-label" for="{{ admin.uniqid }}_per_page">{% trans from 'SonataAdminBundle' %}label_per_page{% endtrans %}</label>
<select class="per-page small" id="{{ admin.uniqid }}_per_page" style="width: auto; height: auto">
{% for per_page in admin.getperpageoptions %}
<option {% if per_page == admin.datagrid.pager.maxperpage %}selected="selected"{% endif %} value="{{ admin.generateUrl('browser', {'filter': admin.datagrid.values|merge({'_per_page': per_page})}|merge(ckParameters)) }}">
{{ per_page }}
</option>
{% endfor %}
</select>
{% endblock %}
{% endblock %}
</div>
</div>
</th>
</tr>
{% block pager_links %}
{% if admin.datagrid.pager.haveToPaginate() %}
<tr>
<td colspan="{{ admin.list.elements|length }}">
<div class="text-center">
<ul class="pagination">
{% if admin.datagrid.pager.page > 2 %}
<li><a href="{{ admin.generateUrl('browser', admin.modelmanager.paginationparameters(admin.datagrid, 1)|merge(ckParameters)) }}" title="{{ 'link_first_pager'|trans({}, 'SonataAdminBundle') }}">&laquo;</a></li>
{% endif %}
{% if admin.datagrid.pager.page != admin.datagrid.pager.previouspage %}
<li><a href="{{ admin.generateUrl('browser', admin.modelmanager.paginationparameters(admin.datagrid, admin.datagrid.pager.previouspage)|merge(ckParameters)) }}" title="{{ 'link_previous_pager'|trans({}, 'SonataAdminBundle') }}">&lsaquo;</a></li>
{% endif %}
{# Set the number of pages to display in the pager #}
{% for page in admin.datagrid.pager.getLinks() %}
{% if page == admin.datagrid.pager.page %}
<li><a href="{{ admin.generateUrl('browser', admin.modelmanager.paginationparameters(admin.datagrid, page)|merge(ckParameters)) }}">{{ page }}</a></li>
{% else %}
<li><a href="{{ admin.generateUrl('browser', admin.modelmanager.paginationparameters(admin.datagrid, page)|merge(ckParameters)) }}">{{ page }}</a></li>
{% endif %}
{% endfor %}
{% if admin.datagrid.pager.page != admin.datagrid.pager.nextpage %}
<li><a href="{{ admin.generateUrl('browser', admin.modelmanager.paginationparameters(admin.datagrid, admin.datagrid.pager.nextpage)|merge(ckParameters)) }}" title="{{ 'link_next_pager'|trans({}, 'SonataAdminBundle') }}">&rsaquo;</a></li>
{% endif %}
{% if admin.datagrid.pager.page != admin.datagrid.pager.lastpage and admin.datagrid.pager.lastpage != admin.datagrid.pager.nextpage %}
<li><a href="{{ admin.generateUrl('browser', admin.modelmanager.paginationparameters(admin.datagrid, admin.datagrid.pager.lastpage)|merge(ckParameters)) }}" title="{{ 'link_last_pager'|trans({}, 'SonataAdminBundle') }}">&raquo;</a></li>
{% endif %}
</ul>
</div>
</td>
</tr>
{% endif %}
{% endblock %}
{% endblock %}
</table>
{% else %}
<p class="notice">
{{ 'no_result'|trans({}, 'SonataAdminBundle') }}
</p>
{% endif %}
</div>
{% endblock %}
{# Filter list #}
{% block list_filters %}
{% if admin.datagrid.filters %}
<form class="BrowserMediaForm sonata-filter-form {{ admin.isChild and 1 == admin.datagrid.filters|length ? 'hide' : '' }}" action="{{ admin.generateUrl('browser') }}" method="GET">
<fieldset class="filter_legend">
<legend class="filter_legend {{ admin.datagrid.hasActiveFilters ? 'active' : 'inactive' }}">{{ 'label_filters'|trans({}, 'SonataAdminBundle') }}</legend>
<div class="filter_container {{ admin.datagrid.hasActiveFilters ? 'active' : 'inactive' }}">
<div>
{% for filter in [admin.datagrid.filters|first] %}
<div class="FilterBrowserMedia clearfix">
<label for="{{ form.children[filter.formName].children['value'].vars.id }}">{{ admin.trans(filter.label) }}</label>
{{ form_widget(form.children[filter.formName].children['type'], {'attr': {'class': 'span8 sonata-filter-option'} }) }}
{{ form_widget(form.children[filter.formName].children['value'], {'attr': {'class': 'span8'} }) }}
</div>
{% endfor %}
</div>
<input type="hidden" name="filter[_page]" id="filter__page" value="1" />
{% set foo = form.children['_page'].setRendered() %}
<input type="submit" class="btn btn-primary" value="{{ 'btn_filter'|trans({}, 'SonataAdminBundle') }}" />
<a class="btn" href="{{ admin.generateUrl('browser', {filters: 'reset'}|merge(ckParameters)) }}">{{ 'link_reset_filter'|trans({}, 'SonataAdminBundle') }}</a>
</div>
{% for paramKey, paramValue in admin.persistentParameters|merge(ckParameters) %}
<input type="hidden" name="{{ paramKey }}" value="{{ paramValue }}" />
{% endfor %}
</fieldset>
</form>
{% endif %}
{% endblock %}
#FOSCkEditorBundle config
fos_ck_editor:
input_sync: true
default_config: default
configs:
default:
toolbar: 'default_toolbar'
uiColor: '#ffffff'
baseFloatZIndex: 9000
filebrowserBrowseRoute: admin_sonata_media_media_browser
filebrowserImageBrowseRoute: admin_sonata_media_media_browser
# Display images by default when clicking the image dialog browse button
filebrowserImageBrowseRouteParameters:
provider: sonata.media.provider.image
filebrowserUploadRoute: admin_sonata_media_media_upload
filebrowserUploadRouteParameters:
provider: sonata.media.provider.file
# Upload file as image when sending a file from the image dialog
filebrowserImageUploadRoute: admin_sonata_media_media_upload
filebrowserImageUploadRouteParameters:
provider: sonata.media.provider.image
toolbars:
configs:
default_toolbar: [ "@document", "/", "@link" , "/", "@combo" ]
items:
document: [ "Source", "Cut", "Copy", "Paste", "PasteText", "PasteFromWord", "-", "Undo", "Redo", "-", "Bold", "Italic", "Underline", "Strike", "-", "NumberedList", "BulletedList", "-", "Outdent", "Indent", "-", "Blockquote", "CreateDiv", "-", "JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock" ]
link: [ "Link", "Unlink", "Anchor", "-", "Image", "Table", "HorizontalRule", "SpecialChar", "Smiley" ]
combo: [ "Styles", "Format", "Font", "FontSize", "TextColor", "BGColor", "ShowBlocks", "Maximize" ]
<?php
namespace App;
use App\Controller\Admin\MediaAdminController;
use App\DependencyInjection\Compiler\AggregatedTaggedServicesPass;
use App\DependencyInjection\Compiler\ReplaceServicesPass;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
/**
* Class Kernel.
*
* Truncated Kernel to just show you how I declare my CompilerPass class
*/
class Kernel extends BaseKernel
{
[...]
/**
* Configure container.
*
* @param ContainerBuilder $container
* @param LoaderInterface $loader
* @throws \Exception
*/
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
[...]
// Add a compiler pass to replace some used class
$container->addCompilerPass(new ReplaceServicesPass());
}
[...]
}
{#
This file is part of the Sonata package.
(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
#}
{% set _preview = block('preview') is defined ? block('preview') : '' %}
{% set _form = block('form') is defined ? block('form') : '' %}
{% set _show = block('show') is defined ? block('show') : '' %}
{% set _list_table = block('list_table') is defined ? block('list_table') : '' %}
{% set _list_filters = block('list_filters') is defined ? block('list_filters') : '' %}
{% set _side_menu = block('side_menu') is defined ? block('side_menu') : '' %}
{% set _content = block('content') is defined ? block('content') : '' %}
{% set _title = block('title') is defined ? block('title') : '' %}
{% set _breadcrumb = block('breadcrumb') is defined ? block('breadcrumb') : '' %}
<!DOCTYPE html>
<html {% block html_attributes %}class="no-js"{% endblock %}>
<head>
{% block meta_tags %}
<meta charset="UTF-8">
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
{% endblock %}
{% block stylesheets %}
{% for stylesheet in admin_pool.getOption('stylesheets', []) %}
<link rel="stylesheet" type="text/css" href="{{ asset(stylesheet) }}" />
{% endfor %}
{% endblock %}
{% block javascripts %}
<script>
window.SONATA_CONFIG = {
CONFIRM_EXIT: {% if admin_pool is defined and admin_pool.getOption('confirm_exit') %}true{% else %}false{% endif %},
USE_SELECT2: {% if admin_pool is defined and admin_pool.getOption('use_select2') %}true{% else %}false{% endif %},
USE_ICHECK: {% if admin_pool is defined and admin_pool.getOption('use_icheck') %}true{% else %}false{% endif %}
};
window.SONATA_TRANSLATIONS = {
CONFIRM_EXIT: '{{ 'confirm_exit'|trans({}, 'SonataAdminBundle')|escape('js') }}'
};
</script>
{% for javascript in admin_pool.getOption('javascripts', []) %}
<script src="{{ asset(javascript) }}" type="text/javascript"></script>
{% endfor %}
{% endblock %}
<title>
{{ 'Admin'|trans({}, 'SonataAdminBundle') }}
{% if _title is not empty %}
{{ _title|raw }}
{% else %}
{% if action is defined %}
-
{% if admin.breadcrumbs is defined %}
{% for menu in admin.breadcrumbs(action) %}
{% if not loop.first %}
&gt;
{% endif %}
{{ menu.label }}
{% endfor %}
{% endif %}
{% endif %}
{% endif%}
</title>
</head>
<body class="sonata-bc {% if _side_menu is empty %}sonata-ba-no-side-menu{% endif %}">
{# initialize block value #}
<div class="container-fluid">
{% block notice %}
{% for notice_level in ['success','error','info', 'warning'] %}
{% set session_var = 'sonata_flash_' ~ notice_level %}
{% for flash in app.session.flashbag.get(session_var) %}
<div class="alert {{ 'alert-' ~ notice_level }}">
{{ flash|trans([], 'SonataAdminBundle') }}
</div>
{% endfor %}
{% endfor %}
{% endblock %}
<div class="row-fluid">
{% if _side_menu is not empty %}
<div class="sidebar span2">
<div class="well sonata-ba-side-menu" style="padding: 8px 0;">{{ _side_menu|raw }}</div>
</div>
{% endif %}
<div class="content {{ _side_menu is not empty ? ' span10' : 'span12' }}">
{% block sonata_admin_content %}
{% if _preview is not empty %}
<div class="sonata-ba-preview">{{ _preview|raw }}</div>
{% endif %}
{% if _list_table is not empty or _list_filters is not empty %}
<div class="row-fluid">
<div class="sonata-ba-filter span2">
{{ _list_filters|raw }}
</div>
<div class="sonata-ba-list span10">
{{ _list_table|raw }}
</div>
</div>
{% endif %}
{% endblock %}
</div>
</div>
</div>
</body>
</html>
<?php
namespace App\Controller\Admin;
use Sonata\MediaBundle\Controller\MediaAdminController as BaseMediaAdminController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
/**
* MediaAdminController.
*
* Adds browser and upload actions to Media entity.
* Adapt from original CoopTilleulsCKEditorSonataMediaBundle
* @Source https://github.com/coopTilleuls/CoopTilleulsCKEditorSonataMediaBundle/blob/master/Controller/MediaAdminController.php
*/
class MediaAdminController extends BaseMediaAdminController {
/**
* Alter create Media action.
*
* @param Request $request
* @return Response
*/
public function createAction(Request $request = null) {
// Prevent anonymous access
$this->admin->checkAccess('create');
// Handle create method in ckeditor
if (!$request->get('provider') && $request->isMethod('get')) {
// Alter the template use to create media
$pool = $this->get('sonata.media.pool');
return $this->render('@SonataMedia/MediaAdmin/select_provider.html.twig', [
'providers' => $pool->getProvidersByContext(
$request->get('context', $pool->getDefaultContext())
),
'action' => 'create',
]);
}
// If this is not the case just call the normal create media action
return parent::createAction($request);
}
/**
* Browse media actions.
*
* @throws AccessDeniedException|\Twig_Error
* @return Response
*/
public function browserAction() {
// Prevent anonymous access
if (false === $this->admin->isGranted('LIST')) {
throw new AccessDeniedException();
}
// Build datagrid of media
$datagrid = $this->admin->getDatagrid();
$datagrid->setValue('context', null, $this->admin->getPersistentParameter('context'));
$datagrid->setValue('providerName', null, $this->admin->getPersistentParameter('provider'));
$formats = [];
foreach ($datagrid->getResults() as $media) {
$formats[$media->getId()] = $this->get('sonata.media.pool')->getFormatNamesByContext($media->getContext());
}
// Build view
$formView = $datagrid->getForm()->createView();
$twig = $this->get('twig');
$twig->getRuntime('Symfony\Component\Form\FormRenderer')->setTheme($formView, $this->admin->getFilterTheme());
return $this->render('admin/media/browser.html.twig', array(
'action' => 'browser',
'form' => $formView,
'datagrid' => $datagrid,
'formats' => $formats,
'base_template' => 'admin/media/layout.html.twig',
));
}
/**
* Upload Media action.
*
* @throws AccessDeniedException
* @return Response
*/
public function uploadAction() {
// Prevent non admin user to access this route
if (false === $this->admin->isGranted('CREATE')) {
throw new AccessDeniedException();
}
// Verify if required parameters are there
$request = $this->getRequest();
$provider = $request->get('provider');
$file = $request->files->get('upload');
if (!$request->isMethod('POST') || !$provider || null === $file) {
throw $this->createNotFoundException();
}
// Create Media entity
$mediaManager = $this->get('sonata.media.manager.media');
$media = $mediaManager->create();
$media->setBinaryContent($file);
$context = $request->get('context', $this->get('sonata.media.pool')->getDefaultContext());
$mediaManager->save($media, $context, $provider);
$this->admin->createObjectSecurity($media);
// Return success response
return new JsonResponse([
'uploaded' => 1,
'fileName' => $media->getName(),
'url' => $this->get($media->getProviderName())->generatePublicUrl($media, 'reference')
]);
}
}
<?php
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdminExtension;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Route\RouteCollection;
/**
* MediaAdminExtension class.
*
* Adds browser and upload routes to the Media Admin.
*/
class MediaAdminExtension extends AbstractAdminExtension
{
/**
* Declare browser and upload routes for Media entity
*
* @param AdminInterface $admin
* @param RouteCollection $collection
*/
public function configureRoutes(AdminInterface $admin, RouteCollection $collection) {
$collection->add('browser', 'browser');
$collection->add('upload', 'upload');
}
}
<?php
namespace App\DependencyInjection\Compiler;
use App\Controller\Admin\MediaAdminController;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Class ReplaceServicesPass.
*/
class ReplaceServicesPass implements CompilerPassInterface {
/**
* During compiler build replace needed class.
*
* @param ContainerBuilder $container
*/
public function process(ContainerBuilder $container) {
// Replace class use for MediaAdminController
$container->getDefinition('sonata.media.admin.media')->setArgument(2, MediaAdminController::class);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment