Problème affichage données

Symfony 3

a marqué ce sujet comme résolu.

Bonjour à tous !

Je reviens vers vous car j’ai un problème, toujours avec Symfony. Pour le moment, l’affichage de base fonctionne très bien avec le bootstrap CSS, l’héritage des templates également. Cependant, j’ai un souci quand j’essaie d’afficher des données stockées dans la base de données mais malheureusement, j’obtiens l’erreur suivante :

“ An exception occured in driver: SQLSTATE[HY000] [2006] MySQL server has gone away 500 Internal Server Error - DriverException 3 linked Exceptions: PDOException » PDOException » PDOException »

J’ai un controller qui s’appelle ProduitController avec une simple action index :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

namespace MPCleanCoreBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use MPCleanCoreBundle\Entity\Produit;

class ProduitController extends Controller
{
    /**
     * @Route("/index")
     */
    public function indexAction()
    {       
        $produits = $this->getDoctrine()->getRepository("MPCleanCoreBundle:Produit")->findAll();

        return $this->render('MPCleanCoreBundle:Produit:index.html.twig', array(
            'produits' => $produits
        ));
    }
}

J’ai bien une entité Produit qui a été généré via la ligne de commande une fois que la base a été créée puis, dans mon index, j’ai un truc tout con :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{% extends "::layout.html.twig" %}

{% block title %}{{ parent() }}{% endblock %}

{% block body %}
    <b>Produits</b>

    {% for produit in produits %}
        {{ produit.libelle_prod }}
    {% endfor %}
{% endblock %}

J’ai également essayé via la méthode getLibelleProd en utilisant l’Entity Manager mais quoique je fasse, j’obtiens cette erreur. Pourtant, j’ai bien extension=php_pdo_mysql.dll qui est décommentée dans PHP.ini.

Merci d’avance pour votre aide !

+0 -0

Salut !

J’ai l’impression qu’il y a un souci avec le serveur MySQL… Ce genre d’erreur m’est arrivé quand le serveur dépasse le temps maximal d’exécution, et du coup, ne répond rien et même coupe la connexion. Tu as vraiment vraiment beaucoup de produits ? Ou tu te connectes à un serveur qui n’est pas local ?

Si jamais, la colodation syntaxique pour des templates Twig, c’est html+django  ;)

+0 -0

Non, justement, c’est pour cela que cela me paraît bizarre. Je n’ai qu’un produit dans la base. Est-ce que le fait que le produit soit relié à plusieurs autres tables puissent engendrer ces erreurs en sachant que les autres tables contiennent au maximum deux entrées ?

Je mets toujours 127.0.0.1, et je n’ai jamais eu aucun soucis.

John

Je me souviens qu’un temps, il m’a fallu utiliser l’une ou l’autre adresse IP, parce que le serveur n’écoutait que sur soit ::1, soit 127.0.0.1, et comme localhost n’est pas nécessairement résolu par les deux…

+0 -0

Effectivement, cela fonctionne maintenant. Apparemment, il faut lui indiquer le port 3306 dans les paramètres.

Maintenant, j’ai juste une question de clarification :

  • On utilise le Repository quand on veut faire une recherche de données dans la base (une requête SELECT, en gros) et on utilise l’Entity Manager quand on veut ajouter/modifier/supprimer des données ?

Ah, et est-ce qu’il existe une fonction pour mettre à jour une entité ? Je n’ai rien trouvé de concret là-dessus.

  • On utilise le Repository quand on veut faire une recherche de données dans la base (une requête SELECT, en gros) et on utilise l’Entity Manager quand on veut ajouter/modifier/supprimer des données ?
Charvalos

C’est l’idée, oui.

Ah, et est-ce qu’il existe une fonction pour mettre à jour une entité ? Je n’ai rien trouvé de concret là-dessus.

Charvalos

