Doctrine fails to update schema. "Nothing to update" (Symfony 3.4.8) - php

I've recently created an Entity with php bin/console doctorine:generate:entity. After creation, I've tried to update my schema with php bin/console doctrine:schema:update --force but got an output of:
Nothing to update - your database is already in sync with the current entity metadata.
Things I've already tried:
php bin/console doctrine:schema:update --dump-sql
Same output
php bin/console doctrine:cache:clear-metadata
Ran, but nothing changed
Clearing cache multiple times
Nothing
php bin/console doctrine:mapping:info
output:
[OK] FOS\UserBundle\Model\Group
[OK] FOS\UserBundle\Model\User
Entity in question:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="WeeklyPaymentReport")
*/
class WeeklyPaymentReport
{
/**
* #var int
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(type="integer", nullable=true)
*/
private $bbid;
/**
* #var String
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $request;
/**
* #var \DateTime
*
* #ORM\Column(name="dateOfBirth", type="date", nullable=true)
*/
private $date;
public function getId()
{
return $this->id;
}
public function setBbid($bbid)
{
$this->bbid = $bbid;
return $this;
}
public function getBbid()
{
return $this->bbid;
}
public function setRequest($request)
{
$this->request = $request;
return $this;
}
public function getRequest()
{
return $this->request;
}
public function setDate($date)
{
$this->date = $date;
return $this;
}
public function getDate()
{
return $this->date;
}
}
Doctrine also generated:
namespace AppBundle\Repository;
/**
* WeeklyPaymentReportRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class WeeklyPaymentReportRepository extends \Doctrine\ORM\EntityRepository
{
}
And also .orm.php for it:
use Doctrine\ORM\Mapping\ClassMetadataInfo;
$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE);
$metadata->customRepositoryClassName = 'AppBundle\Repository\WeeklyPaymentReportRepository';
$metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT);
$metadata->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'id' => true,
'columnName' => 'id',
));
$metadata->mapField(array(
'columnName' => 'bbid',
'fieldName' => 'bbid',
'type' => 'integer',
));
$metadata->mapField(array(
'columnName' => 'request',
'fieldName' => 'request',
'type' => 'string',
'length' => 255,
));
$metadata->mapField(array(
'columnName' => 'date',
'fieldName' => 'date',
'type' => 'datetime',
));
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
What else can I try?
Thank you for your help in advance!

Okay, so right after posting, I've found a post i've never been recommended before which solved the problem.
It's the last sentence, that solved my case.
"After deleting John.orm.php file if i run php bin/console doctrine:schema:update --force then it will generate tables."
Kinda weird solution, I hope I dont encounter weird anomalies in future developments because of it.

Related

Symfony OneToMany updates instead of insert

I am a beginner in Symfony.
I have a strange problem in my form.
I have 2 entities : Proposal_Lsi and Lsi_Beams. One proposal can have multiple beams, but a beam can only have one proposal. I figured I should use a OneToMany/ManyToOne relation, and that my owning side is the beam one, and inverse side is proposal.
I followed the official guide at https://symfony.com/doc/3.1/form/form_collections.html about Form Collections.
Everything renders just fine, I can submit a new proposal with multiple beams, and all is correctly stored in the database.
The problem occurs whenever I try to add new beams to my proposal : the systems overwrites (update query) existing beams (starting by the first one in the database) instead of adding new ones (insert query).
What am I missing ?
Here's some of my code, if that can help.
Proposal Class:
class Proposal_lsi{
/**
* #ORM\OneToOne(targetEntity="Emir2Bundle\Entity\Proposal", inversedBy="proposal_lsi")
* #ORM\JoinColumn(name="proposal", referencedColumnName="id")
* #ORM\Id
*/
private $proposal;
/**
* #ORM\OneToMany(targetEntity="Emir2Bundle\Entity\Lsi_beams", mappedBy="proposal_lsi")
*/
private $lsi_beams;
...
/**
* Add lsiBeam
*
* #param \Emir2Bundle\Entity\Lsi_beams $lsiBeam
* #return Proposal_lsi
*/
public function addLsiBeam(\Emir2Bundle\Entity\Lsi_beams $lsiBeam)
{
$lsiBeam->setProposalLsi($this);
$this->lsi_beams[] = $lsiBeam;
return $this;
}
}
Beams Class:
class Lsi_beams{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Emir2Bundle\Entity\Proposal_lsi", inversedBy="lsi_beams", cascade={"persist"})
* #ORM\JoinColumn(name="proposal_lsi", referencedColumnName="proposal", nullable=false)
*/
private $proposal_lsi;
...
}
And the form in the controller :
$form = $this->createFormBuilder($proposallsi)
->setAction($this->generateUrl('lsi_submission', array('id' => $id)))
->setMethod('POST')
->add('lsi_beams', CollectionType::class, array(
'entry_type' => LsiBeamsType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false
)
)
...
What am I doing wrong ? Let me know if you need more code.
Thanks for any reply !
Notes:
use Doctrine ArrayCollection to better keep track of collections
put cascade={"persist"} at the inverse side of association (where you have mappedBy)
Keep entity names singular (e.g. Lsi_beam instead of Lsi_beams)
Keep your naming strategy clear and strait. Don't use undescores in your class & property names (e.g. use $lsiBeams instead of $lsi_beams)
ProposalLsi
use Doctrine\Common\Collections\ArrayCollection;
class ProposalLsi
{
/**
* #ORM\OneToMany(targetEntity="LsiBeam", mappedBy="proposalLsi", cascade={"persist"})
*/
private $lsiBeams;
public function __construct()
{
$this->lsiBeams = new ArrayCollection();
}
public function addLsiBeam(LsiBeams $lsiBeam)
{
if ($this->lsiBeams->contains($lsiBeam)) {
return;
} else {
$lsiBeam->setProposalLsi($this);
$this->lsiBeams->add($lsiBeam);
}
return $this;
}
public function removeLsiBeam(LsiBeams $lsiBeam)
{
if (!$this->lsiBeams->contains($lsiBeam)) {
return;
} else {
$lsiBeam->setProposalLsi(null);
$this->lsiBeams->removeElement($lsiBeam);
}
return $this;
}
}
LsiBeam
class LsiBeam
{
/**
* #ORM\ManyToOne(targetEntity="ProposalLsi", inversedBy="lsiBeams")
*/
private $proposalLsi;
public function setProposalLsi(?ProposalLsi $proposalLsi)
{
$this->proposalLsi = $proposalLsi;
}
}

