Abstract Class for Doctrine entity - symfony

I am trying to make an abstract class for my entities involving general fields like created_at and updated_at values:
<?php
namespace AppBundle;
use Doctrine\ORM;
abstract class Model {
/**
* #var \DateTime $created_at
*
* #ORM\Column(type="datetime")
*/
private $created_at;
/**
* #var \DateTime $updated_at
*
* #ORM\Column(type="datetime")
*/
private $updated_at;
}
Then, I extend my class:
<?php
namespace AppBundle\Entity;
use AppBundle\Model;
/**
* Entity
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="RB\ProductsBundle\Entity\ProductRepository")
*/
class Entity extends Model
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, nullable=true)
*/
private $name;
}
The problem is: When I make a php app/console doctrine:schema:update --dump-sql, it doesn't recognize the Model fields. How can I change that? Should I use a trait or something like that?
EDIT: I tried to add * #ORM\MappedSuperclass at the top of my abstract class with no luck

The problem is likely to be that your properties in the abstract parent class are defined as private. Change them to protected and it should work.
As an aside, I use traits for this purpose, rather than inheritance, as your entity classes can use multiple traits, but they can only extend one abstract class.

Related

Doctrine doesn't update/generate fields of ManyToOne and OneToMany

I have a superclass that currently works fine (all relations and properties are updating to the database)
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Table;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\OneToMany;
use Doctrine\ORM\Mapping\JoinColumn;
use JMS\Serializer\Annotation as JMS;
/**
* Document
*
* #Table(name="document")
* #Entity(repositoryClass="AcmeBundleDocumentRepository")
*/
class Document
{
/**
* #var string
*
* #Column(name="id", type="string")
* #Id
* #GeneratedValue(strategy="UUID")
*/
protected $id;
/**
* #var string
* #Column(name="name", type="string", length=255)
*/
protected $name;
/**
* #var string
* #Column(name="type", type="string", length=255)
*/
protected $type;
/**
* #var boolean
* #Column(name="has_attachments", type="boolean")
*/
protected $hasAttachments;
/**
* #ManyToOne(targetEntity="Delivery")
* #JoinColumn(name="delivery_id", referencedColumnName="id", nullable=false)
* #JMS\Exclude()
*/
protected $delivery;
/**
* #OneToMany(targetEntity="Extension", mappedBy="document", cascade={"persist","remove"})
**/
protected $extensions;
public function __construct()
{
$this->extensions = new ArrayCollection();
}
/* getter and setters */
}
Now I've created a entity called Note that extends to Document entity
use Doctrine\ORM\Mapping\Table;
use Doctrine\ORM\Mapping\Entity;
/**
* Note
*
* #Table(name="note")
* #Entity(repositoryClass="NoteRepository")
*/
class Note extends Document
{
}
I am suppose that the table/entity note should generate the same things of the class that extends. But not do it
I run php bin/console doctrine:schema:update -f
this only generates properties and not FK (foreing Keys), in this case #ManyToOne and #OneToMany.
Additionally maybe help us, i have those entities on the same database
I am doing something wrong ?
As per docs I think you're missing the #MappedSuperclass annotation or you're using Doctrine inheritance in the wrong way. Be aware that a MappedSupperClass is not an entity by itself instead is just a class for share common methods and properties among it is children classes (same inheritance concept that you should already know).
/**
* #MappedSuperclass
*/
class DocumentSuperClass
{
...
}
/**
* #Table(name="document")
* #Entity(repositoryClass="AcmeBundleDocumentRepository")
*/
class Document extends DocumentSuperClass
{
...
}
/**
* #Table(name="note")
* #Entity(repositoryClass="NoteRepository")
*/
class Note extends DocumentSuperClass
{
...
}

Symfony2 doctrine ManyToMany associations mapping invalid?

I have two entities relating to this issue, and I want a join table to be able to cross reference values in each table.
Here is an explanation:
Entity ContainerType.php:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\Containers;
/**
* ContainerType
*
* #ORM\Table(name="container_type")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
*/
class ContainerType
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="type", type="string", length=255)
*/
private $type;
/**
* #var \DateTime
*
* #ORM\Column(name="date_added", type="datetime")
*/
private $dateAdded;
/**
* #var \DateTime
*
* #ORM\Column(name="date_modified", type="datetime", nullable=true)
*/
private $dateModified;
/**
* #ORM\ManyToMany(targetEntity="Containers", inversedBy="type")
* #ORM\JoinTable(name="container_type_containers")
**/
private $container;
public function __construct()
{
$this->container = new ArrayCollection();
}
And entity Containers.php:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\ContainerType;
/**
* Containers
*
* #ORM\Table(name="containers")
* #ORM\Entity
*/
class Containers
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="number", type="string", length=255)
*/
private $number;
/**
* #ORM\ManyToMany(targetEntity="Containers", mappedBy="container")
*/
private $type;
public function __construct()
{
$this->type = new ArrayCollection();
}
And although the schema update works without problems, when I do a doctrine:schema:validate I get the following fail:
[Mapping] FAIL - The entity-class 'AppBundle\Entity\Containers' mapping is invalid:
* The association AppBundle\Entity\Containers#type refers to the owning side field AppBundle\Entity\Containers#container which does not exist.
But the $container field DOES exist in ContainerType so I do not understand why it's trying to reference a field called container in the Containers entity?
Can anyone shed any light on this?
Thank you
Michael
I think this code should works fine for you :)
ContainerType.php
/**
* #ORM\ManyToMany(targetEntity="Containers", inversedBy="containersType")
* #ORM\JoinTable(name="container_type_containers",
* joinColumns={#ORM\JoinColumn(name="container_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="container_type_id", referencedColumnName="id")})
*/
protected $containers;
Containers.php
/**
* #ORM\ManyToMany(targetEntity="ContainerType", mappedBy="containers")
*/
protected $containersType;
I have just realized my error!
I had used the wrong target Entity in the Containers.php file, I should have used ContainerType as the target, instead I had Containers which is why it was trying to find the field in the wrong table!

