Can I set up a Symfony2 ORM inheritance relationship using MySQL? - mysql

I have one table tech_note and I would like to have 3 tables more tech_note_es, tech_note_en and tech_note_fr (in a future many more tables). And the tech_note can be in the 3 tables at same time.
My idea is attach to tech_note_en and automatically receive attributes from tech_note.
SECOND EDIT:
I would like somthing like that: I search in Tech_note_EN by ID=3 (I recive fields from tech_note_EN with ID=3 and fields tech_note with ID=3.
But if I search in Tech_note_ES BY ID=3 (I recive fields from tech_note_ES with ID=3 and tech_note fields from tech_note with ID=3 (the same fields from above)
The tech_note have a ID=3. Tech_note_EN have ID=3, and Tech_note_ES have ID=3
EDIT WITH NEW CLASSES:
Now I have this error:
Entity 'EVTS\FrontendBundle\Entity\Tech_note_en' has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). This is not supported.
TECH_NOTE
abstract class Tech_note {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var datetime $control_date
*
* #ORM\Column(name="control_date", type="datetime")
*/
private $control_date;
/**
* #var string $comment
*
* #ORM\Column(name="comment", type="string")
*/
private $comment;
TECH_NOTE_EN
class Tech_note_en extends Tech_note {
/**
* #var integer $tech_note_id
*
* #ORM\Id
* #ORM\Column(name="tech_note_id", type="integer")
* #ORM\OneToOne(targetEntity="tech_note")
* #ORM\JoinColumn(name="tech_note_id",referencedColumnName="id")
*/
private $tech_note_id;
/**
* #var text $symptom
*
* #ORM\Column(name="symptom", type="text")
*/
private $symptom;
/**
* #var text $cause
*
* #ORM\Column(name="cause", type="text")
*/
private $cause;
/**
* #var string $solution
*
* #ORM\Column(name="solution", type="string")
*/
private $solution;
OLD CLASSES
TECH_NOTE
class Tech_note {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var datetime $control_date
*
* #ORM\Column(name="control_date", type="datetime")
*/
private $control_date;
/**
* #var string $comment
*
* #ORM\Column(name="comment", type="string")
*/
private $comment;
TECH_NOTE_EN
class Tech_note_en
{
/**
* #var integer $tech_note_id
*
* #ORM\Id
* #ORM\Column(name="tech_note_id", type="integer")
* #ORM\OneToOne(targetEntity="tech_note")
* #ORM\JoinColumn(name="tech_note_id",referencedColumnName="id")
*/
private $tech_note_id;
/**
* #var text $symptom
*
* #ORM\Column(name="symptom", type="text")
*/
private $symptom;
/**
* #var text $cause
*
* #ORM\Column(name="cause", type="text")
*/
private $cause;
/**
* #var string $solution
*
* #ORM\Column(name="solution", type="string")
*/
private $solution;

There is an awesome solution to your problem, which is single table inheritance
What this does is basically Have one central table with general fields, and links to other table with specific fields.
In your case I would use this architectural model:
abstract class TechNote (abstract common entity, which contains common fields)
class TechNoteEn extends TechNote (specific entity which inherits common fields and adds specific EN fields)
and so on.
I find this as the best architectural solution for your problem.

That's your ORM's job.
// Assuming $tech_note_en is a Tech_note_en instance
$tech_note_en->getTechNote();
(something like this ^^)

Related

Doctrine, Many to Many relationship issue

I have Entities: User and Catalog, related relations (as below). The user can create catalogs, and then can share them with other users. I want to search for all the directories assigned to the user (that is, those which he created himself and those that were made available to him).
public function findAllCatalogForUser($id){
return $this->createQueryBuilder('catalog')
->leftJoin('catalog.users','us')
->innerJoin('catalog.user','u')
->where('u.id = :id OR us.id =:id ')
->setParameters([':id'=>$id])
->getQuery()
->getResult();
}
However, when the query is executed, it receives an error:
Type of association must be one of _TO_ONE OR MANY_TO_MANY
It seems to me that the relationships between the tables are correct, but I can not make the query.
How to fix this problem? Thank you in advance for your answer.
User Entity
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* #UniqueEntity(fields="email", message="Ten email już istnieje, musisz użyć innego.")
* #UniqueEntity(fields="username", message="Nazwa użytkownika już istnieje, musisz użyć innej.")
*/
class User implements AdvancedUserInterface, \Serializable
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=255, unique=true)
* #Assert\NotBlank(message="Pole nie może być puste!")
*/
private $username;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Catalog", inversedBy="user")
* #ORM\JoinTable(name="user_catalog",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="catalog_id", referencedColumnName="id")} )
*/
protected $catalogs;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Catalog", mappedBy="user")
*/
protected $catalog;
Catalog Entity
/**
* Catalog
*
* #ORM\Table(name="catalog")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CatalogRepository")
*/
class Catalog
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100)
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="catalog")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\User", mappedBy="catalog")
*/
protected $users;
/**
* Constructor
*/
public function __construct()
{
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
}
In your user entity:
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Catalog", inversedBy="users")
* #ORM\JoinTable(name="user_catalog",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="catalog_id", referencedColumnName="id")} )
*/
protected $catalogs;
In your catalog entity:
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\User", mappedBy="catalogs")
*/
protected $users;

How to make effective index for search

How to make the index on Table for speeding up searching.
I have two tables like these
(I created tables with doctorine from symfony2, but in fetching use plain mysql from python script.)
Now I want to exec this sql many times(changing x value)
select recordDate,closePrice from PriceDay where company_price=x ORDER BY recordDate DESC
So I wan to set the index like indexes={#ORM\Index(name="code_index",columns={"company_price","recordDate"})}) , but I am not sure it is the best solution or not. Pairs of company_price and recordDate are unique. Could you help some ideas??
* #ORM\Table(indexes={#ORM\Index(name="code_index",columns={"company_price","recordDate"})})
PriceDay table
class PriceDay
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\Company")
* #ORM\JoinColumn(name="company_price", referencedColumnName="id")
*/
private $company;
/**
* #ORM\Column(type="float")
*/
private $closePrice = 0;
/**
*
* #ORM\Column(type="date")
*/
private $recordDate;
Company Table
class Company
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string",nullable=false)
*/
private $name;
/**
* #var boolean
* #ORM\Column(name="enabled",type="boolean")
*/
private $enabled = true;

Doctrine2 One2Many related entity filter results

Basically, I have two entities, Place and Event:
/**
* Place
*
* #ORM\Table(name="place")
* #ORM\Entity(repositoryClass="AppBundle\Repository\PlaceRepository")
*/
class Place
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Event", mappedBy="place")
*/
private $events;
}
and
class Event
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
* #JMS\Type("DateTime<'H:i'>")
* #ORM\Column(name="event_starts", type="datetime")
*/
private $eventStarts;
/**
* #var \DateTime
* #JMS\Type("DateTime<'Y/m/d H:i'>")
* #ORM\Column(name="event_ends", type="datetime", nullable=true)
*/
private $eventEnds;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="event_id", type="string", length=70)
*/
private $event_id;
/**
* #JMS\Exclude()
* #ORM\ManyToOne(targetEntity="Place")
* #ORM\JoinColumn(name="place_id", referencedColumnName="id")
*/
private $place;
When I'm querying Places, I would like that not all Events would be joined, but only those which are taking place today (eventStarts = today). Is there a way to do it only with Doctrine or MySQL?
Pretty straightforward.
$qb = $this->getEntityManager()->createQueryBuilder();
If you want to only get places which have an event in a specific date range:
$data = $qb->select('p, e')
->from('YourBundle:Place', 'p')
->join('p.events', 'e')
->where($qb->expr()->between('e.eventStarts', ':start', ':end'))
->setParameter('start', $someStartDateTimeObject)
->setParameter('end', $someEndDateTimeObject)
->getQuery()
->getResult();
If you would like to get all places, even if they don't have an event, but join an event if there is one in the specified range:
$data = $qb->select('p, e')
->from('YourBundle:Place', 'p')
->leftJoin('p.events', 'e', 'WITH', $qb->expr()->between('e.eventStarts', ':start', ':end'))
->setParameter('start', $someStartDateTimeObject)
->setParameter('end', $someEndDateTimeObject)
->getQuery()
->getResult();

Doctrine query builder - any of joined elements

I have the following entities (simplified):
a work is composed of multiple tasks. Each task has a field storing the time it should be due and a field storing the time it has been completed.
/**
* Work
*
* #ORM\Entity
*/
class Work
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Task", mappedBy="work", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="task_work_id", referencedColumnName="id")
*/
protected $task;
/**
* Constructor
*/
public function __construct()
{
$this->task = new ArrayCollection();
}
}
/**
* Task
*
* #ORM\Entity
*/
class Task
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Work", inversedBy="task")
* #ORM\JoinColumn(name="work_id", referencedColumnName="id")
*/
private $work;
/**
* #var \DateTime
*
* #ORM\Column(name="completed", type="datetime", nullable=true)
*/
private $completed;
/**
* #var \DateTime
*
* #ORM\Column(name="duedate", type="datetime", nullable=true)
*/
private $duedate;
}
I am trying to build a query to retrieve all works that have uncompleted overdue tasks.
I initially thought something like this:
$repository = $this->getEntityManager()
->getRepository('MyBundle:Work');
$query = $repository->createQueryBuilder('v');
$query->leftJoin('v.task', 't');
$query->andWhere(
$query->expr()->isNull('t.completed')
)
->andWhere(
$query->expr()->gte('t.duedate', ':now')
)
;
$query->setParameter('now', new \DateTime(), \Doctrine\DBAL\Types\Type::DATETIME);
However, this retrieves works whose all tasks are overdue (I think).
So I tried with a sub-query:
$repository = $this->getEntityManager()
->getRepository('MyBundle:Work');
$query = $repository->createQueryBuilder('v');
$query2 = $this->getEntityManager()
->createQueryBuilder();
$query2->select('t')
->from('v.task', 't');
$query2->andWhere(
$query->expr()->isNull('t.completed')
)
->andWhere(
$query->expr()->gte('t.duedate', ':now')
)
;
$query2->setParameter('now', new \DateTime(), \Doctrine\DBAL\Types\Type::DATETIME);
$query->andWhere(
$query->expr()->any(
$query2->getDql()
)
);
But I get the following error:
QueryException: [Syntax Error] line 0, col 104: Error: Expected known function, got 'ANY'
Any idea on how I could write the query?
Thank you in advance!
You have not defined a repository for $query2

