Doctrine doesn't generate inherited-class's properties - php

I have one abstract MappedSuperClass and another class called "User" which is a child of this MappedSuperClass. The problem is that doctrine doesn't generate the User class's properties. Only the MappedSuperClass's properties. Why?
<?php
namespace IsCoconut\Models;
use DateTime;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\MappedSuperclass;
/** #MappedSuperclass */
abstract class BaseEntity
{
/**
* #var int
* #Id
* #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
protected $id;
/** #Column(type="boolean")
* #var boolean
*/
protected $deleted = false;
/** #Column(name="creation_date_time", type="datetime")
* #var DateTime
*/
protected $creationDateTime;
protected function __construct()
{
$this->creationDateTime = new DateTime();
}
}
And this is my Entity which should be generated in database by Doctrine
<?php
namespace IsCoconut\Models;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Table;
/**
* #Entity
* #Table(name="users")
*/
class User extends BaseEntity
{
/**
* #var string
* #ORM\Column(type="string", length=512)
*/
private $forename;
/**
* #var string
* #ORM\Column(type="string", length=512)
*/
private $surname;
/**
* #var string
* #ORM\Column(type="string", length=512, unique=true, nullable=false)
*/
private $email;
/**
* #var string
* #ORM\Column(type="string", length=512, unique=true, nullable=false)
*/
private $passwordHash;
}
This is output of doctrine orm:schema-tool:create --dump-sql
CREATE TABLE users (id INT NOT NULL, deleted BOOLEAN NOT NULL, creation_date_time TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id));
CREATE SEQUENCE users_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
The User's class entity properties are missing! Why?

Try this
* #ORM\Entity
* #ORM\Table(name="User")

Actually, this might be the solution:
change:
abstract class BaseEntity
to:
class BaseEntity
See if that works. It might not, please try it.

When I removed all #ORM\ prefixes, it works now

I had the same problem, and found it was due to properties set as private.
/**
* #ORM\MappedSuperclass
*/
class BaseClass
{
/**
* #var string
* #ORM\Column(type="string", length=250, nullable=false)
*/
protected $channel;
//private $channel;
}

The mapping on your abstract class should be * #ORM\MappedSuperclass not /** #MappedSuperclass */. The mapping is done by Doctrine so the ORM annotation is important here.
You also need to ensure your properties in your abstract class are protected (which you already said they were)

Related

Class "App\Entities\Test" is not a valid entity or mapped super class. PHP, Doctrine

I catch this error
Class "App\Entities\Test" is not a valid entity or mapped super class
Path to entities is correct
Database's name is too correct. I have checked its about million times.
My entity:
namespace App\Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Class Test
* #package App\Entities
* #ORM\Entity
* #ORM\Table(name="test")
*/
class Test
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", name="id")
*/
protected int $id;
/**
* #ORM\Column(type="string", name="name")
*/
protected string $name;
/**
* #ORM\Column(type="string", name="pass")
*/
protected string $password;
//Getters and setters
}
Initialization:
$test = new Test();
$test->setName('name');
$test->setPassword('123');
$entityManager = $this->container->get(EntityManager::class);
$entityManager->persist($test);
$entityManager->flush();
Where is my mistake? I re-readed documentations many times, googled it

Symfony - how to make Doctrine search in abstract mapped superclass?

I am building an online shop for plastic model makers (hence the 'model').
I have a Product mapped superclass because I want all products (models, tools, paints etc. to have name, price and description):
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\MappedSuperclass;
use Gedmo\Mapping\Annotation as Gedmo; // gedmo annotations
/** #MappedSuperclass */
abstract class Product
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(type="string", length=100, nullable=false)
*/
protected $name;
/**
* #var int
* #ORM\Column(type="decimal", scale=2, nullable=false)
*/
protected $price;
/**
* #var string
* #ORM\Column(type="text", nullable=true)
*/
protected $description;
/**
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="update")
*/
private $updatedAt;
//getters and setters...
}
Then, there's a Model class, for plastic models, this extends the Product class but also has a Category for being able to search from cars, aircraft, ships etc:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="model")
*/
class Model extends Product
{
/**
* #var Category
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="models")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=true)
*/
private $category;
/**
* #return Category
*/
public function getCategory()
{
return $this->category;
}
/**
* #param Category $category
*/
public function setCategory($category)
{
$this->category = $category;
}
}
There will of course be more classes extending Product mapped superclass. Now I want to select the 10 most recently added products, regardless of their kind (models, tools, paints).
How can I tell Doctrine to give me the last 10 added products? Of course I tried something like:
$this->getDoctrine()->getManager()->getRepository("AppBundle:Product");
but of course it throws an exception saying that
SQLSTATE[42S02]: Base table or view not found: 1146 Table
'modeller_app.product' doesn't exist
which obviously is true, because Product is an abstract class and not actually an entity. How can I solve this problem?
You need to use class table inheritance.
Here is a example:
/**
* #ORM\Entity
* #ORM\Table(name="product")
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"product" = "Product", "model" = "Model"})
*/
class Product
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string", length=100, nullable=false)
*/
protected $name;
...
}
/**
* #ORM\Entity
* #ORM\Table(name="product")
*/
class Model extends Product
{
// Custom properties
...
}
Now you can query the Product entity and it will return the result from all entities that inherits it.

