Doctrine: authorize NULL in a foreign composite key - symfony

I have the following entity:
/**
* SeriesAuthorRole
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Blog\Bundle\CoreBundle\Entity\SeriesAuthorRoleRepository")
*/
class SeriesAuthorRole extends AuthorRoleAbstract
{
/**
* #var Series
*
* #ORM\ManyToOne(targetEntity="Blog\Bundle\CoreBundle\Entity\Series", inversedBy="authors")
* #ORM\JoinColumn(name="series", referencedColumnName="id", nullable=false)
* #ORM\Id
*/
private $series;
/**
* #var Author
*
* #ORM\ManyToOne(targetEntity="Blog\Bundle\CoreBundle\Entity\Author")
* #ORM\JoinColumn(name="author", referencedColumnName="id", nullable=false)
* #ORM\Id
*/
protected $author;
/**
* #var Role
*
* #todo Must be nullable
*
* #ORM\ManyToOne(targetEntity="Blog\Bundle\CoreBundle\Entity\Role")
* #ORM\JoinColumn(name="role", referencedColumnName="id", nullable=true)
* #ORM\Id
*/
protected $role;
// ... Getters, setters
}
The idea behind it is quite simple: We have author, role and series entities. A series can have several authors with various roles. A same author can fulfill multiple roles in a series.
Sometimes, we don't know exactly what was the role of the author. In this case, the NULL value will be used for the role, the NULL value standing for "I don't know".
I was taught not to use NULL in foreign composite keys unless it has meaning. Well, it has meaning here, and I know that this could be implemented without Doctrine. However, for now, Symfony 2 throws that error:
Entity of type Blog\Bundle\CoreBundle\Entity\BandAuthorRole is missing an assigned ID for field 'role'. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.
500 Internal Server Error - ORMException
So how can I authorize NULL values in foreign composite keys ? Is it possible at all with Doctrine ?

Your #JoinColumn annotation is correct with referencing to http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#annref-joincolumn
However,
Every entity with a composite key cannot use an id generator other
than “ASSIGNED”. That means the ID fields have to have their values
set before you call EntityManager#persist($entity).
http://docs.doctrine-project.org/en/2.0.x/tutorials/composite-primary-keys.html#general-considerations

Related

Symfony 2 Doctrine unique id from another source

I'm pulling a lot of data to cache locally, the data i pull is in json format and has along with it Unique Id's for each record.
Is there a way i can tell doctrine to use this as the id for the table?
I'm only going to be populating these tables with data from my json, i wont be adding any new records from other sources only from my json pull.
is it possible to get doctrine to use a field from my json pull as the primary key?.
when i use doctrine:generate:entity
it automatically adds an id field I would ideally like to get rid of this and use the uniqueID column from my data pull. ($teamKey)
say for example this is my entity
/**
* Team
*
* #ORM\Table("fp_team)
* #ORM\Entity(repositoryClass="FantasyPro\DataBundle\Entity\TeamRepository")
*/
class Team
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="teamKey", type="string", length=50, nullable=false)
*/
private $teamKey;
/**
more properties ...........
*/
is it just a case of deleting the existing $id property and modifying my $teamKey property to:
/**
* #var string
* #ORM\Id
* #ORM\Column(name="teamKey", type="string", length=50, unique=true, nullable=false)
*/
private $teamKey;
Is it more complex than that or not possible?
does the unique id field for doctrine have to be called $id ?
Theoretically, it depends on your DB. But, generally speaking, any DB type should let you set any ID you want.
So, you can always do $entity->setId() any time you want, and persist it with that ID, with no problem.

Doctrine not found entity id

