Accéder au contenu principal

La couche métier : les entités

L'objectif d'un ORM (pour Object-Relation Mapper, soit en français « lien objet-relation ») est simple : se charger de l'enregistrement de vos données en vous faisant oublier que vous avez une base de données. Comment ? En s'occupant de tout ! Nous n'allons plus écrire de requêtes, ni créer de tables via phpMyAdmin. Dans notre code PHP, nous allons faire appel à Doctrine2, l'ORM par défaut de Symfony2, pour faire tout cela.

Créer une première entité avec Doctrine2

Une entité, c'est juste un objet

Derrière ce titre se cache la vérité. Une entité, ce que l'ORM va manipuler et enregistrer dans la base de données, ce n'est vraiment rien d'autre qu'un simple objet. Voici ce à quoi pourrait ressembler l'objet Advert de notre plateforme d'annonces.


Normalement, vous devez vous poser une question : comment l'ORM va-t-il faire pour enregistrer cet objet dans la base de données s'il ne connaît rien de nos propriétés id et content ? Comment peut-il deviner que notre propriété id doit être stockée dans une colonne de type INT dans la table ? La réponse est aussi simple que logique : il ne devine rien, on va le lui dire !

Une entité, c'est juste un objet… mais avec des commentaires !

OK, je dois avouer que ce n'est pas intuitif si vous ne vous en êtes jamais servi, mais oui, on va ajouter des commentaires dans notre code et Symfony2 va se servir directement de ces commentaires pour ajouter des fonctionnalités à notre application. Ce type de commentaires se nomme l'annotation. Les annotations doivent respecter une syntaxe particulière, regardez par vous-mêmes :

<?php
// src/OC/PlatformBundle/Entity/Advert.php

namespace OC\PlatformBundle\Entity;

// On définit le namespace des annotations utilisées par Doctrine2
// En effet, il existe d'autres annotations, on le verra par la suite,
// qui utiliseront un autre namespace
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Advert
{
  /**
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  protected $id;

  /**
   * @ORM\Column(name="date", type="date")
   */
  protected $date;

  /**
   * @ORM\Column(name="title", type="string", length=255)
   */
  protected $title;

  /**
   * @ORM\Column(name="author", type="string", length=255)
   */
  protected $author;

  /**
   * @ORM\Column(name="content", type="text")
   */
  protected $content;

  // Les getters
  // Les setters
}

