mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
334 lines
12 KiB
ReStructuredText
334 lines
12 KiB
ReStructuredText
.. Copyright (C) 2016 Champs Libres Cooperative SCRLFS
|
|
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 :ref:`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 :ref:`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 :ref:`main-bundle` widget provided by :ref:`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 :
|
|
|
|
.. code-block:: php
|
|
|
|
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 :
|
|
|
|
- :code:`$env` the :class:`\Twig_Environment`, which you can use to render your widget ;
|
|
- :code:`$place` a string representing the place where the widget is rendered ;
|
|
- :code:`$context` the context given by the template ;
|
|
- :code:`$config` the configuration which is, in this case, always an empty array (see :ref:`creating-a-widget-with-config`).
|
|
|
|
.. note::
|
|
|
|
The html returned by the :code:`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>`_.
|
|
|
|
|
|
Declare your widget
|
|
-------------------
|
|
|
|
Declare your widget as a service and add it the tag :code:`chill_widget`:
|
|
|
|
.. code-block:: yaml
|
|
|
|
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 :
|
|
|
|
- :code:`alias`: an alias, which will be used to reference the widget into the config
|
|
- :code:`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.
|
|
|
|
.. code-block:: bash
|
|
|
|
$ 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 :ref:`declaring-widget-by-default`.
|
|
|
|
.. _creating-a-widget-with-config:
|
|
|
|
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 :
|
|
|
|
.. literalinclude:: ./widgets/ChillPersonAddAPersonWidget.php
|
|
: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 :code:`Factory` during next step.
|
|
|
|
|
|
.. code-block:: yaml
|
|
|
|
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.
|
|
|
|
.. literalinclude:: ./widgets/ChillPersonAddAPersonListWidgetFactory.php
|
|
:language: php
|
|
|
|
.. note::
|
|
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 :code:`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>`_.
|
|
|
|
.. code-block:: php
|
|
|
|
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 :code:`Extension` class which provide the place. This is done in the :code: `Bundle` class.
|
|
|
|
.. code-block:: php
|
|
|
|
# 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-widget-by-default:
|
|
|
|
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 :
|
|
|
|
.. literalinclude:: ./widgets/ChillPersonExtension.php
|
|
:language: php
|
|
|
|
|
|
Defining a place
|
|
================
|
|
|
|
Add your place in template
|
|
--------------------------
|
|
|
|
A place should be defined by using the :code:`chill_widget` function, which take as argument :
|
|
|
|
- :code:`place` (string) a string defining the place ;
|
|
- :code:`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 :
|
|
|
|
.. code-block:: html+jinja
|
|
|
|
{# an empty context on homepage #}
|
|
{{ chill_widget('homepage', {} }}
|
|
|
|
.. code-block:: html+jinja
|
|
|
|
{# 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 :
|
|
|
|
.. literalinclude:: ./widgets/ChillMainConfiguration.php
|
|
:language: php
|
|
:emphasize-lines: 17, 30, 32, 52
|
|
:linenos:
|
|
|
|
.. _example-chill-main-extension:
|
|
|
|
You should also adapt the :class:`DependencyInjection\*Extension` class to add ContainerBuilder and WidgetFactories :
|
|
|
|
.. literalinclude:: ./widgets/ChillMainExtension.php
|
|
: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:
|
|
|
|
- :code:`$container` is the container builder
|
|
- :code:`$extension` is the extension name
|
|
- :code:`$parameterName` is the name of the parameter which contains the configuration for widgets (see :ref:`the example with ChillMain above <example-chill-main-extension>`.
|
|
|
|
.. code-block:: php
|
|
|
|
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 :
|
|
|
|
.. code-block:: php
|
|
|
|
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());
|
|
}
|
|
}
|
|
|
|
|