📜 ⬆️ ⬇️

Administrative Interface with SonataAdminBundle

The basic delivery of symfony 2 provides only minimal functionality for creating a CRUD interface . To implement the administrative interface, a number of bundles have been developed, in particular SonataAdminBundle .

What is it for?



With the help of SonataAdminBundle, you can quickly create a configurable interface for editing entities of the ORM model ( bundles for working with MongoDb and PHPCr are also highlighted , but they are still at an early stage of development). At the same time, any part of the interface can be customized. At the end of October 2011, the design was transferred to the Twitter Boostrap framework, so the appearance of the administrative interface is quite modern.

Installation and Basic Configuration


In the deps file, you need to add code to install SonataAdminBundle and additional bundles:
[SonataAdminBundle] git=http://github.com/sonata-project/SonataAdminBundle.git target=/bundles/Sonata/AdminBundle [SonataDoctrineORMAdminBundle] git=http://github.com/sonata-project/SonataDoctrineORMAdminBundle.git target=/bundles/Sonata/DoctrineORMAdminBundle [SonatajQueryBundle] git=http://github.com/sonata-project/SonatajQueryBundle.git target=/bundles/Sonata/jQueryBundle [KnpMenuBundle] git=https://github.com/KnpLabs/KnpMenuBundle.git target=/bundles/Knp/Bundle/MenuBundle [KnpMenu] git=https://github.com/KnpLabs/KnpMenu.git target=/knp/menu 

And then run
 php bin/vendors install 

In the file app / autoload.php you need to add new namespaces, in the file app / AppKernel.php initialization of the installed bundles
 <?php // app/autoload.php $loader->registerNamespaces(array( // ... 'Sonata' => __DIR__.'/../vendor/bundles', 'Knp\Bundle' => __DIR__.'/../vendor/bundles', 'Knp\Menu' => __DIR__.'/../vendor/knp/menu/src', // ... )); // app/AppKernel.php public function registerBundles() { return array( // ... new Sonata\AdminBundle\SonataAdminBundle(), new Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle(), new Knp\Bundle\MenuBundle\KnpMenuBundle(), new Sonata\jQueryBundle\SonatajQueryBundle(), // ... ); } 

In app / config / routing.yml, add the routing for the administrative interface:
 # app/config/routing.yml admin: resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml' prefix: /admin _sonata_admin: resource: . type: sonata_admin prefix: /admin 

And write to the web directory css, js, etc. from the installed bundles
 php app/console assets:install web 

To add a password to the administrative interface, you can use either the regular authorization of Symfony 2, or install an additional bundle FOSUserBundle
')
In the file app / config / config.yml, you can set a title and logo, as well as override the administrative interface templates. First, add an administrative interface header:
 sonata_admin: title: . 

To enable the translator service, you need to modify the app / config / config.yml:
  framework: translator: { fallback: %locale% } 

After installation, when contacting http: // localhost / admin / dashboard (we assume that Symfony 2 is installed on the site named http: // localhost ), an empty administrative interface is displayed for which the entity administration services have not yet been registered.

Note: Translator and IE

In order for the translator component to define the Russian accept-language, you need to add in the IE settings in the Internet Options / General / Languages ​​Russian language with a code ru-Ru

Usage example


As an example, let's create an administrative interface for editing news, whose entities are described in the article Creating a CRUD Application on Symfony 2 . The sources of the entities used can be viewed on Github .

SonataAdminBundle uses the architecture in which the description of the administrative interface is made through a special class Admin in which the configuration of the editing form, the list of records, the search form of records, the record display page is performed. This principle was borrowed from the Django project.

Classes {Entity Name} Admin


