comment configurer les relations entre les tables

Ce sujet est résolu
Default
,

bonjour les amis, je travaille sous une base de donnée sous wampserver mais qui ne contient aucune relations(clé étrangère ..) et j'ai commencé mon projet sous symfony2, j'ai bien testé mais fonctions et tout marche bien, mais quand j'ai voulut ajouter des relations je me bloque

merci de m'aider .

Cordialement

19 Réponse

32285
,

Je vois deux problèmes, déja:

  • Es-tu sur que c'est une relation many-to-one que tu veux ? Tu ne peux pas mettre plusieurs catégories par article ? Si tu peux c'est une relation many-to-many. Regarde cette partie du tuto sdz pour la relation many-to-many. En particulier pense bien a définir categories en tant qu'array collection dans le constructeur d'article:

    public function __construct() {
    $this->categories = new \Doctrine\Common\Collections\ArrayCollection();
    }

  • D'autre part, dans ton entité article je vois que tu as les attributs categories et nomcategorie, les deux ayant la meme target entity. C'est une erreur car le nom de ta ou de tes categories est un attribut de ton entité category, pas de ton entité article.

Avant d'essayer de récupérer tes articles avec leur(s) catégories dans une vue, je te suggère de te faire un controller bidon qui va simplement créer un nouvel article, y associer 1 ou plusieurs catégories, et persister (pas de formulaire, juste cablé en dure dans l'action d'un controller de demo "Hello", par exemple). Vérifie ensuite avec phpmyadmin que tu as bien une sauvegarde de ton article, de ta ou tes catégorie(s), et que les champs qui servent pour les clés sont correctement remplis. Tant que cette étape ne marche pas correctement, c'est que tes entités sont foireuses, et c'est pas la peine d'espérer avoir ce que tu veux dans ta vue !

Default
,

up !!

32285
,

tu utilises doctrine ?

Default
,

oui

32285
,

Ben alors il y a pas de difficulté.

Tu configures tes relations entre tes entités directement dans tes classes, avec les annotations. Tu fais un update de ton schema et doctrine s'occupe de mettre a jour les clés.

De toute façon si tu utilise un ORM, tu ne t'occupe jamais de tes tables MySQL, tu gères tout directement a travers tes entités.

voir ici pour le doc: http://symfony.com/doc/current/book/doctrine.html#entity-relationships-associations

et éventuellement la pour un tuto: http://fr.openclassrooms.com/informatique/cours/developpez-votre-site-web-avec-le-framework-symfony2/les-relations-entre-entites-avec-doctrine2

Default
,

merci pour les tuto ils sont intéressent

Donc j'ai commencer à appliquer les relations, j'ai établit une relation ManyToOne entre article et catégorie et ça marche très bien au niveau du contrôleur sauf au niveau de la vue et voilà quelque portion de code

Default
,

Ma vue: voirarticle.html.twig

{% for article in produit %}
            <center>
                <table border="1" width="500">
                   <tr>
                       <th>Nom</th>
                       <th>Description</th>
                       <th>Image</th>


                       <th style="width: 100px"><center>Prix </center></th>
                       <th>Categorie</th>
                   </tr>
                    <tr>
                        <td>{{ article.nom }}</td>
                        <td>{{ article.description }}</td>
                        <td><img src="{{ article.image }}"></td>
                        <td>{{ article.prix }} Dinars</td>
                        <td> {{ article.categories }}</td> //le problème ce trouve dans cette ligne quand je veux intégrer la catégorie (qui est ma clé étrangère) dans la vue//
                        <td><a href="{{ path('editera', {'id':article.id}) }}" class="button edit">Modifier</a></td>
                        <td><a href="{{ path('supprimerart', {'id':article.id}) }}" class="button delete">Supprimer</a></td>
                        </tr>
                </table>
        </center>
    {% endfor %}
Default
,

Et voilà aussi une portion de code de ArticleType.php notons bien que dans ma classe Article.php j'ai ajouté $categories(avec ses getters et setters) comme étant ManyToOne

