Symfony Single Table Inheritance with translated columns in parent/child entity - symfony

I have a parent abstract Table Location which is defined as an STI:
/**
* #ORM\Entity(repositoryClass=Location::class)
* #InheritanceType("SINGLE_TABLE")
* #DiscriminatorColumn(name="discr", type="string")
* #ORM\Table(
* name="location",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="assignment_unique", columns={"longitude", "latitude", "discr"})
* }
* )
*/
abstract class Location extends Place
which is conform with the Schema org https://schema.org/.
Now in this use case a Discriminator is used for the different types of Locations (there are about 7 currently, up to 15 possible).
Now there are approx 15 translatable columns defined in Place, which are mapped to Location at runtime. Each discriminator might add itself columns that might be translated too.
We've discussed the possibility of adding a translation table to the Location entity, reducing all the translatable columns to that entity and when querying choosing the correct language.
I can live with the fact that the parent table outsources its translatable columns into a language_table - but what if a discriminator now adds itself some translatable columns? When querying for Type B Children of Location, it is not known which fields apply.
Does anyone know a pattern to apply for multi-language discriminators with childrens brining in translatable columns?
Thanks for any help.
This is what i've modelled by now:
so in the end everything will be stored in the location table. if everything is set up and we load an location by its discr column identifying the correct type, the foreign keys will retrieve the correct translations from their respective translation tables.
Can anyone give me feedback on that solution?

Related

Doctrine2 OneToMany with multiple Entities

I have three kinds of Users, every user has some FiscalData and is linked to a UserCredential entry.
Which translates in:
UserX (X=1,2,3) has two FKs referring to FiscalData and
UserCredential tables.
Using Doctrine2, reading the docs http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/association-mapping.html, I believe to need the MappedSuperClass pattern.
I have also read the following questions:
Doctrine 2 - One-To-Many with multiple Entities
Many-To-One with multiple target entities
Doctrine2, Symfony2 - oneToOne with multiple entities?
But in the docs is clearly stated that
A mapped superclass cannot be an entity, it is not query-able and persistent relationships defined by a mapped superclass must be unidirectional (with an owning side only). This means that One-To-Many associations are not possible on a mapped superclass at all. Furthermore Many-To-Many associations are only possible if the mapped superclass is only used in exactly one entity at the moment. For further support of inheritance, the single or joined table inheritance features have to be used.
So, how to achieve what I'm trying to achieve, which is a bidirectional relationship between UserX and FiscalData/UserCredential? (so that f.e. via Doctrine I can get a UserCredential and check what kind of profiles it has associated)
Any complete minimal code example showing how to enforce the relationship I'm looking for (and not just the MappedSuperClass inheritance shown in the docs will be highly appreciated.
Use an abstract entity instead of MappedSuperClass. Single-table is usually the way to go unless you're sure you want class/table.
<?php
/**
* #ORM\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({
* "mentor" = "Mentor",
* "protege" = "Protege"
* })
*/
abstract class User { ... }

Different table name and entity name in Symfony2

