Symfony2 Doctrine2 Relation many-to-many avec deux outils de ligne cmd Owning Sides et Doctrine

Dans mon Symdony2 projet que j'ai deux entités liées: Service et ServiceGroup. Cela devrait être plusieurs-à-plusieurs relations, parce que chaque groupe peut avoir de nombreux services, et chaque service appartient à plusieurs groupes. De plus, j'ai besoin d'une interface utilisateur pour gérer les services et les groupes. Ainsi, lors de l'édition d'un Service, l'utilisateur devrait être en mesure de choisir à quels groupes appartient. De la même façon, lors de l'édition d'un ServiceGroup utilisateur doit être en mesure de choisir les services qui appartient à ce groupe. J'ai déjà atteint ce niveau par la mise en place d'un plusieurs-À-Plusieurs dans ma Doctrine entités. Tout fonctionne comme un charme, y compris l'interface utilisateur de construire sur un formulaire personnalisé types de Symfony2 (j'ai utilisé le terme "entité" type de champ de formulaire pour permettre à l'utilisateur de sélectionner les services en ServiceGroup de l'éditeur et des groupes de l'éditeur de Service). Le seul problème que j'ai c'est que je ne peut pas utiliser la Doctrine de la ligne de commande pour mettre à jour la base de données de schéma plus.

Ici une partie de mes entité de Service code source:

class Service
{
    /**
     * @var ArrayCollection $groups
     * @ORM\ManyToMany(targetEntity="ServiceGroup")
     * @ORM\JoinTable(
     *      name="service_servicegroup",
     *      joinColumns={@ORM\JoinColumn(name="service_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="servicegroup_id", referencedColumnName="id")}
     * )
     */
    private $groups;
}

Et voici une partie de mon ServiceGroup entité code source:

class ServiceGroup
{
    /**
     * @var ArrayCollection $services
     * @ORM\ManyToMany(targetEntity="Service")
     * @ORM\JoinTable(
     *      name="service_servicegroup",
     *      joinColumns={@ORM\JoinColumn(name="servicegroup_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="service_id", referencedColumnName="id")}
     * )
     */
    private $services;
}

Je l'aide JoinTable dans les deux cas, parce que c'est le seul moyen que j'ai trouvé de travail quand il s'agit de sauver les relations de l'interface utilisateur des éditeurs, qui ressemble à ceci:

Service de l'éditeur:

Éditeur de Service

Nom: [ 1 ]

Groupes auxquels ce service appartient:

[x] Groupe A

[ ] Groupe B

[ ] Groupe C

[ ENREGISTRER ]

Et ServiceGroup éditeur:

Groupe éditeur de

Nom: [ Groupe A ]

Services appartient à ce groupe:

[x] Service 1

[ ] Service 2

[ ] Service 3

[ ENREGISTRER ]

Avec ce plusieurs-À-Plusieurs configuration, je suis en mesure d'utiliser cette rédaction (de formes) sans problème, lors de l'utilisation de plusieurs-À-Plusieurs sans JoinTable annotation, je suis en mesure d'utiliser un seul formulaire complètement, et le second est de ne pas enregistrer les modifications dans les "Groupes à qui ce service appartient" ou "Services appartient à ce groupe" (dépend de la direction dans laquelle je suis mappedBy et inversedBy paramètres dans plusieurs-À-Plusieurs annotation déclaration).

Le problème que j'ai est connecté avec la doctrine de génération de schéma de mécanisme, lors de la tentative de mise à jour de schéma à l'aide de Symfony2 commande:

php app/console doctrine:schema:update --dump-sql

Je suis de cette exception:

[Doctrine\DBAL\Schema\SchemaException]                      
The table with name 'service_servicegroup' already exists.

Il ressemble à la Doctrine d'essayer de créer des " service_servicegroup table pour chaque JoinTable déclaration. Donc, c'est de travailler sur le schéma actuel, que j'ai dans la base de données à l'aide de la même commande, mais étape par étape, d'abord quand pas plusieurs-À-Plusieurs relation est définie et la suivante avec seulement un seul, Plusieurs-À-Plusieurs relation de définition (pour le Service de l'entité). Lorsque j'ai ajouté plusieurs-À-Plusieurs rapport à la deuxième entité (ServiceGroup), ma demande coutures de travailler sans problème du point de vue des utilisateurs, mais je ne suis pas en mesure d'utiliser la "doctrine:schema:update' commande plus.

