Files
chill-bundles/docs/source/development/user-interface/widgets.md

10 KiB

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".

Widgets

Rationale

Widgets are useful if you want to publish content on a page provided by another bundle.

Examples :

  • you want to publish a list of people on the homepage ;
  • you may want to show the group belonging (see [group-bundle[) below of the vertical menu, only if the bundle is installed.

The administrator of the chill instance may configure the presence of widget. Although, some widget are defined by default (see declaring-widget-by-default).

Concepts

A bundle may define place(s) where a widget may be rendered.

In a single place, zero, one or more widget may be displayed.

Some widget may require some configuration, and some does not require any configuration.

Example:

=========================================== ======== ============================= ======================================= Use case place place defined by... widget provided by... =========================================== ======== ============================= ======================================= Publishing a list of people on the homepage homepage defined by main-bundle widget provided by person-bundle =========================================== ======== ============================= =======================================

Creating a widget without configuration

To add a widget, you should :

  • define your widget, implementing :class:Chill\MainBundle\Templating\Widget\WidgetInterface ;
  • declare your widget with tag chill_widget.

Define the widget class

Define your widget class by implemeting :class:Chill\MainBundle\Templating\Widget\WidgetInterface.

Example :

namespace Chill\PersonBundle\Widget;

use Chill\MainBundle\Templating\Widget\WidgetInterface;

/**

  • Add a button "add a person"

*/ class AddAPersonWidget implements WidgetInterface { public function render( \Twig_Environment $env, $place, array $context, array $config ) { // this will render a link to the page "add a person" return $env->render("ChillPersonBundle:Widget:homepage_add_a_person.html.twig"); } }

Arguments are :

  • $env the :class:\Twig_Environment, which you can use to render your widget ;

  • $place a string representing the place where the widget is rendered ;

  • $context the context given by the template ;

  • $config the configuration which is, in this case, always an empty array (see creating-a-widget-with-config).

    The html returned by the render function will be considered as html safe. You should strip html before returning it. See also `How to escape output in template ](http://symfony.com/doc/current/templating/escaping.html.md)_.

Declare your widget

Declare your widget as a service and add it the tag chill_widget:

service: chill_person.widget.add_person: class: Chill\PersonBundle\Widget\AddAPersonWidget tags: - { name: chill_widget, alias: add_person, place: homepage }

The tag must contains those arguments :

  • alias: an alias, which will be used to reference the widget into the config
  • place: a place where this widget is authorized

If you want your widget to be available on multiple places, you should add one tag with each place.

Conclusion

Once your widget is correctly declared, your widget should be available in configuration.

$ php app/console config:dump-reference chill_main

Default configuration for extension with alias: "chill_main"

chill_main: [...] # register widgets on place "homepage" homepage:

       # the ordering of the widget. May be a number with decimal
       order:                ~ # Required, Example: 10.58

       # the widget alias (see your installed bundles config). Possible values are (maybe incomplete) : person_list, add_person
       widget_alias:         ~ # Required

If you want to add your widget by default, see [declaring-widget-by-default`.

Creating a widget with configuration

You can declare some configuration with your widget, which allow administrators to add their own configuration.

To add some configuration, you will :

  • declare a widget as defined above ;
  • optionnaly declare it as a service ;
  • add a widget factory, which will add configuration to the bundle which provide the place.

Declare your widget class

Declare your widget. You can use some configuration elements in your process, as used here :

:language: php

Declare your widget as a service

You can declare your widget as a service. Not tag is required, as the service will be defined by the Factory during next step.

services: chill_person.widget.person_list: class: Chill\PersonBundle\Widget\PersonListWidget arguments: - "@chill.person.repository.person" - "@doctrine.orm.entity_manager" - "@chill.main.security.authorization.helper" - "@security.token_storage" # this widget is defined by the PersonListWidgetFactory

You can eventually skip this step and declare your service into the container through the factory (see above).

Declare your widget factory

The widget factory must implements Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface. For your convenience, an :class:Chill\MainBundle\DependencyInjection\Widget\Factory\AbstractWidgetFactory will already implements some easy method.

:language: php

You can declare your widget into the container by overriding the createDefinition method. By default, this method will return the already existing service definition with the id given by getServiceId. But you can create or adapt programmatically the definition. `See the symfony doc on how to do it ](http://symfony.com/doc/current/service_container/definitions.html#working-with-a-definition.md)_.

   public function createDefinition(ContainerBuilder $containerBuilder, $place, $order, array $config)
   {
       $definition = new \Symfony\Component\DependencyInjection\Definition('my\Class');
       // create or adapt your definition here
      return $definition;
  }

You must then register your factory into the Extension class which provide the place. This is done in the Bundle class.

# Chill/PersonBundle/ChillPersonBundle.php

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Chill\PersonBundle\Widget\PersonListWidgetFactory;

class ChillPersonBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
    parent::build($container);

    $container->getExtension('chill_main')
	->addWidgetFactory(new PersonListWidgetFactory());
}
}

Declaring a widget by default

Use the ability `to prepend configuration of other bundle ](http://symfony.com/doc/current/bundles/prepend_extension.html). A living example here :

:language: php

Defining a place

Add your place in template

A place should be defined by using the [chill_widget` function, which take as argument :

  • place (string) a string defining the place ;
  • context (array) an array defining the context.

The context should be documented by the bundle. It will give some information about the context of the page. Example: if the page concerns a people, the :class:Chill\PersonBundle\Entity\Person class will be in the context.

Example :

{# an empty context on homepage #} {{ chill_widget('homepage', {} }}

{# defining a place 'right column' with the person currently viewed {{ chill_widget('right_column', { 'person' : person } }}

Declare configuration for you place

In order to let other bundle, or user, to define the widgets inside the given place, you should open a configuration. You can use the Trait :class:Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait, which provide the method addWidgetConfiguration($place, ContainerBuilder $container).

Example :

:language: php :emphasize-lines: 17, 30, 32, 52 :linenos:

You should also adapt the :class:DependencyInjection\*Extension class to add ContainerBuilder and WidgetFactories :

:language: php :emphasize-lines: 25-39, 48-49, 56 :linenos:

  • line 25-39: we implements the method required by :class:Chill\MainBundle\DependencyInjection\Widget\HasWidgetExtensionInterface ;
  • line 48-49: we record the configuration of widget into container's parameter ;
  • line 56 : we create an instance of :class:Configuration (declared above)

Compile the possible widget using Compiler pass

For your convenience, simply extends :class:Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass. This class provides a doProcess(ContainerBuildere $container, $extension, $parameterName) method which will do the job for you:

  • $container is the container builder

  • $extension is the extension name

  • $parameterName is the name of the parameter which contains the configuration for widgets (see the example with ChillMain above .

    namespace Chill\MainBundle\DependencyInjection\CompilerPass;

    use Symfony\Component\DependencyInjection\ContainerBuilder; use Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass;

    /**

    • Compile the service definition to register widgets.

    */ class WidgetsCompilerPass extends AbstractWidgetsCompilerPass {

     public function process(ContainerBuilder $container)
     {
     $this->doProcess($container, 'chill_main', 'chill_main.widgets');
     }
    

    }

As explained `in the symfony docs ](http://symfony.com/doc/current/service_container/compiler_passes.html), you should register your Compiler Pass into your bundle :

namespace Chill\MainBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use Chill\MainBundle\DependencyInjection\CompilerPass\WidgetsCompilerPass;

class ChillMainBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass(new WidgetsCompilerPass()); } }