Lier la valeur d'un champ en base de données à sa valeur affichable

Des bonnes pratiques ?

Le problème exposé dans ce sujet a été résolu.

Bonjour,

J'ai classé ce sujet en PHP, mais en fait je pense que c'est une problématique qu'on peut retrouver dans plusieurs langages.

J'ai un modèle dans lequel j'ai un champ qui peut contenir une liste de valeurs prédéfinies (mettons des noms de cursus post-bac). En base de données ce champ est un smallint (la liste n'est pas très longue).

Ensuite, pour lier les valeurs numériques de la base de données à leur version affichable, j'utilise un hash statique ainsi qu'un accesseur.

Ça donne un truc de ce style (sous Symfony) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
/**
* @var integer
*
* @ORM\Column(name="section", type="smallint", nullable=true)
* @Assert\Range(min="1", max="4", minMessage="Choisissez une valeur valide.",
*      maxMessage="Choisissez une valeur valide.")
*/
private $section;

/**
* @var array
*/
private static $sectionName = array(
     '1' => 'Classe préparatoire',
     '2' => 'IUT',
     '3' => 'BTS',
     '4' => 'Université'
);

/**
* Get sectionName
* @return array
*/
public static getSectionName ()
{
     return self::$sectionName;
}

L'avantage de cette technique, c'est que je peux l'utiliser assez simplement depuis Twig avec une syntaxe du type {{ user.sectionName[user.section] }}.

Cette manière de faire me convient, le truc c'est que je l'ai « trouvée » par moi-même et un peu par hasard, c'est pour cela que je me demande s'il n'existe pas plutôt une bonne pratique qui pourrait répondre à ce type de problématique et qui serait peut-être plus élégante que ce que je fais actuellement.

Merci pour vos réponse !

+0 -0

Bonjour,

Je trouve que ta solution est valable. Mais personnellement j'aurai plutôt créé une nouvelle classe Section. J'aurai par la suite fais une relation ManyToOne pour directement faire en twig : {{ user.section.name }}, ou en PHP $user->getSection()->getName().

L'avantage de cette méthode est qu'il est plus facile de rajouter par la suite des nouvelles sections. Il suffit de faire une page contenant un simple formulaire pour ajouter des sections dans la base de donnée. Le désavantage serait que cela rallonge la requête SQL :/

Si quelqu'un a une meilleur idée je serai ravi d'en apprendre plus :)

+2 -0

Merci à tous pour vos réponses.

yata > C'est pas mal l'idée de la relation mais le truc c'est que l'entité serait vraiment très très peu amenée à changer. L'exemple que j'ai donné est pas forcément pertinent - c'est le premier qui m'a traversé l'esprit sachant que les données réelles sont de nature un peu plus confidentielle -, mais pour donner une idée il n'y aurait aucun rajout ou suppression et peut-être une modification tous les cinq ou dix ans. C'est pour ça que créer une entité et une table dans ma base de données - déjà bien garnie -, ça me paraît un peu lourd juste pour ça.

yoch > J'ai conscience que ma manière de faire, même si elle fonctionne, est loin d'être parfaite… C'est vrai que j'ai toujours été relativement réticent à mettre des données directement dans le code, mais dans le cas qui m'occupe je considérais plus ça comme des constantes liées au projet que comme des données par conséquent le fait de les fixer dans le code me gênait un peu moins. Concernant ENUM, je ne connaissais pas. Le truc c'est que ça m'ennuie un peu de créer une table dans ma base de données et donc d'alourdir le stockage et le chargement juste pour des constantes de langue qui risquent de changer une fois tous les 10 ans. Après si c'est la seule manière de faire ça « proprement », je m'y résoudrai.