symfony 3 doctrine does not accept primary key

I am new to Symfony and trying to setup entities and relationships. Even though I seemed to have correctly annotated the primary keys.
When running
php bin/console doctrine:schema:validate
I got an error as follows:
The referenced column name 'brandId' has to be a primary key column on the target entity class 'AppBundle\Entity\Brands'.
The entities look like ( only relevant portions):
Thanks
Brands
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="brands")
*/
class Brands
{
/**
* #ORM\Id
* #ORM\Column(type="smallint",length=3,unique=true,options={"unsigned":true})
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $brandId;
/**
* one brands has many models
* #ORM\OneToMany(targetEntity="Models", mappedBy="brandId")
* #ORM\JoinColumn(name="brandId", referencedColumnName="brandId")
*/
private $models;
public function __construct()
{
$this->models = new ArrayCollection();
}
Models:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\ModelsRepository")
* #ORM\Table(name="models")
*/
class Models
{
/**
* #ORM\Column(type="smallint",length=4,unique=true,options={"unsigned":true})
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $modelId;
/**
* #ORM\Column(type="string", length=25)
*/
private $model;
/**
* Many models for one brand
* #ORM\ManyToOne(targetEntity="Brands",inversedBy="models")
* #ORM\JoinColumn(name="brandId", referencedColumnName="brandId")
*/
private $brandId;
A valid and clean entity mapping should be something like:
Brand.php
/**
* #ORM\Entity
* #ORM\Table(name="brands")
*/
class Brand
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* one brands has many models
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Model", mappedBy="brand")
*/
private $models;
public function __construct()
{
$this->models = new ArrayCollection();
}
}
Model.php
class Model
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(type="string", length=25)
*/
private $name;
/**
* Many models for one brand
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Brand",inversedBy="models")
*/
private $brand;
}
for clean and easy usage:
$brand->getId(); //get id of brand
$brand->getModels(); //get array of Model object, ArrayCollection
$model->getBrand()->getId(); // Get id of related brand of some model
$model->getBrand()->getName(); //get the name of other propery of related brand
In your Brands model, this annotation should not be present.
* #ORM\JoinColumn(name="brandId", referencedColumnName="brandId")
JoinColumn only applies to ManyToOne and OneToOne fields. This is because in a one to many relationship, there will not be a join column in the table that contains the data for the owning ("one") side of the relationship.
JoinColumn is for defining a column on the "many" side that identifies which record on the "one" side owns it, so including it in the Models model is okay.
Wrong answer removed...
Bonus tips: Entity classes or better their instances should represent single datasets of a table. So their names should be singular ;)
By chosing not prefixed names for your primary key columns, you can spare some code, because Doctrine can work its magic then.
Also you should not prefix one column with the table name, if you do not prefix all of them.
This all ended up being an issue with Doctrine's naming strategy, which I did not know about. See this article for details
That strategy was set as default, while I was trying to adapt mysql's underscore naming strategy to PHP's camel case naming strategy. This was causing Symfony not to find the primary and thus the error.
Once I learned about that and with the valuable input I've received with this post, I have refactored the entities as below:
Thank you all.
Brands
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="brands")
*/
class Brands
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="smallint",length=3,unique=true,options={"unsigned":true})
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* one brands has many models
*
* #ORM\OneToMany(targetEntity="Models", mappedBy="brandId")
*/
private $models;
public function __construct()
{
$this->models = new ArrayCollection();
}
/**
* #ORM\Column(type="string", length=25)
*/
private $brand;
.......
}
Models
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\ModelsRepository")
* #ORM\Table(name="models")
*/
class Models
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="smallint",length=4,unique=true,options={"unsigned":true})
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=25)
*/
private $model;
/**
* Many models for one brand
* #ORM\ManyToOne(targetEntity="Brands",inversedBy="models")
* #ORM\JoinColumn(name="brand_id", referencedColumnName="id")
*/
private $brandId;
/**
* Many models for one segment
* #ORM\ManyToOne(targetEntity="Segments", inversedBy="models")
* #ORM\JoinColumn(name="segment_id", referencedColumnName="id")
*/
private $segmentId;
.....
}

Doctrine entity inheritance

