Doctrine Abstract - Concrete class ORM - orm

I'm working with doctrine for the mapping of some objects to database tables.
This is what I have now:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="account")
*/
abstract class Account{
/**
* #ORM\Id
* #ORM\Column(type="string")
*/
private $username;
/**
* #ORM\Id
* #ORM\Column(type="string")
*/
private $password;
/*Getters and setters*/
}
/**
* #ORM\Entity
* #ORM\Table(name="player")
*/
abstract class Player extends Account{
/**
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $number;
/*Getters and setters*/
}
/**
* #ORM\Entity
* #ORM\Table(name="coach")
*/
abstract class Coach extends Account{
/**
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $experience;
/*Getters and setters*/
}
This way, all concrete classes will have the username and the password column, what if I would need to store only the username in order to be able to join them later and get the oconcrete object back? Thanks in advance.

What you want is then possibly Class Table Inheritance as described in http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html#class-table-inheritance
namespace MyProject\Model;
/**
* #Entity
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"player" = "Player", "coach" = "Coach"})
*/
abstract class Account
{
// ...
}
/** #Entity */
class Player extends Account
{
// ...
}
/** #Entity */
class Coach extends Account
{
// ...
}
This should create 3 tables Account, Player and Coach, though Account alone cannot be persisted, rather it will have a discriminator column + ID to link to. So, e.g. 'coach' '3' will join to Coach object with id 3.
First Answer:
If I understood you correctly and the password doesn't need to be provided directly, you can add to the $password annotation
* #ORM\Column(type="string", nullable=true)
Is this what you had in mind?

Related

Doctrine 2 get items from related entities

I have an entity with ManyToOne, OneToOne relations. I have another entity, which is linked to the first one and what I want to do is to get information about the first entity as well as all other entities, which are related to it.
For some reason when I make the call, it returns NULL in the related entity.
Code:
<?php
namespace App\Model\Entities;
use Doctrine\ORM\Mapping as ORM,
Doctrine\Common\Collections\ArrayCollection;
use Kdyby\Doctrine\Entities\BaseEntity;
/**
* Doctrine entity for resorts in destinations
* #package App\Model\Entities
* #ORM\Entity
*/
class Resort extends BaseEntity
{
/**
* autoincremented resort id
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* resort name
* #ORM\Column(type="string")
*/
protected $title;
/**
* #ORM\OneToOne(targetEntity="ResortProperties", mappedBy="resort", cascade={"persist"})
*/
private $properties;
public function __construct()
{
$this->properties = new ArrayCollection();
}
/**
* HERE I WANT TO GET DATA FROM ANOTHER ENTITY
* #return type
*/
public function getProperties()
{
return $this->properties;
}
}
And the related entity is this:
<?php
namespace App\Model\Entities;
use Doctrine\ORM\Mapping as ORM,
Doctrine\Common\Collections\ArrayCollection;
use Kdyby\Doctrine\Entities\BaseEntity;
/**
* Doctrine entity for resort properties
* #package App\Model\Entities
* #ORM\Entity
*/
class ResortProperties extends BaseEntity
{
/**
* autoincremented id
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* resort id
* #ORM\OneToOne(targetEntity="Resort", inversedBy="Resort", cascade={"persist", "remove"})
* #ORM\JoinColumn(onDelete="CASCADE")
*/
protected $resort;
/**
* parameter1
* #ORM\Column(type="string")
*/
protected $parameter1;
}
I expected, that when I call $repository->findAll(); I would get all Resort entities and in Resort->properties would be joined ResortProperty entity, but it is NULL.
I don't know what I did wrong, can someone point out my mistake? Thanks
I assume the problem is the JoinColumn-Annotation.
The Entity with the Foreign-key (ResortProperties) needs to know, how to join the two tables.
The "inversedBy"-Statement on the Resort-Entity then uses this rule.
It should look something like the following in your ResortProperties-Entity:
/**
* resort id
* #ORM\OneToOne(targetEntity="Resort", inversedBy="Resort", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="resort_id", referencedColumnName="id")
*/
protected $resort;
"resort_id" is the name of your foreign-key-column.
Hope this helps.
In ResortProperties entity I had to make this change:
class ResortProperties extends BaseEntity
{
/**
* resort id
* #ORM\OneToOne(targetEntity="Resort", inversedBy="properties", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="resort_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $resort;
}
And in Resort entity I had to change it like this:
class Resort extends BaseEntity
{
/**
* #ORM\OneToOne(targetEntity="ResortProperties", mappedBy="resort", cascade={"persist"})
*/
private $properties;
public function __construct()
{
parent::__construct();
$this->properties = new ArrayCollection();
}
}
Now it's working properly, hope this will help others

DQL query in Symfony for ManyToOne unidirectional relationship