Attention par contre pour les prochaines annotations que vous serez amenés à écrire à la main : elles doivent être dans des commentaires de type « /** », avec précisément deux étoiles. Si vous essayez de les mettre dans un commentaire de type « /* » ou encore « // », elles seront simplement ignorées.

 

Générer une entité : le générateur à la rescousse !

En tant que bon développeur, on est fainéant à souhait, et ça, Symfony2 l'a bien compris ! On va donc se refaire une petite session en console afin de générer notre première entité. Entrez la commande suivante et suivez le guide :

1- C:\wamp\www\Symfony>php app/console generate:doctrine:entity
 
2-  
Welcome to the Doctrine2 entity generator



This command helps you generate Doctrine2 entities.

First, you need to give the entity name you want to generate.
You must use the shortcut notation like AcmeBlogBundle:Post.

The Entity shortcut name:_ 

 Grâce à ce que le générateur vous dit, vous l'avez compris, il faut entrer le nom de l'entité sous le format NomBundle:NomEntité. Dans notre cas, on entre donc OCPlatformBundle:Advert.

The Entity shortcut name: OCPlatformBundle:Advert

Determine the format to use for the mapping information.

Configuration format (yml, xml, php, or annotation) [annotation]:_

  Comme je vous l'ai dit, nous allons utiliser les annotations, qui sont d'ailleurs le format par défaut. Appuyez juste sur la touche Entrée.

  3-

Configuration format (yml, xml, php, or annotation) [annotation]:

Instead of starting with a blank entity, you can add some fields now.
Note that the primary key will be added automatically (named id).

Available types: array, simple_array, json_array, object,
boolean, integer, smallint, bigint, string, text, datetime, datetimetz,
date, time, decimal, float, blob, guid.

New field name (press <return> to stop adding fields):_
 
On commence à saisir le nom de nos champs. Lisez bien ce qui est inscrit
 avant : Doctrine2 va ajouter automatiquement l'id, de ce fait, pas 
besoin de le redéfinir ici. On entre donc notre date : date
 
New field name (press <return> to stop adding fields): date
Field type [string]:_ 

C'est maintenant que l'on va dire à Doctrine à quel type correspond notre propriété date.
 La liste des types possibles vous est donné par Symfony juste au 
dessus. Nous voulons une date avec les informations de temps, tapez donc
 datetime.
Répétez les points 3 et 4 pour les propriétés title, author et content. title et author sont de type 
string de 255 caractères (pourquoi pas). Content est par contre de type text.
 
New field name (press <return> to stop adding fields): date
Field type [string]: datetime

New field name (press <return> to stop adding fields): title
Field type [string]: string
Field length [255]: 255

New field name (press <return> to stop adding fields): author
Field type [string]: string
Field length [255]: 255

New field name (press <return> to stop adding fields): content
Field type [string]: text

New field name (press <return> to stop adding fields):_ 

Lorsque vous avez fini, appuyez sur la touche Entrée.
 
New field name (press <return> to stop adding fields):

Do you want to generate an empty repository class [no]?_ 

Oui, on va créer le repository associé, c'est très pratique, nous en reparlerons largement. Entrez donc yes.
Confirmez la génération, et voilà !

Do you want to generate an empty repository class [no]? yes


  Summary before generation


You are going to generate a "OCPlatformBundle:Advert" Doctrine2 entity
using the "annotation" format.

Do you confirm generation [yes]?


  Entity generation


Generating the entity code: OK


  You can now start using the generated code!



C:\wamp\www\Symfony>_

Allez tout de suite voir le résultat dans le fichier Entity/Advert.php. Symfony2 a tout généré, même les getters et les setters ! Vous êtes l'heureux propriétaire d'une simple classe… avec plein d'annotations !



Affiner notre entité avec de la logique métier

L'exemple de notre entité Advert est un peu simple, mais rappelez-vous que la couche modèle dans une application est la couche métier. C'est-à-dire qu'en plus de gérer vos données un modèle contient également la logique de l'application. Voyez par vous-mêmes avec les exemples ci-dessous.
Attributs calculés
Prenons l'exemple d'une entité Commande, qui représenterait un ensemble de produits à acheter sur un site d'e-commerce. Cette entité aurait les attributs suivants :
  • ListeProduits qui contient un tableau des produits de la commande ;
  • AdresseLivraison qui contient l'adresse où expédier la commande ;
  • Date qui contient la date de la prise de la commande ;
  • Etc.
Ces trois attributs devront bien entendu être mappés (c'est-à-dire définis comme des colonnes pour l'ORM via des annotations) pour être enregistrés en base de données par Doctrine2. Mais il existe d'autres caractéristiques pour une commande, qui nécessitent un peu de calcul : le prix total, un éventuel coupon de réduction, etc. Ces caractéristiques n'ont pas à être persistées en base de données, car elles peuvent être déduites des informations que l'on a déjà. Par exemple, pour avoir le prix total, il suffit de faire une boucle sur ListeProduits et d'additionner le prix de chaque produit :
<?php
// Exemple :
class Commande
{
  public function getPrixTotal()
  {
    $prix = 0;
    foreach($this->getListeProduits() as $produit)
    {
      $prix += $produit->getPrix();
    }
    return $prix;
  }
}

N'hésitez donc pas à créer des méthodes getQuelquechose() qui contiennent de la logique métier. L'avantage de mettre la logique dans l'entité même est que vous êtes sûrs de réutiliser cette même logique partout dans votre application. Il est bien plus propre et pratique de faire <?php $commande->getPrixTotal() que d'éparpiller à droite et à gauche différentes manières de calculer ce prix total. Bien sûr, ces méthodes n'ont pas d'équivalent setQuelquechose(), cela n'a pas de sens !
Attributs par défaut
Vous avez aussi parfois besoin de définir une certaine valeur à vos entités lors de leur création. Or nos entités sont de simples objets PHP, et la création d'un objet PHP fait appel… au constructeur. Pour notre entité Advert, on pourrait définir le constructeur suivant :

<?php
// src/OC/PlatformBundle/Entity/Advert.php

namespace OC\PlatformBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Advert
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="OC\PlatformBundle\Entity\AdvertRepository")
 */