I have an entity which I want to use as a base class for other entities (unknown at this time) and I need to store relationships in the base entity:
/**
* #ORM\Entity
* #ORM\Table(name="CMS_content")
*/
class BaseContent {
/**
* #ORM\ManyToOne(targetEntity="BaseContent")
* #ORM\JoinColumn(name="parent", referencedColumnName="id", unique=false)
*/
protected $parent;
/**
* #ORM\ManyToOne(targetEntity="ContentType")
* #ORM\JoinColumn(name="content_type", referencedColumnName="id", unique=false)
*/
protected $contentType;
...
};
/**
* #ORM\Entity
* #ORM\Table(name="CMS_whateverSpecializedContent")
*/
class WhateverSpecializedContent extends BaseContent {};
I cannot use#ORM\InheritanceType("JOINED") because I want to be able to create arbitrary number of subclasses later without touching the base class. I also need to have the base class in a separate database table so the relationship would make sense.
What other options do I have to manage these kind of structure?
Instead of using entity inheritance I ended up using the delegate design pattern. Both Content and BaseContent implements a common interface and the BaseContent delegate the functionality to a joined Content entity.
Now every subclass of this BaseContent will have a joined Content entity and can be used where an IContent is expected.
interface IContent {...}
/**
* #ORM\Entity
* #ORM\Table(name="CMS_content")
*/
class Content implements IContent {
/**
* #ORM\ManyToOne(targetEntity="BaseContent")
* #ORM\JoinColumn(name="parent", referencedColumnName="id", unique=false)
*/
protected $parent;
/**
* #ORM\ManyToOne(targetEntity="ContentType")
* #ORM\JoinColumn(name="content_type", referencedColumnName="id", unique=false)
*/
protected $contentType;
...
};
/**
* #ORM\Entity
* #ORM\Table(name="CMS_whateverSpecializedContent")
*/
class WhateverSpecializedContent extends BaseContent {};
/**
* #ORM\MappedSuperclass
*/
abstract class BaseContent implements IContent {
/**
* #ORM\OneToOne(targetEntity="Content", cascade={"persist", "merge", "remove"})
* #ORM\JoinColumn(name="content", referencedColumnName="id", unique=false)
*/
private $content;
public function implementedMethod() {
$this->content->implementedMethod();
}
};

Symfony2 : Entities not created in database

I'm making entities with Symfony2 and Doctrine2. I made some entities that represent a many-to-many relation between two of my entities.
An example of one of these entities :
/**
* #ORM\Entity
*/
class Contact_Conference_Invitation
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\UserBundle\Entity\Contact")
*/
private $contact;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\ConferenceBundle\Entity\Conference")
*/
private $conference;
/**
* #var datetime dateInvitation
*
* #ORM\Column(name="dateInvitation", type="datetime")
*/
private $dateInvitation;
//Getters and setters
}
I have tried updating my sql schema, but the tables corresponding to these entities do not appear. Is there somewhere I have to declare them (config or such)? If not, what's wrong?
Thanks a lot
Edit : I had forgotten the namespace for these class, and that's why they were omitted by Doctrine. Another case closed :) thanks for the answers!
Assumptions ...
No, you don't need to declare them anywhere else than in your Entity directory.
What's the error message you got?
I guess you added
use Doctrine\ORM\Mapping as ORM;
on the top of your classes to let them be mapped.
I tried ...
I tried to generate your entities by adding a simple Contact & Conference entities and it's working fine.
Here are the code snippets:
Contact_Conference_Invitation.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Contact_Conference_Invitation
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Ahsio\StackBundle\Entity\Contact")
*/
private $contact;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Ahsio\StackBundle\Entity\Conference")
*/
private $conference;
/**
* #var datetime dateInvitation
*
* #ORM\Column(name="dateInvitation", type="datetime")
*/
private $dateInvitation;
//Getters and setters
}
Contact.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Contact
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #param $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Conference.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Conference
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #param $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Here are the generated tables:
NB: I used a specific namespace for the entities generation to work fine, you need to change them.
Also don't forget to check that you have automapping enabled.
In your config.yml you should have
doctrine:
orm:
auto_mapping: true
Came across this question because my entities weren't generated as well, this was my issue, it could save some time to people struggling with the same issue.
I don't see the definition of your ManyToMany relation in the sample of code you provided.
As an example, here's a ManyToMany relationship I implemented for a project
Entity Project.php
/**
* #var Provider[]
*
* #ORM\ManyToMany(targetEntity="Provider", mappedBy="projects")
*/
protected $providers = null;
Entity Provider.php
/**
* #var Project[]
*
* #ORM\ManyToMany(targetEntity="Project", inversedBy="providers")
* #ORM\JoinTable(name="PROVIDER_PROJECT")
*/
protected $projects = null;
As you can see, here you define the join table for your ManyToMany relationship.
Of course those entities are specific for my particular project but you get the idea and you can adapt it easily for your needs.

Categories