Doctrine migration ignores #Table Annotation in #Entity definition - symfony

I have the following Doctrine Entity in Symfony 4.2:
When I run the migration the unique constraints and the indexes are not generated. The result of the Entity are just the following indexes in MySql:
PRIMARY (id)
identifier (identifier), Unique
Media.php
<?php
// src/Entity/Media.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\UniqueConstraint;
/**
* Common\Model\Entity\Media
*
* #Entity
* #Table(name="media",
* uniqueConstraints={
* #UniqueConstraint(name="virtual_unique",
* columns={"virtualname", "virtualfolder"})
* }
* indexes={
* #Index(name="idx_virtual", columns={"virtualname", "virtualfolder"})
* #Index(name="idx_identifier", columns={"identifier"})
* }
* )
*/
/**
* #ORM\Entity(repositoryClass="App\Repository\MediaRepository")
*/
class Media
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", nullable=true, options={"unique": true})
*/
private $identifier;
/**
* #ORM\Column(type="string", length=255, nullable=false)
*/
private $virtualname;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $virtualfolder;
}

First, you have multiple annotation blocks for the same class. Just merge them and have a single annotation block for that entity.
And you are using serveral annotations directly, but not importing their definitions. Specifically:
#Entity
#Index
#UniqueConstraint
#Table
Either you:
Use them prefixed by #ORM(since you are doing use Doctrine\ORM\Mapping as ORM)
This is the most convenient and the one that's usually applied.
A complete fix:
/**
* Common\Model\Entity\Media
*
* #ORM\Entity(repositoryClass="App\Repository\MediaRepository")
* #ORM\Table(name="media",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="virtual_unique",
* columns={"virtualname", "virtualfolder"})
* },
* indexes={
* #ORM\Index(name="idx_virtual", columns={"virtualname", "virtualfolder"}),
* #ORM\Index(name="idx_identifier", columns={"identifier"})
* }
* )
*/
class Media
{}
Or, you use the full namespace declaration in those annotations
You could also use the annotations with the full namespace, like #Doctrine\ORM\Mapping\Table, #Doctrine\ORM\Mapping\UniqueConstraint, etc; but that gets unnecessarily verbose very quickly.
Or, you could import each of the annotations independently
use Doctrine\ORM\Mapping\Table;
use Doctrine\ORM\Mapping\Index;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\UniqueConstraint;
But it also seems wasteful.
The approach you'll see on the docs is the first one. Import Doctrine\ORM\Mapping as ORM, and use the annotations hanging from there.

Probably you need change #Table to #ORM\Table and remove #Entity
try this:
/**
* #ORM\Entity(repositoryClass="App\Repository\MediaRepository")
* #ORM\Table(name="media",
* uniqueConstraints={
* #UniqueConstraint(name="virtual_unique",
* columns={"virtualname", "virtualfolder"})
* }
* indexes={
* #ORM\Index(name="idx_virtual", columns={"virtualname", "virtualfolder"})
* #ORM\Index(name="idx_identifier", columns={"identifier"})
* }
* )
*/

Clearing my cache did the trick for me.
I tried a few other suggestions, but after a cache:clear I got the index in my migration.

Related

Default API Filters Failing when referencing nested properties of related entities

