Doctrine- one of associations doesn't work proper - orm

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.

Related

ManyToMany with composite key with api-platform

I am using Api Platform.
I have two entities Player and Team and one entity PlayerHasTeam to represent in the database the date on which the player joined a team.
This is my PlayerHasTeam entity :
/**
* #ApiResource(
* collectionOperations={
* "get",
* "post"
* },
* itemOperations={
* "get",
* "put",
* "delete"
* }
* )
* #ORM\Table(name="playerHasTeam")
* #ORM\Entity
*/
class PlayerHasTeam
{
/**
* #var Player
*
* #ORM\ManyToOne(targetEntity="App\Entity\Player", inversedBy="id")
* #ORM\JoinColumn(referencedColumnName="idPlayer", name="idPlayer", nullable=false)
*
* #ORM\Id
*/
private $player;
/**
* #var Team
*
* #ORM\ManyToOne(targetEntity="App\Entity\Team", inversedBy="id")
* #ORM\JoinColumn(referencedColumnName="idTeam", name="idTeam", nullable=false)
*
* #ORM\Id
*/
private $team;
/**
* #var DateTime
*
* #ORM\Column(name="joinedAt", type="datetime", nullable=false)
*/
private $joinedAt;
(Getters and Setters)
The problem is the following, I need to do GET, PUT and DELETE request on this Composite Entity.
Api-platform defines the following routes :
GET /player_has_teams
POST /player_has_teams
GET /player_has_teams/{id}
PUT /player_has_teams/{id}
DELETE /player_has_teams/{id}
I cannot use the 3 last because I don't have a generated id.
I want to do my requests with a route like /player_has_teams/{idPlayer}/{idTeam}
It seems that api-platform does not handle this case.
Do you have any suggestions ?
Thank you
Ok, I found a solution.
I just have to call my route like this
GET /player_has_teams/player=1;team=1
PUT /player_has_teams/player=1;team=1

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.

Doctrine2 / SQL cooccurrences query

I actually want to write a Doctrine query (using the query builder), but first I want the SQL query. The query should retrieve the cooccurrences between the countries. In other words, I want to know how many times the country X collaborated with the country Y. FYI, a collaboration is when two (or more) inventors from different countries belong to the same patent.
This is my schema :
The Country class:
namespace Db\CreatorBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Db\CreatorBundle\Entity\Inventor;
/**
* Country
*
* #ORM\Table()
* #ORM\Entity
*/
class Country
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
* #ORM\Id
* #ORM\Column(name="code", type="string", length=5)
*/
private $code;
/**
* #ORM\OneToMany(targetEntity="Inventor", mappedBy="country")
*/
private $inventors;
}
The Patent class:
namespace Db\CreatorBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Db\CreatorBundle\Entity\Country;
/**
* Inventor
*
* #ORM\Table()
* #ORM\Entity
* #ORM\Entity(repositoryClass="Db\CreatorBundle\Entity\InventorRepository")
*/
class Inventor
{
/**
* #var string
* #ORM\Id
* #ORM\Column(name="fullName", type="string", length=255)
*/
private $fullName;
/**
* #ORM\ManyToMany(targetEntity="Patent", mappedBy="inventors")
*/
private $patents;
/**
* #ORM\ManyToOne(targetEntity="Country", inversedBy="inventors")
* #ORM\JoinColumn(name="country_code", referencedColumnName="code")
*/
private $country;
}
I have already written the query that retrieves the cooccurrences between the inventors, now I need the one for the countries.
So the result should be something like this :
Country | Country | Number of cooccurrences
US | FR | 30
US | KR | 12
US | JP | 91
CA | AU | 40
FR | AU | 23
FR | NL | 5
Oh, and thank you !
EDIT #1
This is my first query :
SELECT a.inventor_id, b.inventor_id, count(*) cnt
FROM inventors_patents a INNER JOIN inventors_patents b ON b.patent_id = a.patent_id
AND b.inventor_id > a.inventor_id
GROUP BY a.inventor_id, b.inventor_id
ORDER BY cnt DESC
The result looks like this :
AU1 AU2 8
AU1 AU3 7
AU1 AU4 7
AU2 AU3 6
AU2 AU5 4
AU3 AU6 3

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)