Version

Documentation » Block

4. Profiler »

« 2. Twig Helpers

3. You first block

This quick tutorial explains how to create a RSS reader block.

A block service is just a service which must implements the BlockServiceInterface interface. There is only one instance of a block service, however there are many block instances.

3.1. First namespaces

The BaseBlockService implements some basic methods defined by the interface. The current Rss block will extend this base class. The others use statements are required by the interface and remaining methods.

<?php
namespace Sonata\BlockBundle\Block;

use Symfony\Component\HttpFoundation\Response;

use Sonata\BlockBundle\Model\BlockInterface;

use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Validator\ErrorElement;

3.2. Default settings

A block service needs settings to work properly, so to ensure consistency, the service should define a getDefaultSettings method. In the current tutorial, the default settings are:

  • url : the feed url
  • title : the block title
<?php
function getDefaultSettings()
{
    return array(
        'url'     => false,
        'title'   => 'Insert the rss title'
    );
}

3.3. Form Edition

The BlockBundle relies on the AdminBundle to manage form edition and keep a good consistency.

<?php
public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
{
    $formMapper->add('settings', 'sonata_type_immutable_array', array(
        'keys' => array(
            array('url', 'url', array('required' => false)),
            array('title', 'text', array('required' => false)),
        )
    ));
}

The validation is done at runtime through a validateBlock method. You can call any Symfony2 assertions, like :

<?php
function validateBlock(ErrorElement $errorElement, BlockInterface $block)
{
    $errorElement
        ->with('settings.url')
            ->assertNotNull(array())
            ->assertNotBlank()
        ->end()
        ->with('settings.title')
            ->assertNotNull(array())
            ->assertNotBlank()
            ->assertMaxLength(array('limit' => 50))
        ->end();
}

The sonata_type_immutable_array type is a specific form type which allows to edit an array.

3.4. Execute

The next step is the execute method, this method must return a Response object, this object is used to render the block.

<?php
public function execute(BlockInterface $block, Response $response = null)
{
    // merge settings
    $settings = array_merge($this->getDefaultSettings(), $block->getSettings());

    $feeds = false;
    if ($settings['url']) {
        $options = array(
            'http' => array(
                'user_agent' => 'Sonata/RSS Reader',
                'timeout' => 2,
            )
        );

        // retrieve contents with a specific stream context to avoid php errors
        $content = @file_get_contents($settings['url'], false, stream_context_create($options));

        if ($content) {
            // generate a simple xml element
            try {
                $feeds = new \SimpleXMLElement($content);
                $feeds = $feeds->channel->item;
            } catch(\Exception $e) {
                // silently fail error
            }
        }
    }

    return $this->renderResponse('SonataBlockBundle:Block:block_core_rss.html.twig', array(
        'feeds'     => $feeds,
        'block'     => $block,
        'settings'  => $settings
    ), $response);
}

3.5. Template

A block template is very simple, in the current tutorial, we are looping on feeds or if not defined, a error message is displayed.

{% extends sonata_block.templates.block_base %}

{% block block %}
    <h3>{{ settings.title }}</h3>

    <div class="sonata-feeds-container">
        {% for feed in feeds %}
            <div>
                <strong><a href="{{ feed.link}}" rel="nofollow" title="{{ feed.title }}">{{ feed.title }}</a></strong>
                <div>{{ feed.description|raw }}</div>
            </div>
        {% elsefor %}
            No feeds available.
        {% endfor %}
    </div>
{% endblock %}

3.6. Service

We are almost done! Now just declare the block as a service

<service id="sonata.block.service.rss" class="Sonata\BlockBundle\Block\Service\RssBlockService" public="false">
    <tag name="sonata.block" />
    <argument>sonata.block.service.rss</argument>
    <argument type="service" id="templating" />
</service>

and add it to sonata configuration

#config.yml
sonata_block:
    blocks:
        sonata.block.service.rss:
#           cache: sonata.cache.memcached

Found a typo? Something is wrong in this documentation? Just fork and edit it!