mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
replacing delegated_block api by widget api
This commit is contained in:
parent
812aeac3d7
commit
a3e7c60e01
@ -9,6 +9,8 @@ use Chill\MainBundle\DependencyInjection\ConfigConsistencyCompilerPass;
|
|||||||
use Chill\MainBundle\DependencyInjection\TimelineCompilerClass;
|
use Chill\MainBundle\DependencyInjection\TimelineCompilerClass;
|
||||||
use Chill\MainBundle\DependencyInjection\RoleProvidersCompilerPass;
|
use Chill\MainBundle\DependencyInjection\RoleProvidersCompilerPass;
|
||||||
use Chill\MainBundle\DependencyInjection\CompilerPass\ExportsCompilerPass;
|
use Chill\MainBundle\DependencyInjection\CompilerPass\ExportsCompilerPass;
|
||||||
|
use Chill\MainBundle\DependencyInjection\CompilerPass\WidgetsCompilerPass;
|
||||||
|
|
||||||
|
|
||||||
class ChillMainBundle extends Bundle
|
class ChillMainBundle extends Bundle
|
||||||
{
|
{
|
||||||
@ -20,5 +22,6 @@ class ChillMainBundle extends Bundle
|
|||||||
$container->addCompilerPass(new TimelineCompilerClass());
|
$container->addCompilerPass(new TimelineCompilerClass());
|
||||||
$container->addCompilerPass(new RoleProvidersCompilerPass());
|
$container->addCompilerPass(new RoleProvidersCompilerPass());
|
||||||
$container->addCompilerPass(new ExportsCompilerPass());
|
$container->addCompilerPass(new ExportsCompilerPass());
|
||||||
|
$container->addCompilerPass(new WidgetsCompilerPass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2016 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace Chill\MainBundle\DependencyInjection;
|
namespace Chill\MainBundle\DependencyInjection;
|
||||||
|
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
@ -7,20 +24,43 @@ use Symfony\Component\Config\FileLocator;
|
|||||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
use Symfony\Component\DependencyInjection\Loader;
|
use Symfony\Component\DependencyInjection\Loader;
|
||||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||||
|
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
||||||
|
use Chill\MainBundle\DependencyInjection\Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the class that loads and manages your bundle configuration
|
* This class load config for chillMainExtension.
|
||||||
*
|
|
||||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
|
|
||||||
*/
|
*/
|
||||||
class ChillMainExtension extends Extension implements PrependExtensionInterface
|
class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||||
|
Widget\HasWidgetFactoriesExtensionInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* widget factory
|
||||||
|
*
|
||||||
|
* @var WidgetFactoryInterface[]
|
||||||
|
*/
|
||||||
|
protected $widgetFactories = array();
|
||||||
|
|
||||||
|
public function addWidgetFactory(WidgetFactoryInterface $factory)
|
||||||
|
{
|
||||||
|
$this->widgetFactories[] = $factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return WidgetFactoryInterface[]
|
||||||
|
*/
|
||||||
|
public function getWidgetFactories()
|
||||||
|
{
|
||||||
|
return $this->widgetFactories;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public function load(array $configs, ContainerBuilder $container)
|
public function load(array $configs, ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$configuration = new Configuration();
|
// configuration for main bundle
|
||||||
|
$configuration = $this->getConfiguration($configs, $container);
|
||||||
$config = $this->processConfiguration($configuration, $configs);
|
$config = $this->processConfiguration($configuration, $configs);
|
||||||
|
|
||||||
$container->setParameter('chill_main.installation_name',
|
$container->setParameter('chill_main.installation_name',
|
||||||
@ -34,14 +74,25 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface
|
|||||||
|
|
||||||
$container->setParameter('chill_main.pagination.item_per_page',
|
$container->setParameter('chill_main.pagination.item_per_page',
|
||||||
$config['pagination']['item_per_page']);
|
$config['pagination']['item_per_page']);
|
||||||
|
|
||||||
|
// add the key 'widget' without the key 'enable'
|
||||||
|
$container->setParameter('chill_main.widgets',
|
||||||
|
array('homepage' => $config['widgets']['homepage']));
|
||||||
|
|
||||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||||
$loader->load('services.yml');
|
$loader->load('services.yml');
|
||||||
$loader->load('services/logger.yml');
|
$loader->load('services/logger.yml');
|
||||||
$loader->load('services/repositories.yml');
|
$loader->load('services/repositories.yml');
|
||||||
$loader->load('services/pagination.yml');
|
$loader->load('services/pagination.yml');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getConfiguration(array $config, ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
return new Configuration($this->widgetFactories, $container);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function prepend(ContainerBuilder $container)
|
public function prepend(ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$bundles = $container->getParameter('kernel.bundles');
|
$bundles = $container->getParameter('kernel.bundles');
|
||||||
@ -57,7 +108,8 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface
|
|||||||
|
|
||||||
//add installation_name and date_format to globals
|
//add installation_name and date_format to globals
|
||||||
$chillMainConfig = $container->getExtensionConfig($this->getAlias());
|
$chillMainConfig = $container->getExtensionConfig($this->getAlias());
|
||||||
$config = $this->processConfiguration(new Configuration(), $chillMainConfig);
|
$config = $this->processConfiguration($this
|
||||||
|
->getConfiguration($chillMainConfig, $container), $chillMainConfig);
|
||||||
$twigConfig = array(
|
$twigConfig = array(
|
||||||
'globals' => array(
|
'globals' => array(
|
||||||
'installation' => array(
|
'installation' => array(
|
||||||
|
34
DependencyInjection/CompilerPass/WidgetsCompilerPass.php
Normal file
34
DependencyInjection/CompilerPass/WidgetsCompilerPass.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
@ -4,14 +4,34 @@ namespace Chill\MainBundle\DependencyInjection;
|
|||||||
|
|
||||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||||
|
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
||||||
|
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||||
|
use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the class that validates and merges configuration from your app/config files
|
* Configure the main bundle
|
||||||
*
|
|
||||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
|
|
||||||
*/
|
*/
|
||||||
class Configuration implements ConfigurationInterface
|
class Configuration implements ConfigurationInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
|
use AddWidgetConfigurationTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var ContainerBuilder
|
||||||
|
*/
|
||||||
|
private $containerBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(array $widgetFactories = array(),
|
||||||
|
ContainerBuilder $containerBuilder)
|
||||||
|
{
|
||||||
|
$this->setWidgetFactories($widgetFactories);
|
||||||
|
$this->containerBuilder = $containerBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@ -25,18 +45,18 @@ class Configuration implements ConfigurationInterface
|
|||||||
->scalarNode('installation_name')
|
->scalarNode('installation_name')
|
||||||
->cannotBeEmpty()
|
->cannotBeEmpty()
|
||||||
->defaultValue('Chill')
|
->defaultValue('Chill')
|
||||||
->end()
|
->end() // end of scalar 'installation_name'
|
||||||
->arrayNode('available_languages')
|
->arrayNode('available_languages')
|
||||||
->defaultValue(array('fr'))
|
->defaultValue(array('fr'))
|
||||||
->prototype('scalar')->end()
|
->prototype('scalar')->end()
|
||||||
->end()
|
->end() // end of array 'available_languages'
|
||||||
->arrayNode('routing')
|
->arrayNode('routing')
|
||||||
->children()
|
->children()
|
||||||
->arrayNode('resources')
|
->arrayNode('resources')
|
||||||
->prototype('scalar')->end()
|
->prototype('scalar')->end()
|
||||||
->end()
|
->end() // end of array 'resources'
|
||||||
->end()
|
->end() // end of children
|
||||||
->end()
|
->end() // end of array node 'routing'
|
||||||
->arrayNode('pagination')
|
->arrayNode('pagination')
|
||||||
->canBeDisabled()
|
->canBeDisabled()
|
||||||
->children()
|
->children()
|
||||||
@ -44,11 +64,20 @@ class Configuration implements ConfigurationInterface
|
|||||||
->info('The number of item to show in the page result, by default')
|
->info('The number of item to show in the page result, by default')
|
||||||
->min(1)
|
->min(1)
|
||||||
->defaultValue(50)
|
->defaultValue(50)
|
||||||
->end()
|
->end() // end of integer 'item_per_page'
|
||||||
->end()
|
->end() // end of children
|
||||||
->end()
|
->end() // end of pagination
|
||||||
->end();
|
->arrayNode('widgets')
|
||||||
|
->canBeDisabled()
|
||||||
|
->children()
|
||||||
|
->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder))
|
||||||
|
->end() // end of widgets/children
|
||||||
|
->end() // end of widgets
|
||||||
|
->end() // end of root/children
|
||||||
|
->end() // end of root
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
return $treeBuilder;
|
return $treeBuilder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
388
DependencyInjection/Widget/AbstractWidgetsCompilerPass.php
Normal file
388
DependencyInjection/Widget/AbstractWidgetsCompilerPass.php
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\DependencyInjection\Widget;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||||
|
use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
|
||||||
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
|
use Symfony\Component\DependencyInjection\Definition;
|
||||||
|
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
||||||
|
use Chill\MainBundle\DependencyInjection\Widget\HasWidgetFactoriesExtensionInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile the configurations and inject required service into container.
|
||||||
|
*
|
||||||
|
* The widgets are services tagged with :
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* { name: chill_widget, alias: my_alias, place: my_place }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Or, if the tag does not exist or if you need to add some config to your
|
||||||
|
* service depending on the config, you should use a `WidgetFactory` (see
|
||||||
|
* `WidgetFactoryInterface`.
|
||||||
|
*
|
||||||
|
* To reuse this compiler pass, simple execute the doProcess metho in your
|
||||||
|
* compiler. Example :
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* namespace Chill\MainBundle\DependencyInjection\CompilerPass;
|
||||||
|
*
|
||||||
|
* use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
* use Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass;
|
||||||
|
* class WidgetsCompilerPass extends AbstractWidgetsCompilerPass {
|
||||||
|
*
|
||||||
|
* public function process(ContainerBuilder $container)
|
||||||
|
* {
|
||||||
|
* $this->doProcess($container, 'chill_main', 'chill_main.widgets');
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
|
||||||
|
{
|
||||||
|
private $widgetServices = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var WidgetFactoryInterface[]
|
||||||
|
*/
|
||||||
|
private $widgetFactories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service which will manage the widgets
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const WIDGET_MANAGER = 'chill.main.twig.widget';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the method wich register the widget into give service.
|
||||||
|
*/
|
||||||
|
const WIDGET_MANAGER_METHOD_REGISTER = 'addWidget';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the value of the `name` key in service definitions's tag
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const WIDGET_SERVICE_TAG_NAME = 'chill_widget';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the key used to collect the alias in the service definition's tag.
|
||||||
|
* the alias must be
|
||||||
|
* injected into the configuration under 'alias' key.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const WIDGET_SERVICE_TAG_ALIAS = 'alias';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the key used to collect the authorized place in the service definition's tag
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const WIDGET_SERVICE_TAG_PLACES = 'place';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the key to use to order widget for a given place
|
||||||
|
*/
|
||||||
|
const WIDGET_CONFIG_ORDER = 'order';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the key to use to identify widget for a given place
|
||||||
|
*/
|
||||||
|
const WIDGET_CONFIG_ALIAS = 'widget_alias';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* process the configuration and the container to add the widget available
|
||||||
|
*
|
||||||
|
* @param ContainerBuilder $container
|
||||||
|
* @param string $extension the extension of your bundle
|
||||||
|
* @param string $containerWidgetConfigParameterName the key under which we can use the widget configuration
|
||||||
|
* @throws \LogicException
|
||||||
|
* @throws \UnexpectedValueException if the given extension does not implement HasWidgetExtensionInterface
|
||||||
|
* @throws \InvalidConfigurationException if there are errors in the config
|
||||||
|
*/
|
||||||
|
public function doProcess(ContainerBuilder $container, $extension,
|
||||||
|
$containerWidgetConfigParameterName)
|
||||||
|
{
|
||||||
|
if (!$container->hasDefinition(self::WIDGET_MANAGER)) {
|
||||||
|
throw new \LogicException("the service ".self::WIDGET_MANAGER." should".
|
||||||
|
" be present. It is required by ".self::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
$managerDefinition = $container->getDefinition(self::WIDGET_MANAGER);
|
||||||
|
|
||||||
|
// collect the widget factories
|
||||||
|
/* @var $extensionClass HasWidgetFactoriesExtensionInterface */
|
||||||
|
$extensionClass = $container->getExtension($extension);
|
||||||
|
// throw an error if extension does not implement HasWidgetFactoriesExtensionInterface
|
||||||
|
if (!$extensionClass instanceof HasWidgetFactoriesExtensionInterface) {
|
||||||
|
throw new \UnexpectedValueException(sprintf("The extension for %s "
|
||||||
|
. "do not implements %s. You should implement %s on %s",
|
||||||
|
$extension,
|
||||||
|
HasWidgetFactoriesExtensionInterface::class,
|
||||||
|
HasWidgetFactoriesExtensionInterface::class,
|
||||||
|
get_class($extensionClass)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$this->widgetFactories = $extensionClass->getWidgetFactories();
|
||||||
|
|
||||||
|
// collect the availabled tagged services
|
||||||
|
$this->collectTaggedServices($container);
|
||||||
|
|
||||||
|
// collect the widgets and their config :
|
||||||
|
$widgetParameters = $container->getParameter($containerWidgetConfigParameterName);
|
||||||
|
|
||||||
|
// and add them to the delegated_block
|
||||||
|
foreach($widgetParameters as $place => $widgets) {
|
||||||
|
|
||||||
|
foreach ($widgets as $param) {
|
||||||
|
$alias = $param[self::WIDGET_CONFIG_ALIAS];
|
||||||
|
// check that the service exists
|
||||||
|
if (!array_key_exists($alias, $this->widgetServices)) {
|
||||||
|
throw new InvalidConfigurationException(sprintf("The alias %s".
|
||||||
|
" is not defined.", $alias));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the widget is allowed at this place
|
||||||
|
if (!$this->isPlaceAllowedForWidget($place, $alias, $container)) {
|
||||||
|
throw new \InvalidConfigurationException(sprintf(
|
||||||
|
"The widget with alias %s is not allowed at place %s",
|
||||||
|
$alias,
|
||||||
|
$place
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the order, eventually corrected
|
||||||
|
$order = $this->cacheAndGetOrdering($place, $param[self::WIDGET_CONFIG_ORDER]);
|
||||||
|
|
||||||
|
// register the widget with config to the service, using the method
|
||||||
|
// `addWidget`
|
||||||
|
if ($this->widgetServices[$alias] instanceof WidgetFactoryInterface) {
|
||||||
|
/* @var $factory WidgetFactoryInterface */
|
||||||
|
$factory = $this->widgetServices[$alias];
|
||||||
|
// get the config (under the key which equals to widget_alias
|
||||||
|
$config = isset($param[$factory->getWidgetAlias()]) ?
|
||||||
|
$param[$factory->getWidgetAlias()] : array();
|
||||||
|
// register the service into the container
|
||||||
|
$serviceId =$this->registerServiceIntoContainer($container,
|
||||||
|
$factory, $place, $order, $config);
|
||||||
|
|
||||||
|
$managerDefinition->addMethodCall(self::WIDGET_MANAGER_METHOD_REGISTER,
|
||||||
|
array(
|
||||||
|
$place,
|
||||||
|
$order,
|
||||||
|
new Reference($serviceId),
|
||||||
|
$config
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$managerDefinition->addMethodCall(self::WIDGET_MANAGER_METHOD_REGISTER,
|
||||||
|
array(
|
||||||
|
$place,
|
||||||
|
$order,
|
||||||
|
new Reference($this->widgetServices[$alias]),
|
||||||
|
array() // the config is alway an empty array
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register the service into container.
|
||||||
|
*
|
||||||
|
* @param ContainerBuilder $container
|
||||||
|
* @param WidgetFactoryInterface $factory
|
||||||
|
* @param string $place
|
||||||
|
* @param float $order
|
||||||
|
* @param array $config
|
||||||
|
* @return string the id of the new service
|
||||||
|
*/
|
||||||
|
protected function registerServiceIntoContainer(
|
||||||
|
ContainerBuilder $container,
|
||||||
|
WidgetFactoryInterface $factory,
|
||||||
|
$place,
|
||||||
|
$order,
|
||||||
|
array $config
|
||||||
|
) {
|
||||||
|
$serviceId = $factory->getServiceId($container, $place, $order, $config);
|
||||||
|
$definition = $factory->createDefinition($container, $place,
|
||||||
|
$order, $config);
|
||||||
|
$container->setDefinition($serviceId, $definition);
|
||||||
|
|
||||||
|
return $serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cache of ordering by place.
|
||||||
|
*
|
||||||
|
* @internal used by function cacheAndGetOrdering
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $cacheOrdering = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if the ordering has already be used for the given $place and,
|
||||||
|
* if yes, correct the ordering by incrementation of 1 until the ordering
|
||||||
|
* has not be used.
|
||||||
|
*
|
||||||
|
* recursive method.
|
||||||
|
*
|
||||||
|
* @param string $place
|
||||||
|
* @param float $ordering
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
private function cacheAndGetOrdering($place, $ordering) {
|
||||||
|
// create a key in the cache array if not exists
|
||||||
|
if (!array_key_exists($place, $this->cacheOrdering)) {
|
||||||
|
$this->cacheOrdering[$place] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the order exists
|
||||||
|
if (array_search($ordering, $this->cacheOrdering[$place])) {
|
||||||
|
// if the order exists, increment of 1 and try again
|
||||||
|
return $this->cacheAndGetOrdering($place, $ordering + 1);
|
||||||
|
} else {
|
||||||
|
// cache the ordering
|
||||||
|
$this->cacheOrdering[$place] = $ordering;
|
||||||
|
|
||||||
|
return $ordering;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the places where the service is allowed
|
||||||
|
*
|
||||||
|
* @param Definition $definition
|
||||||
|
* @return unknown
|
||||||
|
*/
|
||||||
|
private function isPlaceAllowedForWidget($place, $widgetAlias, ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
if ($this->widgetServices[$widgetAlias] instanceof WidgetFactoryInterface) {
|
||||||
|
if (in_array($place, $this->widgetServices[$widgetAlias]
|
||||||
|
->getAllowedPlaces())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$definition = $container->findDefinition($this->widgetServices[$widgetAlias]);
|
||||||
|
|
||||||
|
foreach($definition->getTag(self::WIDGET_SERVICE_TAG_NAME) as $attrs) {
|
||||||
|
$placeValue = $attrs[self::WIDGET_SERVICE_TAG_PLACES];
|
||||||
|
|
||||||
|
if ($placeValue === $place) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method collect all service tagged with `self::WIDGET_SERVICE_TAG`, and
|
||||||
|
* add also the widget defined by factories
|
||||||
|
*
|
||||||
|
* This method also check that the service is correctly tagged with `alias` and
|
||||||
|
* `places`, or the factory give a correct alias and more than one place.
|
||||||
|
*
|
||||||
|
* @param ContainerBuilder $container
|
||||||
|
* @throws InvalidConfigurationException
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected function collectTaggedServices(ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
// first, check the service tagged in service definition
|
||||||
|
foreach ($container->findTaggedServiceIds(self::WIDGET_SERVICE_TAG_NAME) as $id => $attrs) {
|
||||||
|
foreach ($attrs as $attr) {
|
||||||
|
|
||||||
|
// check the alias is set
|
||||||
|
if (!isset($attr[self::WIDGET_SERVICE_TAG_ALIAS])) {
|
||||||
|
throw new InvalidConfigurationException("you should add an ".self::WIDGET_SERVICE_TAG_ALIAS.
|
||||||
|
" key on the service ".$id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the place is set
|
||||||
|
if (!isset($attr[self::WIDGET_SERVICE_TAG_PLACES])) {
|
||||||
|
throw new InvalidConfigurationException(sprintf(
|
||||||
|
"You should add a %s key on the service %s",
|
||||||
|
self::WIDGET_SERVICE_TAG_PLACES,
|
||||||
|
$id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the alias does not exists yet
|
||||||
|
if (array_key_exists($attr[self::WIDGET_SERVICE_TAG_ALIAS], $this->widgetServices)) {
|
||||||
|
throw new InvalidArgumentException("a service has already be defined with the ".
|
||||||
|
self::WIDGET_SERVICE_TAG_ALIAS." ".$attr[self::WIDGET_SERVICE_TAG_ALIAS]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// register the service as available
|
||||||
|
$this->widgetServices[$attr[self::WIDGET_SERVICE_TAG_ALIAS]] = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the services defined by factories
|
||||||
|
foreach($this->widgetFactories as $factory) {
|
||||||
|
/* @var $factory WidgetFactoryInterface */
|
||||||
|
$alias = $factory->getWidgetAlias();
|
||||||
|
|
||||||
|
// check the alias is not empty
|
||||||
|
if (empty($alias)) {
|
||||||
|
throw new \LogicException(sprintf(
|
||||||
|
"the widget factory %s returns an empty alias",
|
||||||
|
get_class($factory)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the places are not empty
|
||||||
|
if (!is_array($factory->getAllowedPlaces())) {
|
||||||
|
throw new \UnexpectedValueException("the method 'getAllowedPlaces' "
|
||||||
|
. "should return a non-empty array. Unexpected value on ".
|
||||||
|
get_class($factory));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($factory->getAllowedPlaces()) == 0) {
|
||||||
|
throw new \LengthException("The method 'getAllowedPlaces' should "
|
||||||
|
. "return a non-empty array, but returned 0 elements on ".
|
||||||
|
get_class($factory).'::getAllowedPlaces()');
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the alias does not exists yet
|
||||||
|
if (array_key_exists($alias, $this->widgetServices)) {
|
||||||
|
throw new InvalidArgumentException("a service has already be defined with the ".
|
||||||
|
self::WIDGET_SERVICE_TAG_ALIAS." ".$alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
// register the factory as available
|
||||||
|
$this->widgetServices[$factory->getWidgetAlias()] = $factory;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
243
DependencyInjection/Widget/AddWidgetConfigurationTrait.php
Normal file
243
DependencyInjection/Widget/AddWidgetConfigurationTrait.php
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\DependencyInjection\Widget;
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass as WidgetsCompilerPass;
|
||||||
|
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This trait allow to add automatic configuration for widget inside your config.
|
||||||
|
*
|
||||||
|
* Usage
|
||||||
|
* ======
|
||||||
|
*
|
||||||
|
* 1. Register widget factories
|
||||||
|
* ----------------------------
|
||||||
|
*
|
||||||
|
* Add widget factories, using `setWidgetFactories`
|
||||||
|
*
|
||||||
|
* Example :
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
* use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
|
||||||
|
*
|
||||||
|
* class MyConfig
|
||||||
|
* {
|
||||||
|
*
|
||||||
|
* use addWidgetConfigurationTrait;
|
||||||
|
*
|
||||||
|
* public function __construct(array $widgetFactories = array(), ContainerBuilder $container)
|
||||||
|
* {
|
||||||
|
* $this->setWidgetFactories($widgetFactories);
|
||||||
|
* // will be used on next step
|
||||||
|
* $this->container = $container;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 2. add widget config to your config
|
||||||
|
* -----------------------------------
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
* use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
|
||||||
|
* use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||||
|
*
|
||||||
|
* class MyConfig
|
||||||
|
* {
|
||||||
|
*
|
||||||
|
* use addWidgetConfigurationTrait;
|
||||||
|
*
|
||||||
|
* private $container;
|
||||||
|
*
|
||||||
|
* public function __construct(array $widgetFactories = array(), ContainerBuilder $container)
|
||||||
|
* {
|
||||||
|
* $this->setWidgetFactories($widgetFactories);
|
||||||
|
* $this->container;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public function getConfigTreeBuilder()
|
||||||
|
* {
|
||||||
|
* $treeBuilder = new TreeBuilder();
|
||||||
|
* $root = $treeBuilder->root('my_root');
|
||||||
|
*
|
||||||
|
* $root->children()
|
||||||
|
* ->arrayNode('widgets')
|
||||||
|
* ->canBeDisabled()
|
||||||
|
* ->children()
|
||||||
|
* ->append($this->addWidgetsConfiguration('homepage', $this->container))
|
||||||
|
* ->end()
|
||||||
|
* ->end()
|
||||||
|
* ;
|
||||||
|
*
|
||||||
|
* return $treeBuilder;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* the above code will add to the config :
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* widgets:
|
||||||
|
* enabled: true
|
||||||
|
*
|
||||||
|
* # register widgets on place "homepage"
|
||||||
|
* homepage:
|
||||||
|
* order: ~ # Required
|
||||||
|
* widget_alias: ~ # One of "person_list"; "add_person", Required
|
||||||
|
* person_list:
|
||||||
|
* # options for the person_list
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
trait AddWidgetConfigurationTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param WidgetFactoryInterface[]
|
||||||
|
*/
|
||||||
|
private $widgetFactories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param WidgetFactoryInterface[] $widgetFactories
|
||||||
|
*/
|
||||||
|
public function setWidgetFactories(array $widgetFactories)
|
||||||
|
{
|
||||||
|
$this->widgetFactories = $widgetFactories;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return WidgetFactoryInterface[]
|
||||||
|
*/
|
||||||
|
public function getWidgetFactories()
|
||||||
|
{
|
||||||
|
return $this->widgetFactories;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add configuration nodes for the widget at the given place.
|
||||||
|
*
|
||||||
|
* @param type $place
|
||||||
|
* @param ContainerBuilder $containerBuilder
|
||||||
|
* @return type
|
||||||
|
*/
|
||||||
|
protected function addWidgetsConfiguration($place, ContainerBuilder $containerBuilder)
|
||||||
|
{
|
||||||
|
$treeBuilder = new TreeBuilder();
|
||||||
|
$root = $treeBuilder->root($place)
|
||||||
|
->canBeUnset()
|
||||||
|
->info('register widgets on place "'.$place.'"');
|
||||||
|
|
||||||
|
// if no childen, return the root
|
||||||
|
if (count(iterator_to_array($this->filterWidgetByPlace($place))) === 0) {
|
||||||
|
return $root;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prototypeChildren = $root->prototype('array')->children();
|
||||||
|
|
||||||
|
$prototypeChildren
|
||||||
|
->floatNode(WidgetsCompilerPass::WIDGET_CONFIG_ORDER)
|
||||||
|
->isRequired()
|
||||||
|
->info("the ordering of the widget. May be a number with decimal")
|
||||||
|
->example("10.58")
|
||||||
|
->end()
|
||||||
|
->enumNode(WidgetsCompilerPass::WIDGET_CONFIG_ALIAS)
|
||||||
|
->values($this->getWidgetAliasesbyPlace($place, $containerBuilder))
|
||||||
|
->info("the widget alias (see config for your bundle)")
|
||||||
|
->isRequired()
|
||||||
|
->end()
|
||||||
|
;
|
||||||
|
|
||||||
|
// adding the possible config on each widget under the widget_alias
|
||||||
|
foreach ($this->filterWidgetByPlace($place) as $factory) {
|
||||||
|
$builder = new TreeBuilder();
|
||||||
|
$widgetOptionsRoot = $builder->root($factory->getWidgetAlias());
|
||||||
|
$widgetOptionsRoot->canBeUnset()
|
||||||
|
->info(sprintf('the configuration for the widget "%s" (only required if this widget is set in widget_alias)',
|
||||||
|
$factory->getWidgetAlias()));
|
||||||
|
$factory->configureOptions($place, $widgetOptionsRoot->children());
|
||||||
|
$prototypeChildren->append($widgetOptionsRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all widget factories for the given place.
|
||||||
|
*
|
||||||
|
* @param string $place
|
||||||
|
* @return \Generator a generator containing a widget factory
|
||||||
|
*/
|
||||||
|
protected function filterWidgetByPlace($place)
|
||||||
|
{
|
||||||
|
foreach($this->widgetFactories as $factory) {
|
||||||
|
if (in_array($place, $factory->getAllowedPlaces())) {
|
||||||
|
yield $factory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the all possible aliases for the given place. This method
|
||||||
|
* search within service tags and widget factories
|
||||||
|
*
|
||||||
|
* @param type $place
|
||||||
|
* @param ContainerBuilder $containerBuilder
|
||||||
|
* @return type
|
||||||
|
* @throws InvalidConfigurationException if a service's tag does not have the "alias" key
|
||||||
|
*/
|
||||||
|
protected function getWidgetAliasesbyPlace($place, ContainerBuilder $containerBuilder)
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach ($this->filterWidgetByPlace($place) as $factory) {
|
||||||
|
$result[] = $factory->getWidgetAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
// append the aliases added without factory
|
||||||
|
foreach ($containerBuilder
|
||||||
|
->findTaggedServiceIds(WidgetsCompilerPass::WIDGET_SERVICE_TAG_NAME)
|
||||||
|
as $serviceId => $tags) {
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
// throw an error if no alias in definition
|
||||||
|
if (!array_key_exists(WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS, $tag)) {
|
||||||
|
throw new InvalidConfigurationException(sprintf(
|
||||||
|
"The service with id %s does not have any %d key",
|
||||||
|
$serviceId,
|
||||||
|
WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// add the key to the possible results
|
||||||
|
$result[] = $tag[WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
57
DependencyInjection/Widget/Factory/AbstractWidgetFactory.php
Normal file
57
DependencyInjection/Widget/Factory/AbstractWidgetFactory.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\DependencyInjection\Widget\Factory;
|
||||||
|
|
||||||
|
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow to easily create WidgetFactory.
|
||||||
|
*
|
||||||
|
* Extending this factory, the widget will be created using the already defined
|
||||||
|
* service created "as other services" in your configuration (the most frequent
|
||||||
|
* way is using `services.yml` file.
|
||||||
|
*
|
||||||
|
* If you need to create different service based upon place, position or
|
||||||
|
* definition, you should implements directly
|
||||||
|
* `Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface`
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract class AbstractWidgetFactory implements WidgetFactoryInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* Will create the definition by returning the definition from the `services.yml`
|
||||||
|
* file (or `services.xml` or `what-you-want.yml`).
|
||||||
|
*
|
||||||
|
* @see \Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface::createDefinition()
|
||||||
|
*/
|
||||||
|
public function createDefinition(ContainerBuilder $containerBuilder, $place, $order, array $config)
|
||||||
|
{
|
||||||
|
return $containerBuilder->getDefinition($this
|
||||||
|
->getServiceId($containerBuilder, $place, $order, $config)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
DependencyInjection/Widget/Factory/WidgetFactoryInterface.php
Normal file
103
DependencyInjection/Widget/Factory/WidgetFactoryInterface.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\DependencyInjection\Widget\Factory;
|
||||||
|
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for creating configuration of widgets.
|
||||||
|
*
|
||||||
|
* When you need a widget with some configuration, you should implements this
|
||||||
|
* interface on a factory. The factory will add configuration to the bundle
|
||||||
|
* giving the places for your widget.
|
||||||
|
*
|
||||||
|
* Using this interface, **you do not need** to define the service in your
|
||||||
|
* container configuration (`services.yml` files).
|
||||||
|
*
|
||||||
|
* Once the class is created, you should inject the factory inside the container
|
||||||
|
* at compile time, in your `Bundle` class :
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* namespace Chill\PersonBundle;
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
* // register a widget factory into chill_main :
|
||||||
|
* $container->getExtension('chill_main')
|
||||||
|
* ->addWidgetFactory(new PersonListWidgetFactory());
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface WidgetFactoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* configure options for the widget. Those options will be added in
|
||||||
|
* configuration in the bundle where the widget will be used.
|
||||||
|
*
|
||||||
|
* @param type $place
|
||||||
|
* @param NodeBuilder $node
|
||||||
|
*/
|
||||||
|
public function configureOptions($place, NodeBuilder $node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the widget alias. This alias will be used in configuration (`config.yml`)
|
||||||
|
*/
|
||||||
|
public function getWidgetAlias();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a definition for the service which will render the widget.
|
||||||
|
*
|
||||||
|
* (Note: you can define the service by yourself, as other services,
|
||||||
|
* using the `AbstractWidgetFactory`)
|
||||||
|
*
|
||||||
|
* @param ContainerBuilder $containerBuilder
|
||||||
|
* @param type $place
|
||||||
|
* @param type $order
|
||||||
|
* @param array $config
|
||||||
|
*/
|
||||||
|
public function createDefinition(ContainerBuilder $containerBuilder, $place, $order, array $config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the service id to build the widget.
|
||||||
|
*
|
||||||
|
* @param ContainerBuilder $containerBuilder
|
||||||
|
* @param string $place
|
||||||
|
* @param float $order
|
||||||
|
* @param array $config
|
||||||
|
*
|
||||||
|
* @return string the service definition
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getServiceId(ContainerBuilder $containerBuilder, $place, $order, array $config);
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\DependencyInjection\Widget;
|
||||||
|
|
||||||
|
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register widget factories to an extension.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface HasWidgetFactoriesExtensionInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register a widget factory
|
||||||
|
*
|
||||||
|
* @param \Chill\MainBundle\DependencyInjection\Widget\WidgetFactoryInterface $factory
|
||||||
|
*/
|
||||||
|
public function addWidgetFactory(WidgetFactoryInterface $factory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all the widget factories registered for this extension
|
||||||
|
*
|
||||||
|
* @return WidgetFactoryInterface[]
|
||||||
|
*/
|
||||||
|
public function getWidgetFactories();
|
||||||
|
}
|
@ -58,8 +58,8 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: twig.extension }
|
- { name: twig.extension }
|
||||||
|
|
||||||
chill.main.twig.delegated_block:
|
chill.main.twig.widget:
|
||||||
class: Chill\MainBundle\Templating\DelegatedBlockRenderingTwig
|
class: Chill\MainBundle\Templating\Widget\WidgetRenderingTwig
|
||||||
arguments:
|
arguments:
|
||||||
- "@event_dispatcher"
|
- "@event_dispatcher"
|
||||||
tags:
|
tags:
|
||||||
|
@ -137,6 +137,10 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="homepage_widget">
|
||||||
|
{{ chill_delegated_block('homepage', {} ) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="padding-top:2em; padding-bottom:2em;">
|
<div style="padding-top:2em; padding-bottom:2em;">
|
||||||
{{ chill_menu('homepage', {
|
{{ chill_menu('homepage', {
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Chill\MainBundle\Templating;
|
|
||||||
|
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the function `chill_delegated_block`.
|
|
||||||
*
|
|
||||||
* In a template, you can now allow rendering of a block from other bundle.
|
|
||||||
*
|
|
||||||
* The layout template must explicitly call the rendering of other block,
|
|
||||||
* with the twig function
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* chill_delegated_block('block_name', { 'array' : 'with context' } )
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* This will launch an event
|
|
||||||
* `Chill\MainBundle\Templating\Events\DelegatedBlockRenderingEvent` with
|
|
||||||
* the event's name 'chill_block.block_name'.
|
|
||||||
*
|
|
||||||
* You may add content to the page using the function
|
|
||||||
* `DelegatedBlockRenderingEvent::addContent`.
|
|
||||||
*
|
|
||||||
* See also the documentation of
|
|
||||||
* `Chill\MainBundle\Templating\Events\DelegatedBlockRenderingEvent`
|
|
||||||
* for usage of this event class
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
|
||||||
*/
|
|
||||||
class DelegatedBlockRenderingTwig extends \Twig_Extension
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @var EventDispatcherInterface
|
|
||||||
*/
|
|
||||||
protected $eventDispatcher;
|
|
||||||
|
|
||||||
public function __construct(EventDispatcherInterface $eventDispatcher)
|
|
||||||
{
|
|
||||||
$this->eventDispatcher = $eventDispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'chill_main_delegated_block';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFunctions()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
new \Twig_SimpleFunction('chill_delegated_block',
|
|
||||||
array($this, 'renderingDelegatedBlock'),
|
|
||||||
array('is_safe' => array('html')))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderingDelegatedBlock($block, array $context)
|
|
||||||
{
|
|
||||||
$event = new Events\DelegatedBlockRenderingEvent($context);
|
|
||||||
|
|
||||||
$this->eventDispatcher->dispatch('chill_block.'.$block, $event);
|
|
||||||
|
|
||||||
return $event->getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
10
Templating/Widget/WidgetInterface.php
Normal file
10
Templating/Widget/WidgetInterface.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Templating\Widget;
|
||||||
|
|
||||||
|
use Twig_Environment;
|
||||||
|
|
||||||
|
interface WidgetInterface
|
||||||
|
{
|
||||||
|
public function render(Twig_Environment $env, $place, array $context, array $config);
|
||||||
|
}
|
160
Templating/Widget/WidgetRenderingTwig.php
Normal file
160
Templating/Widget/WidgetRenderingTwig.php
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Templating\Widget;
|
||||||
|
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Chill\MainBundle\Templating\Widget\WidgetInterface;
|
||||||
|
use Chill\MainBundle\Templating\Events\DelegatedBlockRenderingEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the function `chill_delegated_block`.
|
||||||
|
*
|
||||||
|
* In a template, you can now allow rendering of a block from other bundle.
|
||||||
|
*
|
||||||
|
* The layout template must explicitly call the rendering of other block,
|
||||||
|
* with the twig function
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* chill_delegated_block('block_name', { 'array' : 'with context' } )
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This will launch an event
|
||||||
|
* `Chill\MainBundle\Templating\Events\DelegatedBlockRenderingEvent` with
|
||||||
|
* the event's name 'chill_block.block_name'.
|
||||||
|
*
|
||||||
|
* You may add content to the page using the function
|
||||||
|
* `DelegatedBlockRenderingEvent::addContent`.
|
||||||
|
*
|
||||||
|
* See also the documentation of
|
||||||
|
* `Chill\MainBundle\Templating\Events\DelegatedBlockRenderingEvent`
|
||||||
|
* for usage of this event class
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class WidgetRenderingTwig extends \Twig_Extension
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the widget. This is a double dimension array :
|
||||||
|
*
|
||||||
|
* - first key is the place,
|
||||||
|
* - second key is the ordering ;
|
||||||
|
* - the value is an array where the widget is the first argument and the
|
||||||
|
* second is the config
|
||||||
|
*
|
||||||
|
* i.e :
|
||||||
|
*
|
||||||
|
* $widget['place']['ordering'] = array($widget, $config);
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @var array an array of widget by place and ordering
|
||||||
|
*/
|
||||||
|
protected $widget = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var EventDispatcherInterface
|
||||||
|
*/
|
||||||
|
protected $eventDispatcher;
|
||||||
|
|
||||||
|
public function __construct(EventDispatcherInterface $eventDispatcher)
|
||||||
|
{
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'chill_main_widget';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFunctions()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
new \Twig_SimpleFunction('chill_delegated_block',
|
||||||
|
array($this, 'renderingWidget'),
|
||||||
|
array(
|
||||||
|
'is_safe' => array('html'),
|
||||||
|
'needs_environment' => true,
|
||||||
|
'deprecated' => true, 'alternative' => 'chill_widget'
|
||||||
|
)),
|
||||||
|
new \Twig_SimpleFunction('chill_widget',
|
||||||
|
array($this, 'renderingWidget'),
|
||||||
|
array('is_safe' => array('html'), 'needs_environment' => true))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderingWidget(\Twig_Environment $env, $block, array $context = array())
|
||||||
|
{
|
||||||
|
// get the content of widgets
|
||||||
|
$content = '';
|
||||||
|
foreach ($this->getWidgetsArraysOrdered($block) as $a) {
|
||||||
|
/* @var $widget Widget\WidgetInterface */
|
||||||
|
$widget = $a[0];
|
||||||
|
$config = $a[1];
|
||||||
|
|
||||||
|
$content = $widget->render($env, $block, $context, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for old rendering events (deprecated)
|
||||||
|
$event = new DelegatedBlockRenderingEvent($context);
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch('chill_block.'.$block, $event);
|
||||||
|
|
||||||
|
return $content." ".$event->getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add a widget to this class, which become available for a future call.
|
||||||
|
*
|
||||||
|
* This function is used by DependencyInjection\CompilerPass\WidgetCompilerPass,
|
||||||
|
* which add the widget to this class when it is created by from DI, according
|
||||||
|
* to the given config under `chill_main`.
|
||||||
|
*
|
||||||
|
* @param string $place
|
||||||
|
* @param WidgetInterface $widget
|
||||||
|
* @param array $config
|
||||||
|
*/
|
||||||
|
public function addWidget($place, $ordering, $widget, array $config = array())
|
||||||
|
{
|
||||||
|
$this->widget[$place][$ordering] = array($widget, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param string $place
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getWidgetsArraysOrdered($place)
|
||||||
|
{
|
||||||
|
if (!array_key_exists($place, $this->widget)) {
|
||||||
|
$this->widget[$place] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
\ksort($this->widget[$place]);
|
||||||
|
|
||||||
|
return $this->widget[$place];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user