No es sorpresa la gran popularidad que tiene el bundle Sonata Admin, siendo como dicen ellos «El generador de admistradores faltante en Symfony2» (énfasis mío).
Al generar los adminstradores de nuestras entidades es común necesitar desplegar junto con los campos a editar, campos informativos del objeto (fecha de creación, último acceso, autor, etc.). Se puede fácilmente agregar los campos y hacerlos no editables y/o desactivarlos, pero visualmente el resultado no es realmente bueno.
// simple but ugly ->add('created', null, array( 'read_only' => true, 'disabled' => true, 'widget' => 'single_text', 'format' => 'EEE, MMM FF yyyy HH:mm' ))
Podemos utilizar CSS para mejorar considerablemente la imagen, sin embargo esto no funciona si queremos desplegar estructuras más complejas.
Tratándose de Symfony2 y SonataAdmin es posible adaptar los administradores generados para nuestro bundle en la medida que necesitemos sin impactar en otras áreas. En esta ocasión lo aprovecharemos para crear etiquetas informativas insertables como campos dentro de los formularios.
Probado con:
Symfony 2.4
Sonata Admin Bundle 2.2
Dependiendo de los objetivos, lo que hacer es:
– Crear la clase para el nuevo tipo de despliegue
– Crear un transformador para hacer desplegable el objeto
– Configurar las clases de administración con el objeto y el nuevo tipo
– Crear los bloques en Twig con el marcado para el despliegue
Lo siguiente mostrará como desplegar un objecto DateTime, pero la guía es fácilmente adaptable para otros tipos, como números, hipervínculos, entidades, colecciones o cualquier cosa.
Crear la clase para el nuevo tipo de despliegue
Primero necesitamos crear una clase para el nuevo tipo
/* Acme/DemoBundle/Form/StaticTextType.php */Para usar el nuevo tipo podemos incluir la clase e instanciarla en el administrador
/* Acme/DemoBundle/Admin/EntityAdmin.php */ add('id', new StaticTextType()) ...o crear crear un servicio y registrarlo como nuevo tipo de formulario. Esto también permite hacer uso de él a través de su etiqueta.
# Acme/DemoBundle/Resources/config/services.yml services: ... acme_demo.form.type.info: class: Acme\DemoBundle\Form\StaticTextType tags: - { name: form.type, alias: acme_static_text }/* Acme/DemoBundle/Admin/EntityAdmin.php */ ... ->add('id', 'acme_static_text')Para desplegar información básica como números o cadenas no necesitamos crear el transformador pues nuestro tipo hereda las características del tipo 'text'.
Crear un transformador para hacer desplegable el objeto
Para desplegar la fecha y hora necesitamos un transformador que genere la cadena que represente a la instancia
DateTime
./* Acme/DemoBundle/Form/DataTransformer/DateTimeToStringTransformer.php */ format = $format; } /** * Transforms a datetime object to a string. * * @param DateTime|null $date * @return string */ public function transform($dateTime) { return null === $dateTime ? return '' : $dateTime->format($this->format); } /** * Transforms a string date to a DateTime object. * * @param string $dateTime * * @return DateTime|null * * @throws TransformationFailedException if cannot transform to DateTime. */ public function reverseTransform($dateTime) { if (empty($dateTime)) { return null; } $dt = DateTime::createFromFormat($this->format, $dateTime); if (null === $dt) { throw new TransformationFailedException(sprintf( "Unable to transform '%s' to a DateTime object", $dateTime )); } return $dt; } }Configurar las clases de administración con el objeto y el nuevo tipo
Para mostrar los datos de los campos de manera que no sean procesados por el formulario, podemos agregar el campo configurándolo como no mapeado y el dato manualmente agregado o configurarlo como desactivado.
add('id', 'acme_static_text', array( 'required' => false )) // correct display, ignored on save ->add('id', 'acme_static_text', array( 'required' => false, 'disabled' => true, )) $entity = $this->getSubject(); ->add('id', 'acme_static_text', array( 'required' => false, 'mapped' => false, 'data' => $entity->getId(), ))Tip: Como el método
$this->getSubject()
de la clase de administración regresa la entidad que se está gestionando, tambíen se puede aprovechar para desplegar diferentes campos dependiendo de si se está creando una nueva instancia o editando una existente.Nota: Al utilizar subadminstradores
getSubject()
regresa siempre la primera entidad.Para usar el transformador al estructurar nuestro formulario en el administrador no agregamos directamente nuestro objeto con el tipo, sino que creamos un objeto
FormBuilder
al que le agregaremos una instancia del transformador./* Acme/DemoBundle/Admin/EntityAdmin.php */ add( $formMapper->create('created', 'acme_static_text', array( // data_class set to null to avoid object type errors 'data_class' => null, 'required' => false, 'disablex' => true, )) ->addViewTransformer(new DateTimeToStringTransformer('D, M d Y H:i:s')) )Algunos otros ejemplos de configuración:
// 1-to-N collection would be something like this ->add('pages', 'acme_static_text_collection', array( 'label' => false, 'type' => 'entity', 'options' => array( 'class' => 'AcmeDemoBundle:Foo', ), )) // An entity would look like ->add( $formMapper->create('author', 'info', array( 'data_class' => null, 'required' => false, 'mapped' => false, 'data' => $subject->getAuthor(), 'property_path' => null )) ->addViewTransformer(new UserToStringTransformer()) )Crear los bloques en Twig con el marcado para el despliegue
Finalmente vamos a construir los widgets con el HTML para mostrar la información. Como nuestro tipo se llama acme_static_text el bloque lo debemos crear con el nombre acme_static_text_widget.
{# Acme/DemoBundle/Resources/views/Form/widgets.html.twig #} {% block acme_static_text_widget %} {% spaceless %}{{ value }}{% endspaceless %} {% endblock %}Ahora debemos agregar nuestra plantilla con widgets en el administrador para que pueda ser usada. Una manera sencilla es sobrecargando el método
getFormTheme()
de nuestra clase de administración./* Acme/DemoBundle/Admin/EntityAdmin.php */Y con esto terminamos. Si bien la implementación no es tan rápida, no es compleja y es valiosa porque muestra una manera para personalizar cualquier campo en los administradores de nuestros bundles.