J'ai aucune idée de quel est le problème avec mon code, peut-être que cette relation devrait être mis en œuvre de manière différente, ou peut-être que c'est une Doctrine bug/limitation. Toute aide ou suggestion sera la bienvenue.

Mise à JOUR:

J'ai remarqué que ce dont j'ai besoin est de le configurer en relation ManyToMany avoir posséder deux côtés. Par défaut est d'avoir un posséder côté et un côté inverse. La Doctrine la documentation dit que vous pouvez avoir deux posséder côtés en relation ManyToMany, mais n'explique pas beaucoup. N'importe qui peut donner un exemple?

Solution de CONTOURNEMENT:

J'ai trouvé une solution de contournement des solutions, qui n'est peut-être pas l'idéal, mais ça fonctionne pour moi.
Comme il n'existe pas de façon de posséder deux côtés dans plusieurs-à-plusieurs relation, j'ai changé de Doctrine d'annotation pour mes entités. Entité de Service est maintenant le propriétaire de côté:

class Service
{
    /**
     * @var ArrayCollection $groups
     * @ORM\ManyToMany(targetEntity="ServiceGroup", inversedBy="services", cascade={"all"})
     * @ORM\JoinTable(
     *      name="service_to_group_assoc",
     *      joinColumns={@ORM\JoinColumn(name="service_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
     * )
     */
    private $groups;
}

Et ServiceGroup entité est l'inverse côté:

class ServiceGroup
{
    /**
     * @var ArrayCollection $services
     * @ORM\ManyToMany(targetEntity="Service", mappedBy="groups", cascade={"all"})
     */
    private $services;
}

Malheureusement, avec cette configuration, le rapport est mis à jour uniquement lorsque le Service de mise à jour de l'entité. Quand je change de $services dans ServiceGroup objet et persister, la relation ne sera pas modifié. Donc, j'ai changer mon Contrôleur de classe, et avec l'aide de la petite solution de rechange, j'ai obtenu le résultat escompté. C'est une partie de mon code de Contrôleur, qui est responsable de la mise à jour de ServiceGroup entité (avec une utilisation de la coutume de type de formulaire):

//before update - get copy of currently related services:
$services = clone $group->getServices();

//...

//when $form->isValid() etc. updating the ServiceGroup entity:

//add selected services to group
foreach($group->getServices() as $service)
{
    $service->addServiceGroup($group);
    $services->removeElement($service);
}

//remove unselected services from group
foreach($services as $service)
{
    $service->removeServiceGroup($group);
}

Ce sont des implémentations de addServiceGroup et removeServiceGroup méthodes de l'entité de Service de classe:

/**
 * Add group
 *
 * @param ServiceGroup $groups
 */
public function addServiceGroup(ServiceGroup $groups)
{
    if(!in_array($groups, $this->groups->toArray()))
    {
        $this->groups[] = $groups;
    }
}

/**
 * Remove group
 *
 * @param ServiceGroup $groups
 */
public function removeServiceGroup(ServiceGroup $groups)
{
    $key = $this->groups->indexOf($groups);

    if($key!==FALSE) 
    {
        $this->groups->remove($key);
    }
}

Maintenant, j'ai travaillé plusieurs-à-plusieurs rapport à la possession (de Service) et l'inverse (ServiceGroup) et les formulaires mis à jour à la fois de l'entité et de la relation lors de l'enregistrement (formulaire par défaut pour le Service de l'entité est suffisant, mais pour ServiceGroup, j'ai fourni ci-dessus mentionnés aux modifications). Le Symfony/Doctrine de la console sont les outils de travail comme un charme. C'est probablement ce qui peut être résolu en mieux (plus simple?) façon, mais pour moi, c'est assez pour le moment.

source d'informationauteur Darrarski