To edit news, news links and news categories, you need to create 3 classes in the Test / NewsBundle / Admin directory: NewsAdmin, NewsLinkAdmin and NewsCategoryAdmin:
 <?php namespace Test\NewsBundle\Admin; use Sonata\AdminBundle\Admin\Admin; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Show\ShowMapper; use Knp\Menu\ItemInterface as MenuItemInterface; class NewsAdmin extends Admin { /** *    * * @param \Sonata\AdminBundle\Show\ShowMapper $showMapper * @return void */ protected function configureShowField(ShowMapper $showMapper) { $showMapper ->add('id', null, array('label' => '')) ->add('title', null, array('label' => '')) ->add('announce', null, array('label' => '')) ->add('text', null, array('label' => '')) ->add('pubDate', null, array('label' => ' ')) ->add('newsLinks', null, array('label' => '  ')) ->add('newsCategory', null, array('label' => '')); } /** *     * @param \Sonata\AdminBundle\Form\FormMapper $formMapper * @return void */ protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('title', null, array('label' => '')) ->add('announce', null, array('label' => '')) ->add('text', null, array('label' => '')) ->add('pubDate', null, array('label' => ' ')) //by_reference            //  Symfony Form Framework,  setter  News::setNewsLinks ->add('newsLinks', 'sonata_type_collection', array('label' => '', 'by_reference' => false), array( 'edit' => 'inline', //  NewsLink   pos,      //  sortable        'sortable' => 'pos', 'inline' => 'table', )) ->add('newsCategory', null, array('label' => '')) ->setHelps(array( 'title' => '  ', 'pubDate' => '    ' )); } /** *    * * @param \Sonata\AdminBundle\Datagrid\ListMapper $listMapper * @return void */ protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('id') ->addIdentifier('title', null, array('label' => '')) ->add('pubDate', null, array('label' => ' ')) ->add('newsCategory', null, array('label' => '')); } /** * ,        * * @param \Sonata\AdminBundle\Datagrid\DatagridMapper $datagridMapper * @return void */ protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('title', null, array('label' => '')); } /** *         * * @param \Knp\Menu\ItemInterface $menu * @param $action * @param null|\Sonata\AdminBundle\Admin\Admin $childAdmin * * @return void */ protected function configureSideMenu(MenuItemInterface $menu, $action, Admin $childAdmin = null) { $menu->addChild( $action == 'edit' ? ' ' : ' ', array('uri' => $this->generateUrl( $action == 'edit' ? 'show' : 'edit', array('id' => $this->getRequest()->get('id')))) ); } } 

The administrative class for news links contains only the configureFormFields method, since news links are edited with the news:
 <?php namespace Test\NewsBundle\Admin; use Sonata\AdminBundle\Admin\Admin; use Sonata\AdminBundle\Form\FormMapper; class NewsLinkAdmin extends Admin { /** * @param \Sonata\AdminBundle\Form\FormMapper $formMapper * @return void */ protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('url', null, array('label' => 'URL', 'required' => true)) ->add('text', null, array('label' => '')); } } 

NewsCategoryAdmin is created by analogy with NewsAdmin. Sources of administrative classes can be viewed on Github .

Registration of adminstrative services


The administrative class must be registered as a service, for which it must be registered in Test / NewsBundle / Resources / config / services.xml. For administrative interface services, a “sonata.admin” tag is specified, allowing them to be distinguished from other services. The name of the group of menu items (attribute “group”) and the name of the menu item (attribute “label”) are also indicated - these data are used to build the administrative interface menu. In our case, the menu item for editing links to news in the main menu does not need to be shown, because they are entered on the news editing page. Therefore, for the service c id = “test.news.admin.newsLink” we set the show_in_dashboard attribute = “false”.

