Il arrive souvent que dans certains projets web, vous vous retrouvez avec de nombreux types de données tels que des personnes, des entreprises, ou tout simplement des lieux devant contenir des données géographiques. On se retrouve rapidement avec des schémas de bdd très redondants car contenant les mêmes informations.
Nous allons voir dans cette article comment palier à cela proprement, grâce aux Mapped Superclasses de Doctrine2.
Une Mapped Superclass est une sorte de classe modèle permettant de définir des attributs spécifiques pour plusieurs classes enfants.
Si vous ne connaissez pas ce principe, je vous conseille vivement de jeter un œil sur la documentation officiel avant de lire la suite, une traduction est disponible ici pour les francophiles. 🙂
La classe modèle
Pour commencer, nous allons définir notre Mapped Supperclass Google Maps :
<?php namespace Test\TestBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * Test\TestBundle\Entity\AbstractGMapEntity * * @author Sullivan SENECHAL * * @ORM\MappedSuperclass */ abstract class AbstractGMapEntity { /** * @var string * * @ORM\Column(name="address", type="string", length=255, nullable=true) */ protected $address; /** * @var string * * @ORM\Column(name="locality", type="string", length=255, nullable=true) */ protected $locality; /** * @var string * * @ORM\Column(name="country", type="string", length=255, nullable=true) */ protected $country; /** * @var float Latitude of the position * * @ORM\Column(name="lat", type="float", nullable=true) */ protected $lat; /** * @var float Longitude of the position * * @ORM\Column(name="lng", type="float", nullable=true) */ protected $lng; public function setAddress($address) { $this->address = $address; } public function getAddress() { return $this->address; } public function setLocality($locality) { $this->locality = $locality; } public function getLocality() { return $this->locality; } public function setCountry($country) { $this->country = $country; } public function getCountry() { return $this->country; } public function getLat() { return $this->lat; } public function setLat($lat) { if (is_string($lat)) { $lat = floatval($lat); } $this->lat = $lat; } public function getLng() { return $this->lng; } public function setLng($lng) { if (is_string($lng)) { $lng = floatval($lng); } $this->lng = $lng; } } ?>
Notons certaines choses :
- La classe est abstraite, en effet, il s’agit d’une classe modèle qui ne pourra pas être utilisée en tant qu’entité propre.
- Il faut impérativement préciser à Doctrine qu’il s’agit d’une MappedSuperclass dans le commentaire d’en-tête.
- L’adresse, la longitude et la longitude sont des champs obligatoires pour que les données soit exploitables par Google Maps.
La ville est le pays sont ajoutés à titre d’exemple et seront utiles pour mes prochains articles… 🙂 - Attention, la longitude et la latitude sont des floats ! Veillez à faire en sorte que les informations soient enregistrées correctement comme dans l’exemple ci-dessus.
Intégrer le modèle à nos entités
Maintenant que notre modèle est fait, il faut l’appliquer sur nos véritables entités !
Pour ce faire, rien de plus simple ! Il suffit de faire hériter notre classe par notre modèle.
Voici un exemple avec une entité contenant des informations sur une personne :
<?php namespace Test\TestBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Test\TestBundle\Entity\AbstractGMapEntity; /** * Person * * @author Sullivan SENECHAL * * @ORM\Table(name="person") */ class Person extends AbstractGMapEntity { /** * @var string * * @ORM\Column(name="first_name", type="string", length=255, nullable=false) */ protected $firstName; /** * @var string * * @ORM\Column(name="last_name", type="string", length=255, nullable=false) */ protected $lastName; // Vos autres attibuts et méthodes... } ?>
- N’oubliez pas d’importer la classe modèle Google Maps via le mot clé use !
- Intégrez les attributs et méthodes de la classe modèle par un héritage de classe (extends)
Mettez à jour votre bdd via la console symfony, et le tour est joué !
Vous n’avez plus qu’à faire de même pour les autres entités correspondantes…
Conclusion
Pensez régulièrement à factoriser vos entités Doctrine si vous vous retrouvez face à des données communes, cela aide beaucoup à avoir un code propre et organisé ! 😉
Je vous conseille de séparer vos classes modèles, par exemple dans un bundle à part nommé UtilsBundle ! 😉
Une meilleure solution ? Une astuce à ajouter ? N’hésitez pas à m’en parler ! 😀
Voyons maintenant comment intégrer ceci dans nos formulaires avec jQuery Address Picker…