I am configuring a series of ApiFilter classes from the Api-platform stack in a Symfony 4 application. I am finding that any filters using a nested property from an entity relationship takes no effect. Please see my example code below, would really appreciate any assistance with why it may not be working.
The entity I am trying to filter on is:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiProperty;
/**
* PostAuthor
* #ApiResource()
* #ORM\Table(name="POST_AUTHOR", indexes={#ORM\Index(name="IDX_CF3397D94A7000A0", columns={"IDENTITY_ID"})})
* #ORM\Entity(repositoryClass="App\Repository\PostAuthorRepository")
*/
class PostAuthor
{
/**
* #var string
*
* #ORM\Column(name="USER_ID", type="string", length=255, nullable=false)
* #ORM\Id
*/
private $userId;
/**
* #var string
*
* #ORM\Column(name="USERNAME", type="string", length=255, nullable=false)
*/
private $username;
And the collection I am filtering is:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiFilter;
use Symfony\Component\Serializer\Annotation\Groups;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\NumericFilter;
use Doctrine\ORM\Mapping as ORM;
/**
* PostHeader
* #ORM\Table(name="POST_HEADER", indexes={#ORM\Index(name="IDX_1CEEE7D0B65E5FF8", columns={"EMOTION_REF_ID"}), #ORM\Index(name="IDX_1CEEE7D08AFAAB14", columns={"AUTHOR_ID"})})
* #ORM\Entity(repositoryClass="App\Repository\PostHeaderRepository")
* #ApiResource(
* normalizationContext={"groups"={"postheader:read"}},
* denormalizationContext={"groups"={"postheader:write"}},
* )
* #ApiFilter(SearchFilter::class, properties={"author.userId": "partial", "author.username": "partial"})
*/
class PostHeader
{
/**
* #var PostAuthor
*
* #ORM\ManyToOne(targetEntity="PostAuthor")
* #ORM\JoinColumns({#ORM\JoinColumn(name="AUTHOR_ID", referencedColumnName="USER_ID")})
* #Groups({"postheader:read"})
*/
private $author;
I just test on a new project with the same classes than you and it works. I can filter by author.userId.
Please give us your testing request. And the error message ;).

How to set Doctrine Auto Increment Starting Value #ORM\GeneratedValue[starts with 100] using symfony2

How can I set the starting value for an Auto Incremented like 100,101....
My code is
/**
* #ORM\Name
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="name", initialValue=100)
* #ORM\Column(type="integer")
*/
protected $name;
while trying i am getting an error like this
[Doctrine\Common\Annotations\AnnotationException]
[Semantical Error] The annotation "#Doctrine\ORM\Mapping\Name" in property
Epita\CrmBundle\Entity\CandidateAnalysisCrm::$name does not exist, or could
not be auto-loaded.
please help me anyone. Thanks for advance
My entity is:
namespace Epita\CrmBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* category
*
* #ORM\Table(name="candidateanalysiscrm")
* #ORM\Entity
*/
class CandidateAnalysisCrm {
/**
* #ORM\Id
* #ORM\Column(type = "integer", name= "id")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="integer", name="applicationinprogress",length=10,
nullable=true)
*/
protected $applicationinprogress;
/**
* #ORM\Name
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="name", initialValue=100)
* #ORM\Column(name="name", type="integer")
*/
protected $name;
}
You have several issues here:
First, as already mentioned there is no #Name doctrine annotation.
Second, the GeneratedValue annotation only applies if your attribute is annotated with the #Id annotation.
From the documentation
Specifies which strategy is used for identifier generation for an instance variable which is annotated by #Id. This annotation is optional and only has meaning when used in conjunction with #Id.
If this annotation is not specified with #Id the NONE strategy is used as default.
To fix it change your $name attributes annotations to:
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="name", initialValue=100)
* #ORM\Column(name="name", type="integer")
*/
protected $name;
}
If using the $name property as identifier is not an option for you, listening to doctrine events (e.g. prePersist) could be an alternative solution for your problem. But this is a totally different question.
I'm not sure, but i think that ORM\Name doesn't exist.
You have to write :
* #ORM\Column(name="column_name", type="string")

Doctrine OneToOne drives me crazy

