Doctrine query builder find by interests - symfony

today i have an interest task - realize search on DB by some groups and sort it by most relevant criteria
We have 2 entities (User and Interests) on Symfony with ManyToMany relation
We need create query for find users which have most similar interests
ex:
user1 have interests [1,2,3,4,5]
user2 have interests [1,2,4,5,7]
user3 have interests [3,5]
we try find user with interests [2,6,7] and result must be:
[user2, user1, user0]
user2 - 2 similar interests
user1 - 1 similar interests
user3 - 0
Code example:
class User
{
// ...
/**
* Many Users have Many Interests.
* #ManyToMany(targetEntity="Interest")
* #JoinTable(name="users_interests",
* joinColumns={#JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="interest_id", referencedColumnName="id")}
* )
*/
private $interests;
...
I have no idea how to organize it nicely, can somebody help me?
Thanks!

One way of doing it
Find user with at least 1 interest of your list (Simple Dql Query)
Count number of common interest in php.
For example using count(array_intersect($userInterestsIds, $wantedIds))
You have all the wanted info, display it as you want

I suggest you to use simple sql (not DQL) in order to extract only the id of the user that match the criteria.
A simple query could be:
select distinct user_id, count(*) from users_interests
where interest_id in (1,3,5) --- your interest ids
group by 1
order by 2 DESC;
Hope this help

Related

Combining multiple one-to-one relationships in Doctrine on inverse side of relationship

Hoping for some help thinking this through. Say I'm working with two entities here - User and Group. For the purposes of this example, say each Group has a senior moderator and a junior moderator, both of whom are Users and are mutually exclusive (a user can only be in one group, and cannot be both the senior and junior moderator). So in Group, I might have something like:
class Group
{
/**
*
* #OneToOne(targetEntity="User")
*/
private $seniorModerator;
/**
*
* #OneToOne(targetEntity="User")
*/
private $juniorModerator;
}
Now in User, I don't care whether the user is a senior moderator or junior moderator. I just want to be able to return what group a user is in. I know I'll have to add mappedBys in the Group properties, but I'm sort of stumped because I know I can't have two mappedBys assigned to the same thing ($group for example).
Would the best solution here be to just create two separate inverse properties in User (like $group1 and $group2) and then create a getGroup() getter method that just checks whether either of those properties is populated and returns the one that is?
Is there a less hacky method I'm not thinking of? Appreciate any advice, thanks in advance.
I have similar situation so I have created a third table with manyToOne to User, manyToOne to Group and one field that says if this user for this group is manager. So you can do the same add and two fields that states if user is senior or junior.
i think the best solution is to do a "one to one Unidirectional" association in both group and user entities, so the code for your group will be :
class Group
{
private idGroup;
/**
*
* #OneToOne(targetEntity="User")
* #JoinColumn(name="seniorModerator_id", referencedColumnName="idUser")
*/
private $seniorModerator;
/**
*
* #OneToOne(targetEntity="User")
* #JoinColumn(name="juniorModerator_id", referencedColumnName="idUser")
*/
private $juniorModerator;
}
For your User :
class User{
private idUser;
/**
*
* #oneToOne(targetEntity="Group")
* #JoinColumn(name="group_id", referencedColumnName="idGroup")
*/
private $group;
}
if you want more information on Association Mapping hir are the documentation : http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-one-unidirectional

Accessing Fields of a has_one relation Silvestripe

I have a DataObject Team that has a has_one relation to Member. I would like to use the ORM to search Team but be able to filter records by the value of one field of the related Member table. Just to be more clear, I can achieve the same result with SQL:
SELECT * FROM Member
LEFT JOIN Team ON Team.MemberID=Member.ID
WHERE Member.CityID=142
AND Team.Target='Boy'
AND Team.GenreID=51
AND Team.Fyr <= 9
AND Team.Tyr >= 9
Okay, I got it. The answer is:
$teams= Team::get()->filter(array('Member.CityID:ExactMatch' => $var));
and later simply filter $teams

Use permission/authorization checking scheme for object other than user?

I'm a bit new to this, and I haven't found a good way to make this work.
Lets say I have a user who is an employee of 1 company. This employee may decide to put his company's stocks for sales on the stock market.
Obviously we need to check for 2 permissions:
Does this employee have the right to put the stocks on stock market?
Are this company's stocks authorized to be put on the stock market?
The first check is simple, we simply use voter or ACL to do so. The second check is what I'm trying to figure out because so far in all the documents I have read the roles/permissions are only associated with user, not with arbitrary object (the company in this case)
Why not:
/**
* #ORM\Table(name="company")
* #ORM\Entity(")
*/
class Company
{
...
/**
* #ORM\Column(name="sellable", type="boolean", nullable=true)
*/
private $sellable;
...
}
Then something like:
if ($user->hasRightToSell() && $company->isSellable())?

Doctrine Query Builder Where Count of ManyToMany is greater than

Im using the Doctrine Query Builder, and have a very specific requirement that came through.
I am using the ManyToMany field in my entity, related to User entity association (Array of User account entities).
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="User", cascade={"persist"})
* #ORM\JoinTable(name="post_user_list")
*/
protected $userList;
Amongst the requirements of displaying "public posts" requires that the Entity have a published boolean set to true, a published date less than the current date, and two users associated with entity.
In my query builder, I have setup this:
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select($select)->from($this->getEntityName(), 'p');
$criteria = $qb->expr()->andX();
$criteria->add($qb->expr()->eq('p.editor_published', 1))
->add($qb->expr()->lte('p.datePublished', ':now'));
and that only handles the first two requirements, now I need a criteria entry for counting the amount of user entities in userList, and the where clause specifically for greater than or equal to two users.
Not exactly sure where to proceed..
Try this. The query uses HAVING to only display entities that are associated with 2 or more users.
$qb->select($select)
->from($this->getEntityName(), 'p')
->innerJoin('p.userList','u')
->where('p.editor_published = 1')
->andWhere('p.datePublished <= :now')
->groupBy($select) //not sure what's in $select may need to change this
->having('count(u.id) > 1'); //assuming user has an id column otherwise change it
->setParameter('now',new \DateTime());