I have an existing database. Lets say that I have a table named "transactions" and I want to create the corresponding Entity named "Transaction". How can I do that?
you can set the name of the table using the #ORM\Table annotation
/**
* #ORM\Entity
* #ORM\Table(name="transactions")
*/
class Transaction
{
If you don't use Annotations, you can find details about other mappings from this link.
BTW, You can also generate Entities from an Existing Database.
You could set name param for mapping
http://symfony.com/doc/current/book/doctrine.html#add-mapping-information

Symfony2 and Doctrine - ManyToOne

I am trying to understand Symfony2, but there is something that is not making sense to me. I reversed engineered an existing database to produce my entities, so maybe thats the problem.
I have a table called availability_alert, nothing special, a few fields including an id (which is the primary key). This table has no link to anything else.
I then have a second table called booking_class, once again nothing special, but it does have the field $availabilityAlert which links to the availability_alerts tables id.
In essence, an Availability Alert can have one or many Booking Class.
Now in my booking class entity, I have the link
/**
* #var \AlertBundle\Entity\AvailabilityAlert
*
* #ORM\ManyToOne(targetEntity="AlertBundle\Entity\AvailabilityAlert")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="availability_alert_id", referencedColumnName="id")
* })
*/
private $availabilityAlert;
So this all looks ok. The setter for it though came out like so
public function setAvailabilityAlert(\AlertBundle\Entity\AvailabilityAlert $availabilityAlert = null)
{
$this->availabilityAlert = $availabilityAlert;
return $this;
}
So that appears to take an AvailabilityAlert Object as a parameter, not the AvailabilityAlert id?
So with the above, I am presuming doing something like this in my controller will not work?
$alert = new AvailabilityAlert();
$bookingClass = new BookingClass();
$bookingClass->setAvailabilityAlert($alert->getId());
Could someone give me some advice on whether things are correct here, or if I should be doing something else? Essentially AvailabilityAlert should be a static table, other tables link to this.
Any advice appreciated.
Thanks
Yes this is correct.
In the Doctrine world, you are working with objects, not with integers or strings, when it comes to relationships between Entities.
You can read more about Doctrine 2 relationships here: http://symfony.com/doc/current/book/doctrine.html#entity-relationships-associations
That's correct. You don't use integers, strings. It's because the relationships are given in entity annotations and Doctrine uses them to figure out what is used exactly to reference the one object from the other. This even let you change how objects reference themselves - for example you change the id to a compound primary key in AvailabilityAlert class and your code wouldn't change much except for the annotations.

Doctrine generate code with other naming conventions

We are starting with Symfony2 and Doctrine. I need to select some data from tables that already exist. These tables and column names do not use the naming conventions as defined by Doctrine.
I was wondering if I could create my own naming scheme somewhere. Mainly, we use PascalCase table and columnnames, without underscored. This results in Entity properties like $firstpromotiondatetime while the column is FirstPromotionDateTime, so i'd like my property to be firstPromotionDateTime.
You don't necessarily need to use doctrine's entity generator to generate new entities, you can also manually do it. However, you can also generate the entities via the command line, and then open your entity classes and change the property names as you see fit. Just make sure that the doctrine mapping (use the following annotation for instance) is still pointing to the correct column name in your database.
/**
* #var \DateTime $firstPromotionDateTime
*
* #ORM\Column(name="FirstPromotionDateTime", type="datetime")
*/
private $firstPromotionDateTime;
Edit:
If you manually change the property names, also make sure you have correctly modified the setters & getters as well.

Symfony2 - how to construct id = product mapping

I want to do mapping that does this:
User can own multiple Games. Games can have multiple owners.
I have id column in game table and game and user columns in ownership table. How I can connect these fields? I want to have game and user fields in ownership related to user and game tables.
I tried OneToMany and ManyToMany, but the first one results in generating additional columns. I don't want to insert anything in game table.
--edit--
My #ManyToMany code:
/**
* #ORM\ManyToMany(targetEntity="Ownership")
* #ORM\JoinTable(name="ownership",
* joinColumns={JoinColumn(name="user", referencedColumnName="id")},
* inverseJoinColumns={JoinColumn(name="game", referencedColumnName="id")}
* )
*/
It causes an error in Symfony's command line:
[Doctrine\Common\Annotations\AnnotationException]
[Semantical Error] Couldn't find constant JoinColumn, property GameShelf\Us
ersBundle\Entity\User::$ownership.
Of course you need many to many relations if, like you said:
User can own multiple Games. Games can have multiple owners.
The Doctrine should create third table (which could contains only two foreign keys: game_id and ownership_id).
The error is caused because Doctrine dosen't know what JoinColumn is. You just did wrong annotation because you forgot (again! ;)) precede JoinColumn with `#ORM. The right annotation should look like this:
/**
* #ORM\ManyToMany(targetEntity="Ownership")
* #ORM\JoinTable(name="ownership",
* joinColumns={#ORM\JoinColumn(name="user", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="game", referencedColumnName="id")}
* )
*/
Sounds like you need to introduce a new entity (something like OwnedGame) that holds the connection between a Game and an Owner (and possibly its own properties like when it was bought and such).
Then OwnedGame would be ManyToOne with Game and with Owner, and neither Game nor Owner would need to include a new column.
Your description of what you want doesn't fit at all.
On the one hand you want to have a relation between only Users and Games, and only between Games and Owners.
But on the other hand you say that Users and Owners are related in some way, but Games and Users aren't.
You should read through
http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html#many-to-many-unidirectional
and try to find what you really need.
I would recommend a ManyToMany relation with a join table. Thus you don't have to deal with additional fields in your tables

Resources