doctrine 2 many to many with translation

I have problem with doctrine 2.
I have following db tables :
So, Doctrine generate entities which retrive data from desk settings for site, but I need, to retrieve all settings from desk_settings table and overwrite its values from desk_settings_values table using desk_id
DB image -> https://docs.google.com/file/d/0B7rOFTJGfJwTWEQ3bXZFU1hXZlU/edit?usp=sharing
Doctrine entities which was generate with script:
/**
* Desk
*
* #ORM\Table(name="desk")
* #ORM\Entity
*/
class Desk
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="code", type="string", length=100, nullable=false)
*/
private $code;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=255, nullable=false)
*/
private $description;
/**
* #var \DateTime
*
* #ORM\Column(name="created", type="datetime", nullable=false)
*/
private $created;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="PayBox\Entity\DeskSettings", mappedBy="desk")
*/
private $deskSettings;
}
use Doctrine\ORM\Mapping as ORM;
/**
* DeskSettings
*
* #ORM\Table(name="desk_settings")
* #ORM\Entity
*/
class DeskSettings
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="setting_key", type="string", length=100, nullable=false)
*/
private $settingKey;
/**
* #var string
*
* #ORM\Column(name="setting_value", type="string", length=255, nullable=false)
*/
private $settingValue;
/**
* #var \DateTime
*
* #ORM\Column(name="created", type="datetime", nullable=false)
*/
private $created;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="PayBox\Entity\Desk", inversedBy="deskSettings")
* #ORM\JoinTable(name="desk_settings_values",
* joinColumns={
* #ORM\JoinColumn(name="desk_settings_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="desk_id", referencedColumnName="id")
* }
* )
*/
private $desk;
}
From Doctrine documentation:
Why are many-to-many associations less common? Because frequently you
want to associate additional attributes with an association, in which
case you introduce an association class. Consequently, the direct
many-to-many association disappears and is replaced by
one-to-many/many-to-one associations between the 3 participating
classes.
You need to change your class structure to one-to-many/many-to-one. See this blog.