pagerfanta - DoctrineORMAdapter Sorting

Although I know this is trivial I'm stuck trying to implement the pagerfanta Paginator using the DoctrineORMAdapter, I want to paginate all entities sorted by id in descending order, the final SQL I want is this:
SELECT id, name FROM User ORDER BY id DESC LIMIT 0, 5;
Suppose I had users from A to Z and I want to limit them by 5 each page, what DoctrineORMAdapter is paginating results in User E to A listed in the first page, while what I actually expect is to see User Z to user V in the first page, U to Q in the second page and so on. The DQL I'm passing to DoctrineORMAdapter is as follow:
SELECT u FROM My\FluffyBundle\Entity\User u ORDER BY u.id DESC
On execution this is the final DQL for the first page:
SELECT DISTINCT id0 FROM (SELECT u0_.id AS id0, u0_.name AS name1 FROM User u0_
ORDER BY u0_.id DESC) dctrn_result LIMIT 5 OFFSET 0
Please note that when using the ArrayAdapter instead of DoctrineORM's it works as expected, but it's not a good idea to rely on ArrayAdapter when you have thousands of complex Doctrine Entities, not even with extra lazy loading :D.
This is the only relevant code:
$queryBuilder = $repo->createQueryBuilder('u')->orderBy('u.id', 'DESC');
$adapter = new DoctrineORMAdapter($queryBuilder);
$pager = new Pagerfanta($adapter);
$pager->setMaxPerPage(5);
Thanks.
This will help you:
$adapter = new DoctrineORMAdapter($queryBuilder, false);
Had the same problem this morning.
By default Pagerfanta is treating your query as one with joins. Setting second argument to false makes it use simple query handling.
In Kunstmaan Bundle, in AdminListConfiguration class, you have to overide function that is creating Pagerfanta, if you want to sort simple entity.

Resources