Consultez la FAQ sur le ZF avant de poster une question
Vous n'êtes pas identifié.
Bonjour, j'ai deja travaillé rapidement sur petit projet sur ZF2 mais je viens de débuter sur ZF3 et surtout sur Doctrine, donc s'il y a des réponses, prenez en copte que je suis débutant svp
PS: c'est la premiere fois que je poste sur un forum pour un probleme de dev, dsl d'avance si j'ai mal fait les choses.
mon probleme est claire qu'il vient de l'association manyToMany mais je ne sais pas où ça cloche, j'ai une antité annonce, et une entité category, et j'assaie de mettre une categorie à mon annonce via un form (qui m'affiche bien la liste de mes categories), j'ai cet erreur.
File:
C:\wamp64\www\offre_emploi\vendor\doctrine\orm\lib\Doctrine\ORM\ORMInvalidArgumentException.php:206
Message:
Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "Annonce\Entity\Annonce#$categories", got "array" instead
PS: j'ai dans ma BDD la table annonce_category qui contient annonce_id et category_id
voila mes fichiers
Annonce:
<?php namespace Annonce\Entity; use Annonce\Entity\Category; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** * This class represents a registered user. * @ORM\Entity() * @ORM\Table(name="annonce") */ class Annonce { /** * @ORM\ManyToOne(targetEntity="\User\Entity\User", inversedBy="annonces") * @ORM\JoinColumn(name="user_id", referencedColumnName="id") */ protected $user; /** * @ORM\ManyToMany(targetEntity="Annonce\Entity\Category", inversedBy="categories") * @ORM\JoinTable(name="annonce_category", * joinColumns={@ORM\JoinColumn(name="annonce_id", referencedColumnName="id")}, * inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")} * ) */ private $categories; public function __construct() { $this->categories = new ArrayCollection(); } /** * Add category * * @param \Annonce\Entity\Category $category * */ public function addCategory($category) { $this->categories[] = $category; } public function removeCategory($category) { $this->categories->removeElement($category); } public function getCategories() { return $this->categories; } /* * Returns associated user. * @return \User\Entity\User */ public function getUser() { return $this->user; } /** * Sets associated user. * @param \User\Entity\User $user */ public function setUser($user) { $this->user = $user; $user->addAnnonce($this); } /** * @ORM\Id * @ORM\Column(name="id") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(name="title") */ protected $title; /** * @ORM\Column(name="content") */ protected $content; /** * @ORM\Column(name="date") */ protected $date; /** * Returns user ID. * @return integer */ public function getId() { return $this->id; } /** * Sets user ID. * @param int $id */ public function setId($id) { $this->id = $id; } /** * Returns title. * @return string */ public function getTitle() { return $this->title; } /** * Sets title. * @param string $title */ public function setTitle($title) { $this->title = $title; } /** * Returns content. * @return text */ public function getContent() { return $this->content; } /** * Sets content * @param string $content */ public function setContent($content) { $this->content = $content; } /** * Returns date. * @return date */ public function getDate() { return $this->date; } /** * Sets date * @param string $date */ public function setDate($date) { $this->date = $date; } }
Category
<?php namespace Annonce\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity() * @ORM\Table(name="category") */ class Category { /** * @ORM\Id * @ORM\Column(name="id") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(name="name") */ protected $name; /** * Returns user ID. * @return integer */ public function getId() { return $this->id; } /** * Sets user ID. * @param int $id */ public function setId($id) { $this->id = $id; } /** * Returns name. * @return string */ public function getName() { return $this->name; } /** * Sets Name. * @param string $name */ public function setName($name) { $this->name = $name; } }
Form
<?php namespace Annonce\Form; use Zend\Form\Form; use Zend\Form\Fieldset; use Zend\InputFilter\InputFilter; /** * This form is used to collect user's login, password and 'Remember Me' flag. */ class AnnonceForm extends Form { /** * Entity manager. * @var Doctrine\ORM\EntityManager */ private $entityManager; /** * Constructor. */ public function __construct($entityManager = null) { // Define form name parent::__construct('annnonce-form'); // Set POST method for this form $this->setAttribute('method', 'post'); $this->entityManager = $entityManager; $this->addElements(); $this->addInputFilter(); } /** * This method adds elements to form (input fields and submit button). */ protected function addElements() { $this->add([ 'type' => 'DoctrineModule\Form\Element\ObjectSelect', 'name' => 'categories', 'attributes' => [ 'multiple' => true, ], 'options' => [ 'object_manager' => $this->entityManager, 'target_class' => 'Annonce\Entity\Category', 'property' => 'name', 'label' => 'Les catégories', ], ]); $this->add([ 'type' => 'text', 'name' => 'title', 'options' => [ 'label' => 'Titre de l\'annonce', ], ]); // Add "password" field $this->add([ 'type' => 'textarea', 'name' => 'content', 'options' => [ 'label' => 'Description de l\'annonce', ], ]); // Add "redirect_url" field $this->add([ 'type' => 'hidden', 'name' => 'redirect_url' ]); // Add the CSRF field /*$this->add([ 'type' => 'csrf', 'name' => 'csrf', 'options' => [ 'csrf_options' => [ 'timeout' => 600 ] ], ]);*/ // Add the Submit button $this->add([ 'type' => 'submit', 'name' => 'submit', 'attributes' => [ 'value' => 'Sign in', 'id' => 'submit', ], ]); }
AnnonceManager
<?php namespace Annonce\Service; use Annonce\Entity\Annonce; use User\Entity\User; use Zend\Crypt\Password\Bcrypt; use Zend\Math\Rand; use Doctrine\Common\Collections\ArrayCollection; class AnnonceManager { /** * Doctrine entity manager. * @var Doctrine\ORM\EntityManager */ private $entityManager; /** * Authentication service. * @var \Zend\Authentication\AuthenticationService */ private $authService; private $categories; /** * Constructs the service. */ public function __construct($entityManager, $authService) { $this->entityManager = $entityManager; $this->authService = $authService; $this->categories = new ArrayCollection(); } /** * This method adds a new user. */ public function addAnnonce($data) { // Create new User entity. $annonce = new Annonce(); $annonce->setTitle($data['title']); $annonce->setContent($data['content']); $user = $this->entityManager->getRepository(User::class) ->findOneByEmail($this->authService->getIdentity()); $annonce->setUser($user); $currentDate = date('Y-m-d H:i:s'); $annonce->setDate($currentDate); //var_dump($data); $annonce->addCategory($data['categories']); // Add the entity to the entity manager. $this->entityManager->persist($annonce); // Apply changes to database. $this->entityManager->flush(); return $annonce; } /** * This method updates data of an existing user. */ public function updateAnnonce($annonce, $data) { $annonce->setTitle($data['title']); $annonce->setContent($data['content']); // Apply changes to database. $this->entityManager->flush(); return true; } }
Dernière modification par kroan (16-01-2018 15:49:30)
Hors ligne
Bonjour,
Jusqu’où à tu pu faire fonctionner ton code ci-dessus ?
Car de ce que je vois, il n'y as pas qu'un seul problème.
Donc avant de te donner une quelconque information, il me faudrait savoir si tu as déjà fait fonctionner quelque chose de ce formulaire.
Que donne la ligne de commande ci dessous :
php public/index.php orm:validate-schema
Tu auras des erreurs qui te seront montré, essayes dans un 1er temps de les corriger, et ensuite ton formulaire te sera plus simple à construire
Dernière modification par JGreco (17-01-2018 14:10:57)
Hors ligne
Bonjour et merci pour ta réponse
mon formulaire si on enleve la partie des categories il fonctionnement correctement, j'arrive à enregistrer mes annonces avec tous les champs.
et la commande me donnne pour seule erreure qu'une notice
Notice: Undefined index: APPLICATION_ENV in C:\wamp64\www\offre_emploi\public\index.php on line 13
car j'avais ajouté une petit script pour palier à une erreur que je me rappelle meme pas
voila le bout de code que j'ai ajouté au fichier index.php
// Define application environment defined('APPLICATION_ENV')|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'development')); if ($_SERVER['APPLICATION_ENV'] === 'development') { error_reporting(E_ALL); ini_set("display_errors", 1); }
Hors ligne
Ton erreur n'est pas lié à notre problème.
php public/index.php orm:validate-schema
Est censé valider tout ton schéma doctrine.
Hors ligne
kroan a écrit:
et la commande me donnne pour seule erreure qu'une notice
Notice: Undefined index: APPLICATION_ENV in C:\wamp64\www\offre_emploi\public\index.php on line 13
car j'avais ajouté une petit script pour palier à une erreur que je me rappelle meme pas
voila le bout de code que j'ai ajouté au fichier index.phpCode:
// Define application environment defined('APPLICATION_ENV')|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'development')); if ($_SERVER['APPLICATION_ENV'] === 'development') { error_reporting(E_ALL); ini_set("display_errors", 1); }
Hello, à un moment donné on peut pas faire tout à ta place, tu customises le comportement par défaut c'est ton choix mais du coup c'est à toi d'adapter les commandes qu'on te demande de lancer pour t'aider de façon à ce qu'elle fonctionne.
Là ton soucis c'est juste que t'as besoin en lançant la commande de passer une variable d'environnement. De mémoire un truc du genre :
APPLICATION_ENV=development php public/index.php orm:validate-schema
Un peu de recherche t'aurais permis d'avancer et du coup d'avoir des réponses à ton problème
Hors ligne
j'ai bien précisé au début que j'étais débutant, que ce soit dans le dev ou meme dans les commandes, loin de moi l'idée de profiter des gens en les laissant faire le travail à ma place, comme vous avez pu le remarquer c'est un petit projet pour apprendre rien de plus, je comprends ta réaction vu le nombre de questions qu'on pose sur le forum, mais c'est quand meme pas sympa de me lyncher (bien que gentiment je dois l'avouer) juste parceque je demande l'aide et que je ne sais pas faire.
pour le probleme, j'arrive toujours pas à trouver de resultat en lançant la commande, bien que j'ai essayé de commanter la partie sur la variable APPLICATION_ENV, à savoir je ne l'ai pas ajouté comme variable d'environnement dans mon system, je l'ai ajouté juste dans mon fichier .htaccess: (SetEnv APPLICATION_ENV development) du coup avec ta commande j'ai un "«APPLICATION_ENV=development» n'est pas reconnu comme nom d'applet de commande"
ps: en lançant la commande
php vendor/bin/doctrine-module orm:validate-schema
j'ai ça:
merci encore d'avoir pris le temps de me repondre
Dernière modification par kroan (18-01-2018 13:53:43)
Hors ligne
Bonjour,
De ce que je vois tu as installé cygwin sur ton windows pour taper des commandes, c'est une bonne chose. J'utilise personnellement un outil un poil plus simple a configurer et mieux conçu "Cmder"
Mais en ligne de commande tu n'appelle pas la même instance de PHP que celle de ton navigateur donc le APPLICATION_ENV doit être déclaré.
Idéalement tu pourrais (vu que tu es sous wamp) déclarer dans ton vhost si tu en as un (situé dans un chemin du genre : C:\wamp\bin\apache\apache2.4.18\conf\extra\httpd-vhosts.conf):
SetEnv APPLICATION_ENV "development"
https://stackoverflow.com/questions/2378871/set-application-env-via-virtual-host-config-and-read-this-in-php
Penses ensuite à redémarrer les services.
Tiens moi au courant
Dernière modification par JGreco (18-01-2018 15:34:43)
Hors ligne
Pour le message d'erreur juste au dessus, il ne faut pas utiliser
php vendor/bin/doctrine-module
mais juste
vendor/bin/doctrine-module
En fait si tu regardes dans le vendor en question, il y a un fichier bat qui s'occupe de tout, et ça marche, alors que quand tu mets php devant le truc marche pas... merci Windows
Hors ligne
Bonjour,
alors oui la bizarrement la commande suivante
vendor/bin/doctrine-module
fonctionne bien, ce qui m'a fait voir quelques erreurs sur mes relations orm que je crois avoir corrigé du coup avec la commande
vendor/bin/doctrine-module orm:validate-schema
je me retrouve avec le message suivant
[Mapping] OK - The mapping files are correct.
[Database] FAIL - The database schema is not in sync with the current mapping file.
j'ai fait quelques recherches et tests avant de reposter, mais quand je fais un
vendor/bin/doctrine-module orm:schema-tool:update --dump-sql
la console me sors tous ces updates à faire
jusque là tout va bien je pense mais lorsque je fais
vendor/bin/doctrine-module orm:schema-tool:update --dump --force
j'ai cette erreur que je ne sais pas comment régler
ps: j'ai remarque que quand je fais ça, ça supprime la colonne " id " de ma table annonce_category en changeant les annonce_id et category_id en VARCHAR
Merci encore pour vos réponses
Hors ligne
Vérifie que tu es bien en innodb sur toutes tes tables, et que les ids à matcher sont de type similaires.
Article sur l'erreur 1215 de mysql
Hors ligne
j'ai changé en innodb mais mes ids se convertissent automatiquement en VARCHAR à chaque je lance la commande
orm:schema-tool:update --dump --force
Hors ligne
JGreco a écrit:
Mais en ligne de commande tu n'appelle pas la même instance de PHP que celle de ton navigateur donc le APPLICATION_ENV doit être déclaré.
Idéalement tu pourrais (vu que tu es sous wamp) déclarer dans ton vhost si tu en as un (situé dans un chemin du genre : C:\wamp\bin\apache\apache2.4.18\conf\extra\httpd-vhosts.conf):Code:
SetEnv APPLICATION_ENV "development"
C'est surtout qu'un fichier .htaccess n'est lu que par apache donc en ligne de commande c'est normal que ça ne fonctionne pas.
Par contre pour les id en varchar c'est très bizarre t'es sur quelle version de mysql ?
Hors ligne
UPDATE:
mon problem des ids est dû à mes déclarations de de column dans mes entités, vu que dans aucun champ je ne précise le type de champ ( integer, varchar...) je pense que doctrine met par defaut VARCHAR à chaque que j'update la bdd, en tout cas en ajoutant les types de champs je n'ai plus ce soucis, du coup je me retrouve avec
je suis bien content mais en revenant tester mon form je tombe sur la meme erreur du début
Hors ligne
Heu, normalement avec doctrine tu peux préciser que c'est un integer quand tu met :
[lang=php] /** * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id;
Pour ton problème de formulaire, il faut maintenant que tu prenne pleinement acte de ce que tu as dans ton mapping doctrine (qui est juste selon doctrine) et ce que tu demande a ton formulaire de persister en base.
Il y a une différence entre les deux. L'hydration doctrine ne fonctionne pas car ton formulaire n'est pas correctement configuré pour fonctionner avec de l'hydration automatique comme tu le demande ici :
[lang=php] //var_dump($data); $annonce->addCategory($data['categories']);
Au niveau de ton formulaire, peux tu nous donner le résultat de ton POST ? une fois le formulaire validé.
EDIT : Ta méthode addCategory ne fonctionne pas du tout : avec la manière dont tu l'appelles ou ce qu'elle fait tout est incohérent à ce niveau.
Dernière modification par JGreco (22-01-2018 17:52:15)
Hors ligne
et pour la methode addCategory j'ai suivi ce ce qui a été mentionné dans le tuto doctrine
http://docs.doctrine-project.org/projec … ssociation
Hors ligne
Bah je te le dis clairement, non.
Ton code ne marche pas
[lang=php] <?php class Article { private $tags; public function addTag(Tag $tag) { $tag->addArticle($this); // synchronously updating inverse side $this->tags[] = $tag; } } class Tag { private $articles; public function addArticle(Article $article) { $this->articles[] = $article; } }
Dans l'exemple ci dessus tu as la méthode addArticle qui as un paramètre typé Article, tu n'a pas typé ta méthode addCategory de la même manière. D'autre part, ton POST ne correspond pas a ce que tu veux.
Dans la méthode addArticle de l'exemple, la méthode accepte UN seule article pour l'ajouter à la collection.
Toi avec
[lang=php] $annonce->addCategory($data['categories']);
Tu lui donnes des categorieSSSSSSSSSSSSSS (j'insiste sur le S comme tu le vois). En plus de cela tu lui donne donc un array avec une entrée valant 1, alors qu'il attend un objet de type Category.
Dorénavant tu as toutes les infos, je ne peux t'aider plus.
Donc non ça ne fonctionne pas
Dernière modification par JGreco (23-01-2018 15:41:37)
Hors ligne
Et je me permettrais de rajouter juste un truc :
Quand on maitrise mal, ou que l'on découvre une nouvelle techno ou que l'on est en phase d'apprentissage, le copié-collé c'est mal :
- Tu ne comprends pas ce que tu fais du coup.
- Tu fais des erreurs
- Tu n'entraines pas ton cerveau a réfléchir à ce que tu fait et doit faire ensuite.
J'ai pour preuve que tu est sur une publication d'annonce avec catégorization et que ton formulaire à pour valeur de bouton "Sign in". Ou alors j'ai rien capté à ton code...
Si tu veux progresser, banni un poil le copié-collé au profit d'une vraie écriture, c'est plus long, mais tu t'y retrouveras dans le futur. Sinon tu ne sera rien de plus qu'un script kiddies (en plus soft :p).
Aller bon courage
Dernière modification par JGreco (23-01-2018 16:29:54)
Hors ligne
Hello, j'ai regardé aussi un peu plus en détail tes entités il y a pas mal de choses peu logiques :
- Attributs parfois privés, parfois protected. Fais un choix mais dans la majeur partie des cas faut utiliser private sauf si tu fais de l'héritage
- Ensuite type bien les paramètres de tes méthodes, les annotations php c'est cool mais tu peux utiliser du typage sur les entité et si t'es sur php7+ tu peux tout typer donc profites en, tu auras des erreurs plus claires et surtout tu vas y voir plus clair. Tu vas facilement comprend que quand tu attends une entité de type Category et que tu lui passes un tableau d'ids ça répond pas trop au contrat .
- Pour ton formulaire, normalement si tu utilises l'hydrateur doctrine tu n'as rien à faire côté AnnonceManager. En fait si tu as bien tout configuré quand tu vas faire un $form->getData(); ou $form->getValue(); je ne sais plus quel est le contrat sur les formulaires (je ne les utilises plus depuis très longtemps) tu vas récupérer directement une entité de type Annonce avec toutes ces relations (notamment les catégories), tu n'as plus qu'à te contenter de faire un $this->entityManager->persit($annonce); puis $this->entityManager->flush(); dans ton service et le tour est joué .
Hors ligne
Orkin a écrit:
$form->getData(); ou $form->getValue(); je ne sais plus quel est le contrat sur les formulaires (je ne les utilises plus depuis très longtemps)
C'est getData().
Je plussoie ce que dit Orkin.
Hors ligne
merci pour vos reponses, je continuerais de chercher meme si j'avoue ne pas voir tres claire, oui j'ai compris que dans mon $data['categories'] il y'a un array d'ids et qu'il faut qu'il soit un objet de type entité Category, mais à quel niveau je dois le faire ? dans mon form avec le champ categories ? dans mon service AnnonceManager, dans la methode addCategory?... enfin bref je suis dans le flou, je pensais qu'avec Doctrine rien qu'avec l'association tout se faisait automatiquement..
Hors ligne
kroan a écrit:
merci pour vos reponses, je continuerais de chercher meme si j'avoue ne pas voir tres claire, oui j'ai compris que dans mon $data['categories'] il y'a un array d'ids et qu'il faut qu'il soit un objet de type entité Category, mais à quel niveau je dois le faire ? dans mon form avec le champ categories ? dans mon service AnnonceManager, dans la methode addCategory?... enfin bref je suis dans le flou, je pensais qu'avec Doctrine rien qu'avec l'association tout se faisait automatiquement..
C'est Doctrine qui le fait automatiquement pour toi, à la condition que tu ai configuré l'hydrateur doctrine et là à priori c'est pas le cas. Il y a un exemple sur DoctrineORMModule ou DoctrineModule
Hors ligne
ok j'ai beau cherché je ne sais pas comment faire, je suis désolé si je vous demande beaucoup mais là je bloque.
j'ai essayé d'hydrater comme dit en haut en suivant les exemples qu'il y a sur DoctrineORMModule meme si j'ai pas trouvé ce que je cherchai mais j'ai essayé d'adapter et le resultat et presque pareil
$hydrator = new DoctrineHydrator($this->entityManager); $annonce = new Annonce(); $annonce = $hydrator->hydrate($data, $annonce); // Add the entity to the entity manager. $this->entityManager->persist($annonce); // Apply changes to database. $this->entityManager->flush();
resultat la meme erreur sauf que là il me dit que je lui donne un ArrayCollection, je pensais que c'est ce qui etait voulu non !?
Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "Annonce\Entity\Annonce#$categories", got "Doctrine\Common\Collections\ArrayCollection" instead.
Hors ligne
Honnêtement je comprend pas où tu bugs ... Je pense surtout que tu n'as pas lu la doc jusqu'au bout tu as un exemple complet AVEC un formulaire : ICI
Donc regardes si tu arrives à faire fonctionner tout avec l'exemple présent et ensuite adapter à ton cas d'usage.
Hors ligne