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;
Related
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;
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();
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
I have a small misunderstanding in how the joining in Doctrine2 work.
We have a pretty complex structure in our app and we are building management screens for it.
The area of concern is as follows:
Once of the objects 'Application' looks like this:
class Application
{
/**
* List of supported statuses
*
* #var array
*/
private $statuses = array('released', 'expired');
/**
*
* #var integer $id
*
* #Column(name="id", type="integer", columnDefinition="INT(10) UNSIGNED")
* #Id
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #Column(name="Name", type="string", length=100)
*/
private $name;
/**
* #var Customer
*
* #ManyToOne(targetEntity="libraries\persona\Entity\Customer")
* #JoinColumn(name="Customers_id", referencedColumnName="id", nullable=true, columnDefinition="INT(10) UNSIGNED")
*/
private $customer;
/**
* #var integer
*
* #Column(name="Partners_id", type="integer", nullable=true)
*/
private $partnerId;
/**
* #var string
*
* #Column(name="appID", type="string", length=48)
*/
private $appId;
/**
* #var string
*
* #Column(name="status", type="string", length=15)
*/
private $status;
/**
* #var \DateTime
*
* #Column(name="eventStartDate", type="date")
*/
private $eventStartDate;
/**
* #var \DateTime
*
* #Column(name="eventEndDate", type="date")
*/
private $eventEndDate;
/**
* #var string
*
* #Column(name="timeZone", type="string", length=45)
*/
private $timeZone;
/**
* #ManyToOne(targetEntity="libraries\application\Entity\ApplicationType", inversedBy="applications")
* #JoinColumn(name="ApplicationTypes_id", referencedColumnName="id")
*/
private $applicationType;
/**
* #var integer
*
* #Column(name="syncPeriod", type="integer", length=10, nullable=true)
*/
private $syncPeriod;
/**
* #var \DateTime
*
* #Column(name="lastSync", type="datetime", nullable=true)
*/
private $lastSync;
/**
* #var string
*
* #Column(name="lastSyncStatus", type="string", length=127, nullable=true)
*/
private $lastSyncStatus;
/**
* #var string
*
* #Column(name="syncScript", type="string", length=250, nullable=true)
*/
private $syncScript = '/var/www/quickstart/application/controllers/scripts/qdissync.php';
/**
* #var integer
*
* #Column(name="size", type="integer", length=10)
*/
private $size = 400;
/**
* #var text
*
* #Column(name="metaData", type="text", nullable=true)
*/
private $metaData;
/**
* #var \DateTime
*
* #Column(name="metaDataChangedTime", type="datetime", nullable=true)
*/
private $metaDataChangedTime;
/**
* #var tinyint
*
* #Column(name="isSecure", type="smallint", length=1)
*/
private $isSecure = 2;
/**
* #var integer
*
* #Column(name="Users_id", type="integer", nullable=true)
*/
private $userId;
/**
* #var string
*
* #Column(name="singleEventAppId", type="string", length=48, nullable=true)
*/
private $singleEventAppId;
/**
* #var string
*
* #Column(name="project_db", type="string", length=50)
*/
private $projectDb;
/**
* #var string
*
* #Column(name="appName", type="string", length=12)
*/
private $appName;
/**
* #var boolean
*
* #Column(name="mobileLog", type="boolean")
*/
private $mobileLog = false;
/**
* #var tinyint
*
* #Column(name="eventType", type="smallint", length=1)
*/
private $eventType = 1;
/**
* #ManyToOne(targetEntity="libraries\application\Entity\Project", inversedBy="applications")
* #JoinColumn(name="project_id", referencedColumnName="id")
*/
private $project;
/**
* #OneToMany(targetEntity="libraries\platform\Entity\Platform", mappedBy="application")
**/
private $platforms;
/**
* #var SnapEventAttributes
*
* #OneToOne(targetEntity="libraries\application\Entity\SnapEventAttributes", mappedBy="application")
**/
private $snapEventAttributes;
//GETTERS & SETTERS
}
One of the related objects 'SnapEventAttributes':
class SnapEventAttributes
{
/**
*
* #var integer
*
* #Column(name="id", type="integer", columnDefinition="INT(11)")
* #Id
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #Column(name="directSelectId", type="string", length=10, nullable=true)
*/
private $directSelectId;
/**
* #var string
*
* #Column(name="description", type="text", nullable=true)
*/
private $description;
/**
* #var string
*
* #Column(name="access", type="string", length=10, nullable=false)
*/
private $access;
/**
* #var string
*
* #Column(name="status", type="string", length=10, nullable=false)
*/
private $status;
/**
* #var string
*
* #Column(name="snapAppVersion", type="string", length=5, nullable=true)
*/
private $snapAppVersion;
/**
* #var string
*
* #Column(name="pwd", type="string", length=250, nullable=true)
*/
private $password;
/**
* #var string
*
* #Column(name="thumbnailUrl", type="string", length=250, nullable=true)
*/
private $thumbnailUrl;
/**
* #var string
*
* #Column(name="location", type="string", length=45, nullable=true)
*/
private $location;
/**
* #OneToOne(targetEntity="libraries\application\Entity\Application", inversedBy="snapEventAttributes")
* #JoinColumn(name="Applications_id", referencedColumnName="id", unique=true, nullable=false)
*/
private $application;
// GETTERS & SETTERS
}
In one of our work flows we need to join these two with bunch of additional joins and we got something like this:
$qb = $this->createQueryBuilder('e');
$qb->innerJoin('e.applicationType', 'et', Expr\Join::WITH, 'et.mobileEvent = :mobileEvent AND et.snapApp = :snapApp AND et.snapEvent = :snapEvent');
$qb->innerJoin('e.snapEventAttributes', 'attrs');
$qb->innerJoin('e.project', 'p');
$qb->innerJoin('p.applications', 'a');
$qb->innerJoin('a.applicationType', 'at', Expr\Join::WITH, 'at.mobileEvent = :vMobileEvent AND at.snapApp = :vSnapApp AND at.snapEvent = :vSnapEvent');
$qb->leftJoin('e.customer', 'cust');
$qb->leftJoin('p.partner', 'partn');
$qb->setParameters(array(
'mobileEvent' => false,
'snapApp' => false,
'snapEvent' => true,
'vMobileEvent' => false,
'vSnapApp' => true,
'vSnapEvent' => false,
));
return $qb;
All the logic works perfectly fine, however once I execute this query:
$qb->getQuery()->getResult();
the main query is getting executed as expected but automatically doctrine executes bunch of queries to get the SnapEventAttributes objects:
SELECT t0.id AS id1, t0.directSelectId AS directSelectId2, t0.description AS description3, t0.access AS access4, t0.status AS status5, t0.snapAppVersion AS snapAppVersion6, t0.pwd AS pwd7, t0.thumbnailUrl AS thumbnailUrl8, t0.location AS location9, t0.Applications_id AS Applications_id10 FROM SnapEventAttributes t0 WHERE t0.Applications_id = ?
What am I missing? What could be a reason for this behavior?
Thanks,
A.
get the repository
Controller
$snapEvents = $this->em->snapEvents ( 'Entity\SnapEventAttributes' )->findAll ();
$data ['snapEvents '] = $snapEvents ;
then on the view
View
foreach ($snapEvents $sanpEvent) {
echo "<tr>".
"<td>" . $sanpEvent->getAppliction()->getApplicationType() . "</td>".
"<td>" . $sanpEvent->getAppliction()->getCutomer() . "</td>".
}
Like this keep on calling what u want since u have already joined columns at the model
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.