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 :
-
$envthe :class:\Twig_Environment, which you can use to render your widget ; -
$placea string representing the place where the widget is rendered ; -
$contextthe context given by the template ; -
$configthe configuration which is, in this case, always an empty array (see creating-a-widget-with-config).The html returned by the
renderfunction 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 configplace: 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:
-
$containeris the container builder -
$extensionis the extension name -
$parameterNameis 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()); } }