<?php
namespace Yoss\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ArticleType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('nom')
            ->add('description')
            ->add('image')
            ->add('prix')
            ->add('categories', 'entity', array(
                    'class' => 'YossAdminBundle:Categorie',
                    'property' => 'nomcategorie',
                    'multiple' => true)
            );
        ;
    }
32285
,

Dans ta vue tu peux faire un debug de article, pour voir comment il s'organise. Mais vu qu'a priori article.categories est un objet ou un arrayCollection, twig ne peux pas le linéariser en string.

Essaue peut-etre un truc comme 'article.categories.nom' si categories est un objet avec un attribut 'nom'; ou bien 'article.categories[0].nom' si categories est un arraycollection d'objets qui ont un attribut 'nom' ...

... enfin tu vois le genre ;)

Default
,

Merci pour ton aide Vallyan, ça marche bien avec la fonction voir() mais quand je veux ajouter un article ce message m’apparaît:

Neither the property "categorie" nor one of the methods "getCategorie()", "isCategorie()", "hasCategorie()", "__get()" exist and have public access in class "Yoss\AdminBundle\Entity\Article".
32285
,

Va falloir que tu nous montres tes entités article et categories, du coup !

Default
,

Article.php

<?php
namespace Yoss\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
 * Article
 *
 * @ORM\Table(name="article")
 * @ORM\Entity
 */
class Article
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;


    /**
     * @var string
     *
     * @ORM\Column(name="nom", type="string", length=255, nullable=false)
     */
    private $nom;
    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text", nullable=false)
     */
    private $description;
    /**
     * @var string
     *
     * @ORM\Column(name="image", type="string", length=255, nullable=false)
     */
    private $image;
    /**
     * @var float
     *
     * @ORM\Column(name="prix", type="float", precision=10, scale=0, nullable=false)
     */
    private $prix;
    /**
     * @ORM\ManyToOne(targetEntity="Yoss\AdminBundle\Entity\Categorie", cascade={"persist"})
     * @ORM\JoinColumn(nullable=false)
     */
    private $categories;


    /**
     * @ORM\ManyToOne(targetEntity="Yoss\AdminBundle\Entity\Categorie", cascade={"persist"})
     * @ORM\JoinColumn(nullable=false)
     */
    private $nomcategorie;


    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * @param string $nom
     */
    public function setNom($nom)
    {
        $this->nom = $nom;
    }
    /**
     * @return string
     */
    public function getNom()
    {
        return $this->nom;
    }
    /**
     * @param string $description
     */
    public function setDescription($description)
    {
        $this->description = $description;
    }
    /**
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }
    /**
     * @param string $image
     */
    public function setImage($image)
    {
        $this->image = $image;
    }
    /**
     * @return string
     */
    public function getImage()
    {
        return $this->image;
    }
    /**
     * @param float $prix
     */
    public function setPrix($prix)
    {
        $this->prix = $prix;
    }
    /**
     * @return float
     */
    public function getPrix()
    {
        return $this->prix;
    }
    /**
     * @param mixed $categories
     */
    public function setCategories($categories)
    {
        $this->categories = $categories;
    }
    /**
     * @return mixed
     */
    public function getCategories()
    {
        return $this->categories;
    }
    /**
     * @param mixed $nomcategorie
     */
    public function setNomcategorie($nomcategorie)
    {
        $this->nomcategorie = $nomcategorie;
    }
    /**
     * @return mixed
     */
    public function getNomcategorie()
    {
        return $this->nomcategorie;
    }






}
Default
,

Categorie.php

<?php
namespace Yoss\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
 * Categorie
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Yoss\AdminBundle\Entity\CategorieRepository")
 */
