I'm searching for a solution for the following problem with a database inheritance using Doctrine 2 built in Symfony 2 framework. This is what I want to do...
I want to create two tables (UredniHodiny, KonzultacniHodiny) with the same interface as the abstract class Hodiny. This is how I'm trying to do it
<?php
// src/CvutPWT/ImportBundle/Entity/Hodiny.php
namespace CvutPWT\ImportBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
*/
abstract class Hodiny
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Osoba")
*/
protected $osoba;
/**
* #ORM\ManyToOne(targetEntity="Mistnost")
*/
protected $mistnost;
/**
* #ORM\Column(type="datetime")
*/
protected $zacatek;
/**
* #ORM\Column(type="datetime")
*/
protected $konec;
}
<?php
// src/CvutPWT/ImportBundle/Entity/KonzultacniHodiny.php
namespace CvutPWT\ImportBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="konzultacnihodiny")
*/
class KonzultacniHodiny extends Hodiny
{
}
<?php
// src/CvutPWT/ImportBundle/Entity/UredniHodiny.php
namespace CvutPWT\ImportBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="urednihodiny")
*/
class UredniHodiny extends Hodiny
{
}
Now when I run php app/console doctrine:generate:entities CvutPWTImportBundle Symfony generates all variables (more precisely columns) from class Hodiny as private variables to both child classes. Now when I'm trying to create those tables with app/console doctrine:schema:update --force I'm getting errors that $id must be protected or weaker. When I change this protection manually I am able to create tables but there is only one column (id). But this is not what I was hoping for. Can somebody give me any advice what I'm doing wrong?
This is not table inheritance. Mapped super classes are just mapping inheritance.
The tables corresponding to your final entities will not be relied together in any way.
If you want real table inheritance (single table or joined table), use this: http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/inheritance-mapping.html#single-table-inheritance
If you still want to use mapped super classes, then you will have to put the #ORM\Id definition in both final classes. You can not put ids in mapped super classes.
Related
We encounter an issue with inheritance on Symfony 5.
We created a UserBundle bundle which includes a simple User entity (id, email, password): the purpose of this bundle is to be able to easily reimport it into our various projects.
In some projets, we want to extend this entity to add some specific fields (phone, address, ...), but that's not always the case.
Here is the code we had set up:
UserBundle > User class:
<?php
namespace MyCompany\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\MappedSuperclass()
*/
class User implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
...
User entity inherited:
<?php
namespace App\Entity;
use MyCompany\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity
* #UniqueEntity(fields={"email"})
*/
class User extends BaseUser
{
/**
* #ORM\Column(type="string", length=50)
*/
private $phone;
...
The inheritance works fine: the problem comes from projects for which the User entity of the bundle is sufficient for us.
=> The User class of the bundle is defined as Mapped superclass in order to be able to extend it but Doctrine can't create an associated table if there is no class which inherits from it...
We could systematically create an empty User class in src/ which inherits from the User class of the bundle, but that doesn't seem super clean to me...
I went on this post but that doesn't seem to work: Doctrine Inheritance replacement
Could anyone help us on this problem? I imagine that a solution must exist...
Thank you in advance!
The idea below does not work.
As #Cerad already pointed out, the best approach probably really is to define the concrete User in each app. Thats also what FOSUserBundle does.
I'd go with the following approach: Declare the mapped superclass abstract.
/**
* #ORM\MappedSuperclass()
*/
abstract class AbstractBaseUser implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
...
And implement a concrete empty child class User inside your bundle.
/**
* #ORM\Entity
*/
class User extends AbstractBaseUser
{
}
That way each app can either use the User of your library or inherit from it.
I have an entity that stores large files as blobs to the DB.
I would now like to get Symfony to never ever load these blobs unless I specifically request them via the appropriate getter.
In essence I want the same idea as lazy-loading relationships but for a string property.
What I have tried so far is to put all my other properties that hold the file meta data into a trait and then apply that trait to two entities.
namespace App\Entity\Traits;
use Doctrine\ORM\Mapping as ORM;
trait DocumentMetaData
{
/**
* #var int|null
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime|null
*
* #ORM\Column(type="datetime")
*/
private $date_uploaded;
}
One entity has nothing to it but the trait...
namespace App\Entity;
use App\Entity\Traits\DocumentMetaData;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="documents")
* #ORM\Entity()
*/
class Document
{
use DocumentMetaData;
}
...the other has the added blob property:
namespace App\Entity;
use App\Entity\Traits\DocumentMetaData;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="documents")
* #ORM\Entity()
*/
class DocumentFile
{
use DocumentMetaData;
/**
* #var string|null
*
* #ORM\Column(type="blob")
*/
private $blob;
}
Now, if I don't want the blob to be loaded, for example for a listing of files, I simply use the entity that doesn't have the blob.
This approach sort of works but causes issues as I need to point both entities at the same table (see the class level ORM annotations).
Specifically, it makes doctrine freak out when running migrations:
The table with name 'myapp.documents' already exists.
That makes perfect sense and really I'm hoping that someone can point me to a nicer solution.
How can I tell doctrine not to load the blob unless its explicitly asked for?
So as per the comments on my question - the way to do this so that migrations do not break is to leverage doctrine's ability to lazy load relationships between tables.
Basically I had to go and create a new entity that only holds my giant blobs and then establish a one to one relationship between the original entity and the blob entity.
I then set that relationship to load EXTRA_LAZY and as a result I can now control when precisely the blobs of giant data should be loaded.
I don't think this is ideal in terms of normalising the DB design but it works a lot better than anything else so happy with that.
I'm just making a new Entity as usual, but something goes wrong and console report this error and I couldn't generate the entity setter/getter:
[Doctrine\ORM\Mapping\MappingException]
Class "AppBundle\Entity\Admin_Actions" is not a valid entity or mapped super class.
Here is my Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="admin_actions")
*/
class Admin_Actions
{
/**
* #ORM\Column(name="id",type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="uid",type="string",length=100)
*/
private $uid;
/**
* #ORM\Column(name="type",type="integer")
*/
private $type;
/**
* #ORM\Column(name="linedate",type="datetime")
*/
private $linedate;
}
If I do doctrine:mapping:info:
[Exception]
You do not have any mapped Doctrine ORM entities according to the current configuration. If you have
entities or mapping files you should check your mapping configuration for errors.
I've just waste an hour trying to investigate the problem and I've already tried to rewrite it from new but I'm missing something. What's wrong with this?
May be datetime field has same name as function/implementation in doctrine, I have got same mistake by naming a table "condition" which may be condition function in MySql query
I have a scenario where I need to use the MappedSuperclass functionality of Doctrine (using Symfony2), and also create a unique constraint on some superclass columns. Let's say:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
*/
class Base
{
/**
* #ORM\Column(type="integer", nullable=false)
*/
private $someColumn;
}
/**
* #ORM\Entity
* #ORM\Table(uniqueConstraints={#ORM\UniqueConstraint(name="column_idx", columns={"someColumn"})})
*/
class Concrete extends Base
{
}
The problem is at processing of #ORM\Table annotation during schema generation:
[Doctrine\DBAL\Schema\SchemaException]
There is no column with name 'someColumn' on table 'Concrete'.
Is there a way to define a unique constraint of a mapped superclass?
Since the answer author didn't post the answer himself, let me quote him:
Try to use protected instead of private for entity field. You should always use protected or public for entity fields
I have an existing ZF2 project to which I have added entities before, and I have just added a new entity by copying an existing one and changing the details as necessary. This UserCmsPermission entity links to the User entity via the User entity's cmsPermissions property.
I have redeployed the database using the following commands:
doctrine-module orm:schema-tool:drop --force
doctrine-module orm:schema-tool:create
doctrine-module data-fixture:import
This executes successfully with no errors at all. However, when I access my application I receive the following error:
The target-entity Application\\Entity\\UserCmsPermission cannot be found in
'Application\\Entity\\User#cmsPermissions'.
The relevant code from each entity is as follows:
module/Application/src/Application/Entity/User.php
<?php
/**
* User model
*
*
*/
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Tilt\Entity\Base\User as TiltUser;
/**
* #ORM\Entity
*/
class User extends TiltUser
{
// … etc …
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="UserChallenge", mappedBy="user", cascade={"all"})
*/
protected $challenges;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="UserCmsPermission", mappedBy="user", cascade={"all"})
*/
protected $cmsPermissions;
// … etc …
}
module/Application/src/Application/Entity/UserCmsPermission.php
<?php
/**
* User CMS Permission model
*
*
*/
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Tilt\Exception\InvalidArgumentException;
use Tilt\Entity\Base\Entity as BaseEntity;
/**
* #ORM\Entity
*/
class UserCmsPermission extends BaseEntity
{
// … etc …
/**
* #var User
*
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* #ORM\ManyToOne(targetEntity="User", inversedBy="cmsPermissions", cascade={"all"})
*/
protected $user;
// … etc …
}
As far as I can tell, the code is correct, and I have also removed data/DoctrineORMModule/ in case the entity metadata was being cached, but this hasn't fixed the problem, and neither has restarting PHP5-FPM in case something was being cached there, so I've now run out of ideas.
Anyone got a clue as to what could be causing this to happen?
Finally figured out what is causing this. Doctrine throws this error if you are using a class map to load classes rather than the standard ZF2 autoloader and you've forgotten to update your class map, which was what I'd not done.
Simply running this in the project folder fixed it:
php vendor/zendframework/zendframework/bin/classmap_generator.php
Et voila.