i have a problem mapping entities in Doctrine 2 (with Symfony2). Symfony says that error is in Perfil entity, but the Doctrine section profiler says that the error is en Funcion entity.
This is the error (on the browser):
The column id must be mapped to a field in class
AppsManantiales\CommonBundle\Entity\Perfil since it is referenced by a
join column of another class.
But, in the profiler:
AppsManantiales\CommonBundle\Entity\Funcion: The referenced column
name 'id' has to be a primary key column on the target entity class
'AppsManantiales\CommonBundle\Entity\Funcion'. The referenced column
name 'id' has to be a primary key column on the target entity class
'AppsManantiales\CommonBundle\Entity\Perfil'.
This is the relation er:
The Perfil entity, basically is:
class Perfil implements RoleInterface{
/**
* #ORM\Id
* #ORM\Column(type="integer", length=10)
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $idperfil;
/**
* #ORM\ManyToMany(targetEntity="Funcion", mappedBy="perfiles")
* #ORM\JoinTable(name="perfil_funcion",
* joinColumns={#ORM\JoinColumn(name="perfil", referencedColumnName="idperfil")},
* inverseJoinColumns={#ORM\JoinColumn(name="funcion", referencedColumnName="idfuncion")}
* )
*/
protected $funciones;
// More code...
}
The Funcion entity basically is:
class Funcion {
/**
* #ORM\Id
* #ORM\Column(type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $idfuncion;
/**
* #ORM\ManyToMany(targetEntity="Perfil", inversedBy="funciones")
*/
protected $perfiles;
// More code...
}
Any ideas ? Thanks !
I think by default Doctrine relies on the convention that all primary keys in entities are represented by an attribute called $id. Two solutions :
Rename your primary keys from $idperfil and $idfuncion to $id (which I recommend);
Explicit the join criterion on your Funcion object on the $perfiles property:
* #ORM\JoinTable(name="perfil_function"),
* joinColumns={#ORM\JoinColumn(name="funcion", referencedColumnName="idfuncion")},
* inverseJoinColumns={#ORM\JoinColumn(name="perfil", referencedColumnName="idperfil")}
* )

Doctrine2 - Custom persister

I'm busy working on a project and I've ran into a slight issue. I was just wondering whether there is any way to customize the persist action of a specific entity? In my case specifically I want to, on update, remove some fields from other tables before re-saving the entity.
Let's, for arguments sake, say my entity that I want a custom persist action on looks like this:
/**
* #ORM\Table()
* #ORM\Entity
*/
class A {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="B", mappedBy="bar")
* #ORM\Column(name="foo")
*/
private $foo;
//Some additional getters and setters here
}
/**
* #ORM\Table()
* #ORM\Entity
*/
class B {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="A", inversedBy="foo")
* #ORM\JoinColumn(name="bar", referencedColumn="id")
*/
private $bar;
//Getters and setters here.
}
Now I know with a simple example like this doctrine will automatically just update $bar in class B if you update that, but let's just say I'd like to first remove $bar completely (not just update it) and re-save it with the new value? Is this possible?
This could also just be done manually before persisting in my update action, but that feels a bit hacky?
The actual code I want to do this with is much too long to post here, so I'm just opting for a simple proof-of-concept here.
Thanks for any assist!
EDIT
Technically the other entities will be related to the current one, via a OneToMany/ManyToMany/ManyToOne relationship, as in the example above. So isn't there something like preHydrate that I can use to clear current data before hydrating the entity with the submitted data?
You should use event-listeners or -subscribers instead of LifecycleCallbacks (i.e. #PrePersist ) as recommended in Cyrus's answer.
Using LifecycleCallbacks you don't have access to unrelated entities while you can change/remove these with a listener/subscriber where you have direct access to the entity-manager with dependency injection.
Please see the documentation chapter How to Register Event Listeners and Subscribers.
You can use prepersist:
/**
* #ORM\PrePersist
*/
There are preupdate, preremove, etc.
Here you have all the info to do that: http://symfony.com/doc/current/book/doctrine.html

Doctrine2 - How can i make a relationship with string column

I having a following issue, I need to make a relationship with two tables, but with no regular id, i need to use strings column. Something like this:
/**
* #ORM\Entity
* #ORM\Table(name="sigtap_tb_procedimento")
*/
class Procedimento
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="ExcecaoCompatibilidade", mappedBy="procedimento_restricao")
* #ORM\JoinColumn(name="co_procedimento_restricao", referencedColumnName="co_procedimento")
*/
private $restricoes;
}
And another Entity
/**
* #ORM\Entity
* #ORM\Table(name="sigtap_rl_excecao_compatibilidade")
*/
class ExcecaoCompatibilidade
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Procedimento", inversedBy="restricoes")
* #ORM\JoinColumn(name="co_procedimento_restricao", referencedColumnName="co_procedimento")
*/
private $procedimento_restricao;
}
co_procedimento_restricao and co_procedimento_restricao are string type, The relation does not working. How can i solve this issue?
Your relation needs to reference a primary key in the other table.
May be I misunderstood your question but cant you reference the id collumn the relationship like this:
/**
* #ORM\OneToMany(targetEntity="ExcecaoCompatibilidade", mappedBy="procedimento_restricao")
*/
private $restricoes;
/**
* #ORM\ManyToOne(targetEntity="Procedimento", inversedBy="restricoes")
* #ORM\JoinColumn(name="co_procedimento_restricao", referencedColumnName="id")
*/
private $procedimento_restricao;
Take a look here:
http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html
using one-to-many relations with doctrine
The side using #OneToMany is always the inverse side of a relation from doctrine's pov ( possibly not what you consider being the inverse side ) and never has a join-column definition.
Remove the #JoinColumn annotation from class Procedimento.
#OneToMany has to use mappedBy and #ManyToOne (the owning side) uses inversedBy.
The join-column (or join-table) definition has to be on the owning side together with #ManyToOne.
When using a join-column the name of this column (which will be added to the table of the owning side entity aka the side being "many") will be specified by name="column_name" and the referenced foreign key to store in there is the referencedColumnName="id"definition of the #JoinColum annotation.