Strange error : Cannot find Tree type for class

when I run this command php app/console doctrine:generate:form AcmeMyBundle:StudentUser, I get this error :
[Gedmo\Exception\InvalidMappingException]
Cannot find Tree type for class: Sylius\Bundle\CoreBundle\Model\Taxon
Any Idea?
EDIT :
Ok I don't think so that error have an relationship with StudentUser,because the same thing with all entities :
namespace APP\Bundle\FrontBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use PUGX\MultiUserBundle\Validator\Constraints\UniqueEntity;
use Sylius\Bundle\CoreBundle\Model\User;
/**
* #ORM\Entity(repositoryClass="App\Bundle\FrontBundle\Entity\UserRepository")
* #ORM\Table(name="sylius_user_student")
* #UniqueEntity(fields = "username", targetClass = "Sylius\Bundle\CoreBundle\Model\User", message="fos_user.username.already_used")
* #UniqueEntity(fields = "email", targetClass = "Sylius\Bundle\CoreBundle\Model\User", message="fos_user.email.already_used")
*/
class StudentUser extends User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="package_name", type="string", length=100)
*/
protected $package_name;
/**
* #var string
*
* #ORM\Column(name="students_available", type="string", length=100)
*/
protected $studens_available;
....
I must be an error from Sylius Bundle,
When this error happens i means that this entity must have in the class notations
/**
* #Gedmo\Tree(type="nested")
* #ORM\Entity
*/
class Service
{
}
Because some of the properties are using Gedmo notations like
#Gedmo\TreeLevel, #Gedmo\TreeRight
Example:
/**
* #Gedmo\TreeLeft
* #ORM\Column(name="lft", type="integer", nullable=true)
*/
private $lft;
So you could override that entity and correct the mistake.
I wish i could help.

Multiple JoinColumns in Symfony2 using Doctrine annotations?

Here is the problem:
Class Routing with attributes objectId and objectType. objectId is an int, and objectType is a string. The reason for this was to allow the same table to hold data for different kind of routings. For instance for the routing of Products, Department and Brand. So, the combination of the objectType and the objectId is my JoinColumn.
How do I create such a bidirectional relationship with Doctrine2? I looked at inherited relationships, but none of the concepts seemed to be what I'm looking for.
I could create some views in the database and just have a couple of different Routing entities, but this does not seem the best route.
Here are my entities Department, Product and Brand.
../Entity/Department.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table(name="departments")
*/
class Department implements DescribableInterface
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="status", type="string", length=1)
*/
private $status;
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
...
../Entity/Product.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="products")
*/
class Product implements DescribableInterface
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="status", type="string", length=1)
*/
private $status;
/**
* #ORM\Column(name="product_code", type="string", length=100, nullable=true)
*/
private $productCode = '';
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
...
../Entity/Brand.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="brands")
*/
class Brand
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="status", type="string", length=1)
*/
private $status = 'a';
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
...
Each product, brand and department has its own URL that is held in the routing table set by the object_type and object_id where the object_type is simply department, product or brand and the object_id is the unique id of the corresponding product, brand or department.
../Entity/Routing.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="routing")
*/
class Routing
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="object_id", type="integer", length=11)
*/
private $objectId;
/**
* #ORM\Column(name="object_type", type="string", length=100)
*/
private $objectType;
/**
* #ORM\Column(name="url", type="text")
*/
private $url;
...
What I am really struggling with is how do I setup the relationship, so the departments, products and brands can access their URL from the single routing entity.
I have tried adding the relationships to the $objectId, but it doesn't seem to like that. Is it possible to set this up like this?
What I am basically trying to achieve is to get the data object and have the ability to get the URL of an object, for example:
$departments = $em->getRepository("AdamStaceySiteBundle:Department")->findAll();
foreach ($departments as $department)
{
echo ''.$department->getMenuTitle().';
}
Can anyone help?
After further researching I found a man (Dirk Olbertz) in the know who had the same problem.
Information can be found at: Google Groups: Multiple JoinColumns?
I have now implemented this and I will explain how I did it incase it might help anyone else.
The answer to my problem was the use of single table inheritance.
The first thing I needed to do was update the routing entity to use single table inheritance:
../Entity/Routing.php
/**
* #ORM\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="object_type", type="string")
* #ORM\DiscriminatorMap({"product" = "ProductRouting", "department" = "DepartmentRouting", "brand" = "BrandRouting"})
* #ORM\Table(name="routing")
*/
class Routing
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer", length=11)
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
The DiscriminatorColumn allowed me to specify what column would be used to link, which in this case was the object_type field.
The DiscriminatorMap allowed me to specify what object_type will link with what entities.
These entities then had to be created that extended the Routing entity.
../Entity/ProductRouting.php
/**
* #ORM\Entity
*/
class ProductRouting extends Routing
{
/**
* #ORM\ManyToOne(targetEntity="Product")
* #ORM\JoinColumn(name="object_id", referencedColumnName="id")
*/
protected $product;
...
../Entity/DepartmentRouting.php
/**
* #ORM\Entity
*/
class DepartmentRouting extends Routing
{
/**
* #ORM\ManyToOne(targetEntity="Department")
* #ORM\JoinColumn(name="object_id", referencedColumnName="id")
*/
protected $department;
...
../Entity/BrandRouting.php
/**
* #ORM\Entity
*/
class BrandRouting extends Routing
{
/**
* #ORM\ManyToOne(targetEntity="Brand")
* #ORM\JoinColumn(name="object_id", referencedColumnName="id")
*/
protected $brand;
...
Then in each of the Product, Department and Brand entities I needed to add the new $routings.
../Entity/Product.php
...
class Product
{
...
/**
* #ORM\OneToMany(targetEntity="ProductRouting", mappedBy="product", cascade={"all"})
*/
private $routings;
...
../Entity/Department.php
...
class Department
{
...
/**
* #ORM\OneToMany(targetEntity="DepartmentRouting", mappedBy="department", cascade={"all"})
*/
private $routings;
...
../Entity/Brand.php
...
class Brand
{
...
/**
* #ORM\OneToMany(targetEntity="BrandRouting", mappedBy="brand", cascade={"all"})
*/
private $routings;
...
Hope that helps...

JMSSerializerBundle RuntimeException: you must define a type for Entity::$field

I'm having this issue with JMSSerializerBundle. It basically gives me an exception for something that I've already done. This is my entity:
Edited to avoid confusion about annotation lines
<?php
namespace My\ProjectBundle\Entity;
use JMS\SerializerBundle\Annotation\Type;
use Doctrine\ORM\Mapping as ORM;
/**
* My\ProjectBundle\Entity\Music
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="My\ProjectBundle\Entity\MusicRepository")
*/
class Music extends Post
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string $album
*
* #ORM\Column(name="album", type="string")
* #Type("string")
*/
protected $album;
/**
* #var string $artist
*
* #ORM\Column(name="artist", type="string")
* #Type("string")
*/
protected $artist;
/**
* #var integer $duration
*
* #ORM\Column(name="duration", type="bigint")
* #Type("int")
*/
protected $duration;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string")
* #Type("string")
*/
protected $title;
/**
* #var array $genres
*
* #ORM\Column(name="genres", type="array")
* #Type("array")
*/
protected $genres;
As you can see, I've added #Type() annotations for the fields, but it still gives me the exception when I call:
$listenedMusic = $serializer->deserialize($content, 'My\ProjectBundle\Entity\Music', 'json');
I've checked and the $content variable is not empty and has all the fields mapped in JSON format.
In my Monolog files, this is the exact Exception:
[2012-11-29 23:39:07] request.CRITICAL: JMS\SerializerBundle\Exception\RuntimeException:
You must define a type for My\ProjectBundle\Entity\Music::$album. (uncaught exception)
at /vendor/jms/serializer-bundle/JMS/SerializerBundle/Serializer/GenericDeserializationVisitor.php line 177
Why does it still give me this exception?
I'm fairly certain it's because you have two comment strings with different pieces of the whole annotation. Symfony only looks at the comment string directly preceding the class member.
Try replacing:
/** #Type("string")*/
/**
* #var string $album
*
* #ORM\Column(name="album", type="string")*/
protected $album;
with:
/**
* #Type("string")
*
* #var string $album
*
* #ORM\Column(name="album", type="string")*/
protected $album;
(and in every other place you have these duplicate annotation comments)
It's only a guess, but I think it'll fix it. When I tried doing this:
class Something
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
/**
*
*/
private $id;
}
...Symfony gave me this error:
No identifier/primary key specified for Entity 'SomeApp\SomeBundle\Entity\Something'. Every Entity must have an identifier/primary key.
I have fixed this by updating my entire project to dev-master packages. It seemed it was a bug in JMSSerializer, because without modifying any code, I stopped getting this error.
/**
* #var integer $duration
*
* #ORM\Column(name="duration", type="bigint")
* #Type("int")
*/
protected $duration;
Type 'int' doesn't exist for serialization, you must use 'integer'.

Resources