Ymox > À moins que je ne fasse erreur, le problème d'une telle solution c'est que je pourrais pas l'utiliser dans une vue qui ne possède par ledit formulaire. Pour reprendre l'exemple que j'ai donné, j'ai bien sûr un formulaire permettant de choisir le type d'étude que poursuit l'utilisateur de mon entité, mais dans une vue qui ne ferait que l'affichage des données sans possibilité d'agir dessus (donc pas de formulaire), je ne pourrais pas accéder à ce type. L'un des avantages de ma manière de faire c'est que même depuis les formulaires je peux accéder assez facilement aux valeurs que j'ai définies en mettant User::getSectionName() associé à la clé choices des paramètres liés à mon champ choice.

+0 -0

Si tu tiens réellement à ne pas avoir à traiter les textes, pourquoi ne les enregistres-tu pas directement dans la BDD, plutôt que des nombres ? Si c'est pour pouvoir les changer plus tard, tu as donc un raisonnement que je ne trouve pas logique : faire s'afficher du texte en fonction de données, c'est le travail soit du contrôleur, soit de la vue.

Le problème de l'utilisation dans une vue, pour avoir les valeurs textuelles, n'en est pas réellement un, surtout si tu sépares ton squelette de la langue qu'il parle  ;)

Typiquement, si tu imaginais que ton site allait devenir multilingue, je te conseillerais vivement d'extraire tout ton texte lisible et de le mettre dans des catalogues. Tu veux changer du texte ? Tu ne changes pas la structure HTML ni du code fonctionnel, mais vraiment que du texte. Et pour ce qui est de traductions "dynamiques", pour ma part, je ne me gêne pas d'utiliser des choses comme {{ ('vendor.bundle.template.status.' ~ entity.status)|trans }}. Tu conserves des nombres en BDD, tu peux changer rapidement et aisément les textes liés sans risquer de gêner tes données. L'ajout est presque aussi rapide, la suppression aussi.

+1 -0

yoch > Concernant ENUM, je ne connaissais pas. Le truc c'est que ça m'ennuie un peu de créer une table dans ma base de données et donc d'alourdir le stockage et le chargement juste pour des constantes de langue qui risquent de changer une fois tous les 10 ans. Après si c'est la seule manière de faire ça « proprement », je m'y résoudrai.

Ekron

Il n'y a pas de table à créer, il s'agit juste de transformer la colonne SMALLINT en ENUM, ce qui est optimisé automatiquement au niveau mémoire. En fait ça revient exactement à faire ce que tu as fait dans ton code sauf que c'est géré au niveau de la db (qui stocke des entiers dans les champs, et utilise une table de correspondance pour savoir quel symbole renvoyer).

+1 -0

Ymox > Parce que jusque là je pensais que la seule solution était de stocker la chaîne à afficher dans la base de données. Or derrière j'ai aussi besoin de cette valeur pour faire des tests, du coup c'est un peu moins pratique sur une chaîne de caractères que sur un entier. Maintenant, avec ce que viens de m'expliquer yoch, il semblerait qu'avec ENUM ce soit une bonne solution, donc effectivement je vais adopter cette façon de faire, merci à toi ! Quant au composant translation, sachant que le site ne sera pas multilingue, ça me paraît un peu lourd juste pour ce problème.

yoch > Ah d'accord, au temps pour moi. Du coup, bien que l'implémentation d'ENUM sur Doctrine nécessite visiblement un peu de bidouillage, je vais m'orienter vers cette solution. Merci pour tes explications !

+0 -0

yoch > Du coup, bien que l'implémentation d'ENUM sur Doctrine nécessite visiblement un peu de bidouillage, je vais m'orienter vers cette solution. Merci pour tes explications !

Ekron

Remarque si ton orm rend les choses compliquées avec un enum, ça ne vaut peut-être pas le coup.

yoch > Du coup, bien que l'implémentation d'ENUM sur Doctrine nécessite visiblement un peu de bidouillage, je vais m'orienter vers cette solution. Merci pour tes explications !

Ekron

Remarque si ton orm rend les choses compliquées avec un enum, ça ne vaut peut-être pas le coup.

yoch

Dans ce cas tu me conseillerais quelle solution ?

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte