Doctrine2 - multiple relations on one field - orm

I have the following database setup:
Tag (Integer id)
ItemTag (Integer id, Integer tag_id, Integer item_id, Integer item_type)
Artwork (Integer id)
Photo (Integer id)
I tried using the item_id field in ItemTag for both the Artwork id and Photo id like below
class ItemTag {
/**
* #Id #GeneratedValue
* #Column(type="integer")
*/
private $id;
/**
* #Column(type="integer")
*/
private $item_type;
/**
* #ManyToOne(targetEntity="Artwork")
* #JoinColumn(name="item_id", referencedColumnName="id")
*/
private $artwork;
/**
* #ManyToOne(targetEntity="Photo")
* #JoinColumn(name="item_id", referencedColumnName="id")
*/
private $photo;
/**
* #ManyToOne(targetEntity="Tag")
*/
private $tag;
}
The setup above does not produce any errors and works fine when I try to save a "photo item", however when saving an "artwork item" the item_id is NULL.
Is there a way to be able to save both relations into a single item_id field?

Yes, you can use inheritance.
You can define an abstract class "Item" and have both Photo and Artwork extend it.
http://www.doctrine-project.org/docs/orm/2.0/en/reference/inheritance-mapping.html
This requires you to change your schema slightly though.

Related

Doctrine - Missing value for primary key

I have this entity:
/**
* Class ParserURLs
* #package AppBundle\Entity
* #ORM\Entity(repositoryClass="AppBundle\Entity\ParserURLsRepository")
*/
class ParserURLs
{
/**
* #ORM\Id
* #ORM\Column(type="string", length=50)
*/
protected $external_id;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Parser")
*/
protected $parser;
...
}
Any I try to get results filtering by $parser, like this:
$query = $this->doctrine->getManager()->createQuery(
'SELECT u
FROM AppBundle:ParserURLs u
WHERE u.parser = :parser')
->setParameter('parser', $this->parser);
$result = $query->getResult();
But Doctrine tell me: Missing value for primary key parser on AppBundle\Entity\ParserURLs
I think that the problem es because the multiple primary key external_id-parser but now, I only want search by one of their. It's not possible in Doctrine? I need this primary keys.
Thanks you in advance
Looks like you are missing name property in your annotations. Your definition should look like this:
/**
* #var string
*
* #ORM\Column(name="id", type="string", length=9)
* #ORM\Id
*/
private $id;
Where name="id" is your name of the field from you DB
If your ID has autoincrement you have to add this line:
#ORM\GeneratedValue(strategy="AUTO")

Doctrine2 - get group which hasn't hidden person

The first entity called BUNDLE
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Course\Course
* #ManyToMany(targetEntity="Akademie\Course\Course", mappedBy="bundles")
*/
private $courses;
The second entity is called COURSE
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Bundle\Bundle
* #ManyToMany(targetEntity="Akademie\Bundle\Bundle", inversedBy="courses")
*/
private $bundles;
/**
* #var \Doctrine\Common\Collections\Collection of \Akademie\Course\CourseDate
* #OneToMany(targetEntity="Akademie\Course\CourseDate", mappedBy="course")
*/
private $courseDates;
/**
* #var int
* #Column(type="boolean")
*/
private $hidden;
and the third is called COURSEDATE
/**
* #var \Akademie\Course\Course
* #ManyToOne(targetEntity="Akademie\Course\Course", inversedBy="courseDates")
* #JoinColumn(nullable=false)
*/
private $course;
/**
* #var \DateTime
* #Column(type="datetimetz", nullable=true)
*/
private $beginDate;
I have parameter course and I need to get all bundles, which contains this course. What's more, all other courses in that bundle has to have courseDate newer than current date and can't be hidden. Otherwise I don't want to get this bundle. I hope it is clear now...
I am not familiar with MEMBER OF but i think you are better of with an INNER JOIN.
DQL:
SELECT group
FROM path\to\entity\Group group
INNER JOIN group.persons person
INNER JOIN person.city city
WHERE person.hidden = FALSE AND city.name = :name
QueryBuilder:
$em->createQueryBuilder()
->select('group')
->from('path\to\entity\Group', 'group')
->innerJoin('group.persons', 'person')
->innerJoin('person.city', 'city')
->where('person.hidden = FALSE')
->andWhere('city.name = :name')
->setParameter('name', $yourName)
->getQuery()->getResult();
I assumed that your person entity has an attribute called hidden and that your person-city relationship is bidirectional.

Doctrine- one of associations doesn't work proper

I have problem with associations in Doctrine 2
I have two associations which look the same. One works fine, the second one work in weird way. I'll explain it a bit later.
Here is my main entity- Product:
**
* Product
*
* #ORM\Table(name="product", indexes={
* #ORM\Index(name="category_index", columns={"category_id"}),
* #ORM\Index(name="partner_index", columns={"partner_id"})
* })
* #ORM\Entity
*/
class Product
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
private $name;
/**
* #var Category
*
* #ORM\ManyToOne(targetEntity="Category")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $categoryId;
/**
* #var Partner
*
* #ORM\ManyToOne(targetEntity="Partner")
* #ORM\JoinColumn(name="partner_id", referencedColumnName="id")
*/
private $partnerId;
}
Category Entity:
/**
* Category
*
* #ORM\Table(name="category")
* #ORM\Entity
*/
class Category
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="category_name", type="string", length=100, nullable=false)
*/
private $categoryName;
}
Partner Entity:
/**
* Partner
*
* #ORM\Table(name="partner")
* #ORM\Entity
*/
class Partner
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=150, nullable=false)
*/
private $name;
}
As you can see I have two identical associations:
Product#categoryId
Product#partnerId
The first one- categoryId works as it should, but the second one- partnerId doesn't:
First thing I noticed is that Doctrine create proxy class with Partner Entity,
while Category Entity doesn't need proxy class to work, so one of
this doesn't work proper.I just started with Doctrine so I might be
wrong.
I have 4 records in Partner table. When I try to modify Product
record manually, in partner_id field I can't set 1-4, I can set
something like this:
(empty)
1 - 1
2 - 2
3 - 3
4 - 4
(empty)
1 - 1
2 - 2
3 - 3
4 - 4
First time I see something like this.
And the last thing I noticed:
$query = $em->createQuery('
SELECT pp.name, p.id
FROM Application\Entity\Product AS p
LEFT JOIN Application\Entity\Partner AS pp WITH p.partner_id = pp.id GROUP by p.partner_id
');
$items = $query->getResult();
Shows me error:
Doctrine\ORM\Query\QueryException: [Semantical Error] line 0, col 148 near 'partner_id =': Error: Class Application\Entity\Product has no field or association named partner_id in
Thanks for any help and tips.
Edit
So, the question is. Why does Doctrine create proxy class for Partner Entity, but not for Category?
As far as I know Doctrine will only create proxies when functionality for the entity it belongs to is used.
You can also manually generate the proxies using the command line tools.
About the error:
You should use partnerId instead of partner_id. Partner_id is the name of your database column, not of the attribute defined in your Product entity.
$query = $em->createQuery('
SELECT pp.name, p.id
FROM Application\Entity\Product AS p
LEFT JOIN Application\Entity\Partner AS pp WITH p.partnerId = pp.id GROUP by p.partnerId
');
$items = $query->getResult();
Have a good look at the DQL documentation:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html
Maybe it will give you some extra insights about the difference between SQL and DQL.

Doctrine ManyToOne with join table - filter results

I have a Customer entity and User entity with a JOIN relationship table customers_users.
In the Customer entity I have this.
/**
* #var User
*
* #ORM\ManyToMany(targetEntity="Entity\User")
* #ORM\JoinTable(name="customers_users",
* joinColumns={#ORM\JoinColumn(name="customer_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id", unique=true)}
* )
*
*/
private $users;
I want that when a customer is created I can assign the users to it and actually it works well, however I want filter the users to show only those that don't are assigned to none customer.
For example, I have two customers and two users and the first customer has assigned two users; then when I edit the second customer, two users appear to be assigned to it but when I select these and I send the form, it throws the following exception:
An exception occurred while executing 'INSERT INTO customers_users (customer_id, user_id) VALUES (?, ?)' with params [2, 1]:
SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "uniq_2763c6cca76ed395"
DETAIL: Key (user_id)=(1) already exists.
/**
* #var User
*
* #ORM\ManyToMany(targetEntity="Entity\User", inversedBy="customers")
* #ORM\JoinTable(name="customers_users",
* joinColumns={#ORM\JoinColumn(name="customer_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id", unique=true)}
* )
*
*/
private $users;
and in the User entity, in customers annotation you should put:
* #ORM\ManyToMany(targetEntity="Entity\Customer", inversedBy="users")
(...)
What I actually did in this situation, is:
// UserAdmin.php that extends SonataAdminBundle's User admin
/**
* {#inheritdoc}
*/
public function createQuery($context = 'list')
{
/** #var QueryBuilder $query */
$query = parent::createQuery();
$request = Request::createFromGlobals();
// Could not find another way to detect that admin list is created from
// sonata_type_model_list parent.
// Of course, this applies only to sonata_type_model_list field type.
if ($request->query->get('pcode') == 'demo.admin.customer') {
$alias = $query->getRootAliases()[0];
$query->leftJoin($alias . '.customers', 'c');
// $query-> ... do filtering here
}
return $query;
}
This way I could filter Users in any way I wanted.

Doctrine 2 where two associations exists query

I have two entities related, and I need a query that checks if entityOne have two different relations (extra column as diff field) to entityTwo.
A simple "WHERE entityTwo.diff_field = 1 AND entityTwo.diff_field = 2" don't work.
How can I achive this?
Thanks
UPDATE:
$query = $this->createQueryBuilder('one');
$query->addSelect('two')->leftJoin('one.two', 'two');
$query->where('two.id = :a')->setParameter('a',1);
$query->andWhere('two.id = :b')->setParameter('b',2);
EntityOne
class EntityOne {
/**
* #ORM\Id
* #ORM\Column(type="integer", nullable=false);
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="EntityTwo", mappedBy="one")
*/
protected $two;
}
EntityTwo
class EntityTwo {
/**
* #ORM\Id
* #ORM\Column(type="integer", nullable=false);
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="EntityOne", inversedBy="two", cascade={"persist"})
* #ORM\JoinTable(name="one_two_xref")
*/
protected $one;
}
I think you need two EXISTS subqueries.
You want (I think) to select entityOnes which have
a linked entityTwo with diffType 1 and also a linked entityTwo with difftype 2.
If you scroll down to 'EXISTS in WHERE clause with correlated Subquery' in this documentation:
http://docs.doctrine-project.org/en/2.1/reference/dql-doctrine-query-language.html
I think what you need is a similar query but with two separate EXISTS subqueries, something like :
WHERE EXISTS (SELECT EntityTwo ... DiffType = 1)
AND EXISTS (SELECT EntityTwo ... DiffType = 2)