Possible to dynamically change Doctrine Entity mappings?

I have a PSR-loaded package that defines a series of relationships around a 'User' entity it provides.
In many of the use cases where you use this package, you may want to keep all entities intact, but, substitute your own User entity.
As concrete example, the package gives me this Entity (using Annotations here to keep things clear):
namespace CirclicalUser\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* An example entity that represents an action rule.
*
* #ORM\Entity
* #ORM\Table(name="acl_actions_users")
*
*/
class UserActionRule
{
/**
* #var int
* #ORM\Id
* #ORM\ManyToOne(targetEntity="CirclicalUser\Entity\ActionRule", inversedBy="user_exceptions")
* #ORM\JoinColumn(name="action_rule_id", referencedColumnName="id")
*/
protected $action_rule;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="CirclicalUser\Entity\User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
}
Given the above, is there any way I could supplant the user relationship in UserActionRule::$user, that targets CirclicalUser\Entity\User, with my own user: Acme\Entity\User (assuming it is a Doctrine Entity in its own right)
e.g., pretend PHP:
function onBoostrap( $e ){
DoctrineMagic::getMapping(UserActionRule::class)->get('user')->getManyToOne()->setTargetEntity(Acme\Entity\User::class);
}
Thank you!
I managed to solve this by listening to the loadClassMetadata event.
namespace CirclicalUser\Listener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\Common\EventSubscriber;
class UserEntityListener implements EventSubscriber
{
const DEFAULT_ENTITY = 'CirclicalUser\Entity\User';
private $userEntity;
public function __construct($userEntity)
{
$this->userEntity = $userEntity;
}
public function getSubscribedEvents()
{
return ['loadClassMetadata'];
}
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
/** #var \Doctrine\ORM\Mapping\ClassMetadata $classMetadata */
$classMetadata = $eventArgs->getClassMetadata();
if ($this->userEntity == self::DEFAULT_ENTITY) {
return;
}
switch ($classMetadata->getName()) {
case 'CirclicalUser\Entity\UserActionRule':
$classMetadata->associationMappings['user']['targetEntity'] = $this->userEntity;
break;
}
}
}
This listener successfully substitutes the mapping for the user-defined entity class.
Adding the listener (Zend Framework) was trivial:
'doctrine' => [
'eventmanager' => [
'orm_default' => [
'subscribers' => [
UserEntityListener::class,
],
],
],
Separately, in service manager config:
'service_manager' => [
'invokables' => [
UserAuthenticationLogMapper::class => UserAuthenticationLogMapper::class,
],
'factories' => [
UserEntityListener::class => UserEntityListenerFactory::class,
],
],

In Symfony-Sonata all fields are sortable except for one

In Sonata I have created several lists and all work fine. (Please not that that was a while ago, so I may have done something there which fixed the issue I will describe here...).
Now I have created a new listing of Playlist entities:
As you can see in the picture, both the "Id" column and the "Aangemaakt op" columns are sortable, however the "Playlist" column is not.
Both the "Aangemaakt op" and the "Playlist" fields are date-fields, but since the "Aangemaakt op" field is sortable I would say that has nothing to do with it.
I have been searching the Sonata documentation, Google and StackOverflow, but haven't found any clue concerning this issue. I did find thread about sorting a list based on an Entity field, but my field isn't an entity.
Relevant code:
/**
* #param ListMapper $listMapper
*/
protected function configureListFields(ListMapper $listMapper) {
$listMapper
->add('id')
->add('playlist_date', 'date', array('label' => 'Playlist'))
->add('created', 'datetime', array('label' => 'Aangemaakt op'))
->add(
'_action', 'actions', array(
'actions' => array(
'delete' => array(),
)
)
);
}
Some StackOverflow threads and an answer below mention adding 'sortable' => true to the field that must be sortable.
Doing that indeed makes the column clickable to sort, but clicking it results in the following exception:
Catchable Fatal Error: Argument 1 passed to
Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery::entityJoin()
must be of the type array, null given, called in
/path/of/my/project/sonata-project/doctrine-orm-admin-bundle/Datagrid/ProxyQuery.php
on line 142 and defined.
According to other StackOverflow threads that is because a join must be created. However, the field is simply a field of the same Mysql record as the other fields. I did find a StackOverflow thread mentioning this as well and in which they joined the same record in order to make this work, but I didn't get that to work. Besides, I thank that shouldn't be the way to order the contents of a column.
Does anyone have a clue?
Update in reaction to Hibatallah Aouadni's answer
As Hibatallah suggests, I added the following to my PlaylistsAdmin:
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('id')
->add('playlist_date')
->add('created');
}
This resulted in the following error message:
Notice: Undefined index: playlist_date
So I inspected my Entity and I found that it has a UniqueConstraint:
uniqueConstraints={#ORM\UniqueConstraint(name="playlist_date", columns={"playlist_date"})}
It does not have an actual "index" defined, but ofcourse it is. However as a test I added the following:
, indexes={#ORM\Index(name="playlist_date", columns={"playlist_date"})}
This didn't give any different result.
So still no luck at all :(
** Entity and Entity admin **
Entity Admin:
<?php
namespace Company\AdminBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\AdminBundle\Route\RouteCollection;
class PlaylistsAdmin extends Admin
{
protected $baseRoutePattern = 'playlists';
protected $baseRouteName = 'playlists';
protected function configureRoutes(RouteCollection $collection) {
$collection->clearExcept(array('list', 'delete', 'show'));
}
/**
* #param ListMapper $listMapper
*/
protected function configureListFields(ListMapper $listMapper) {
$listMapper
->add('id')
->add('playlist_date', 'date', array('label' => 'Playlist'))
->add('created', 'datetime', array('label' => 'Aangemaakt op'))
->add(
'_action', 'actions', array(
'actions' => array(
'show' => array(),
/*'edit' => array(),*/
'delete' => array(),
)
)
);
}
public function getBatchActions() {
return array();
}
}
Entity:
<?php
namespace Company\AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Playlist
*
* #ORM\Table(name="playlist", uniqueConstraints={#ORM\UniqueConstraint(name="playlist_date", columns={"playlist_date"})})
* #ORM\Entity()
*/
class Playlist
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", options={"unsigned"=true})
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var \DateTime
*
* #ORM\Column(name="playlist_date", type="date", nullable=true)
*/
protected $playlistDate;
/**
* #var \DateTime
*
* #ORM\Column(name="created", type="datetime", nullable=true)
*/
protected $created;
/**
* #var \Doctrine\Common\Collections\Collection
*/
protected $video;
/**
* Constructor
*/
public function __construct() {
$this->video = new \Doctrine\Common\Collections\ArrayCollection();
$this->setCreated(new \DateTime());
}
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set playlistDate
*
* #param \DateTime $playlistDate
* #return Playlist
*/
public function setPlaylistDate($playlistDate) {
$this->playlistDate = $playlistDate;
return $this;
}
/**
* Get playlistDate
*
* #return \DateTime
*/
public function getPlaylistDate() {
return $this->playlistDate;
}
/**
* Set created
*
* #param \DateTime $created
* #return Playlist
*/
public function setCreated($created) {
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated() {
return $this->created;
}
/**
* Add video
*
* #param \Company\AppBundle\Entity\Video $video
* #return Playlist
*/
public function addVideo(\Company\AppBundle\Entity\Video $video) {
$this->video[] = $video;
return $this;
}
/**
* Remove video
*
* #param \Company\AppBundle\Entity\Video $video
*/
public function removeVideo(\Company\AppBundle\Entity\Video $video) {
$this->video->removeElement($video);
}
/**
* Get video
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getVideo() {
return $this->video;
}
}
Finally I found it, it's so absurd, in the configureListFields method, you have to call the attribute with its name not the DataBase name, so:
change
->add('playlist_date', 'date', array('label' => 'Playlist'))
to
->add('playlistDate', 'date', array('label' => 'Playlist'))
:D I can't beleive we spend all this time for some absurd mistake ;)
all you need to do is to add the argument sortable to array and true as value:
->add('playlist_date', 'date', array(
'label' => 'Playlist',
'sortable' => true
))
try to add the playlist field in configureDatagridFilters in your entity admin:
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('id')
->add('playlist_date')
->add('created');
}
and it will work ;)

Symfony2 embedded form OneToMany relationship, how to persist related data

I've been struggling with this for a few days now, so I hope somebody can help.
I have a OneToMany relation between a table Resources and my FOSUserBundle provided User entity, so that one user can have posted many resources.
Note: the entities have been edited for brevity, however I don't believe I removed anything important for this question
My Resources entity:
<?php
namespace SFI\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="SFI\MainBundle\Entity\ResourcesRepository")
* #ORM\Table(name="resources")
*/
class Resources {
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id()
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255)
*/
protected $name;
/**
* #ORM\Column(type="string", length=255)
*/
protected $type;
/**
* #ORM\Column(type="string", length=255)
*/
protected $link;
/**
* #ORM\Column(type="text")
*/
protected $description;
/**
* #ORM\Column(type="datetime")
*/
protected $created_time;
/**
* #ORM\ManyToOne(targetEntity="SFI\UserBundle\Entity\User", inversedBy="created_by")
* #ORM\JoinColumn(name="created_by", referencedColumnName="id")
*/
protected $created_by;
---rest of getters and setters---
/**
* Set created_by
*
* #param \SFI\UserBundle\Entity\User $createdBy
* #return Resources
*/
public function setCreatedBy(\SFI\UserBundle\Entity\User $createdBy = null)
{
$this->created_by = $createdBy;
return $this;
}
/**
* Get created_by
*
* #return \SFI\UserBundle\Entity\User
*/
public function getCreatedBy()
{
return $this->created_by;
}
}
My User entity:
<?php
namespace SFI\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass="SFI\UserBundle\Entity\UserRepository")
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
}
/**
* #ORM\Column(type="string", length=255)
*
* #Assert\NotBlank(message="Please enter your name.", groups={"Registration", "Profile"})
* #Assert\Length(
* min=3,
* max="255",
* minMessage="The name is too short.",
* maxMessage="The name is too long.",
* groups={"Registration", "Profile"}
* )
*/
protected $name;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return User
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #ORM\OneToMany(targetEntity="SFI\MainBundle\Entity\Resources", mappedBy="created_by")
*/
protected $created_by;
/**
* Add created_by
*
* #param \SFI\MainBundle\Entity\Resources $createdBy
* #return User
*/
public function addCreatedBy(\SFI\MainBundle\Entity\Resources $createdBy)
{
$this->created_by[] = $createdBy;
return $this;
}
/**
* Remove created_by
*
* #param \SFI\MainBundle\Entity\Resources $createdBy
*/
public function removeCreatedBy(\SFI\MainBundle\Entity\Resources $createdBy)
{
$this->created_by->removeElement($createdBy);
}
/**
* Get created_by
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCreatedBy()
{
return $this->created_by;
}
}
I have a couple of Form Types but the main one I'm working with is ResourceType:
<?php
namespace SFI\MainBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ResourceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//Setting date and time
$created_at = new \DateTime('now');
$builder
->add('name', 'text', array(
'required' => true,
'attr' => array(
'class' => 'form-control',
'placeholder' => 'Resource name',
),
))
->add('type', 'choice', array(
'required' => true,
'empty_value' => 'Choose a type',
'choices' => array('w' => 'Website', 'v' => 'Video', 'a' => 'Audio'),
'attr' => array(
'class' => 'form-control',
),
))
->add('link', 'text', array(
'required' => true,
'attr' => array(
'class' => 'form-control',
'placeholder' => 'Add a link',
),
))
->add('description', 'textarea', array(
'required' => true,
'attr' => array(
'class' => 'textarea',
'style' => 'width: 100%; height: 200px; font-size: 14px; line-height: 18px; border: 1px solid #dddddd; padding: 10px;',
'placeholder' => 'Write a description...',
),
))
->add('created_time', 'datetime', array(
'disabled' => true,
'data' => $created_at,
))
->add('save', 'submit', array(
'attr' => array('class' => 'btn btn-primary'),
));
}
public function getName()
{
return 'resource';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'SFI\MainBundle\Entity\Resources',
));
}
}
My controller for the Resource form part:
public function resourcesAction(Request $request)
{
$breadcrumbs = $this->get("white_october_breadcrumbs");
$breadcrumbs->addItem("SFI Portalen", $this->get("router")->generate("sfi_static_index"));
$breadcrumbs->addItem("Teacher Dashboard", $this->get("router")->generate("sfi_teacher_dashboard"));
$breadcrumbs->addItem("Resources");
$em = $this->getDoctrine()->getManager();
$resource = new Resources();
$newResourceForm = $this->createForm(new ResourceType(), $resource);
$newResourceForm->handleRequest($request);
if ($newResourceForm->isValid()) {
$session = $this->getRequest()->getSession();
//$session->getFlashBag()->add('notice', 'Form processed');
$session->getFlashBag()->add('notice', 'Form processed, testing, no persist');
//$em->persist($resource);
//$em->flush();
return $this->redirect($this->generateUrl('sfi_teacher_resources'));
}
return $this->render('SFIMainBundle:Teacher:resources.html.twig', array(
'form' => $newResourceForm->createView(),
));
}
What I need to do is relate these entities when a new Resource is created, to "assign" it to the logged in user via the relation in the tables.
I've looked into embedded forms and other suggestions on Symfony's documentation, but I can't wrap my head around how to apply what I read to this specific example. I have followed the example with the tasks and the tags and the categories and all that, but I can't understand how it applies to my situation, having the User entity in another bundle, and a User form type that relates the user to their school and just adds an extra full name field, while inheriting FOSUserBundle's original form type.
I also have a funny feeling that I haven't tackled or "layed out" the relationship correctly in my code so as to make it easier to understand which objects relate.
Any help would be much appreciated! Also please let me know if you require other code or further information.
You should just be able to set the user manually before persisting the Resources entity.
if ($newResourceForm->isValid()) {
...
$resource->setCreatedBy($this->getUser());
$em->persist($resource);
$em->flush();
...
}
Symfony makes use of the $this->getUser() shortcut in controllers (see http://symfony.com/doc/current/book/security.html#retrieving-the-user-object). I'm assuming you only allow this form when the user is logged in.
Also if you are using Doctrine I would recommend using it to generate your entities and getters/setters for you, as it will generate sensible names that coincide with Symfony conventions. For instance, your entity would end up being named 'Resource' vs. 'Resources', and your variables would be camelCased ($createdBy vs. $created_by).
OK so based on Jason's suggestion, and the previous one by sjagr, I have renamed a few things for consistency and better understand, and I have written the following, which works correctly!
Thank you all for your help!
public function resourcesAction(Request $request)
{
$breadcrumbs = $this->get("white_october_breadcrumbs");
$breadcrumbs->addItem("SFI Portalen", $this->get("router")->generate("sfi_static_index"));
$breadcrumbs->addItem("Teacher Dashboard", $this->get("router")->generate("sfi_teacher_dashboard"));
$breadcrumbs->addItem("Resources");
$em = $this->getDoctrine()->getManager();
$resource = new Resource();
$createdBy = $em->getRepository('SFIUserBundle:User')->find($this->getUser()->getId());
$newResourceForm = $this->createForm(new ResourceType(), $resource);
$newResourceForm->handleRequest($request);
if ($newResourceForm->isValid()) {
//Getting current date and time
$created_time = new \DateTime('now');
$resource->setCreatedTime($created_time);
$resource->setCreatedBy($createdBy);
$session = $this->getRequest()->getSession();
$session->getFlashBag()->add('notice', 'Form processed');
$em->persist($resource);
$em->flush();
return $this->redirect($this->generateUrl('sfi_teacher_resources'));
}
return $this->render('SFIMainBundle:Teacher:resources.html.twig', array(
'form' => $newResourceForm->createView(),
));
}
All I needed was to pass the current user's entire object in setCreatedBy and the relation works correctly.
Thank you all again!

Symfony2 : Many-To-Many with a custom link table

I'm working on a form with 3 entities :
order (idorder)
support reference table (idsupport)
link table (idorder, idsupport)
And when i try to select one or more support i got this error:
Catchable Fatal Error: Argument 1 passed to Myapp\MyBundle\Entity\PcastCmdsupports::setIdsupports() must be an instance of Myapp\MyBundle\Entity\PcastSupports, instance of Doctrine\Common\Collections\ArrayCollection given,
called in C:\wamp\www\php\Symfony\vendor\symfony\src\Symfony\Component\Form\Util\PropertyPath.php on line 347 and defined in C:\wamp\www\php\Symfony\src\Myapp\MyBundle\Entity\PcastCmdsupports.php line 62
Since i already created my link table i saw on the web that i can simply create 2 Many-To-One relation in my link table :
/**
* #var PcastSupports
*
* #ORM\ManyToOne(targetEntity="PcastSupports")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="IDSUPPORTS", referencedColumnName="IDSUPPORTS")
* })
*/
private $idsupports;
/**
* #var PcastOrder
*
* #ORM\ManyToOne(targetEntity="PcastOrder")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="IDORDER", referencedColumnName="IDORDER")
* })
*/
private $idorder;
and my setters and getters :
/**
* Set idsupports
*
*/
public function setIdsupports(\Myapp\MyBundle\Entity\PcastSupports $idsupports)
{
$this->idsupports = $idsupports;
}
/**
* Get idsupports
*
*/
public function getIdsupports()
{
return $this->idsupports;
}
/**
* Set idorder
*
*/
public function setIdcommande(\Myapp\MyBundle\Entity\PcastOrder $idorder)
{
$this->idorder = $idorder;
}
/**
* Get idorder
*
*/
public function getIdorder()
{
return $this->idorder;
}
In my order form i can choose one or many supports so i created my form like this:
$form_clips = $this->createFormBuilder($cmdclips)
->add('idorder', new CmdsupportsType)
->getForm();
And finally my supportsType form:
$builder
->add('idsupports', 'entity', array(
'class' => 'MyappMyBundle:PcastSupports',
'property' => 'name',
'expanded' => true,
'multiple' => true,
'query_builder' => function(EntityRepository $er)
{
return $er->createQueryBuilder('pts')
->orderBy('pts.idsupports','ASC');
},
));
I'm not using any arraycollection so i don't understand the issue. And the issue happened during this action:
$form_clips->bindRequest($request);
Thank a lot for your help !
I tried to make it work with the many-to-many relation in a simple case (user, company and a user_company entities) but i got a problem when i try to add a company to a user:
Warning: oci_bind_by_name() [<a href='function.oci-bind-by-name'>function.oci-bind-by-name</a>]: Invalid variable used for bind in C:\wamp\www\php\Promocast\Symfony\vendor\doctrine-dbal\lib\Doctrine\DBAL\Driver\OCI8\OCI8Statement.php line 113
I googling a lot but i didn't find anything on this error... According to stack trace the error is when doctrine try to add the company object :
array('column' => ':param10', 'variable' => object(PcastCompany), 'type' => '1')
My user entity (societe = company):
/**
* #ORM\ManyToMany(targetEntity="PcastSociete", inversedBy="users")
* #ORM\JoinTable(name="PcastLienusersociete",
* joinColumns={#ORM\JoinColumn(name="ImUser_iduser", referencedColumnName="iduser")},
* inverseJoinColumns={#ORM\JoinColumn(name="PcastLienusersociete_idsociete", referencedColumnName="idsociete")}
* )
*/
private $societes;
public function getSocietes()
{
return $this->societes;
}
public function addSociete(\Myapp\MyBundle\Entity\PcastSociete $societe)
{
$this->societes[] = $societe;
}
My company entity:
/**
* #ORM\ManyToMany(targetEntity="ImUser", mappedBy="societes")
*/
private $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
If anybody have any idea...
Thanks
You should not have an entity representing the link table. If you annotate both your entities correctly, Doctrine will handle the creation of the link table by itself.
Moreover, you do not need any link table to do a Many-to-One relationship in the first place, what you want to do is use the Many-to-Many annotations in both entities.
http://readthedocs.org/docs/doctrine-orm/en/latest/reference/association-mapping.html?highlight=many%20to%20one#many-to-many-bidirectional
Start with the basics. I was curious about something else concerning ManyToMany so I grabbed your entities as a test case. Before diving into forms and such, make sure you can execute a simple test case from the command line such as:
use Zayso\ArbiterBundle\Entity\PcastSociete as Company;
use Zayso\ArbiterBundle\Entity\ImUser as User;
protected function test1()
{
$em = $this->getContainer()->get('doctrine.orm.entity_manager');
$company = new Company();
$em->persist($company);
$user = new User();
$user->addSociete($company);
$em->persist($user);
$em->flush();
}
For entities I used:
namespace Zayso\ArbiterBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
*/
class ImUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer",name="iduser")
* #ORM\GeneratedValue
*/
protected $id;
public function getId() { return $this->id; }
/**
* #ORM\ManyToMany(targetEntity="PcastSociete", inversedBy="users")
* #ORM\JoinTable(name="PcastLienusersociete",
* joinColumns={#ORM\JoinColumn(name="ImUser_iduser", referencedColumnName="iduser")},
* inverseJoinColumns={#ORM\JoinColumn(name="PcastLienusersociete_idsociete", referencedColumnName="idsociete")}
* )
*/
private $societes;
public function getSocietes()
{
return $this->societes;
}
public function addSociete(PcastSociete $societe)
{
$this->societes[] = $societe;
}
public function __construct()
{
$this->societes = new ArrayCollection();
}
}
namespace Zayso\ArbiterBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
*/
class PcastSociete
{
/**
* #ORM\Id
* #ORM\Column(type="integer", name="idsociete")
* #ORM\GeneratedValue
*/
protected $id;
public function getId() { return $this->id; }
/**
* #ORM\ManyToMany(targetEntity="ImUser", mappedBy="societes")
*/
private $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
}
Get the above working then we can move on to the forms problem.

Categories