i have the following problem :
I extend an entity tableA in a tableB entity and i want to override the #assert/notblank annotation on a field.
Class tableA{
...
/**
* #ORM\Column(type="string", length=4)
* #Assert\NotBlank(message="please.enter.a.value")
*/
protected $myfield;
}
The extended class :
Class tableB extends tableA{
...
/**
* #ORM\Column(type="string", length=4, nullable=true)
*/
protected $myfield;
}
The not blank constraints of TableA is still active when i make a form using tableB.
Any idea ?
I have tried with #ORM\AttributeOverride annotation but it dont works...
It seems indeed Symfony Validation component fails to understand what's going on.
A way around isto put the Validation constraint on the getter:
Class tableA{
/**
* #ORM\Column(type="string", length=4)
*/
protected $myfield;
}
/**
* #Assert\NotBlank(message="please.enter.a.value")
*/
public function getMyfield()
{
// ...
}
And in the extended class:
Class tableAB extends tableA{
public function getMyfield()
{
// ...
}
Related
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
{
...
}
I'm trying to create an entity that is connected with another entity 1:1. The whole point is that Equip has to have an Estadi, and just one. I can update the schema correctly, the database is okay, but on the webpage debugger appears a mapping error.
The association AppBundle\Entity\Equip#estadi refers to the inverse
side field AppBundle\Entity\Estadi#nom which is not defined as
association.
The association AppBundle\Entity\Equip#estadi refers to the inverse
side field AppBundle\Entity\Estadi#nom which does not exist
This is entity Estadi:
/**
* #ORM\Entity
* #ORM\Table(name="estadis")
*/
class Estadi{
/**
* #ORM\Column(type="string",length=30)
* #ORM\OneToOne(targetEntity="Equip",mappedBy="estadi",cascade={"persist"})
* #ORM\Id
*/
protected $nom;
/**
* #ORM\Column(type="integer")
*/
protected $aforament;
/**
* #ORM\Column(type="integer")
*/
protected $num_portes;
/**
* #ORM\Column(type="string",length=50)
*/
protected $direccio;
/**
* #ORM\Column(type="string", length=4)
*/
protected $any_construccio;
/**
* #ORM\Column(type="string", length=30)
*/
protected $nom_aficio;
}
This is Entity Equip:
/**
* #ORM\Entity
* #ORM\Table(name="equips")
*/
class Equip{
/**
* #ORM\Column(type="string",length=30)
* #ORM\Id
*/
protected $nom;
/**
* #ORM\Column(type="integer")
*/
protected $punts_lliga;
/**
* #ORM\Column(type="integer")
*/
protected $num_jugadors;
/**
* #ORM\OneToOne(targetEntity="Estadi",inversedBy="nom")
* #ORM\JoinColumn(name="nom_estadi",referencedColumnName="nom",onDelete="SET NULL")
*/
protected $estadi;
/**
* #ORM\OneToOne(targetEntity="Entrenador",inversedBy="nom")
* #ORM\JoinColumn(name="nom_entrenador",referencedColumnName="nom",onDelete="SET NULL")
*/
protected $entrenador;
/**
* #ORM\ManyToOne(targetEntity="Lliga",inversedBy="equips")
* #ORM\JoinColumn(name="nom_lliga",referencedColumnName="nom",onDelete="SET NULL")
*/
protected $lliga;
/**
* #ORM\OneToMany(targetEntity="Jugador",mappedBy="nom_equip")
*/
protected $jugadors;
public function __construct(){
$this->jugadors = new ArrayCollection();
}
}
When you define the #OneToOne annotation, it should not be on your primary key. Either the owning entity should contain a single association (unidirectional), or each entity should contain an association to the other - as entities, not connected to a primary key.
Your Equip mapping should instead look like this:
/**
* #ORM\OneToOne(targetEntity="Estadi", inversedBy="equip")
* #ORM\JoinColumn(name="nom_estadi", referencedColumnName="nom")
*/
protected $estadi;
public function setEstadi(Estadi $estadi)
{
$this->estadi = $estadi;
return $this;
}
public function getEstadi()
{
return $this->estadi;
}
Your Estadi mapping should instead look like this:
/**
* #OneToOne(targetEntity="Equip", mappedBy="estadi")
*/
protected $equip;
public function getEquip(Equip $equip)
{
return $this->equip;
}
I removed the cascade and onDelete, because if you're handling everything through Doctrine it should handle that for you automatically, but you still might have a use for them. I also only put the setter on the owning entity from the way you described, but you could put it back on your Estadi entity as well - that's up to you.
I have a #ManyToMany relation with two entities.
I have (short code)
class Photo
{
/**
* #ORM\ManyToMany(targetEntity="Application\Sonata\UserBundle\Entity\User", mappedBy="photos")
*/
protected $users;
}
class User
{
/**
* #ORM\ManyToMany(targetEntity="MyBundle\PhotoBundle\Entity\Photo", inversedBy="users", cascade={"persist"})
* #ORM\JoinTable(name="user_photos")
*/
protected $photos;
}
php app/console doctrine:schema:validate
-> [Mapping] FAIL - The entity-class 'MyBundle\PhotoBundle\Entity\Photo' mapping is invalid:
* The association MyBundle\PhotoBundle\Entity\Photo#users refers to the owning side field Application\Sonata\UserBundle\Entity\User#photos which does not exist.
I looked in stack and i try somethings but i still have the problem.
Try this
class Photo
{
/**
* #ORM\ManyToMany(targetEntity="Application\Sonata\UserBundle\Entity\User", mappedBy="photo")
*/
protected $users;
}
class User
{
/**
* #ORM\ManyToMany(targetEntity="MyBundle\PhotoBundle\Entity\Photo", inversedBy="users", cascade={"persist"})
* #ORM\JoinTable(name="user_photos")
*/
protected $photos;
}
I have 3 entity : Invoice, InvoiceItemService, Asset.
First, I create an Invoice and an InvoiceItemService, and I link them together with a ManyToOne relation on InvoiceItemService side (so InvoiceItemService is the owner side).
Then, I can create an Asset, from the Invoice object. An asset is kind of a copy of an Invoice, with a negative total. When I create an Asset, I link the Invoice's InvoiceItemService to the Asset too, with a ManyToOne relation between InvoiceItemService and Asset.
When I delete an Invoice, everything works fine, Invoice, Asset and InvoiceItemService are deleted with a cascade={"remove"} option.
When I delete an Asset, I would like only the asset to be deleted. But I get this foreign key error.
Here are my entities :
class Invoice
{
/**
* #ORM\OneToMany(targetEntity="Evo\BackendBundle\Entity\Asset", mappedBy="invoice", cascade={"remove"})
*/
protected $assets;
/**
* #ORM\OneToMany(targetEntity="Evo\BackendBundle\Entity\InvoiceItemService", mappedBy="invoice", cascade={"persist", "remove"})
*/
protected $services;
}
class Asset
{
/**
* #ORM\ManyToOne(targetEntity="Evo\BackendBundle\Entity\Invoice", inversedBy="assets")
* #ORM\JoinColumn(nullable=false)
* #Exclude
*/
protected $invoice;
/**
* #ORM\OneToMany(targetEntity="Evo\BackendBundle\Entity\InvoiceItemService", mappedBy="asset")
*/
protected $services;
}
class InvoiceItemService extends InvoiceItem
{
/**
* #ORM\ManyToOne(targetEntity="Evo\BackendBundle\Entity\Invoice", inversedBy="services")
* #ORM\JoinColumn(nullable=false, onDelete="CASCADE")
* #Type("Evo\BackendBundle\Entity\Invoice")
* #Exclude
*/
protected $invoice;
/**
* #ORM\ManyToOne(targetEntity="Evo\BackendBundle\Entity\Asset", inversedBy="services")
* #ORM\JoinColumn(nullable=true, onDelete="SET NULL")
* #Type("Evo\BackendBundle\Entity\Asset")
* #Exclude
*/
protected $asset;
}
As Cerad mentioned in the comments above, you'll need to implement this behavior yourself.
Since you'll need access to the entity manager, you can't do this with a simple lifecycle callback on the Asset entity itself. Instead, you'll need to register a service to listen for the event and perform the action at that point.
Example implementation
app/config.yml
services:
your.bundle.association.manager:
class: Your\Bundle\Model\AssociationManager
tags:
- { name: doctrine.event_listener, event: preRemove }
And then, the service class itself (unstested - might have bugs)
namespace Your\Bundle\Model;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\EntityManager;
use Your\Bundle\Entity\Asset;
class AssociationManager
{
public function preRemove(LifecycleEventArgs $args)
{
if ($entity instanceof Asset)
{
$this->removeAssetAssociations($asset, $args->getEntityManager());
return;
}
}
protected function removeAssetAssociations(Asset $asset, EntityManager $em)
{
foreach ($asset->getServices() as $invoiceItemService)
{
$invoiceItemService->asset = null;
$em->persist($invoiceItemService);
}
}
}
Hope this helps.
I have 2 entity in my Symfony2 class:
class InstagramShopPicture
{
/**
* #Exclude()
* #ORM\OneToMany(targetEntity="InstagramPictureTag", mappedBy="picture", cascade={"remove"})
*/
protected $tags;
}
and
class InstagramPictureTag
{
/**
* #ORM\ManyToOne(targetEntity="InstagramShopPicture", inversedBy="tags")
* #ORM\JoinColumn(name="picture_id", referencedColumnName="id", nullable=false)
*/
private $picture;
}
I wanted to make sure such that when I delete InstagramShopPicture the InstagramPictureTag also gets deleted. The issue now is that whenever I try to do that with the current setup, it always complaint about some foreign key issues. What am I doing wrong here?
You need to define how to handle this deletion. Check Docs
In your case :
class InstagramShopPicture
{
/**
* #Exclude()
* #ORM\OneToMany(targetEntity="InstagramPictureTag", mappedBy="picture", orphanRemoval=true)
*/
protected $tags;
}
You can rely on Database level to handle it for you, by using onDelete
class InstagramShopPicture
{
/**
* #Exclude()
* #ORM\OneToMany(targetEntity="InstagramPictureTag", mappedBy="picture", onDelete="CASCADE")
*/
protected $tags;
}