Non, il n’y en a pas de spéciale, parce qu’il suffit de persister l’objet modifié, comme s’il était créé. Doctrine s’arrange derrière pour savoir s’il faut faire une mise à jour ou une insertion.

+0 -0

OK mais en si, par exemple, je modifier le nom d’un champ dans ma base ou j’en rajoute un, Symfony ne vas pas mettre jour l’entité automatiquement non ?

Dernière question également : comment gérer l’héritage dans un modèle de base de données (en gros, j’ai une entité (dans le sens MCD) Marchandise et de ça, j’ai deux entités Prestation & Produit qui en découlent).

+0 -0

Ce n’est plus la même chose si tu changes le nom d’un champ  ^^
Tu devras du coup modifier ton entité en conséquence. Si tu ajoutes une propriété, pareil, tu dois lancer la commande pour mettre à jour ton schéma.

Pour ce qui est de l’héritage, Doctrine propose deux implémentations, à toi de voir si ça te convient.

+0 -0

Ok, merci.

J’ai regardé pour l’héritage et cela ne semble pas si compliqué que cela. Cependant, j’en reviens un peu à ma question d’avant : est-ce que si je fais une modification d’une entité, est-ce qu’il y moyen de dire à Symfony de mettre à jour dans la base (ou vice-versa)? Car Symfony ne remarque pas qu’il s’agit d’héritage dans ma base. Le seul lien qui relie les produits et prestations à marchandises est la clé primaire de marchandises qui devient une clé étrangère dans les deux autres tables. La seul donnée commune qui est donc dans la table marchandise est le prix.

Je sais qu’il existe des commandes telles que generate::entities (truc du genre) mais je n’ai pas l’impression qu’il existe une commande qui ressemblerait à update::entities ou quelquec chose du genre. Ou alors, le mieux est de supprimer toutes entités et de les générer pour avoir un truc clean.

+0 -0

C’est quand-même à ça que set la commande doctrine:schema:update que tu dois déjà avoir utilisée…

Ymox

Je pense que sa question porte sur autre chose, mais ce n’est pas très clair.

De ce que je comprends il demande si, dans le cas d’entités étendues, l’entité mère est automatiquement mise à jour lorsque l’entité fille est modifiée et persistée. Si telle est la question, la réponse est oui. Si ni la réponse d’Ymox ni la mienne ne conviennent, il va falloir être plus clair dans la demande.

+0 -0

En fait, ma question est simple mais peut paraître stupide. On peut mettre à jour la base de données via schema:udpate si je fais une modification dans les entités mais est-ce que l’inverse est possible ? C’est-à-dire mettre à jour les entités si je fais une modifications dans la base de données ?

C’est possible, mais je ne pense pas que tu puisses le faire simplement. Il existe une commande pour créer des entités depuis la base de données, mais justement, c’est uniquement pour créer, pas pour mettre à jour, ce qui veut dire que l’utiliser pour mettre à jour va probablement tout écraser… Je ne pense pas que ce soit la volonté.

Maintenant, je suis curieux : pourquoi vouloir mettre à jour la base de données plutôt que les entités ? Normalement, on s’occupe du domaine, pas de la partie stockage persistant, il me semble.

+1 -0

Pour te répondre, c’est sûrement dû au fait que pour moi, la base de données sert de base et que les entités se basent là-dessus et pas le contraire.

Enfin bref, j’avance gentiment mais j’ai encore quelques soucis. J’essaie de mettre en place l’héritage.

Dans ma base de données, cela ressemble à ceci :

Table marchandises : id_marc, prix_marc

Table produit : id_prod, fk_cat (catégorie du produit), fk_type (type de produit), fk_marq (Marque du produit), libelle_prod, description_prod, qte_prod, fk_med (image reliée), fk_marc (relié à la table marchandises)

Table prestation : id_prestation, fk_art (relié à une table article), libelle_serv, description_serv, fk_marc (même champ que la table produits).

Marchandises.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