class Advert
{
  // ...

  public function __construct()
  {
    // Par défaut, la date de l'annonce est la date d'aujourd'hui
    $this->date = new \Datetime();
  }
 
  // ...
}

Conclusion

N'oubliez pas : une entité est un objet PHP qui correspond à un besoin dans votre application.
N'essayez donc pas de raisonner en termes de tables, base de données, etc. Vous travaillez maintenant avec des objets PHP, qui contiennent une part de logique métier, et qui peuvent se manipuler facilement. C'est vraiment important que vous fassiez l'effort dès maintenant de prendre l'habitude de manipuler des objets, et non des tables.



En résumé

  • Le rôle d'un ORM est de se charger de la persistance de vos données : vous manipulez des objets, et lui s'occupe de les enregistrer en base de données.
  • L'ORM par défaut livré avec Symfony2 est Doctrine2.
  • L'utilisation d'un ORM implique un changement de raisonnement : on utilise des objets, et on raisonne en POO. C'est au développeur de s'adapter à Doctrine2, et non l'inverse !
  • Une entité est, du point de vue PHP, un simple objet. Du point de vue de Doctrine, c'est un objet complété avec des informations de mapping qui lui permettent d'enregistrer correctement l'objet en base de données.
  • Une entité est, du point de vue de votre code, un objet PHP qui correspond à un besoin, et indépendant du reste de votre application.



Commentaires

Posts les plus consultés de ce blog

cPanel DDOS attack - Mitigate Slowloris Attacks - mod_qos

Apache mod_evasive Mod_evasive is a module available for the Apache HTTP server that can automatically block attacks by rate-limiting any IP that sends too many requests in a short time. Start by installing the module from WHM’s  EasyApache 4  interface. Select the  Currently Installed Packages  profile, search for  mod_evasive  in the  Apache Modules  section, and then install it. The default settings are good for most servers, but you can tweak them further by editing the configuration file  /etc/apache2/conf.d/300-mod_evasive.conf . You can also whitelist specific IP addresses or classes, so legitimate requests are not blocked. Configure CSF to block attacks While  mod_evasive  works very well, it only protects the Apache webserver. In order to harden other services as well, you can install the free  ConfigServer Security & Firewall  (CSF), which also includes a WHM plugin. As the  root  user, install CSF with these terminal commands: cd /usr/src rm -fv csf.tgz wget https://down

Spool file is locked (another process is handling this message)

LOG: MAIN cwd=/usr/local/cpanel/whostmgr/docroot 4 args: /usr/sbin/exim -v -Mrm 1dUoey-0006YJ-3A Message 1dUoey-0006YJ-3A is locked LOG: skip_delivery MAIN Spool file is locked (another process is handling this message) To do this you can run the following commands. |exim -Mt 1dUoey-0006YJ-3A |exim -Mrm 1dUoey-0006YJ-3A I am also providing the following page in case you want more information regarding the exim command options. http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html

Open Media Vault NAS change password

Known Root Password Login to the OMV using the root user and the current password via SSH or Console enter the following command passwd root The new password is now active. Unknown Root Password, but Admin Access to OMV GUI is Available In this scenario we still can help ourselves with the GUI. The method we use is, that we create a cron job for the root user which then resets the password. Navigate to System -> Cron Jobs Press the +Add button UN-tick the enabled box, so that the cronjob does not run automatically. put into the command field the following line, replace newpasswd with your password: echo "root:newpasswd" | chpasswd press okay select the newly created cron job Click the run button. in the opening window click the start button. It will shortly deactivate and activate again. open ssh or console and login as root with your new password. Root and Admin Password Unknown If you do not know the root password, you need to boot with a Li