Propriétés conviviales d'entité

De Wiki de Jordan LE NUFF
Sauter à la navigation Sauter à la recherche
Ligne 189 : Ligne 189 :
  
 
=== Modification de la vue ===
 
=== Modification de la vue ===
 +
Enfin, les informations étant passées à la vue par le contrôleur, le tableau affichant les données relatives à la liste des entités peut se faire dynamiquement de façon convivial avec le code Twig suivant :
 +
<syntaxhighlight lang="twig" highlight="6,7,14,15">
 +
...
 +
{% if applications %}
 +
<table class="table table-hover table-sm table-striped">
 +
<thead>
 +
<tr>
 +
{% for name,friendlyName in propertiesNames %}
 +
<th scope="col">{{ friendlyName }}</th>
 +
{% endfor %}
 +
</tr>
 +
</thead>
 +
<tbody>
 +
{% for application in applications %}
 +
<tr>
 +
{% for name,friendlyName in propertiesNames %}
 +
<td><a href="{{ path('application_show', {id: application.id})  }}">{{ attribute(application,name) }}</a></td>
 +
{% endfor %}
 +
</tr>
 +
{% endfor %}
 +
</tbody>
 +
</table>
 +
{% endif %}
 +
...
 +
</syntaxhighlight>
 +
Ce qui donnera l'affichage suivant :
 +
:[[Fichier:ClipCapIt-200226-183323.PNG]]

Version du 26 février 2020 à 17:35

Présentation

Cette page a pour objet de décrire comment définir un nom convivial d'une propriété d'une entité et de comment la récupérer dans Symfony.

Contexte

Dans le cadre de la mise en place d'un simple CRUD sous Symfony, il peut être nécessaire de pouvoir lister dans un tableau un ensemble d'entités. Ce tableau devra donc comporter des titres de colonnes. Idéalement, ces titres doivent correspondre à la description de la propriété de l'entité.

Par exemple, une propriété pourrait se nommer $teamLeader, mais la description de cette propriété correspondrait à Chef d'équipe. Les propriétés des entités étant des variables PHP, il n'est pas possible de leur donner un nom convivial tel quel.

De ce fait, où renseigner cette information ?

Plusieurs choix sont possibles :

  • Dans la définition ORM de l'entité, en annotation, avec la syntaxe * @ORM\Column(type="string", length=255, nullable=true, options={"comment":"Chef d'équipe"}) par exemple
    • Cette astuce permettra d'assigner un commentaire descriptif à la colonne en base de données. Toutefois, la récupération de cette information est laborieuse et il sera préférable de mettre en oeuvre d'autres solutions.
  • Dans une table supplémentaire dédiée à la description de chacune des propriétés de chaque entité.
    • Cette solution est envisageable, mais demande une maintenance particulière. De plus, l’algorithme de l'application devra tenir compte de cette architecture.
  • Dans chacune des vues ou contrôleurs qui auront besoin de cette information.
    • Le problème majeur de cette solution est la duplication de code. L'information sera présente à chaque endroit où elle sera nécessaire
  • Dans la définition de l'entité même
    • Cela rejoint à peu près la solution de l'ORM, et c'est cette solution qui va être détaillée dans cette page
  • Et d'autres solutions...

Mise en oeuvre

La mise en oeuvre se déroulera en 5 étapes :

  • Création d'une classe d'annotation
  • Ajout d'informations dans l'entité
  • Création d'une fonction globale
  • Modification du contrôleur
  • Modification de la vue

Création d'une classe d'annotation

Les annotations PHP est un projet porté par Doctrine. La documentation officielle est accessible à l'URL : https://www.doctrine-project.org/projects/doctrine-annotations/en/1.6/index.html

En ce qui concerne cette mise en oeuvre, il suffira de s'inspirer de la documentation sur la création de classe d'annotations personnalisée.

Ce qui donne, par exemple, la classe suivante :

<?php
// src/Annotations/FriendlyAnnotation.php
namespace App\Annotations;

/**
 * @Annotation
 */
class FriendlyAnnotation
{
    public $friendlyName;
}

Ajout d'informations dans l'entité

L'annotation personnalisée étant créée, il est alors possible de renseigner des champs personnalisés dans les entités.

Plus particulièrement, pour avoir un nom convivial pour chaque propriété, il est possible de faire ceci :

<?php
// src/Entity/Application.php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use App\Annotations\FriendlyAnnotation;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ApplicationRepository")
 */