I know that is a recurrent question but after creating a OneToOne relation between 2 entities and run 'php app/console doctrine:schema:validate' I get this error:
'[Mapping] FAIL - The entity-class 'HO\CisBundle\Entity\AffiliateSalesAccounts' mapping is invalid:
* The association HO\CisBundle\Entity\AffiliateSalesAccounts#affiliate refers to the inverse side field HO\HasoffersBundle\Entity\Affiliate#affiliateSalesAccounts which does not exist.'
This is part of the code with both entities:
AffiliatesSalesAccount Entity
namespace HO\CisBundle\Entity;
use HO\HasoffersBundle\Entity\Affiliate;
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Table(name="AffiliateSalesAccounts")
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks
*/
class AffiliateSalesAccounts {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
private $id;
/**
* #var \HO\HasoffersBundle\Entity\Affiliate
*
* #ORM\OneToOne(targetEntity="HO\HasoffersBundle\Entity\Affiliate", inversedBy="affiliateSalesAccounts")
* #ORM\JoinColumn(name="affiliate_id", referencedColumnName="id")
*
*/
private $affiliate;
...
/**
* #param Affiliate $affiliate
*/
public function setAffiliate(Affiliate $affiliate)
{
$this->affiliate = $affiliate;
}
/**
* #return Affiliate
*/
public function getAffiliate()
{
return $this->affiliate;
}
}
Affiliate Entity
namespace HO\HasoffersBundle\Entity;
use HO\CisBundle\Entity\AffiliateSalesAccounts;
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Table(name="ho_Affiliate")
*/
class Affiliate
{
/**
* #var AffiliateSalesAccounts
*
* #ORM\OneToOne(targetEntity="HO\CisBundle\Entity\AffiliateSalesAccounts", mappedBy="affiliate")
*/
private $affiliateSalesAccounts;
....
/**
* #param \HO\CisBundle\Entity\AffiliateSalesAccounts $affiliateSalesAccounts
*/
public function setAffiliateSalesAccounts($affiliateSalesAccounts)
{
$this->affiliateSalesAccounts = $affiliateSalesAccounts;
}
/**
* #return \HO\CisBundle\Entity\AffiliateSalesAccounts
*/
public function getAffiliateSalesAccounts()
{
return $this->affiliateSalesAccounts;
}
}
I have other similar OneToOne relations between 2 entities and it works great.
Someone can I help me?
Thanks a lot..
I am not sure about your problem but I notice that I do it in a different way I just let the code here so that you will be able to check it
/**
* #ORM\OneToOne(targetEntity="Profile", mappedBy="user", cascade={"remove"})
**/
private $profile;
The other class:
/**
* #var \Lifecrops\LCUserBundle\Entity\User
*
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\OneToOne(targetEntity="Lifecrops\LCUserBundle\Entity\User", inversedBy="profile")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="User_id", referencedColumnName="id")
* })
*/
private $user;
Ussually I do something like this:
namespace HO\CisBundle\Entity;
use HO\HasoffersBundle\Entity\Affiliate;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="AffiliateSalesAccounts")
* #ORM\Entity()
*/
class AffiliateSalesAccounts {
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="Affiliate", inversedBy="affiliateSalesAccounts")
* #ORM\JoinColumn(name="affiliate_id", referencedColumnName="id")
*
*/
private $affiliate;
/**
* #param Affiliate $affiliate
*/
public function setAffiliate(Affiliate $affiliate)
{
$this->affiliate = $affiliate;
}
/**
* #return Affiliate
*/
public function getAffiliate()
{
return $this->affiliate;
}
}
And the second entity:
namespace HO\HasoffersBundle\Entity;
use HO\CisBundle\Entity\AffiliateSalesAccounts;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="ho_Affiliate")
* #ORM\Entity()
*/
class Affiliate
{
/**
* #ORM\OneToOne(targetEntity="AffiliateSalesAccounts", mappedBy="affiliate")
*/
private $affiliateSalesAccounts;
/**
* #param AffiliateSalesAccounts $affiliateSalesAccounts
*/
public function setAffiliateSalesAccounts($affiliateSalesAccounts)
{
$this->affiliateSalesAccounts = $affiliateSalesAccounts;
}
/**
* #return AffiliateSalesAccounts
*/
public function getAffiliateSalesAccounts()
{
return $this->affiliateSalesAccounts;
}
}
Clearing cache is imortant part, and if all goes bad you can look to:
doctrine:
orm:
auto_mapping: true
Ok, I solved the problem... First, sorry for bothering you because it was a stupid silly absent-mindedness... Since we use Redis to cache doctrine (with sncRedisBundle), specially metadata and query, Affiliate entity was cached in Redis but without the new field declaration "affiliateSalesAccounts". After deleting the key which store Affiliate entity the problem was solved.
Thank so much for your comments

Doctrine Blameable: on="change" doesn't work while on="create" and "update" do

