SonataAdminBundle : display non crud (statistics)
Asked Answered
S

5

26

I'm using sonata admin bundle to generate my backend, I'm so happy with it that I would like to use my backend to display statistics as well.

I guess I can do that by tweaking bundle's views, "standard_layout.html.twig" maybe.

Problem is, I can't find examples or even people speaking about it, so I'm wondering, is that possible ? Aren't people speaking about it because it's too simple ? Did you do it ?

I really would like to have a single backend, so pls enlighten me !

Thank you, copndz

Soledadsolely answered 12/4, 2013 at 8:30 Comment(0)
S
20

Since pulzarraider explained us one way to do this I'll explain the other.

The block bundle's way allow to custom the dashboard in a pretty powerful way. You can follow Block bundle doc at the same time

1. Create StatisticsBlockService.php in Copndz\MyBundle\Block\Service

I want to display stats by doing maths with data stored : I need to

  • import the EntityManager
  • add attribute $em to the service
  • add constructor __construct which will call its parent constructor and set $em with EntityManager passed in argument

namespace Copndz\MyBundle\Block\Service;
use Symfony\Component\HttpFoundation\Response;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Validator\ErrorElement;
use Sonata\BlockBundle\Model\BlockInterface;
use Sonata\BlockBundle\Block\BaseBlockService;
use Doctrine\ORM\EntityManager;

class StatisticsBlockService extends BaseBlockService
{
    private $em;
    
    /**
     * {@inheritdoc}
     */
    public function execute(BlockInterface $block, Response $response = null)
    {
        $settings = array_merge($this->getDefaultSettings(), $block->getSettings());
        
        $myentityrepository = $this->em->getRepository('CopndzMyBundle:MyEntity');
        $myentity = $myentityrepository->find('5');
        
        return $this->renderResponse('CopndzMyBundle:Block:block_statistics.html.twig', array(
            'block'     => $block,
            'settings'  => $settings,
            'myentity' => $myentity,   
        ), $response);
    }

    /**
     * {@inheritdoc}
     */
    public function validateBlock(ErrorElement $errorElement, BlockInterface $block)
    {
        // TODO: Implement validateBlock() method.
    }