namespace MPCleanCoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Marchandises
 *
 * @ORM\Table(name="marchandises", uniqueConstraints={@ORM\UniqueConstraint(name="ind_id_marc", columns={"id_marc"})})
 * @ORM\Entity
 * @ORMInheritance("JOINED")
 * @ORMDiscriminatorColumn(name = "type", type = "string")
 * @ORMDiscriminatorMap({"prestation" = "Prestation", "produit" = "Produit"})
 */
abstract class Marchandises
{
    /**
     * @var string
     *
     * @ORM\Column(name="prix_marc", type="decimal", precision=10, scale=0, nullable=false)
     */
    private $prixMarc;

    /**
     * @var integer
     *
     * @ORM\Column(name="id_marc", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $idMarc;
}

Produit.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<?php
namespace MPCleanCoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
 * Produit
 *
 * @ORM\Table(name="produit", uniqueConstraints={@ORM\UniqueConstraint(name="ind_id_produit", columns={"id_prod"})}, indexes={@ORM\Index(name="produit_marchandise", columns={"fk_marc"}), @ORM\Index(name="ind_fk_media", columns={"fk_med"}), @ORM\Index(name="ind_fk_cat", columns={"fk_cat"}), @ORM\Index(name="ind_fk_type", columns={"fk_type"}), @ORM\Index(name="ind_fk_marq", columns={"fk_marq"})})
 * @ORM\Entity
 */
class Produit extends Marchandises
{
    /**
     * @var integer
     *
     * @ORM\Column(name="fk_cat", type="integer", nullable=false)
     */
    private $fkCat;
    /**
     * @var integer
     *
     * @ORM\Column(name="fk_type", type="integer", nullable=false)
     */
    private $fkType;
    /**
     * @var integer
     *
     * @ORM\Column(name="fk_marq", type="integer", nullable=false)
     */
    private $fkMarq;
    /**
     * @var string
     *
     * @ORM\Column(name="libelle_prod", type="text", length=255, nullable=false)
     */
    private $libelleProd;
    /**
     * @var string
     *
     * @ORM\Column(name="description_prod", type="text", length=255, nullable=false)
     */
    private $descriptionProd;
    /**
     * @var integer
     *
     * @ORM\Column(name="qte_prod", type="integer", nullable=false)
     */
    private $qteProd;
    /**
     * @var integer
     *
     * @ORM\Column(name="id_prod", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $idProd;
    /**
     * @var \MPCleanCoreBundle\Entity\Media
     *
     * @ORM\ManyToOne(targetEntity="MPCleanCoreBundle\Entity\Media")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="fk_med", referencedColumnName="id_med")
     * })
     */
    private $fkMed;
    /**
     * @var \MPCleanCoreBundle\Entity\Produit
     *
     * @ORM\ManyToOne(targetEntity="MPCleanCoreBundle\Entity\Marchandises")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="fk_marc", referencedColumnName="id_marc")
     * })
     */
    private $fkMarc;
}

Prestation.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?php

namespace MPCleanCoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Prestation
 *
 * @ORM\Table(name="prestation", indexes={@ORM\Index(name="marchandise_prestation", columns={"fk_marc"}), @ORM\Index(name="marchandise_article", columns={"fk_art"})})
 * @ORM\Entity
 */
class Prestation extends Marchandises
{
    /**
     * @var integer
     *
     * @ORM\Column(name="fk_art", type="integer", nullable=false)
     */
    private $fkArt;

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

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

    /**
     * @var integer
     *
     * @ORM\Column(name="id_prestation", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $idPrestation;

    /**
     * @var \MPCleanCoreBundle\Entity\Marchandises
     *
     * @ORM\ManyToOne(targetEntity="MPCleanCoreBundle\Entity\Marchandises")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="fk_marc", referencedColumnName="id_marc")
     * })
     */
    private $fkMarc;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="MPCleanCoreBundle\Entity\OptionPrestation", inversedBy="fkMarc")
     * @ORM\JoinTable(name="contenir",
     *   joinColumns={
     *     @ORM\JoinColumn(name="fk_marc", referencedColumnName="id_prestation")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="fk_opt", referencedColumnName="id_opt")
     *   }
     * )
     */
    private $fkOpt;

}