class MenuItem
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="MenuCategory")
* #ORM\JoinColumn(name="menu_id", referencedColumnName="id")
*/
protected $catagory;
}
Category class
class MenuCategory
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\Column(type="integer")
*/
protectted $ordering;
}
I want to query all of the items ordered by the ordering property in the category. Here is my query that I tried. I am new to SQL/DQL and am not sure how to access the ordering property in the query. This query is the the MenuItemRepository.php file.
class MenuItemRepository extends EntityRepository
{
public function getOrderedMenu()
{
return $this->createQueryBuilder('i')
->select('i')
->orderBy('i.catagory.ordering', 'ASC') //????
->getQuery()
->getResult()
}
}
Is there a way to get all the items orderedBy ordering?
You have cat a gory in your orderBy clause instead of cat e gory!
Further protectted instead of protected in front of your $ordering property.
The following should work:
return $this->createQueryBuilder('i')
->leftJoin('i.category', 'c')
->orderBy('c.ordering', 'ASC')
->getQuery()
->getResult();

doctrine entity with foreign key to this entity

I have a simple table for recursive categories:
id
name
parent_id - is a link to id, NULL - for root categories
I need to create a table with foreign key. My class doesn't create this key. How can I change this class to create table with foreign key using "doctrine:schema:create"? What I have tried:
<?php
namespace Test\BackEndBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="category")
*/
class Category
{
/**
* #ORM\Id
* #ORM\Column(type="bigint", length=20)
* #ORM\GeneratedValue(strategy="AUTO")
* #var int
*/
protected $id;
/**
* #ORM\Column(type="string", length="255")
* #var string
*/
protected $name;
/**
* #ORM\Column(name="parent_id", type="bigint", length=20, nullable="true")
* #ORM\OneToMany(targetEntity="Category")
* #ORM\JoinColumn(name="id", onDelete="CASCADE", onUpdate="CASCADE")
* #var int
*/
protected $parentId;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
}
You reversed OneToMany with ManyToOne !
See here: http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html#one-to-many-self-referencing
In fact, you want that plural subcategories can have one parent cat !
What you need:
/**
* #OneToMany(targetEntity="Category", mappedBy="parent")
*/
private $children;
/**
* #ManyToOne(targetEntity="Category", inversedBy="children")
* #JoinColumn(name="parent_id", referencedColumnName="id")
*/
private $parent;
// ...
public function __construct() {
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
}
You can replace $parent for $parentId (and mappedBy="parent" for mappedBy="parentId"), but this is not a good coding convention ^^

symfony/Doctrine: about many to many relations, owning side and inverse side

I have found this text:
For ManyToMany bidirectional relationships either side may be the
owning side (the side that defines the #JoinTable and/or does not make
use of the mappedBy attribute, thus using a default join table).
and this code:
/** #Entity */
class User
{
// ...
/**
* #ManyToMany(targetEntity="Group", inversedBy="users")
* #JoinTable(name="users_groups")
*/
private $groups;
public function __construct() {
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
/** #Entity */
class Group
{
// ...
/**
* #ManyToMany(targetEntity="User", mappedBy="groups")
*/
private $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
Is there anything wrong is some of them (text or code)?
Since (another quote)
The owning side of a bidirectional relationship must refer to its
inverse side by use of the inversedBy attribute
I expected the inversedBy attribute in both sides (User and Group)...
Javier

How to store priority in a Many-to-Many relationship with Doctrine 2.0

My problem is simple:
I have Users and Stories in a many to many relationship, I would like to store a couple of attribute in the UserStory relationship:
Priority (In order to set the ordering of the display for a given user)
Main (flags which one is the main story)
How can I do that ?
Let say we have the following :
<?php
/** #Entity */
class User
{
// ...
/**
* #ManyToMany(targetEntity="Story", inversedBy="users")
* #JoinTable(name="users_stories")
*/
private $stories;
public function __construct() {
$this->stories = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
/** #Entity */
class Story
{
// ...
/**
* #ManyToMany(targetEntity="User", mappedBy="stories")
*/
private $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
?>
As Crozin suggested, this question is a duplicate of:
Doctrine2: Best way to handle many-to-many with extra columns in reference table
In my specific case the solution is simple. The Many-To-Many relationship needs to be build by hand, and extra fields need to be added manually. So two OneToMany relationship need to be build.
So here are my 3 objects and the associated meta information for each attribute:
<?php
/**
* #Entity
* #Table(name="users")
*/
class User{
/**
* #Id
* #Column(type="integer", name="id")
* #GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #OneToMany(targetEntity="UserStory", mappedBy="user")
*/
private $user_stories;
// ...
}
/**
* #Entity
* #Table(name="user_stories")
*/
class UserStory{
/**
* #Id
* #Column(type="integer", name="id")
* #GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ManyToOne(targetEntity="User", inversedBy="user_stories")
*/
private $user;
/**
* #ManyToOne(targetEntity="Story", inversedBy="user_stories")
*/
private $stories;
/**
* #Column(type="integer")
*/
private $priority;
/**
* #Column(type="integer")
*/
private $priority_tmp;
/**
* #Column(type="integer")
*/
private $main;
// ...
}
/**
* #Entity
* #Table(name="stories")
*/
class Story
{
/**
* #Id
* #Column(type="integer", name="id")
* #GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #OneToMany(targetEntity="UserStory", mappedBy="stories")
*/
private $user_stories;
// ...
}
?>