    /**
     * {@inheritdoc}
     */
    public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
    {
        $formMapper->add('settings', 'sonata_type_immutable_array', array(
            'keys' => array(
                array('content', 'textarea', array()),
            )
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'Text (core)';
    }

    /**
     * {@inheritdoc}
     */
    public function getDefaultSettings()
    {
        return array(
            'content' => 'Insert your custom content here',
        );
    }
    
    public function __construct($name, $templating, EntityManager $entityManager)
    {
            parent::__construct($name, $templating);
            $this->em = $entityManager;
    }
}

2. Create the service in MyBundle\Ressources\config\services.yml

 sonata.block.service.statistics:
      class: Copndz\MyBundle\Block\Service\StatisticsBlockService
      tags:
        - { name: sonata.block }
      arguments:
        - "sonata.block.service.statistics"
        - @templating
        - @doctrine.orm.entity_manager

3. Add this service to sonata_block in my config.yml

sonata_block:
    default_contexts: [cms]
    blocks:
        sonata.admin.block.admin_list:
            contexts:   [admin]

        sonata.block.service.text:
        sonata.block.service.rss:
        sonata.block.service.statistics:

4. Create the template block_statistics.html.twig in Copndz\MyBundle\Ressources\views\Block

{% extends sonata_block.templates.block_base %}

{% block block %}
    {{ myentity.name }}
{% endblock %}

5. And finally call the service in the admin bundle configuration in config.yml

sonata_admin:
    dashboard:
        blocks:
            # display a dashboard block
            - { position: left, type: sonata.admin.block.admin_list }
            - { position: right, type: sonata.block.service.statistics }
Soledadsolely answered 15/4, 2013 at 10:22 Comment(2)
I think that may not work with latest version of block bundle, due to some recent change in their code.Soledadsolely
see the last version of official doc here : sonata-project.org/bundles/block/master/doc/reference/…Assurbanipal
G
38

Yes, it`s possible. It can be done with Sonata Block or using your own controller.

If you use your controller, you can overload (one or more) actions from default CRUD controller and how the rendered result will look like depends on you.

  1. Replace default controller SonataAdminBundle:CRUD with your controller AcmeDemoAdminBundle:ProductStatisticsAdmin in definition of your admin service and remove entity because we will try to render our statistics without CRUD operations.

    <service id="acme_demo_admin.product_statistics" class="Acme\Bundle\DemoAdminBundle\Admin\ProductStatisticsAdmin">
        <tag name="sonata.admin" manager_type="orm" group="statistics_group" label_catalogue="admin" label="Product Statistics" />
        <argument />
        <argument />
        <argument>AcmeDemoAdminBundle:ProductStatisticsAdmin</argument>
    </service>
    
  2. Create admin service ProductStatisticsAdmin in Acme/Bundle/DemoAdminBundle/Admin/ProductStatisticsAdmin.php. The class will be very simple, because we will need only list action and no other CRUD operation.

    <?php
    namespace Acme\Bundle\DemoAdminBundle\Admin;
    
    use Sonata\AdminBundle\Admin\Admin;
    use Sonata\AdminBundle\Route\RouteCollection;
    
    class ProductStatisticsAdmin extends Admin
    {
        protected $baseRoutePattern = 'product-statistics';
        protected $baseRouteName = 'productStatistics';
    
        protected function configureRoutes(RouteCollection $collection)
        {
            $collection->clearExcept(array('list'));
        }
    }
    
  3. Create your controller ProductStatisticsAdminController in Acme/Bundle/DemoAdminBundle/Controller/ProductStatisticsAdminController.php and overload listAction() from Sonata`s CRUDController. Inside this action you can call your DB and retrieve statistics and then render them with your template.

    <?php
    
    namespace Acme\Bundle\DemoAdminBundle\Controller;
    
    use Sonata\AdminBundle\Controller\CRUDController as Controller;
    use Symfony\Component\Security\Core\Exception\AccessDeniedException;
    
    class ProductStatisticsAdminController extends Controller
    {
        public function listAction()
        {
            if (false === $this->admin->isGranted('LIST')) {
                throw new AccessDeniedException();
            }
    
            //... use any methods or services to get statistics data
            $statisticsData = ...
    
           return $this->render('AcmeDemoAdminBundle:ProductStatistics:product_statistics.html.twig', array(
                        'statistics_data'  => $statisticsData,
                    ));
        }
    }
    
  4. Create template product_statistics.html.twig to generate graphs and display statistics in Acme/Bundle/DemoAdminBundle/Resources/views/ProductStatistics/product_statistics.html.twig

    {% extends base_template %}
    
    {% block javascripts %}
        {{ parent() }}
        {# put links to javascript libraries here if you need any #}
    {% endblock %}
    
    {% block content %}
        {# put some html code to display statistics data or use some javascript library to generate cool graphs #}
    {% endblock %}
    
Guendolen answered 13/4, 2013 at 11:32 Comment(3)
I'm not sure if this is in the new version of sonata admin only, but I had to add the $baseRouteName to the admin class for it to work properly.Doublequick
This is working in the actual version, too, but it doesn't add the breadcrumbs at the top in 'navbar-left'. Aside from that, good job with this!Turnstile
Work, but Sonata search gives error: "An exception has been thrown during the rendering of a template ("Class does not exist")."Schnorkle
S
20

Since pulzarraider explained us one way to do this I'll explain the other.

The block bundle's way allow to custom the dashboard in a pretty powerful way. You can follow Block bundle doc at the same time

1. Create StatisticsBlockService.php in Copndz\MyBundle\Block\Service

I want to display stats by doing maths with data stored : I need to

  • import the EntityManager
  • add attribute $em to the service
  • add constructor __construct which will call its parent constructor and set $em with EntityManager passed in argument

namespace Copndz\MyBundle\Block\Service;
use Symfony\Component\HttpFoundation\Response;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Validator\ErrorElement;
use Sonata\BlockBundle\Model\BlockInterface;
use Sonata\BlockBundle\Block\BaseBlockService;
use Doctrine\ORM\EntityManager;

class StatisticsBlockService extends BaseBlockService
{
    private $em;
    
    /**
     * {@inheritdoc}
     */
    public function execute(BlockInterface $block, Response $response = null)
    {
        $settings = array_merge($this->getDefaultSettings(), $block->getSettings());
        
        $myentityrepository = $this->em->getRepository('CopndzMyBundle:MyEntity');
        $myentity = $myentityrepository->find('5');
        
        return $this->renderResponse('CopndzMyBundle:Block:block_statistics.html.twig', array(
            'block'     => $block,
            'settings'  => $settings,
            'myentity' => $myentity,   
        ), $response);
    }

    /**
     * {@inheritdoc}
     */
    public function validateBlock(ErrorElement $errorElement, BlockInterface $block)
    {
        // TODO: Implement validateBlock() method.
    }

    /**
     * {@inheritdoc}
     */
    public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
    {
        $formMapper->add('settings', 'sonata_type_immutable_array', array(
            'keys' => array(
                array('content', 'textarea', array()),
            )
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'Text (core)';
    }

    /**
     * {@inheritdoc}
     */
    public function getDefaultSettings()
    {
        return array(
            'content' => 'Insert your custom content here',
        );
    }
    
    public function __construct($name, $templating, EntityManager $entityManager)
    {
            parent::__construct($name, $templating);
            $this->em = $entityManager;
    }
}

2. Create the service in MyBundle\Ressources\config\services.yml

 sonata.block.service.statistics:
      class: Copndz\MyBundle\Block\Service\StatisticsBlockService
      tags:
        - { name: sonata.block }
      arguments:
        - "sonata.block.service.statistics"
        - @templating
        - @doctrine.orm.entity_manager

3. Add this service to sonata_block in my config.yml

sonata_block:
    default_contexts: [cms]
    blocks:
        sonata.admin.block.admin_list:
            contexts:   [admin]

        sonata.block.service.text:
        sonata.block.service.rss:
        sonata.block.service.statistics:

4. Create the template block_statistics.html.twig in Copndz\MyBundle\Ressources\views\Block

{% extends sonata_block.templates.block_base %}

{% block block %}
    {{ myentity.name }}
{% endblock %}

5. And finally call the service in the admin bundle configuration in config.yml

sonata_admin:
    dashboard:
        blocks:
            # display a dashboard block
            - { position: left, type: sonata.admin.block.admin_list }
            - { position: right, type: sonata.block.service.statistics }
Soledadsolely answered 15/4, 2013 at 10:22 Comment(2)
I think that may not work with latest version of block bundle, due to some recent change in their code.Soledadsolely
see the last version of official doc here : sonata-project.org/bundles/block/master/doc/reference/…Assurbanipal
L
15

Actually using blocks and creating separate pages are a little bit different. I think the OP is trying to create separate page inside sonata admin.

  1. Create a controller, configure its routes in routing.yml file, set a prefix same as sonata admin's prefix if you want the URL to appear similar to sonata admin.

  2. Render the template. There is two trick here.

    First you need to extend from sonata admin's "layout" template. If you have changed it in config.yml, update the code accordingly. Ref

    {% extends "SonataAdminBundle::standard_layout.html.twig" %}
    

    Now you'll see sonata admin's menu bar and footer has come to this new page. But the menu is empty. To show the menu, you need to pass admin_pool from controller to template.

    $admin_pool = $this->get('sonata.admin.pool');
    
    return array(
        'admin_pool' => $admin_pool,
        // Other variables to pass to template
    );
    
Lavellelaven answered 12/5, 2014 at 17:3 Comment(2)
Thank you, this was simple and exactly what I needed!Reinke
I got this error: Variable "admin" does not exist in app/Resources/views/base.html.twig at line 84Combes
C
1

Here is another solution to your Problem: http://blog.eike.se/2014/03/custom-page-controller-in-sonata-admin.html

Cassiani answered 19/3, 2014 at 13:15 Comment(1)
Link only answers are discouraged as they tend to break. Please pull the relevant portion of your link into this answer so that the information is available, even if the other site is not.Assam
W
0

I believe what you're trying to acheive could be done using the Sonata Block Bundle part of Sonata Admin Bundle.

Documentation for Sonata Admin Dashboard http://sonata-project.org/bundles/admin/2-1/doc/reference/dashboard.html

I have not done it myself though.

Weiler answered 12/4, 2013 at 11:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.