php - update - symfony manytomany




Dans Doctrine, comment réaliser des fonctionnalités de modèle supplémentaires pour l'Entité (3)

Disons que j'ai une entité Doctrine (version 2) comme suit:

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * User
 *
 * @ORM\Table(name="users")
 * @ORM\Entity
 */
class User {
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=50, nullable=false)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="group_id", type="string", length=6, nullable=true)
     */
     private $groupId;

    // Getters and setters...
}

Maintenant, je voudrais gérer la relation de l'utilisateur avec le Group , mais avec certaines conditions, comme:

  1. renvoyant NULL (ou une sorte de squelette / modèle de \AppBundle\Entity\Group avec des valeurs fixes non chargées de la base de données) si le Group de users.group_id n'existe pas, même s'il est défini sur une valeur (aucune restriction de clé définie dans base de données pour empêcher ce comportement), donc une sorte de validation / vérification nécessaire
  2. Group chargement paresseux, lors de l'appel de $user->getGroup()

Je lis Google encore et encore et je suis confus de la façon d'y parvenir correctement (dans la ligne avec la méthode Doctrine / Symfony).

Je pourrais ajouter un ManyToOne à la relation de classe de l'entité comme ceci:

/**
 * @var \AppBundle\Entity\Group
 *
 * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Group")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="group_id", referencedColumnName="id")
 * })
 */
private $group;

Mais alors comment empêcher les exceptions causées par des clés étrangères non existantes? Par exemple, je voudrais récupérer les détails du groupe de l'utilisateur quand il est disponible dans ma base de données, mais quand ce n'est pas le cas, je ne veux pas que Doctrine lance une exception et plante mon application.

Les gens disent que l'utilisation d'un Entity Manager à l'intérieur d'une Entity est une très mauvaise pratique et je suis d'accord. Mais je suis confus à propos de l'utilisation des objets proxy ou mappage d'héritage à cette fin.

Il semble que l'utilisation de Models pourrait être le moyen, mais je n'ai pas trouvé de documentation solide sur la façon de les implémenter correctement dans Doctrine2 .

S'il vous plait aidez si vous le pouvez. Dans Kohana, c'était tellement simple (mais immature de cette façon).

MODIFIER:

@Massimiliano Fedel a suggéré d'essayer d' intercepter une exception dans la méthode User::getGroup() , pour finalement rendre les groupes non-existants retournés comme NULL .

J'ai donc engagé ce code:

/**
 * Get group
 *
 * @return \AppBundle\Entity\Group
 */
public function getGroup() {
    try {
        $group = $this->group;
    } catch (\Doctrine\ORM\EntityNotFoundException $e) {
        $group = null;
    }
    return $group;
}

Malheureusement, il semble que l'exception ne puisse pas être interceptée de cette façon, car le framework se termine par une Doctrine\ORM\EntityNotFoundException :

Entity of type 'AppBundle\Entity\Group' for IDs id(999) was not found

EDIT 2:

Vous trouverez ci-dessous un schéma de base du flux User , c'est-à-dire pourquoi je ne peux pas garantir que tous les Users auront des Groups disponibles dans ma base de données. http://oi64.tinypic.com/1sfno5.jpg

https://code.i-harness.com


1) Avez-vous essayé d'attraper l'exception dans la méthode getter du "groupe"? afin que vous puissiez attraper l'exception et retourner "null" en cas d'exception.

2) à partir de la documentation de la doctrine 2.1: "Les associations sont marquées comme paresseuses par défaut, ce qui signifie que l'objet de collection entier pour une association est rempli la première fois qu'il est accédé." http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html


Eh bien, qu'en est-il de la création d'un service, qui va envelopper vos opérations CRUD sur l'entité User , disons UserService ? De cette façon, vous pouvez laisser group_id tel quel et ajouter un champ de group qui n'est pas géré (pas d'annotations, pas de persistance dans DB).

UserService aura la méthode getGroup , qui prendra User comme argument, puis récupèrera son group_id et utilisera EntityManager (ou bien GroupService ) pour récupérer l'entité Group , si aucun n'a été trouvé, vous GroupService null , sinon vous allez définir le Group retourné au champ non géré de l'entité, vous n'avez donc pas à le récupérer la prochaine fois.


OK, tout d'abord, votre relation User - Group n'est pas correctement définie. Vous devez absolument ajouter la relation ManyToOne :

/**
 * @var \AppBundle\Entity\Group
 *
 * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Group")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="group_id", referencedColumnName="id")
 * })
 */
private $group;

Un mot à ce sujet. Dans la clause JoinColumns , par défaut, la relation est nullable, ce qui signifie que vous pouvez avoir la NULL au lieu de la clé étrangère dans la colonne group_id résultante (la colonne de jointure que Doctrine va créer pour vous).

Si vous voulez avoir une relation non-nullable, la définition doit aller comme ceci:

/**
 * @var \AppBundle\Entity\Group
 *
 * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Group")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="group_id", referencedColumnName="id", nullable=false)
 * })
 */
private $group;

Ainsi, par défaut, vous pouvez avoir un groupe NULL pour un User . Une fois que cela est correctement défini, en ce qui concerne vos questions:

1.

Si votre application est correctement créée, vous ne devez jamais vous retrouver avec un User lié à un Group qui n'a pas encore été validé dans la base de données. Chaque Group vous attachez à un User doit être retiré de Doctrine d'une manière ou d'une autre avant de persister dans l' User lui-même. Que ce soit à partir de l'application ou à partir d'un formulaire. Si vous devez valider que le Group existe avant de persister, vous devez résoudre le problème en amont, en étant sûr à 100% que tout Group vous utilisez est extrait de la base de données.

Dans ce contexte spécifique, le setGroup setter devrait déjà s'assurer que ce qui est fourni est bien une entité Group (sinon vous devriez ajouter un typehint), et Doctrine s'assure déjà que cette entité existe déjà dans la base de données. Je suis d'accord sur le fait que les erreurs de Doctrine peuvent être moche, mais un produit livré ne devrait pas inclure n'importe lequel d'entre eux.

Comprendre que la validation de Symfony est généralement utilisée avec des formulaires, avec l'intention de valider les violations potentielles introduites par l'utilisateur final, et non par le développeur (généralement).

2.

Avec une relation correctement définie, comme indiqué ci-dessus, Doctrine prendra soin de cela automatiquement pour vous. Par défaut, toutes les relations Doctrine sont chargées paresseusement.

Aussi:

/**
 * Get group
 *
 * @return \AppBundle\Entity\Group
 */
public function getGroup() {
    try {
        $group = $this->group;
    } catch (\Doctrine\ORM\EntityNotFoundException $e) {
        $group = null;
    }
    return $group;
}

Vous n'avez pas besoin de faire ça. Retirez-le.