I changed this code
/**
* #ORM\ManyToOne(targetEntity="Comiti\UserBundle\Entity\Member", fetch="EAGER")
* #ORM\JoinColumn(name="member_id", referencedColumnName="id")
*/
protected $member;
By
/**
* #ORM\ManyToOne(targetEntity="Comiti\UserBundle\Entity\User", fetch="EAGER")
* #ORM\JoinColumn(name="member_id", referencedColumnName="id")
*/
protected $member;
I need now migrate the old Member ids to the good User ids. Unfortunately, i can't find a way to get old ids i tried
$subscription->getMember()->getId()
which is null
i tried too
$subscription->getMemberId()
Thks for help
Do you renamed the Entity Member to User and kepp the same mysql (or whatever) table or do you change mysql table too?
If you change table, you have to play directly with your dbrm to upgrade your data.
Related
The original problem
The reasons, notes and members fields bellow where #ORM\Column(type="string", length=20000) which did not work because that is too long for a VARCHAR so I changed them all to #ORM\Column(type="text")
And Now
It is possible that I have misunderstood the correct way to handle migrations in productions but I can't get my database to match my entity. Running php bin/console doctrine:migrations:diff or php bin/console doctrine:schema:update --dump-sql doctrine tries to update the database to an old version of Request.php like it has been cached but even after running clear-metadata the migrations all say VARCHAR(20000) like in this sql dump after I manually changed the database:
ALTER TABLE request CHANGE reasons reasons VARCHAR(20000) NOT NULL, CHANGE notes notes VARCHAR(20000) DEFAULT NULL, CHANGE members members VARCHAR(20000) NOT NULL;
Current Request.php
namespace App\Entity;
use App\Repository\RequestRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass=RequestRepository::class)
*/
class Request
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="time")
* #Assert\LessThan(propertyPath="endTime", message="The booking must start before it ends")
*/
private $startTime;
/**
* #ORM\Column(type="time")
*/
private $endTime;
/**
* #ORM\Column(type="date")
*/
private $date;
/**
* #ORM\Column(type="text")
*/
private $reasons;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $notes;
/**
* #ORM\Column(type="text")
*/
private $status;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="requests")
* #ORM\JoinColumn(nullable=true)
*/
private $user;
/**
* #ORM\Column(type="text")
*/
private $members;
I have tried removing the Request.php entity but then doctrine gets upset that it is gone. (I do have a relational link to the user table here but it is one to many).
Changing the names of members reasons and notes worked but when I changed the names back it wanted to set them back to VARCHAR(20000). Where is it holding this info. How do I get rid of it?
Doctrine Metadata is cached. When you clear the cache (and warming it back up), symfony runs "compiler passes" that among other things read annotations to build the metadata, proxy objects, registers repositories, all this kind of stuff (obviously other doctrine-unrelated stuff as well).
Running bin/console cache:clear should solve your problems. (It also should be part of your deployment process. And unless you copy over the vendor dir as well, composer install too).
I am using Gedmo extension in addition with Symfony 3.2 and Doctrine 2.5.6 and I'm encountering an issue. I can't make Gedmo\Blameable and UniqueEntity constraint work together. Indeed, the blamed field is still null at validation time. Is there any way to make it work or a possible work-around ?
Here is my entity
/**
* #UniqueEntity(
* fields={"author", "question"},
* errorPath="question",
* message="This author already has an answer for that Question"
* )
* #ORM\Entity
*/
class TextAnswer
{
/**
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* #Gedmo\Blameable(on="create")
*/
private $author;
/**
* #Assert\NotNull()
* #ORM\ManyToOne(targetEntity="Question", inversedBy="textAnswers")
* #ORM\JoinColumn(name="question_id", referencedColumnName="id")
*/
private $question;
}
Thanks
EDIT : SOLUTION
Rather than manually setting the user (which removes Gedmo\Blameable interests), I created my own entity validator.
I give it doctrine and token storage as arguments so it can make a query on db to validate my criteria with the currently connected user (that will be later used by Gedmo\Blameable).
The BlameableListener is invoked during the Doctrine's flush operation, which normally happens after the entity has been validated. That's why $author is null at validation time.
The most straightforward workaround is to set $author yourself beforehand.
I'm working to fix some bugs and add new features to a project already in production.
What I need to do I think is very simple for who knows Symfony2 and Doctrine but I'm newbie and I don't know how to achive what i need:
I've got an existing entity on PHP side that is associated with a table in the database.
What I need is to create another entity that has some foreign key with other table.
I've tried to create the table into database first, but I don't know how to create the associated entity in PHP ( with correct annotation pointing to the foreign keys) and how to edit the other entities that need new attribute in class.
What I've also tried is to create an annotated PHP class as this:
<?php
namespace MyProject\MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Annotation\Groups;
use JMS\Serializer\Annotation\SerializedName;
use JMS\Serializer\Annotation\Type;
use JMS\Serializer\Annotation\VirtualProperty;
use MyProject\MyBundle\Model\ItemThumb;
/**
* #ORM\Entity
* #ORM\Table(name="wall_message_comment_answer")
*/
class WallMessageCommentAnswer {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #Groups({"user_details", "search_around"})
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="wall_message_comments")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
* #Groups({})
*/
public $user;
/**
* #var WallMessage
* #ORM\ManyToOne(targetEntity="WallMessage", inversedBy="users_comments")
* #ORM\JoinColumn(name="wall_message_id", referencedColumnName="id", onDelete="CASCADE")
*/
public $wall_message;
/**
* #var WallMessage
* #ORM\OneToMany(targetEntity="WallMessageComment", mappedBy="comment_answers")
* #ORM\JoinColumn(name="wall_message_comment_id", referencedColumnName="id", onDelete="CASCADE")
*/
public $wall_message_comment;
/**
* #var string
* #ORM\Column(type="string")
* #Groups({"user_details", "search_around"})
*/
public $content;
/**
* #var int
* #ORM\Column(type="integer")
* #Groups({"user_details", "search_around"})
*/
public $timestamp;
}
and then, trying to create getter and setter, launch the command:
php app/console doctrine:generate:entities MyProjectMyBundle/Entity/WallMessageCommentAnswer
But it gives me that error:
[Symfony\Component\Debug\Exception\FatalErrorException]
Compile Error: Cannot redeclare MyProject\MyBundle\Entity\User::setDocumentNumber()
as it tries to create again other entities.
Could anyone help me?
Thanks!
Why don't you try creating Entity using php app/console doctrine:generate:entity command. This will ask you for Bundle name, Entity name and columns.
After this you'll have .php file created in specified bundle. Following this URL to manually add relationship between your current and new entity.
http://symfony.com/doc/current/book/doctrine.html#relationship-mapping-metadata
This is how you can give manyToOne relationship in Symfony usng annotations, you can switch your way to assigning this relationship. (YML or any other supported by Symfony)
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
And specify oneToMany in target entity like this
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
After you're done with this run the following command to get the SQL queries of the changes.
php pap/console doctrine:schema:update --dump-sql
You'll have SQL queries output which you need to copy and run on the production environment. If your production and testing environment are same run following command.
php pap/console doctrine:schema:update --force
For above procedure you don't have the table to be created in database. Doctrine does that for you.
If you already have table created you can remove that as it's going to be created automatically when you force the schema.
I'm working on a OneToOne join in doctrine2/symphony 2.8.2 and I keep getting:
The association X\BaseDesignBundle\Entity\SessionDesign#user refers to the inverse side field X\UserBundle\Entity\User#SessionDesign which does not exist.
User:
/**
* #ORM\OneToOne(targetEntity="X\BaseDesignBundle\Entity\SessionDesign")
* #ORM\JoinColumn(name="fcid", referencedColumnName="id")
*/
private $sessionDesign;
Session Design:
/**
* #ORM\OneToOne(targetEntity="x\UserBundle\Entity\User")
* #ORM\JoinColumn(name="id", referencedColumnName="fcid")
*/
private $user;
I have 0 idea whats wrong at this point and I have tried everything I can think of. Thanks for any help you can give.
JoinColumn should only appear on the entity where the FK is.
E.g (assuming FK is on Session Design.)
Session Design
/**
* #ORM\OneToOne(targetEntity="X\BaseDesignBundle\Entity\User")
* #ORM\JoinColumn(name="fcid", referencedColumnName="id")
*/
private $user;
User:
/**
* #ORM\OneToOne(targetEntity="x\UserBundle\Entity\SessionDesign", inversedBy="user")
*/
private $sessionDesign;
For your own sanity I would recommend naming your FK better. fcid doesn't mean much at a glance, why not call it user_id or session_design_id (depending on where you put the FK).
E.g. * #ORM\JoinColumn(name="session_design_id", referencedColumnName="id")
It just makes things easier to parse
See the documentation for more info.
I would add to previous answer:
#ORM\OneToOne(targetEntity="X\BaseDesignBundle\Entity\User", mappedBy="sessionDesign")
I have a View entity that represents the primary page record, and then I have an associated entity called ViewVersion which stores multiple versions of the entity as it's changed over time. The View entity sets the current "Published" ViewVersion in the VersionId field. This makes for a simple OneToOne association. But in some contexts I will also want to get all the versions associated with this View entity, e.g. if I want to allow the user to review older versions and revert back. So I will need another mapping which is a OneToMany. The first viewVersion will map to the active "published" version, and the second viewVersions will show all the versions.
Entity Definitions
/**
* #ORM\Entity
* #ORM\Table(name="view")
* #ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewRepository")
*/
class View extends Entity\Base {
/**
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", inversedBy="view", cascade={"persist", "remove"}, orphanRemoval=true)
* #ORM\JoinColumn(name="versionId", referencedColumnName="id")
*/
protected $viewVersion;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $versionId = NULL;
/**
* #ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="viewAll", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $viewVersions;
}
/**
* #ORM\Entity
* #ORM\Table(name="view_version")
* #ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewVersionRepository")
*/
class ViewVersion extends Entity\Base {
/**
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", mappedBy="viewVersion", cascade={"persist"})
*/
protected $view;
/**
* #ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="viewVersions")
* #ORM\JoinColumn(name="viewId", referencedColumnName="id")
*/
protected $viewAll;
/**
* The primary view entity that this version belongs to.
* #ORM\Column(type="integer", nullable=true)
*/
protected $viewId;
}
This "works" but is it recommended to have two associations with the same entity like this? Or is this a really bad idea?
The ViewVersion entity will reference a single View entity in both cases, but the mapped associations need two separate variables, e.g. View and ViewAll. I'm not exactly sure how the internals work for the association, and how the reference variable with the mapping is used.
Alternatively, I could get rid of the OneToOne association, and just set a ViewRepository function to get the current published version based on the versionId (just like the old mapped entity used to do with the getVersion()). That would work, but is it more internal overhead, because it would make two queries... or will Doctrine be smart enough to optimize this, just like it did with the getVersion().
NOTE:
These other answers are not complete.
References:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html
http://doctrine-orm.readthedocs.org/en/2.0.x/reference/association-mapping.html#one-to-many-bidirectional
Typically, I have found the best approach is to solve this in a different way.
One common pattern I have seen before is you use a single table to hold all records, and have an 'active' flag.
If your query to select the active one works like so:
SELECT * FROM table WHERE active = true ORDER BY updated_at DESC LIMIT 1;
Then enabling a new one becomes as simple as:
UPDATE table SET active = 1, updated_at = '<timestamp>' WHERE id = <new id>;
UPDATE table SET active = 0, updated_at = '<timestamp>' WHERE id = <old id>;
Your new page will be active as soon as the first query hits, and your second query will avoid any sort of weirdness as that row will already be no longer active.
If you have other models that depend on a consistent ID to reference, then another route which also maintains some sanity would be to have one table for the active entries (in whole, not in part) and then a second table with additional metadata to track versions.
The latter approach could be nicely handled via Doctrine's inheritance system (http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html) which would let you define the base View class, and then for the "ViewRevision" model, extend View and add a "Revised on" type timestamp.
Per the advice from #jmather I've decided this model is "okay", because I need a single View entity that other entities can access (e.g. Routing urls that point to a single View, i.e. "page").
I've changed the OneToOne relationship for View to be unidirectional only, because the ViewVersion already has an association back to the View via the other OneToMany (so it doesn't need two paths back).
This allows me to keep a simple method for $view->getPublished() handy and seems more logical.
/**
* #ORM\Entity
* #ORM\Table(name="view")
*/
class View extends Entity\Base {
/**
* This is a OneToOne Unidirectional association, just so that we can get the
* current published version easily, based on the publishedId.
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\TestVersion")
* #ORM\JoinColumn(name="publishedId", referencedColumnName="id")
*/
protected $published;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $publishedId = NULL;
/**
* This is the regular OneToMany Bi-Directional Association, for all the versions.
* #ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="view", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $versions;
}
/**
* #ORM\Entity
* #ORM\Table(name="view_version")
*/
class ViewVersion extends Entity\Base {
/**
* #ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="versions")
* #ORM\JoinColumn(name="viewId", referencedColumnName="id")
*/
protected $view;
/**
* The primary view entity that this version belongs to.
* #ORM\Column(type="integer", nullable=true)
*/
protected $viewId;
}
However, I've discovered that as long as the $view->publishedId is set the view can't be deleted from the database because of foreign key constraints (even though it's uni-directional). So I have to break that foreign key link before removing. I think that's fine. I posted details about that here: Overlapping Entity Association causing Database Foreign Key Constraint Errors when Removing Entity