In the above example, the services use the standard SonataAdminBundle: CRUD controller, however, if necessary, you can create your own controllers.
 <?xml version="1.0" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="test.news.admin.news" class="Test\NewsBundle\Admin\NewsAdmin"> <tag name="sonata.admin" manager_type="orm" group="" label=""/> <argument/> <argument>Test\NewsBundle\Entity\News</argument> <argument>SonataAdminBundle:CRUD</argument> </service> <service id="test.news.admin.newsLink" class="Test\NewsBundle\Admin\NewsLinkAdmin"> <tag name="sonata.admin" manager_type="orm" show_in_dashboard="false" /> <argument/> <argument>Test\NewsBundle\Entity\NewsLink</argument> <argument>SonataAdminBundle:CRUD</argument> </service> <service id="test.news.admin.newsCategory" class="Test\NewsBundle\Admin\NewsCategoryAdmin"> <tag name="sonata.admin" manager_type="orm" group="" label=" "/> <argument/> <argument>Test\NewsBundle\Entity\NewsCategory</argument> <argument>SonataAdminBundle:CRUD</argument> </service> </services> </container> 

What happened


After rebooting, the administrative interface looks like this:


Clicking on the “News / List” link displays a list of news with the ability to filter posts:



The page for editing the new one looks like this:


Changing the position of bound entities


Links linked to news are added without reloading the page. In the essence of "NewsLink" added field pos, which is sorted when requesting links to the news. Specifying the option 'sortable' => 'pos' for the type of the sonata_type_collection field adds to the interface the ability to change the order of the news by dragging the rows of the table:



However, to change the position of the link reflected in the database, you need to add the NewsAdmin class (not sure if the solution is correct, but at least it works):
 #src/Test/NewsBundle/Admin/NewsAdmin.php class NewsAdmin { .. /** *      * @param $news   * @return void */ public function preUpdate($news) { //     $emptyObj = $this->getNewInstance(); // ,     onfigureFormFields  NewsAdmin, //     //      -    ,  //  NewsLink  ,    html- //(        NewsLink) //     NewsLink   -  ,   Doctrine $this->getForm()->setData($emptyObj)->bindRequest($this->getRequest()); $newLinkPos = array(); //  NewsLink foreach ($emptyObj->getNewsLinks() as $link) $newLinkPos[] = $link->getUrl(); $newLinkPos = array_flip($newLinkPos); //     foreach ($news->getNewsLinks() as $pos => $link) $link->setPos($newLinkPos[$link->getUrl()]); } .. } 

Navigation


In the basic delivery of SonataAdminBundle there is the Russian localization of the standard names of buttons, headers, etc. In order for the localization to be complete, for the created sections of the administrative interface, you need to create header translations that are automatically created based on the names of entities, for example, News List, News Create. To do this, in the Test / NewsBundle / Resources / translations directory, you need to create the file files.ru.ru.xliff (you can read about the broadcast service here )

Attention! In the tags </ sour with e> in the example below, the English c is replaced with Russian with , otherwise the code formatting flies



 <?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="ru" datatype="plaintext" original="" > <body> <trans-unit id="News List"> <source>News List</soure> <target> </target> </trans-unit> <trans-unit id="News Create"> <source>News Create</soure> <target> </target> </trans-unit> <trans-unit id="News Edit"> <source>News Edit</soure> <target> </target> </trans-unit> <trans-unit id="News Category List"> <source>News Category List< soure> <target>  </target> </trans-unit> <trans-unit id="News Category Create"> <source>News Category Create</soure> <target>  </target> </trans-unit> <trans-unit id="News Category Edit"> <source>News Category Edit</soure> <target>  </target> </trans-unit> </body> </file> </xliff> 

Conclusion


The result was a functional, extensible record editing interface. All templates and controllers used by SonataAdmin can be overridden in the application configuration. Developers based on SonataAdmin have made several useful bundles for developing web applications that implement a number of basic functions: SonataUserBundle (user management), SonataNewsBundle (blog), SonataMediaBundle (media resource management) and SonataPageBundle (prototype CMS). A big problem is poor documentation, especially SonataPageBundle, although at first it’s an interesting product.

Update 2012-07-20: the current version of the article with the innovations of symfony 2.1 is here

Source: https://habr.com/ru/post/136659/


All Articles