Vu que j’utilise un héritage multitables, j’ai utilisé le JOINED .

Quand je vais sur ma page produit, j’obtiens l’erreur suivante :

Duplicate definition of column ’id_marc’ on entity ’MPCleanCoreBundle\Entity\Produit’ in a field or discriminator column mapping.

Si je fais le doctrine:schema:update via la console, j’obtiens l’erreur suivante :

[Doctrine\ORM\Mapping\MappingException] Entity ’MPCleanCoreBundle\Entity\Prestation’ has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). T his is not supported.

Je suis en train de me demander s’il ne vaut mieux pas que je supprime toutes mes entités vu que je n’ai encore quasiment rien dedans et de les générer à nouveaux.

+0 -0

J’ose te demander de mettre tes pavés de code dans des balises [[secret]] ?

Edit : Merci, c’est moins ennuyeux de scroller ainsi

Et si jamais, vu les soucis, il n’y a pas besoin de mettre les getters/adders/setters  ;)

Pour te répondre, c’est sûrement dû au fait que pour moi, la base de données sert de base et que les entités se basent là-dessus et pas le contraire.

Charvalos

Alors désolé, mais le propre de Doctrine, c’est justement de travailler dans l’autre sens, parce qu’il n’est pas imaginé pour des personnes qui s’y connaissent en bases de données, mais en PHP  :p


Attention : avec l’héritage Doctrine, tu n’as pas besoin de matérialiser les relations entre Marchandise et Produit ou Prestation (donc pas de @OneToMany ou autre pour l’héritage), Doctrine va se charger lui-même d’ajouter une colonne type dans ta base de données (table "Marchandises") et de faire les jointures nécessaires en cas de récupération d’un Produit ou d’une Prestation.

Autre point : je n’avais pas vraiment compris ton problème, et t’ai aiguillé vers deux implémentations qui ne sont malheureusement pas adaptées à ton cas. Un héritage de table de classes (qu’il soit joint ou unique) ne permet pas d’avoir une classe abstraite et deux enfants distincts, il faudra soit décider que Produit est parent de Prestation, soit l’inverse. L’autre possibilité (qui serait probablement plus proche de ce que tu souhaites) serait d’utiliser MappedSuperclass. Imagine ça un peu comme un interface Marchandise, seulement vu que Doctrine ne gère pas les annotations sur les interfaces, on fait une classe abstraite — et ça permet du coup d’y mettre les méthodes communes aux classes qui hériteront.

+0 -0

Je n’avais pas vu que t’avais édité ton message.

Pourtant, en me basant sur ce site ou ici, c’est exactement mon problème. J’ai utilisé JOINED vu que j’ai un héritage multi-tables.

Donc, j’avoue que je suis un peu perdu là. :(

EDIT : J’ai modifié les codes de mon message précédent en ne mettant que les attributs.

+0 -0

[…] en me basant sur ce site ou ici, c’est exactement mon problème. J’ai utilisé JOINED vu que j’ai un héritage multi-tables.

Donc, j’avoue que je suis un peu perdu là. :(

Charvalos

Au temps pour moi, je ne savais pas que c’était possible, tu m’as fait découvrir quelque chose de bien pratique, là  :)

Du coup, en ayant supprimé tes "jointures d’héritage" explicites, tu as pu t’en sortir ?

EDIT : J’ai modifié les codes de mon message précédent en ne mettant que les attributs.

Charvalos

Merci. C’était moins nécessaire que d’éviter du scroll, mais j’apprécie aussi  ^^

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte