Je suis en train de suivre le tuto sur Symfony, et je suis coincé sur quelque chose que je souhaite faire.
Peut-être n'ai-je pas bien assimilé certaines notions, mais après plusieurs recherches, je ne trouve pas vraiment de réponse à ma question, alors je m'essaie ici !
Concrètement, j'ai une entité User dans laquelle j'ai créé un attribut $role. Cela me sert à stocker, comme vous vous en doutez, le rôle qu'aura un utilisateur (ex: Utilisateur, Administrateur, Modérateur, etc...), à savoir que cette liste est modifiable aussi bien en ajout qu'en suppression.
J'ai donc créé une autre entité rôle (à priori les types enum sont vivement déconseillés par la communauté et mettre une énumération PHP dans ma classe User rendrait cette liste de rôles fixe) dans laquelle j'ai un attribut unique=true $name.
Voici mon entité User (partiel, je vous met le plus important) :
<?php
namespace RB\BackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="RB\BackBundle\Repository\UserRepository")
*/
class User
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="mail", type="string", length=255, unique=true)
*/
private $mail;
/**
* @var string
*
* @ORM\Column(name="username", type="string", length=255, unique=true)
*/
private $username;
/**
* @var \stdClass
*
* @ORM\OneToOne(targetEntity="RB\BackBundle\Entity\Role", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
*/
private $role;
public function __construct()
{
$this->inscriptionDate = new \DateTime;
}
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set mail
*
* @param string $mail
*
* @return User
*/
public function setMail($mail)
{
$this->mail = $mail;
return $this;
}
/**
* Get mail
*
* @return string
*/
public function getMail()
{
return $this->mail;
}
/**
* Set username
*
* @param string $username
*
* @return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set role
*
* @param \stdClass $role
*
* @return User
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
/**
* Get role
*
* @return \stdClass
*/
public function getRole()
{
return $this->role;
}
}
Et voici mon entité Role :
<?php
namespace RB\BackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Role
*
* @ORM\Table(name="role")
* @ORM\Entity(repositoryClass="RB\BackBundle\Repository\RoleRepository")
*/
class Role
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
* @ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
*
* @return Role
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
}
Maintenant, j'ai créer une fixture Doctrine pour pouvoir pré-remplir ma base lors des tests.
Fixture LoadRole :
<?php
namespace RB\BackBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use RB\BackBundle\Entity\Role;
class LoadRole implements FixtureInterface
{
public function load(ObjectManager $manager)
{
// Liste des noms de catégorie à ajouter
$names = array(
'Administrateur',
'Utilisateur'
);
foreach($names as $name)
{
$role = new Role;
$role->setName($name);
$manager->persist($role);
}
$manager->flush();
}
}
Et Fixture LoadUser :
<?php
namespace RB\BackBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use RB\BackBundle\Entity\User;
use RB\BackBundle\Entity\Role;
class LoadUser implements FixtureInterface
{
public function load(ObjectManager $manager)
{
// Liste des noms de catégorie à ajouter
$user = new User;
$role = new Role;
$role->setName('Administrateur');
$user->setMail('test@test.fr');
$user->setUsername('admin_root');
$user->setRole($role);
$manager->persist($user);
$manager->flush();
}
}
C'est là que je bloque car pour moi le problème est ici. Lorsque je l'exécute avec l'attribut name de mon entité Role à unique=false, tout fonctionne MAIS j'obtiens une entrée (Administrateur) en double.
Mais si je l'exécute avec unique=true, j'obtiens ce message d'erreur :
C:\wamp64\www\Symfony>php bin/console doctrine:fixtures:load
Careful, database will be purged. Do you want to continue y/N ?y
> purging database
> loading RB\BackBundle\DataFixtures\ORM\LoadCategory
> loading RB\BackBundle\DataFixtures\ORM\LoadRole
> loading RB\BackBundle\DataFixtures\ORM\LoadUser
[Doctrine\DBAL\Exception\UniqueConstraintViolationException]
An exception occurred while executing 'INSERT INTO role (name) VALUES (?)' with params ["Administrateur"]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicata du champ 'Administrateur' pour la clef 'UNIQ_57698A
6A5E237E06'
[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicata du champ 'Administrateur' pour la clef 'UNIQ_57698A
6A5E237E06'
[PDOException]
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicata du champ 'Administrateur' pour la clef 'UNIQ_57698A
6A5E237E06'
doctrine:fixtures:load [--fixtures [FIXTURES]] [--append] [--em EM] [--shard SHARD] [--purge-with-truncate] [--multiple-transactions] [-h|--help] [-q|--quiet] [-v|vv|vvv|--verbose] [-V|--version] [--ansi] [--no-ansi] [-n|--no-interaction] [-e|--env ENV] [--no-debug] [--] <command>
J'ai également essayé de ne pas mettre le persist dans User :
C:\wamp64\www\Symfony>php bin/console doctrine:fixtures:load
Careful, database will be purged. Do you want to continue y/N ?y
> purging database
> loading RB\BackBundle\DataFixtures\ORM\LoadCategory
> loading RB\BackBundle\DataFixtures\ORM\LoadRole
> loading RB\BackBundle\DataFixtures\ORM\LoadUser
[Doctrine\ORM\ORMInvalidArgumentException]
A new entity was found through the relationship 'RB\BackBundle\Entity\User#role' that was not configured to cascade
persist operations for entity: RB\BackBundle\Entity\Role@00000000557b5a30000000007588f904. To solve this issue: Ei
ther explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association
in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the probl
em implement 'RB\BackBundle\Entity\Role#__toString()' to get a clue.
doctrine:fixtures:load [--fixtures [FIXTURES]] [--append] [--em EM] [--shard SHARD] [--purge-with-truncate] [--multiple-transactions] [-h|--help] [-q|--quiet] [-v|vv|vvv|--verbose] [-V|--version] [--ansi] [--no-ansi] [-n|--no-interaction] [-e|--env ENV] [--no-debug] [--] <command>
J'ai donc bel et bien un problème de construction logique de ma base, mais je ne suis pas habitué à "penser" objet au niveau de mes bases de données Donc si vous avez des idées, je suis preneur !
Quand tu fais ta fixture LoadUser avec unique = false ... Dans quel ordre se charge les fixtures ? car si tu as Role avant User cela me semble normal que tu ais 2 fois Administrateur.
Idem si ta fixture LoadUser est faite après la fixture LoadRole où tu demandes un unique, tu ne peux plus saisir un rôle avec le nom Administrateur puisque tu demandes à ce qu'il soit unique.
Je ne pense pas que ce soit un problème de construction logique d'entité (et non de base restons dans le vocabulaire Symfony).
Quand j'exécute ma commande cela me donne d'abord :
C:\wamp64\www\Symfony>php bin/console doctrine:fixtures:load
Careful, database will be purged. Do you want to continue y/N ?y
> purging database
> loading RB\BackBundle\DataFixtures\ORM\LoadCategory
> loading RB\BackBundle\DataFixtures\ORM\LoadRole
> loading RB\BackBundle\DataFixtures\ORM\LoadUser
Je suppose donc que Role est chargée avant User.
Le truc, c'est que lorsque je créer un User, je veux simplement lui associer u rôle déjà existant et non plus en créer un nouveau (sauf si celui-ci n'existe pas à la limite). Donc j'ai bien une relation, puisque je souhaite avoir accès au rôle depuis mon utilisateur et qu'un utilisateur "possède" un rôle, mais je ne souhaite pas que cela m'en créer un nouveau, sinon à chaque inscription, cela me ferait une nouvelle instance (une nouvelle insertion en bdd pour vulgariser) de Role à chaque fois, or, je souhaite réutiliser ces rôles.
Je ne sais pas si je suis bien clair ? ^^' Peut-être est-ce le type de relation qui coince ? Je suis en OneToOne et User est propriétaire de la relation actuellement.
Merci d'avance
[EDIT]
J'ai bien modifié la relation en ManyToOne avec User comme propriétaire, mais le problème reste inchangé. Je pense que c'est la façon dont j'ajoute le rôle à l'utilisateur qui coince...
Si je ne dois pas faire de new Role, je suppose que je dois passer par le Manager Doctrine pour récupérer mon entité depuis la base de données ? Cependant, j'ai essayé ces deux versions, mais j'obtiens toujours une erreur :
[Symfony\Component\Debug\Exception\UndefinedMethodException]
Attempted to call an undefined method named "getContainer" of class "RB\BackBundle\DataFixtures\ORM\LoadUser".
[Symfony\Component\Debug\Exception\UndefinedMethodException]
Attempted to call an undefined method named "getDoctrine" of class "RB\BackBundle\DataFixtures\ORM\LoadUser".
Est-ce que j'oublierai un include ?
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use RB\BackBundle\Entity\User;
use RB\BackBundle\Entity\Role; use Doctrine\ORM\EntityManager;
Merci d'avance !
[EDIT]
Le <br> dans le dernier bout de code est une bug de l'éditeur d'OC, dans mon code c'est bien un retour à la ligne hein !
[EDIT2] - Solution
Après quelques autre recherches, j'ai fini par trouver !
Cependant, j'ai lu qu'il était préférable de faire la façon décrite par la doc Symfony
Si jamais ça intéresse les prochains !
Merci de ton aide monkey3d !
- Edité par Algorun 19 novembre 2017 à 13:12:04
Celui qui croit tout savoir ne sait rien
[Synfony3][Doctine2] - Entité stockant une liste
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.