Doctrine 2 - How to have an association class with a mapped superclass? - php

I'm having trouble with a Doctrine 2 mapped superclass, to define a ManyToMany Relation.
My code is :
use Doctrine\Common\Collections\ArrayCollection;
/** #MappedSuperclass */
abstract class MyAbstractClassA
{
/**
* #Id
* #GeneratedValue
* #Column(type="integer")
* #var int
*/
protected $id;
/**
* #ManyToMany(targetEntity="MyClassE")
* #var MyClassE[]
*/
protected $my_class_es;
// ... Other fields and methods
}
/** #Entity() */
class MyConcreteClassAa extends MyAbstractClassA
{
/**
* #Column(type="string")
* #var string
*/
public $aa_param;
// ... Other fields and methods
}
/** #Entity() */
class MyConcreteClassAb extends MyAbstractClassA
{
/**
* #Column(type="string")
* #var string
*/
public $ab_param;
// ... Other fields and methods
}
/** #Entity() */
class MyClassE
{
/**
* #Id
* #Column(type="integer")
* #var int
*/
protected $id;
/**
* #Column(type="string")
* #var string
*/
protected $e_param;
/**
* #ManyToOne(targetEntity="MyClassF")
* #var MyClassF
*/
protected $my_class_f;
// ... Other fields and methods
}
/** #Entity() */
class MyClassF
{
/**
* #Id
* #Column(type="integer")
* #var int
*/
protected $id;
// ... Other fields and methods
}
So here is the schema of what i have : http://pix.toile-libre.org/upload/original/1385651287.png
And there is what i want : http://pix.toile-libre.org/upload/original/1385651300.png
I don't know how to obtain this result, could someone tell me if it's possible ?
Thank you for helping me.

Related

Override default property value in Doctrine2 Mapped Superclass

The idea is that extending my Employee class and setting my isManager property would store it as true in the database whenever a DepartmentHead entity was created. This isn't working. Does anyone know why DepartmentHead entities are being stored with isManager equal to false?
/**
* #Entity
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"employee" = "Employee", "dphead" = "DepartmentHead"})
*/
class Employee
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\Column(type="boolean")
*/
protected static $isManager = false;
/**
* #return bool
*/
public static function isManager(): bool
{
return static::$isManager;
}
/**
* #param bool $isManager
*/
public static function setIsManager(bool $isManager): void
{
static::$isManager = $isManager;
}
}
/**
* #Entity()
*/
class DepartmentHead extends Employee
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
protected $id;
protected static $isManager = true;
}
Do not use static properties, Doctrine cannot cope with them properly.
With a common property, everything works as expected.
/**
* #ORM\Column(type="boolean")
*/
protected $isManager = true;

Fatal error: Cannot redeclare class "Activity" in PHP

