Parametros de configuracion de un bundle distribuible

Hola amigos ¡

Para los que no hayais leido los anteriores posts sobre como crear un bundle y distribuirlo a los proyectos, os recomiendo que os paseis antes por aqui.

El truco de hoy consiste en como incluimos parametros de configuracion obligatorios en nuestros bundles distribuibles, para que el usuario que haga uso de este bundle se encargue de definirlos correctamente para el buen funcionamiento del bundle.

Para ello y revisando la documentacion oficial de Symfony explicare paso a paso como se consigue de una forma mas facil y clara (al menos a mi me a costado trabajo comprenderlo).

Imaginemos que nuestro bundle distribuible tiene un servicio que necesita varios parametros para conectarse a un API de terceros y por lo tanto hay que forzar al usuario a definir esa configuracion.

1- Definir los parametros en el DependencyInjection/Configuration.php

/**
 * This is the class that validates and merges configuration from your app/config files.
 *
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
 */
class Configuration implements ConfigurationInterface
{
    /**
     * {@inheritdoc}
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('common');

        // Here you should define the parameters that are allowed to
        // configure your bundle. See the documentation linked above for
        // more information on that topic.
        $rootNode
            ->children()
                ->arrayNode('request_manager')
                    ->children()
                        ->scalarNode('api_url')->end()
                        ->scalarNode('api_user')->end()
                        ->scalarNode('api_password')->end()
                        ->scalarNode('api_token_auth')->end()
                    ->end()
                ->end()
            ->end();

        return $treeBuilder;
    }
}

En mi caso necesito 4 parametros a configurar en mi bundle distribuible llamado ‘common‘ que son:

-api_url

-api_user

-api_password

-api_token_auth

2- Añadir los parametros en el DI y sustituirlos en el servicio que los necesite en el archivo DependencyInjection/CommonBundle (sustituye Common por el nombre de tu bundle)

/**
 * This is the class that loads and manages your bundle configuration.
 *
 * @link http://symfony.com/doc/current/cookbook/bundles/extension.html
 */
class CommonExtension extends Extension
{
    /**
     * {@inheritdoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('routing_api.yml');
        $loader->load('services.yml');

        $def = $container->getDefinition('my_vendor.request_manager_api');
        $def->replaceArgument(0, $config['request_manager']['api_url']);
        $def->replaceArgument(1, $config['request_manager']['api_user']);
        $def->replaceArgument(2, $config['request_manager']['api_password']);
        $def->replaceArgument(3, $config['request_manager']['api_token_auth']);
    }
}

De esta forma lo que se consigue es sustituir los parametros en la definicion del servicio por los que el usuario configure. Este servicio concreto tiene la siguiente definicion:

services:
    my_vendor.request_manager_api:
        class: MyVendor\CommonBundle\Services\RequestManagerAPI
        arguments:
            - '%api_url%'
            - '%api_email%'
            - '%api_password%'
            - '%api_token_auth%'
            - '@monolog.logger'
            - '@mrjeff.common.serializer'

Este servicio recibe 4 parametros en el constructor que sustituimos en el CommonExtension.

Guardamos los cambios del bundle en GIT  para que cuando lo actualicemos en otro proyecto se descarguen correctamente.

3- Actualizar el bundle en el proyecto donde lo usemos añadiendo la configuracion necesaria para dicho bundle y que nos dara error si no lo hacemos porque son parametros obligatorios. Para ello:

$ composer update

Esto nos instalara la nueva version del bundle con dichos parametros obligatorios

Ahora tenemos que crear esta configuracion con la misma estructura en el archivo app/config/config.yml, y quedaria algo asi:

common:
    request_manager:
        api_url: %api_url%
        api_user: %api_email%
        api_password: %api_password%
        api_token_auth: %api_token_auth%

Y como estamos haciendo referencia a parametros de nuestra aplicacion, tendremos que definirlos en nuestroparameters.yml/parameters.yml.dist tal que:

api_url: http://my-api-url.com
api_email: user@my-domain.com
api_password: XXX
api_token_auth: my-secret-token-is-not-visible

De esta forma nuestro proyecto ya podra usar el bundle con la configuracion necesaria para que funcione correctamente.

Espero haber sido claro y conciso sobre la forma de conseguirlo. Si teneis dudas no dudeis en preguntar o consultar la documentacion oficial para su uso de forma avanzada en http://symfony.com/doc/current/bundles/configuration.html

Un saludo SymfonyDevs ¡¡¡

Recordad compartir este articulo en vuestras redes sociales, no os cuesta nada y puede ayudar a muchos compañeros ¡

 

Anuncios

Propagar parametros custom de un FormType a un FormType Embebido

Al hilo del mi ultimo post acerca de pasar parametros custom a un FormType desde un controlador, para por ejemplo rellenar un select con valores que vienen de otro sitio, me a surgido la duda siguiente:

¿Es posible propagar ese campo custom a un formulario embebido dentro del mismo FormType? Es decir, imaginad que tenemos un FormType con una serie de campos y dentro de ese FormType tenemos otro FormType con otros campos el cual un de ellos tambien se rellena con información externa.

Ejemplo:

CreateIncidentType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $incidentType = $options['incident_type'];
    $incidentTypesOptions = array('' => '');
    /** @var IncidentType $item */
    foreach ($incidentType as $item) {
     $incidentTypesOptions[$item->getName()] = $item->getCode();
    }

    $builder
         ...OTROS CAMPOS
         ->add('visit_delivery', VisitType::class, array(
              'label' => 'Visita de Entrega',
              'incident_type' => $incidentType,
              'attr' => array(
                     'class' => 'form-control visit-delivery hide'
               ),
              'label_attr' => array(
                    'class' => 'hide'
              )
     ));
}
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => CreateIncident::class,
        'incident_type' => null
    ));
}

He marcado en color las cosas a tener en cuenta. En mi caso VisitType es un formulario embebido dentro del CreateIncidentType y que tb recibe un parametro custom. Para ello, hacemos exactamente lo mismo que antes:

VisitType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $incidentType = $options['incident_type']; 
    $builder
        ->add('visit_type_code', ChoiceType::class, array(
             'label' => 'Tipo',
             'choices' => $incidentType,
             'attr' => array(
                  'class' => 'form-control visit-type-code',
             ),
             'required' => true
         ));
}

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => Visit::class,
        'incident_type' => null
    ));
}

De esa forma, hemos “propagado” el parametro que recibe el formtype inicial hacia el formulario embebido para usarlo dentro de el.

Por cierto, recordad que en el controller cuando creais el Form teneis que hacerlo asi:

$incidentModel = new CreateIncident();
$incidentForm = $this->createForm(CreateIncidentType::class, $incidentModel, array(
 'incident_type' => $incidentTypes
));

Espero que os sirva de ayuda o os de una idea de como enfocarlo.

Si te a gustado, ya sabes retuit, comparte y comenta ¡¡

Saludos Devs ¡¡¡