I'm trying to combine Doctrine's Extensions Blameable and Softdeleteable: when I execute $em->remove($myEntity);, I want to get the fields deleted and deletedBy updated accordingly.
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #Gedmo\SoftDeleteable(fieldName="deleted", timeAware=false)
*/
[...]
/**
* DateTime of softdeletion
* #var \DateTime
*
* #ORM\Column(name="deleted", type="datetime", nullable=true)
* #Assert\DateTime()
*/
private $deleted;
/**
* Softdeleted by
* #var MyProject\UserBundle\Entity\User $deletedBy
*
* #Gedmo\Blameable(on="change", field="deleted")
* #ORM\ManyToOne(targetEntity="MyProject\UserBundle\Entity\User")
* #ORM\JoinColumn()
*/
private $deletedBy;
I have a similar configuration for created/createdBy (with Blameable(on="create")) and updated/updatedBy (with Blameable(on="update")).
Even weirder, if I replace the code above by the one below, the field deletedBy is correctly updated:
/**
* Softdeleted by
* #var MyProject\UserBundle\Entity\User $deletedBy
*
* #Gedmo\Blameable(on="update")
* #ORM\ManyToOne(targetEntity="MyProject\UserBundle\Entity\User")
* #ORM\JoinColumn()
*/
private $deletedBy;
So it seems that it is only the Blameable(on="change", field="deleted") part which doesn't work, and I have no idea why...

Symfony2 Doctrine2 ManyToMany Composite key Column name referenced does not exist

I have a ManyToMany relation with a composite key on the reverse side.
When I use the console command doctrine:schema:update I have the following error:
[Doctrine\ORM\ORMException]
Column name `keyword` referenced for relation from Map\MapBundle\Entity\
Student towards Map\MapBundle\Entity\SkillType does not exist.
I have an entity student (unique key) with a ManyToMany relation with an entity skill (composite key) which has a ManyToOne relation with skillType (unique key).
Here is the different class mapping I have:
Class Student
<?php
namespace Map\MapBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Student
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Map\MapBundle\Entity\StudentRepository")
*/
class Student {
/**
*
* #var integer #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToMany(targetEntity="Map\MapBundle\Entity\SkillType")
* #ORM\JoinTable(name="students_skills",
* joinColumns={
* #ORM\JoinColumn(name="keyword", referencedColumnName="keyword"),
* #ORM\JoinColumn(name="attribut", referencedColumnName="attribut")
* })
*/
private $skills;
}
Class skill
<?php
namespace Map\MapBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Skill
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Map\MapBundle\Entity\SkillRepository")
*/
class Skill {
/**
* #ORM\ManyToOne(targetEntity="Map\MapBundle\Entity\skillType")
* #ORM\JoinColumn(name="keyword", referencedColumnName="keyword")
* #ORM\Id
*/
private $keyword;
}
Classe skillType
<?php
namespace Map\MapBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* SkillType
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Map\MapBundle\Entity\SkillTypeRepository")
*/
class SkillType {
/**
* #var string
*
* #ORM\Column(name="keyword", type="string", length=255)
* #ORM\Id
*/
private $keyword;
}
I tried to exchange the keyword and attribut #joinColumn lines, but I have the same error message with attribut instead of keyword.
I can't see what's wrong with my mapping. The table skill exists and has columns named keyword and attribut.
I hope that somebody will see where I made a mistake (probably a typo error like a missing character or a case mistake).
Thank you for your answer. It helped me a lot and i succeded doing the schema update.
Here is the code I finaly used
/**
* #ORM\ManyToMany(targetEntity="Carte\CarteBundle\Entity\Skill")
* #ORM\JoinTable(name="students_skills",
* joinColumns={#ORM\JoinColumn(name="student_id", referencedColumnName="id")},
* inverseJoinColumns={
* #ORM\JoinColumn(name="keyword", referencedColumnName="keyword"),
* #ORM\JoinColumn(name="attribut", referencedColumnName="attribut")
* })
*/
private $skills;
You write that you want Student to have the many-to-many relation with Skill, but you connected it with SkillType instead. And you're missing the inverseJoinColumns property and you didn't referenced Student properly.
Try the following annotation (untested and after looking at the documentation):
/**
* #ORM\ManyToMany(targetEntity="Map\MapBundle\Entity\Skill")
* #ORM\JoinTable(name="students_skills",
* joinColumns={#ORM\JoinColumn(name="student_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="skill_keyword", referencedColumnName="keyword")}
* )
*/
private $skills;

Resources