class Application
{
    /**
     * @FriendlyAnnotation(friendlyName="Id")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer", options={"comment":"Id"})
     */
    private $id;

    /**
     * @FriendlyAnnotation(friendlyName="Nom")
     * @ORM\Column(type="string", length=255, options={"comment":"Nom"})
     */
    private $name;

    /**
     * @FriendlyAnnotation(friendlyName="Alias")
     * @ORM\Column(type="string", length=255, options={"comment":"Alias"})
     */
    private $alias;

    /**
     * @FriendlyAnnotation(friendlyName="Responsable MOE")
     * @ORM\Column(type="string", length=255, nullable=true, options={"comment":"Responsable MOE"})
     */
    private $applicationManager;

    /**
     * @FriendlyAnnotation(friendlyName="Responsable MOA")
     * @ORM\Column(type="string", length=255, nullable=true, options={"comment":"Responsable MOA"})
     */
    private $businessManager;

    /**
     * @FriendlyAnnotation(friendlyName="Société")
     * @ORM\Column(type="string", length=255, options={"comment":"Société"})
     */
    private $company;

    /**
     * @FriendlyAnnotation(friendlyName="Description")
     * @ORM\Column(type="string", length=255, nullable=true, options={"comment":"Description"})
     */
    private $description;

// et le reste des getters et setters ci-dessous ...
}

Création d'une fonction globale

Extraire les informations depuis les annotations ne se faisant pas en une seule ligne de code, d'une part, et pouvant potentiellement se faire depuis plusieurs endroits dans l'application, d'autre part, il est donc privilégié de recourir à une fonction globale. Cela évitera la duplication de code et simplifiera l'appel à l'extraction des informations.

Voici donc la fonction permettant d'extraire les noms conviviaux des propriétés d'une classe :

<?php
// src/Functions.php
namespace App;

use Doctrine\Common\Annotations\AnnotationReader;

function getFriendlyNames ($className)
{
    $annotationReader = new AnnotationReader();
    $reflectedClass = new \ReflectionClass($className);
    $propertiesList = $reflectedClass->getProperties();
    $propertiesNames= array();
    foreach ($propertiesList as $property)
    {
        $propertyAnnotations = $annotationReader->getPropertyAnnotations(new \ReflectionProperty($className, $property->getName()));
        $propertiesNames[$property->getName()] = ((array) $propertyAnnotations[0])["friendlyName"];
    }
    return $propertiesNames;
}

Modification du contrôleur

Comme indiqué précédemment, il est désormais possible de réaliser l'extraction des informations depuis l'appel à la fonction globale getFriendlyNames().

Voici un exemple d'appel de la fonction et de passage des informations à la vue depuis un contrôleur :

<?php
// src/Controller/ApplicationController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Application;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use App\Repository\ApplicationRepository;

use function App\getFriendlyNames;

/**
 * @Route("/application", name="application")
 */
class ApplicationController extends AbstractController
{
    /**
     * @Route("/", name="")
     */
    public function index(ApplicationRepository $applicationRepository)
    {
		$applications = $applicationRepository
			->findAll();
		
		if (!$applications) {
			throw $this->createNotFoundException(
				'No application found'
			);
		}

        $propertiesNames = getFriendlyNames('App\Entity\Application');

        return $this->render('application/index.html.twig', [
            'propertiesNames' => $propertiesNames,
			'applications' => $applications,
            'controller_name' => 'ApplicationController',
		]);
    }
// et le reste du contrôleur ci-dessous ...

Modification de la vue

Enfin, les informations étant passées à la vue par le contrôleur, le tableau affichant les données relatives à la liste des entités peut se faire dynamiquement de façon convivial avec le code Twig suivant :

...
	{% if applications %}
		<table class="table table-hover table-sm table-striped">
			<thead>
				<tr>
					{% for name,friendlyName in propertiesNames %}
					<th scope="col">{{ friendlyName }}</th>
					{% endfor %}
				</tr>
			</thead>
			<tbody>
				{% for application in applications %}
				<tr>
					{% for name,friendlyName in propertiesNames %}
					<td><a href="{{ path('application_show', {id: application.id})  }}">{{ attribute(application,name) }}</a></td>
					{% endfor %}
				</tr>
				{% endfor %}
			</tbody>
		</table>
	{% endif %}
...

Ce qui donnera l'affichage suivant :

ClipCapIt-200226-183323.PNG