I am working on a legacy application and I now need to change an existing table (called categories) so that it has a parent_id field which is a foreign key to the primary key of it’s own table (the categories table)
The issue I am having is that I cannot get Doctrine to set the parent field in the database
I have the following entity orm:
ModelBundle\Entity\Category:
type: entity
table: category
indexes:
fki_parent_to_id:
columns:
- parent_id
uniqueConstraints:
uniq_64c19c1989d9b62:
columns:
- slug
uniq_name:
columns:
- name
id:
id:
type: integer
nullable: false
options:
unsigned: false
id: true
generator:
strategy: SEQUENCE
fields:
name:
type: string
nullable: false
length: 255
options:
fixed: false
slug:
type: string
nullable: false
length: 255
options:
fixed: false
description:
type: string
nullable: true
length: 255
options:
fixed: false
isActive:
type: boolean
nullable: false
options:
default: false
column: is_active
displayOrder:
type: integer
nullable: true
options:
unsigned: false
column: display_order
oneToOne:
parent:
targetEntity: Category
joinColumns:
parent_id:
referencedColumnName: id
lifecycleCallbacks: { }
Here is the entity class:
<?php
namespace ModelBundle\Entity;
use Doctrine\Common\Collections\Collection;
use JMS\Serializer\Annotation\Expose;
use Symfony\Cmf\Bundle\SeoBundle\Extractor\TitleReadInterface;
use Symfony\Cmf\Bundle\SeoBundle\Extractor\DescriptionReadInterface;
use Symfony\Cmf\Bundle\SeoBundle\Extractor\ExtrasReadInterface;
class Category implements ExtrasReadInterface, TitleReadInterface, DescriptionReadInterface
{
/** @var int */
private $id;
/** @var string */
private $slug;
/**
* @Expose
*
* @var string
*/
private $name;
/** @var bool */
protected $isActive;
/** @var string */
private $description;
/** @var Collection */
private $products;
/** @var int */
private $displayOrder;
/**
* @var Category
*/
private $parent;
public function getId(): int
{
return $this->id;
}
public function setName(string $name): Category
{
$this->name = $name;
return $this;
}
public function getName(): string
{
return $this->name;
}
public function setIsActive(bool $isActive): Category
{
$this->isActive = $isActive;
return $this;
}
public function getIsActive(): bool
{
return $this->isActive;
}
public function setDescription(string $description): Category
{
$this->description = $description;
return $this;
}
public function getDescription(): string
{
return $this->description ?: '';
}
public function __construct()
{
$this->products = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addProduct(Product $products): Category
{
$this->products[] = $products;
return $this;
}
public function removeProduct(Product $products)
{
$this->products->removeElement($products);
}
public function getProducts(): Collection
{
return $this->products;
}
public function setSlug(string $slug): Category
{
$this->slug = $slug;
return $this;
}
public function getSlug(): string
{
return $this->slug ?: '';
}
public function getSeoTitle(): string
{
return $this->getName();
}
public function getSeoDescription(): string
{
return $this->getDescription();
}
public function getSeoExtras(): array
{
return [
'property' => [
'og:title' => $this->name,
'og:description' => $this->description,
'og:type' => 'product:category'
],
];
}
function getDisplayOrder(): ?int
{
return $this->displayOrder;
}
public function setDisplayOrder($displayOrder): Category
{
$this->displayOrder = $displayOrder;
return $this;
}
public function getParent() : Category
{
return $this->parent;
}
public function setParent(Category $parent): void
{
$this->parent = $parent;
}
}
This maps out what I have said above. This is similar to what is here in the docs: https://www.doctrine-project.org/projects/doctrine-orm/en/2.5/reference/association-mapping.html#one-to-one-self-referencing There is no yaml in the examples but I got this yaml from doctrine (using the generation commands).
No matter what I do I can never save what is set in the parent.
Example code:
$em = $this->get('doctrine')->getManager();
$repo = $em->getRepository(Category::class);
$newCat = new Category();
$newCat->setName('Test11');
$newCat->setSlug('slug1');
$newCat->setDescription('desc1');
$newCat->setIsActive(true);
$newCat->setDisplayOrder(1);
$newCat->setParent($repo->find(11)); //<-- This does not get saved in the DB
var_dump($newCat);
$em->persist($newCat);
$em->flush();
The $repo->find(11)
returns a Category entity that has a parent (I set it manually in the database) but the parent field is NULL. (I have also tried with an entity that has no parent, same result)
Here is the var_dump:
object(ModelBundle\Entity\Category)[421]
private 'id' => null
private 'slug' => string 'slug1' (length=42)
private 'name' => string 'Teste11' (length=33)
protected 'isActive' => boolean true
private 'description' => string 'desc1' (length=5)
private 'products' =>
object(Doctrine\Common\Collections\ArrayCollection)[422]
private 'elements' =>
array (size=0)
empty
private 'displayOrder' => int 1
private 'parent' =>
object(ModelBundle\Entity\Category)[435]
private 'id' => int 11
private 'slug' => string 'entertaining' (length=12)
private 'name' => string 'Browse Entertaining' (length=19)
protected 'isActive' => boolean false
private 'description' => string 'Selection of great food for any occasion.' (length=41)
private 'products' =>
object(Doctrine\ORM\PersistentCollection)[458]
private 'snapshot' =>
array (size=0)
protected 'initialized' => boolean false
private 'displayOrder' => null
private 'parent' => null
This code creates a new category in the database but the parent field is set to NULL.
What am I doing wrong here? What do I need to do to get this to save the parent to the database. NOTE: I don’t want oneToMany I just want one category to have one parent and that is all.
Versions:
doctrine/annotations v1.3.1
doctrine/cache v1.6.1
doctrine/collections v1.4.0
doctrine/common v2.7.2
doctrine/data-fixtures v1.2.2
doctrine/dbal v2.5.12
doctrine/doctrine-bundle 1.6.7
doctrine/doctrine-cache-bundle 1.3.0
doctrine/doctrine-fixtures-bundle v2.4.0
doctrine/doctrine-migrations-bundle v1.2.1
doctrine/inflector v1.1.0
doctrine/instantiator 1.0.5
doctrine/lexer v1.0.1
doctrine/migrations v1.5.0
doctrine/orm v2.5.6
oro/doctrine-extensions 1.2.0
EDIT: Sorry guys, after 2 days of trying to get this to work, I noticed that doctrine had the following for caching (in symfony config):
orm: auto_generate_proxy_classes: "%kernel.debug%" entity_managers: default: naming_strategy: doctrine.orm.naming_strategy.underscore auto_mapping: true metadata_cache_driver: apcu query_cache_driver: apcu
As soon as I removed that cache, everything started to work. I was removing the caching directory manually but failed to see that doctrine was also being cached with apcu.