class Categorie
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var string
     *
     * @ORM\Column(name="nomcategorie", type="string", length=255)
     */
    private $nomcategorie;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Set nomcategorie
     *
     * @param string $nomcategorie
     * @return Categorie
     */
    public function setNomcategorie($nomcategorie)
    {
        $this->nomcategorie = $nomcategorie;
        return $this;
    }
    /**
     * Get nomcategorie
     *
     * @return string 
     */
    public function getNomcategorie()
    {
        return $this->nomcategorie;
    }
}
Default
,

Merci

Default
,

Mais concernant la relation ManyToOne je vois qu'elle est plus logique que ManyToMany parce que tout simplement elle se traduit comme ça "Many Article To One Categorie" c'est à dire qu' Une categorie peut contenir plusieurs articles, alors qu'un article n'appartient qu'à une seule categorie

32285
,

Tu veux dire qu'un article aura toujours une seule catégorie ?

J'avais un doute parce que tu utilise categories (au pluriel) comme nom ...

Default
,

oui un article aura une seule categorie, et dans la classe categorie je l'ai écrit sans S c'est juste au niveau de la classe article et comme étant catégories une clé étrangère donc j'ai ajouté le S juste pour spécifier que c'est la clé et non pas la classe

32285
,

J'ai fait un test, c'est un code un peu bidon et hyper simplifié mais il fonctionne. Par contre fait gaffe quand tu le recopies pour que ca colle avec ta config (namespaces en particulier)

Article.php

<?php
namespace Tests\Bundle\ArticleBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
 * Article
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Tests\Bundle\ArticleBundle\Entity\ArticleRepository")
 */
class Article
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var string
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;
    /**
    * @ORM\ManyToOne(targetEntity="Tests\Bundle\ArticleBundle\Entity\Category", cascade={"persist"})
    * @ORM\JoinColumn(nullable=false)
    */
    private $category;


    /**
     * Get id
     * @return integer 
     */
    public function getId() {
        return $this->id;
    }
    /**
     * Set name
     * @param string $name
     * @return Article
     */
    public function setName($name) {
        $this->name = $name;
        return $this;
    }
    /**
     * Get name
     * @return string 
     */
    public function getName() {
        return $this->name;
    }
    /**
     * Set category
     * @param \stdClass $category
     * @return Article
     */
    public function setCategory(\Tests\Bundle\ArticleBundle\Entity\Category $category) {
        $this->category = $category;
        return $this;
    }
    /**
     * Get category
     * @return \stdClass 
     */
    public function getCategory() {
        return $this->category;
    }
}

Category.php

<?php
namespace Tests\Bundle\ArticleBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
 * Category
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Tests\Bundle\ArticleBundle\Entity\CategoryRepository")
 */
class Category
{
    /**
     * @var integer
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var string
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;


    /**
     * Get id
     * @return integer 
     */
    public function getId() {
        return $this->id;
    }
    /**
     * Set name
     * @param string $name
     * @return Category
     */
    public function setName($name) {
        $this->name = $name;
        return $this;
    }
    /**
     * Get name
     * @return string 
     */
    public function getName() {
        return $this->name;
    }
}

DefaultController.php

<?php
namespace Tests\Bundle\ArticleBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Tests\Bundle\ArticleBundle\Entity\Article;
use Tests\Bundle\ArticleBundle\Entity\Category;
class DefaultController extends Controller
{
    public function indexAction( $name )
    {
        $article = new Article;
        $article->setName('La san felice');
        $category = new Category;
        $category->setName('livre');
        $article->setCategory( $category );
        $em = $this->getDoctrine()->getManager();
        $em->persist( $article );
        $em->flush();
        return $this->render('TestsArticleBundle:Default:index.html.twig', array('article' => $article));
    }
}

index.html.twig

<body>
    Article: {{ article.name }}
    <br />
    Catégorie {{ article.category.name }}
</body>

Les trucs auxquels il faut faire gaffe:

  • Le mapping ManyToOne, avec cascade={persiste} (Article.php, ligne 26)
  • La contrainte de type pour l'attribut category (Article.php, ligne 63)
  • Bien faire un 'app/console doctrine:schema:update --force'
Default
,

merci :)