Doctrine: Update discriminator for SINGLE_TABLE Inheritance
It is not a good sign when the type of an instance of an object needs to change over time. I'm not talking about downcasting/upcasting here, but about the need to change the real type of an object.
First of all, let me tell you why it is a bad idea:
- A subclass might define more attributes and do some additionnal work
in it's constructor. Should we run the new constructor again? What
if it overwrites some of our old object's attributes? - What if you were working on an instance of that Person in some part of your code, and then it suddenly transforms into an Employee (which might have some redefined behavior you wouldn't expect)?!
That is part of the reason why most languages will not allow you to change the real class type of an object during execution (and memory, of course, but I don't want to get into details). Some let you do that (sometimes in twisted ways, e.g. the JVM), but it's really not good practice!
More often than not, the need to do so lies in bad object-oriented design decisions.
For those reasons, Doctrine will not allow you to change the type of your entity object. Of course, you could write plain SQL (at the end of this post - but please read through!) to do the change anyway, but here's two "clean" options I would suggest:
I realize you've already said the first option wasn't an option but I spent a while writing down this post so I feel like I should make it as complete as possible for future reference.
- Whenever you need to "change the type" from
Person
toEmployee
, create a new instance of the Employee and copy the data you want to copy over from the old Person object to the Employee object. Don't forget to remove the old entity and to persist the new one. - Use composition instead of inheritance (see this wiki article for details and links to other articles). EDIT: For the hell of it, here's a part of a nice conversation with Erich Gamma about "Composition over Inheritance"!
See related discussions here and here.
Now, here is the plain SQL method I was talking about earlier - I hope you won't need to use it!
Make sure your query is sanitized (as the query will be executed without any verification).
$query = "UPDATE TABLE_NAME_HERE SET discr = 'employee' WHERE id = ".$entity->getId();
$entity_manager->getConnection()->exec( $query );
Here is the documentation and code for the exec method which is in the DBAL\Connection
class (for your information):
/**
* Execute an SQL statement and return the number of affected rows.
*
* @param string $statement
* @return integer The number of affected rows.
*/
public function exec($statement)
{
$this->connect();
return $this->_conn->exec($statement);
}
Doctrine Inheritance: Discriminator from Entity attribute and not table column?
Given the fact that shopType
is a rather static property (in the sense that it will always be the same for all instances of a class) you can simply define the shopType
as default for the property, and use the existing column as discriminator column:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="shopType", type="string")
* @ORM\DiscriminatorMap({"local" = "LocalShop", "foreign" = "ForeignShop"})
*/
class Shop
{
protected const TYPE_LOCAL = 'local';
protected const TYPE_FOREIGN = 'foreign';
// ...
}
/**
* @Entity
*/
class LocalShop extends Shop
{
protected $shopType = Shop::TYPE_LOCAL;
// ...
}
/**
* @Entity
*/
class ForeignShop extends Shop
{
protected $shopType = Shop::TYPE_FOREIGN;
// ...
}
Doctrine's hydrators will take a new instance of your class, which gets instantiated with all default values applied, and then write all the fetched information from the database to the mapped properties.
Since your property has the expected value in the defaults, and is not mapped, its correct default value will not be changed by the hydration process and have the expected value, even when fetched from the database.
In that process, the constructor is not called (Entities are either cloned or produced by Reflection's newInstanceWithoutConstructor), which is why the original code did not work.
Doctrine Inheritance - Single_Table inheritade from Joined table
You need a case for your "AccountBackend" class in your @DiscriminatorMap
e.g
@DiscriminatorMap({"1"="FeaturedAuthor","2"="Administrator", "3"="AccountBackend"})
As explain in the Documentation
All entity classes that is part of the mapped entity hierarchy (including the topmost class) should be specified in the @DiscriminatorMap. In the case above Person class included.
Single Table Inheritance - discriminator map
Look this link maybe it'll help you.
https://medium.com/@jasperkuperus/defining-discriminator-maps-at-child-level-in-doctrine-2-1cd2ded95ffb
Map a discriminator column to a field with Doctrine 2
Sadly, there is no documented way to map the discr column to an entity. That's because the discr column is really part of the database and not the entity.
However, it's quite common to just put the discr value directly in your class definition. It's not going to change and you will always get the same class for the same value anyways.
class Person
{
protected $discr = 'person';
class Employee extends Person
{
protected $discr = 'employee';
Related Topics
Getting Imagegrabscreen to Work
Any PHP Code to Detect the Browser with Version and Operating System
Google Drive API - PHP Client Library - Setting Uploadtype to Resumable Upload
Simulate PHP Array Language Construct or Parse with Regexp
Pdo Cannot Execute Queries While Other Unbuffered Queries Are Active
Move the Variation Price Location in Woocommerce
Good Tutorial on How to Update Your MySQL Database with a PHP Form
In Htaccess, I'D Like to Replace Underscores with Hyphens and Then Redirect the User the New Url
How to Access Element Attributes with Simplexml
How to Install PHP_Id3 on Wamp
Iterating Through a Stdclass Object in PHP
How to Disable PHP Magic Quotes at Runtime
PHP $_Server['Remote_Addr'] Shows Ipv6
How to Get Column Names from Pdo's Fetchall Result
PHP - How to Get Shell Errors Echoed Out to Screen
Phpmailer Send Gmail Smtp Timeout
How to Create PHP Two Column Table with Values from the Database