Symfony2 ORM FK Composite

I'm new with Symfony2 and Doctrine 2 ORM, then i got a problem with composite FK association.
While the association OneToMany-ManyToOne by a single auto-increment ID works good, i got many troubles with the same kind of association but through a composite PK.
What i would like to do is an entity-structure that mirrors the below shema.
http://imageshack.us/photo/my-images/9/z07m.jpg (Sorry but I cannot insert images into the post)
where
prd_product_data.product_id
prd_product_data.language_id
make up together the PK of 'prd_product_data'
and
prd_product_image.pdoduct_id
prd_product_image.language_id
make up the FK linked to the table 'prd_product_data'.
These below
prd_product_image.pdoduct_id
prd_product_image.language_id
prd_product_image.file_image_id
make up, all together, the PK of 'prd_product_image'.
I read that Doctrine 2.1 and up, supports natively the composed PK - FK association but there are very few examples. Moreover, surfing on the web, i found just scattered fragments of similar situations but nothing of useful.
The main issue now, is that i'm unable to create one unique object for the two ids, like such an unique id.
For example...
Snapshot for the Entity ProductData where "product and language should make up the same object:
/**
*
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="product")
*/
protected $products_Pimgs;
/**
*
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="language")
*/
protected $products_Limgs;
Snapshot for the Entity ProductImage where *product_id* and *language_id* made up the FK for the entity ProductData:
/**
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="ProductData", inversedBy="products_Pimgs")
* #ORM\JoinColumn(name="product_id", referencedColumnName="product_id")
*/
protected $product;
/**
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="ProductData", inversedBy="products_Limgs")
* #ORM\JoinColumn(name="language_id", referencedColumnName="language_id")
*/
protected $language;
/**
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="FileImage", inversedBy="files_images")
* #ORM\JoinColumn(name="file_image_id", referencedColumnName="id")
*/
protected $file_image;
From these snapshots it's evident that those keys are working separately.
In the end, this is my doctrine version, taken from the composer:
"doctrine/orm": ">=2.2.3,<2.4-dev",
How can i create an unique reference with two objects with ORM?
Read the documentation chapter Composite Primary Keys.
/**
* #ORM\Id
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="product")
*/
protected $products_Pimgs;
/**
* #ORM\Id
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="language")
*/
protected $products_Limgs;

Resources