How to customize the doctrine of class inheritance in Symfony?

My problem is I am having trouble grabbing the DisccriminatorColumn and DiscriminatorMap in the inheritance of the Doctrine class.

I have a product object that is considered a parent class / table.

There are several child objects that inherit the product object. (models, parts and options)

It seems to me that I should use the primary key to link both tables ... But how do I do this with DiscriminatorColumn?

Here is a general idea of ​​what I want ...

Get all model objects from the database when inheriting from the parent product object

SELECT object 
FROM parts_object parts
LEFT JOIN products_object po
ON parts.product_fk = po.product_id

      

Or ... Get all objects part from the database when inheriting from the parent product object

SELECT object 
FROM parts_object parts
LEFT JOIN products_object po
ON parts.product_fk = po.product_id

      

Ideally, I want this to be done with Doctrine rather than custom SQL.

Do I need to set the "type" column for the parent table so that each row determines whether it is a part, a model, or a parameter?

Doctrine doctrine doctrine

+3


source to share


2 answers


If you want to use DiscriminatorMap for Doctrine, you should use Doctrine, not SQL.

Basic setup:

/**
 * @ORM\Table(name="product")
 * @ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\ProductRepository")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="productType", type="string")
 * @ORM\DiscriminatorMap({
 *   "Product" = "Product",
 *   "Model" = "Model",
 *   "Part" = "Part",
 *   "Option" = "Option",
 * })
 */
class Product
{
...
}

      

MyApp \ ProductBundle \ Entity \ Model

/**
 * @ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\ModelRepository")
 */
class Model extends Product 
{
}

      

MyApp \ ProductBundle \ Entity \ h

/**
 * @ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\PartRepository")
 */
class Part extends Product 
{
}

      



MyApp \ ProductBundle \ Entity \ Option

/**
 * @ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\OptionRepository")
 */
class Option extends Product 
{
}

      

Then if you need to get all products on the controller

 $em = $this->getDoctrine()->getManager(); 
 $repo = $em->getRepository("MyAppProductBundle:Product");
 $products = $repo->findAll();

      

Then if you need to select all models, just set up the appropriate repository

 $repo = $em->getRepository("MyAppProductBundle:Model");
 $models = $repo->findAll();

      

+4


source


Ok, I'll try to explain this as simply as possible.

Let's start with DiscriminatorColumn

A discriminator column is basically, as it says, a column in your database. It is used to store the key if you like, which helps determine which object you are currently requesting based on configuration DiscriminatorMap

.

DiscriminatorMap

is a way to map each of these keys to an entity. You said you have the following

  • Product [parent]
  • Model [child of parent]
  • The [child of the parent] part
  • Parameter [child of parent]

Then your discriminator map should look something like this:

@DiscriminatorMap({
    "model" = "AppBundle\Entity\Model", 
    "Part" = "AppBundle\Entity\Part",
    "Option" = "AppBundle\Entity\Option"
})

      

Always pay attention to your last definition in your collation. The last line must end without a comma!

As in InheritanceType

, I suggest you use @InheritanceType("JOINED")

because it will allow you to have a separate table for each of your child classes.

Each child class must extend your entity class Product

, which is obviously the parent. Each child class does not have to define a property $id

because of the inheritance mapping.

Then a request for records of a particular type comes with the following request:

"SELECT product FROM AppBundle\Entity\Product product WHERE product INSTANCE OF AppBundle\Entity\Part"

      



The query will only search for records matched only to this object.

If you have any questions, do not hesitate to ask.

Edit as new comment

-----------------------

A bit more explanation. You don't need to create extra property / column in entity mappings. When you add this annotation, @DiscriminatorColumn(name="discr", type="string")

doctrine will automatically create this column for you. The column from this example will be named discr

with type VARCHAR

.

I still don't understand what is used to join tables. As the doctrine knows, associate identifiers between product and model.

About this part. If you use @InheritanceType("JOINED")

it means that your id GeneratedValue

will be set in your main entity - Product

. Then each of the child entities that extend Product

will automatically get the same ID, so you don't need to specify the property $id

on the children.

Finally, how can you check the type of entity you are currently viewing, eg. Consider the following scenario, each of your child entities expands Product

and we will do a dummy record lookup:

$product = $entityManager->find('AppBundle:Product', 1); // example

      

Now if you really go and do var_dump($product)

, you will notice something interesting. The object will be an instance of either Model

, Part

or Option

, because each of these entities is defined in your discriminator map, and Doctrine will automatically render your records based on that. This can come in handy later in situations like this:

if( $product instanceof \AppBundle\Entity\Part ) {
    // do something only if that record belongs to part.
}

      

+2


source







All Articles