Skip to content

Instantly share code, notes, and snippets.

@yann-eugone
Last active August 13, 2018 07:49
Show Gist options
  • Save yann-eugone/8b7414e02aedd0dc75e9e22481d68e63 to your computer and use it in GitHub Desktop.
Save yann-eugone/8b7414e02aedd0dc75e9e22481d68e63 to your computer and use it in GitHub Desktop.
Automatically Register Sonata Admin services
<?php
namespace App\Admin\Translator;
use Sonata\AdminBundle\Translator\LabelTranslatorStrategyInterface;
class EntityTranslatorStrategy implements LabelTranslatorStrategyInterface
{
/**
* @var string
*/
private $code;
public function __construct(string $code)
{
$this->code = $code;
}
/**
* @inheritDoc
*/
public function getLabel($label, $context = '', $type = ''): string
{
if ($type === 'link' && $context === 'breadcrumb') {
return sprintf(
'%s.breadcrumb.%s',
$this->code,
$this->underscore(substr(strrchr($label, '_'), 1))
);
}
if ($type === 'label') {
$type = 'field';
}
return sprintf(
'%s.%s.%s',
$this->code,
$type,
$this->underscore(str_replace('.', '_', $label))
);
}
private function underscore(string $string): string
{
return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $string));
}
}
<?php
namespace App;
use App\DependencyInjection\RegisterAdminPass;
//...
class Kernel extends BaseKernel implements CompilerPassInterface
{
//...
protected function build(ContainerBuilder $container)
{
$container->addCompilerPass(
new RegisterAdminPass(),
PassConfig::TYPE_BEFORE_OPTIMIZATION,
10 // higher priority so service are created before the sonata admin compiler pass
);
}
}
<?php
namespace App\DependencyInjection;
use App\Admin\Translator\EntityTranslatorStrategy;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
class RegisterAdminPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
$camelize = function (string $string): string {
return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', str_replace('\\', '', $string)));
};
foreach (array_keys($container->findTaggedServiceIds('sonata.admin_to_register')) as $adminClass) {
if (!preg_match('#^App\\\\Admin\\\\([\w\\\\]+)Admin$#', $adminClass, $matches)) {
continue;
}
$entityClass = sprintf('App\\Entity\\%s', $matches[1]);
if (!class_exists($entityClass)) {
continue;
}
$controllerClass = sprintf('App\\Controller\\Admin\\%sController', $matches[1]);
$controller = null;
if (class_exists($controllerClass)) {
$controller = $controllerClass;
}
$code = $camelize($matches[1]);
$label = sprintf('%s.name', $code);
$definition = new Definition($adminClass);
$definition
->setAutowired(true)
->setArguments(
[null, $entityClass, $controller]
)
->addTag('sonata.admin', ['manager_type' => 'orm', 'label' => $label])
->addMethodCall('setTranslationDomain', ['admin'])
->addMethodCall(
'setLabelTranslatorStrategy',
[new Definition(EntityTranslatorStrategy::class, [$code])]
)
;
$container->setDefinition(sprintf('admin.%s', $code), $definition);
}
}
}
services:
# default configuration for services in *this* file
_defaults:
autowire: true
autoconfigure: true
public: false
_instanceof:
Sonata\AdminBundle\Admin\AdminInterface:
tags: ['sonata.admin_to_register']
App\:
resource: '../src/*'
exclude: '../src/{Entity,Kernel.php}'
@yann-eugone
Copy link
Author

yann-eugone commented Jun 9, 2018

Considering that

  • the admin class App\Admin\PostAdmin exists
  • the entity App\Entity\Post exists
  • a controller App\Controller\Admin\PostController exists (optional)

Then, this snippet will register your admin like if you did the following :

services:
    admin.post:
        class: App\Admin\PostAdmin
        arguments: [ null, App\Entity\Post, App\Controller\Admin\PostController ]
        calls:
            -
                - setLabelTranslatorStrategy
                -
                    - !service
                        class: App\Admin\Translator\EntityTranslatorStrategy
                        arguments: [post]
            - [ setTranslationDomain, [admin] ]
        tags:
            - { name: sonata.admin, manager_type: orm, label: post.name }

And the EntityTranslatorStragegy will allow you to use this kind of translation structure

post:
  name: Posts
  breadcrumb:
    list: Posts
    create: New post
  tab:
    content: Content
    comments: Comments
  fieldset:
    general: General information
    taxonomy: Taxonomy
  field:
    author: Author
    category: Category
    content: Content
    published_at: Published at
    tags: Tags
    title: Title
    uri: URI

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment