by

How to integrate bbCode editor to SonataAdmin

Here we came to the real-world application of FMBBCodeBundle, i.e. how to make bbCode editor work in SonataAdmin. The best way is to create new bbCode editor form type.

Of course, all related source code is provided at the bottom of page.

First install SonataAdmin. If you haven’t done this yet, consider checking SonataAdmin’s Installation entry in reference.

The most general case of SonataAdmin installation is described further.

Let’s consider that application bundle is called AppBundle.

1. Install SonataAdmin bundles

Use next composer commands to install necessary bundles:

composer require sonata-project/admin-bundle
composer require sonata-project/doctrine-orm-admin-bundle

2. Enable installed bundles

Add next lines into app/AppKernel.php to enable installed bundles.

<?php

// app/AppKernel.php

public function registerBundles()
{
    return array(
        // ...

        // The admin requires some twig functions defined in the security
        // bundle, like is_granted
        new Symfony\Bundle\SecurityBundle\SecurityBundle(),

        // Add your dependencies
        new Sonata\CoreBundle\SonataCoreBundle(),
        new Sonata\BlockBundle\SonataBlockBundle(),
        new Knp\Bundle\MenuBundle\KnpMenuBundle(),
        //...

        // If you haven't already, add the storage bundle
        // This example uses SonataDoctrineORMAdmin but
        // it works the same with the alternatives
        new Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle(),

        // Then add SonataAdminBundle
        new Sonata\AdminBundle\SonataAdminBundle(),

        // ...
    );
}

Beware, that Symfony\Bundle\SecurityBundle\SecurityBundle could be already enabled, so you have not to enable it twice.

3. Enable Symfony Translator component

Translator component can be enabled by uncommenting following line in app/config/config.yml:

# ...

framework:
    #esi:             ~
    translator:      { fallbacks: ["%locale%"] }

# ...

Othewise, you will get an error:

The “translator” service is not yet enabled.
It’s required by SonataAdmin to display all labels properly.
To learn how to enable the translator service please visit:
http://symfony.com/doc/current/book/translation.html#book-translation-configuration

4. Configure SonataAdmin

Write SonataAdmin configuration to app/config/config.yml:

# app/config/config.yml

# ...

twig:
  # ...
  form_themes:
    - 'AppBundle::fields.html.twig'
    - 'SonataDoctrineORMAdminBundle:Form:form_admin_fields.html.twig'

# ...

sonata_block:
  default_contexts: [ cms ]
  blocks:
    # Enable the SonataAdminBundle block
    sonata.admin.block.admin_list:
      contexts: [ admin ]
    # Your other blocks

AppBundle::fields.html.twig will contain code for new bbCode editor form type. It is important to point, that you mustn’t create two twig sections (at least it didn’t work well for me in Symfony 3.1.1) and add form_themes into existing twig section.

5. Register SonataAdmin routes

Write SonataAdmin routes to app/config/routing.yml.

sonata_admin_routing:
    resource: [email protected]/Resources/config/routing/sonata_admin.xml'
    prefix: /admin
    
_sonata_admin:
    resource: .
    type: sonata_admin
    prefix: /admin

6. Create test entity

Create test entity class src/AppBundle/Entity/Work.php and place there following code:

<?php

// AppBundle/Entity/Work.php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * Work
 *
 * @UniqueEntity(fields="title")
 * @ORM\Table()
 * @ORM\Entity()
 */
class Work
{
  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;

  /**
   * @var string
   *
   * @ORM\Column(name="title", type="string", length=255, unique=true)
   */
  private $title;

  /**
   * @var string
   *
   * @ORM\Column(name="description", type="text")
   */
  private $description;


  public function __toString()
  {
    return $this->title;
  }

  /**
   * Get id
   *
   * @return integer
   */
  public function getId()
  {
    return $this->id;
  }

  /**
   * Set title
   *
   * @param string $title
   * @return Work
   */
  public function setTitle($title)
  {
    $this->title = $title;

    return $this;
  }

  /**
   * Get title
   *
   * @return string
   */
  public function getTitle()
  {
    return $this->title;
  }

  /**
   * Set description
   *
   * @param string $description
   * @return Work
   */
  public function setDescription($description)
  {
    $this->description = $description;

    return $this;
  }

  /**
   * Get description
   *
   * @return string
   */
  public function getDescription()
  {
    return $this->description;
  }
}

7. Update database schema

php bin/console doctrine:schema:update --force

This is needed to create schema for new entity in database.

8. Create admin panel class for test entity

Create admin panel class in src/AppBundle/Admin/WorkAdmin.php and place there next code:

<?php

// AppBundle\Admin\WorkAdmin.php

namespace AppBundle\Admin;

use AppBundle\Entity\Work;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use AppBundle\Form\Type\BBCodeEditorType;

class WorkAdmin extends Admin
{
  // Fields to be shown on create/edit forms
  protected function configureFormFields(FormMapper $formMapper)
  {
    $formMapper
      ->with('General')
        ->add('title', 'text', array('label' => 'Title'))
        ->add('description', BBCodeEditorType::class, array(
            'label' => 'Description',
            'attr' => array(
              'rows' => 10,
              'class' => 'form-control'
            ),
          )
        )
      ->end();
  }

  // Fields to be shown on filter forms
  protected function configureDatagridFilters(DatagridMapper $datagridMapper)
  {
    $datagridMapper
      ->add('title');
  }

  // Fields to be shown on lists
  protected function configureListFields(ListMapper $listMapper)
  {
    $listMapper
      ->addIdentifier('title');
  }
}

9. Register admin panel

Add admin panel configuration into src/AppBundle/Resources/config/admin.yml.

services:
  sonata.admin.work:
    class: AppBundle\Admin\WorkAdmin
    tags:
      - { name: sonata.admin, manager_type: orm, group: "Portfolio", label: "Work" }
    arguments:
      - ~
      - AppBundle\Entity\Work
      - ~
    calls:
      - [ setTranslationDomain, [AppBundle]]

10. Add configuration files to dependency injection container

Add code for dependency injection container into src/AppBundle/DependencyInjection/AppExtension.php, so new form type and admin panel could be registered:

<?php

// AppBundle/DependencyInjection/AppExtension.php

namespace AppBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

/**
 * This is the class that loads and manages your bundle configuration
 *
 * To learn more see [email protected] http://symfony.com/doc/current/cookbook/bundles/extension.html}
 */
class AppExtension extends Extension
{
  /**
   * [email protected]}
   */
  public function load(array $configs, ContainerBuilder $container)
  {
    $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
    $loader->load('admin.yml');
  }
}

11. Create new form type class

Place bbcode_editor form type class into src/AppBundle/Form/Type/BBCodeEditorType.php:

<?php

// AppBundle/Form/Type/BBCodeEditorType.php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;

class BBCodeEditorType extends AbstractType
{
  public function __construct()
  {
  }

  public function buildView(FormView $view, FormInterface $form, array $options)
  {
    // Nothing to do here yet
  }

  public function setDefaultOptions(OptionsResolverInterface $resolver)
  {
    $resolver->setDefaults(array(
      'empty_data' => ''
    ));
  }

  public function getParent()
  {
    return TextareaType::class;
  }

  public function getBlockPrefix()
  {
    return 'bbcode_editor';
  }
}

12. Create new form type view

Place bbcode_editor view into src/AppBundle/Resources/views/fields.html.twig:

{% block bbcode_editor_widget %}
  {% spaceless %}
    <div class="bbcode-editor">
      <textarea {{ block('widget_attributes') }}>{{ value }}</textarea>
    </div>

    <script>
      if (typeof InitializeSCEditor === 'undefined') {
        InitializeSCEditor = function() {
          $('head').append(
            '<link rel="stylesheet" href="{{ asset("bundles/sceditor/themes/square.min.css") }}" type="text/css" media="all" />'
          ).append(
            '<script type="text/javascript" src="{{ asset("bundles/sceditor/jquery.sceditor.bbcode.min.js") }}"><\/script>'
          );

          $('.bbcode-editor textarea').sceditor({
            plugins: 'bbcode',
            style: '{{ asset('bundles/sceditor/jquery.sceditor.default.min.css') }}',
          });

          $.sceditor.BBCodeParser.QuoteType = $.sceditor.BBCodeParser.QuoteType.always;
        };

        $(function () {
          $("body").append("<script>InitializeSCEditor();<\/script>");
        });
      }
    </script>
  {% endspaceless %}
{% endblock %}

SonataAdmin already has link to jQuery in its view’s code, so we don’t place it once again with one more append call.

$('head').append(...)

Done!

Now you can check how beautifully SCEditor works in SonataAdmin for your text field in admin panel on route /web/app_dev.php/admin/app/work/create. 😉

SonataAdmin with bbCode editor

Source code: http://www.mediafire.com/download/9nli23cnm7vyb19/SonataAdmin%2BSCEditor_example.zip

Write a Comment

Comment