// I really dont have any class like that I checked everywhere...even if I give it different name .. I get the same error
// This is my Php file which is an Entity for Doctrine
use Doctrine\ORM\Mapping AS ORM;
/**
* Description of Activity
*
* #author pawanadhikari
*/
/**
* #Entity
* #Table(name="pulse_activity")
*/
class Activity {
/**
* #var integer $id
* #Id
* #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer $patientId
* #Id
* #Column(type="integer")
*/
private $patientId;
/**
* #var integer $steps
* #Column(type="integer")
*/
private $steps;
/**
* #var double $calories
* #Column(type="double")
*/
private $calories;
/**
* #var double $distance
* #Column(type="double")
*/
private $distance;
/**
* #var integer $elevation
* #Column(type="integer")
*/
private $elevation;
/**
* #var integer $secondsActivitySoft
* #Column(type="integer")
*/
private $secondsActivitySoft;
/**
* #var integer $secondsActivityModerate
* #Column(type="integer")
*/
private $secondsActivityModerate;
/**
* #var integer $secondsActivityIntense
* #Column(type="integer")
*/
private $secondsActivityIntense;
/**
* #var string $date
* #Column(type="string")
*/
private $date;
/**
* #var string $timeStamp
* #Column(type="string")
*/
private $timeStamp;
/**
* #ManyToOne(targetEntity = "Person", inversedBy = "personActivities" )
* * #JoinColumn(name="patientId", referencedColumnName="id")
*
*/
protected $patientActivity;
public function getId() {
return $this->id;
}
public function getPatientId() {
return $this->patientId;
}
public function getSteps() {
return $this->steps;
}
public function getCalories() {
return $this->calories;
}
public function getDistance() {
return $this->distance;
}
you've declared your own unique namespace, right? you're just not showing it?
where are you getting the error? are you are calling these from custom runtime pages or is the error occuring when you generate the model.
This kind of error is common when include() and require() are used instead of include_once() or require_once() - particularly if used in an autoload function for the classes.

Doctrine 2 multiple mappedBy?

I've got a problem setting up the Doctrine mapping correctly.
I have a CashRegister Entity which has a bin location and a return bin location. Both locations are from the same Type (BinLocation Entity).
Outgoing from CashRegister, CashRegister->getBinLocations() and CashRegister->getReturnBinLocations() are working fine, but how can I achieve that BinLocation->getCashRegisters() returns all CashRegister Entities that are referenced (binLocation + returnBinLocation)?
/**
* CashRegister
*
* #ORM\Table(name="cash_registers")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class CashRegister
{
...
/**
* #var BinLocation
*
* #ORM\ManyToOne(targetEntity="BinLocation", inversedBy="cashRegisters")
* #ORM\JoinColumn(name="bin_location_id", referencedColumnName="id")
*/
private $binLocation;
/**
* #var BinLocation
*
* #ORM\ManyToOne(targetEntity="BinLocation", inversedBy="cashRegisters")
* #ORM\JoinColumn(name="return_bin_location_id", referencedColumnName="id")
*/
private $returnBinLocation;
/**
* #return BinLocation
*/
public function getBinLocation()
{
return $this->binLocation;
}
/**
* #return BinLocation
*/
public function getReturnBinLocation()
{
return $this->returnBinLocation;
}
...
}
/**
* BinLocation
*
* #ORM\Table(name="bin_locations")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class BinLocation
{
...
/**
* #var CashRegister[]
*
* #ORM\OneToMany(targetEntity="CashRegister", mappedBy="binLocation") <= Here is the problem, in this case mappedBy need to be an array [binLocation, returnBinLocation]
*/
private $cashRegisters;
/**
* #return CashRegister[]
*/
public function getCashRegisters()
{
return $this->cashRegisters;
}
...
}
The simple answer is that you cannot. mappedBy accepts only one argument.
The solution to achieve what you want is however simple. Create a second property in BinLocation called: cashRegisters2 as follows:
/**
* #var CashRegister[]
*
* #ORM\OneToMany(targetEntity="CashRegister", mappedBy="binLocation")
*/
private $cashRegisters;
/**
* #var CashRegister[]
*
* #ORM\OneToMany(targetEntity="CashRegister", mappedBy="binLocation")
*/
private $cashRegisters2;
Then merge the Collections in your getCashRegisters method.
/**
* #return CashRegister[]
*/
public function getCashRegisters()
{
return new ArrayCollection(
array_merge($cashRegisters->toArray(), $cashRegisters2->toArray())
);
}
Also change your CashRegister mappings accordingly:
/**
* #var BinLocation
*
* #ORM\ManyToOne(targetEntity="BinLocation", inversedBy="cashRegisters")
* #ORM\JoinColumn(name="bin_location_id", referencedColumnName="id")
*/
private $binLocation;
/**
* #var BinLocation
*
* #ORM\ManyToOne(targetEntity="BinLocation", inversedBy="cashRegisters2")
* #ORM\JoinColumn(name="return_bin_location_id", referencedColumnName="id")
*/
private $returnBinLocation;
Note: I did not test the code. This example is to server guide only.
Note2: The ArrayCollection merge was inspired from here: https://stackoverflow.com/a/16871539/2853903
I have also searched for solutions and made a patch for Doctrine so you can have custom_attributes linked to a variety of entity types.
Doctrine 2.6: https://github.com/danielbeeke/doctrine2/commit/2d8530176b872cb490c5c88b8c8e17d8d0091388
Doctrine 2.7: https://github.com/danielbeeke/doctrine2/commit/5bde696848ea9fe7035fadc4d46baa4c0d51f3a2
/**
* #Entity
* #Table(name="product")
* #HasLifecycleCallbacks
**/
class Product {
/**
* One Product has Many Attributes.
*
* #OneToMany(
* targetEntity="CustomAttribute",
* mappedBy="EntityId",
* mappedByType={
* "field": "EntityType",
* "value": "product"
* }
* )
*
* #var $CustomAttributes ArrayCollection
*/
protected $CustomAttributes;
}
/**
* #Entity
* #Table(name="custom_attribute")
* #HasLifecycleCallbacks
**/
class CustomAttribute_entity {
/** #Id #Column(type="integer") #GeneratedValue */
protected $Id;
/**
* Many Attributes have One Entity of the EntityType provided.
* #ManyToOne(targetEntity="Product", inversedBy="CustomAttributes")
* #JoinColumn(name="EntityId", referencedColumnName="Id")
*/
protected $EntityId;
/** #Column(type="string") */
protected $EntityType;
/** #Column(type="string") */
protected $Type;
/** #Column(type="string") */
protected $Value;
}

Doctrine Orm lazy load with group by

I have the following situation:
/**
* #Entity
* #Table(name="users")
*/
class Users{
/**
*
* #Id #Column(type="integer")
* #GeneratedValue
*/
protected $id_user;
/**
* #OneToMany(targetEntity="Items",mappedBy="user")
*/
private $items;
//this method sould return distinct items by name or group by name
public function getItems(){
return $this->items;
}
}
/**
* #Entity
* #Table(name="items")
*/
class Items{
/**
*
* #Id #Column(type="integer")
* #GeneratedValue
*/
protected $id_item;
/**
*
* #Id #Column(type="string")
*/
protected $name;
/**
* #ManyToOne(targetEntity="User",inversedBy="items")
* #JoinColumn(name="id_user", referencedColumnName="id_user" ,onDelete="CASCADE")
*/
protected $user;
}
In my view i send an $UserEntity, my problem is that i want to display only items that have unique name.
So If i do $items=$userEntity->getItems(); i receive all user items, not only unique one.
How can i solve this situation?
Thanks
select distinct with DQL should do the trick

Triple split mapping issue with Doctrine2

I'm encountering a strange problem using Doctrine2.
I'm getting the following error:
doctrine orm:validate-schema
[Mapping] FAIL - The entity-class 'EmailVerification' mapping is invalid:
* The referenced column name 'id' does not have a corresponding field with this
column name on the class 'OurUsers'.
[Database] OK - The database schema is in sync with the mapping files.
My scenario is as follows:
I have 3 tables sharing a primary key.
Table Auth which holds user_id PK.
Table OurUsers for which Auth.user_id is shared PK.
Table EmailVerification for which OurUsers.user_id is shared PK.
I also have NotOurUsers - hence the split.
Entities are declared as follows:
/**
* #Entity
* #Table(name="auth")
*/
class Auth {
/** #Id #Column(type="integer", name="user_id") #GeneratedValue #var int */
private $id;
/* ... */
}
/**
* #Entity
* #Table(name="our_users")
*/
class OurUsers {
/**
* #Id
* #OneToOne(targetEntity="Auth")
* #JoinColumn(nullable=false, name="user_id", referencedColumnName="user_id")
* #var Auth
*/
private $id;
/* ... */
}
/**
* #Entity
* #Table(name="email_verification")
*/
class EmailVerification {
/**
* #Id
* #OneToOne(targetEntity="OurUsers")
* #JoinColumn(nullable=false, name="user_id", referencedColumnName="user_id")
* #var OurUsers
*/
private $id;
/* ... */
}
I'm using Dosctrine 2.1.
btw Doctrine 2.2 validates mappings as good, but I get same error at run time as with 2.1.
I think the problem is that EmailVerfication points to OurUSers intead of to Auth, the error message is misleading though. I am not sure the triple mapping is possible from the internals (i am pretty sure i implemented an exception for this some where as well, i have to look why this is not triggered).
You tell in your JoinColumn statements that you work with a user_id column.
But your column definition for OurUser::id creates a id column by default.
You either have to modify the JoinColumn statement to use id:
/**
* #Entity
* #Table(name="email_verification")
*/
class EmailVerification {
/**
* #Id
* #OneToOne(targetEntity="OurUsers")
* #JoinColumn(nullable=false, name="user_id", referencedColumnName="id")
* #var OurUsers
*/
private $id;
/* ... */
}
OR
add a Column annotation on OurUser::id, like that:
/**
* #Entity
* #Table(name="our_users")
*/
class OurUsers {
/**
* #Id
* #OneToOne(targetEntity="Auth")
* #Column(type="integer", name="user_id")
* #JoinColumn(nullable=false, name="user_id", referencedColumnName="user_id")
* #var Auth
*/
private $id;
/* ... */
}
I think it would be better to switch to something like this, it's a lot more clear and should create less problems:
/**
* #Entity
* #Table(name="auth")
*/
class Auth {
/** #Id #Column(type="integer", name="user_id") #GeneratedValue #var int */
private $id;
/* ... */
}
/**
* #Entity
* #Table(name="our_users")
*/
class OurUsers {
/**
* #Id
* #GeneratedValue
*/
private $id;
/**
* #OneToOne(targetEntity="Auth")
* #var Auth
*/
private $auth;
/* ... */
}
/**
* #Entity
* #Table(name="email_verification")
*/
class EmailVerification {
/**
* #Id
* #GeneratedValue
*/
private $id;
/**
* #OneToOne(targetEntity="OurUsers")
* #var OurUsers
*/
private $ourUser;
/* ... */
}

Categories