My query using DQL is:
$query = $this->_em->createQuery(
'SELECT v, a
FROM MyBundle:Products v
JOIN v.category a WITH a.id = :id
WHERE v.main = 1'
)
->setMaxResults(1)
->setParameters(array('id' => $id));
$result = $query->getOneOrNullResult();
var_dump($result->getCategory()->getId());
Please, can sombody explain me, why var_dump returns nothing (white page)? I spent a lot of time of solving this, but i dont uderstand, what is the reason of this behavior.
I know, I can select only id of category table I need hole object of category. Query above is just example, that neither ID is returned.
Or is there another way to get object of related table?
First of all, is the entity's name really Products and not Product?
Second, check that the inverse mapping is set up properly for category.
I just tried a simple example with the exact same use case, and it works fine.
$em = $this->get('doctrine')->getEntityManager();
$query = $em->createQuery(
'SELECT p, c
FROM TestTestBundle:P p
JOIN p.children c WITH c.id = :id
WHERE p.main = 1'
)
->setMaxResults(1)
->setParameters(array('id' => $id));
if (null !== $result = $query->getOneOrNullResult()) {
foreach ($result->getChildren() as $child) {
var_dump($child->getTitle());
}
}
Do as NHG said and enable error reporting so that we could get a hint of what is wrong.
Here's the ORM mapping for the two entities used.
The Parent
class P
{
/**
* #ORM\OneToMany(targetEntity="Test\TestBundle\Entity\C", mappedBy="parent")
*/
private $children;
public function getChildren()
{
return $this->children;
}
The Child
class C
{
/**
* #ORM\ManyToOne(targetEntity="Test\TestBundle\Entity\P", inversedBy="children")
*/
private $parent;
Thanks for all your responses. I found the problem, which was in my dumps. But only in case, when I dumped big objects as was my entity with relations. Skript stoped on it, or something and never continue. So when I removed these dumps, it works correctly.
Maybe, workable solution, for dumping large objects, could be in Enterx's comment, but I could't try it, becouse my app is on remote server, where I have no access to php.ini.
Related
tl;dr; trying to get a course module instance via a course module through mysql or the official moodle api. My solution in the end seems rather scrappy though, so i would like some advice.
Hi Moodle people
I am trying to retrieve the corresponding course module instance for each row in mdl_course_modules, a instance in this context would be a single row from mdl_quiz, mdl_wiki or some other course_modules instance.
I have tried a few things, the one i expected to work was:
function get_all_course_modules($course_id) {
global $DB;
$course = $DB->get_record('course', array('id' => $course_id));
$mod_info = get_fast_modinfo($course);
}
I wasn't able to get the course modules instance from $mod_info .
So i tried to do some custom mysql instead,
SELECT course.id, course.fullname, cm.course, cm.section, m.name
FROM mdl_course AS course
JOIN mdl_course_modules AS cm ON cm.course = course.id
JOIN mdl_modules AS m ON m.id = cm.module
JOIN CONCAT('mdl_', m.name) AS module_type ON ...somethingsomething
WHERE course.id = 2;
The sql isn't quite finished, i stumbled on the fact that i dont know all of the different course modules beforehand, that means that i have to use the name of the course_module dynamically to select which instance table i want to join on, or just LEFT JOIN on all of the possible course modules instance tables, but that would take forever and would stop working if someone put in a new course module instance.
Right now im doing the following:
$result = array();
$course_mods = get_course_mods($course_id);
if($course_mods) {
foreach($course_mods as $course_mod) {
$DB->get_records_sql('some sql that selects the instance');
}
}
return $result;
This last piece of code would eventually work, i would be able to able to dynamically create the query from the $course_mod variables such as $course_mod->instance, $course_mod->mod_name etc.
But i think this seems tough. Have any of you guys suceeded in getting the course_module instance in a easier way??
Thanks!!
This is the function i ended up using, to retrieve course module instances, its not so pretty, but whatever.
function get_all_course_modules($course_id) {
global $DB;
$course_mods = get_course_mods($course_id);
$result = array();
if($course_mods) {
foreach($course_mods as $course_mod) {
$course_mod->course_module_instance = $DB->get_record($course_mod->modname, array('id' =>$course_mod->instance ));
$result[$course_mod->id] = $course_mod;
}
}
return $result;
}
Good morning, as seen in the image below, I have some tables linked.
Using Doctrine (in Symfony2) I'm trying to get an array of Objects Issue which itself contains all IssueMessages and IssueStatusChanged objects but can not.
I have no idea how I can do to join two tables (IssueMessage and IssueStatusChanged) to through their identifiers.
The most we've done is get all Issue with an account of the messages that have:
$dql = 'SELECT x, COUNT(im.id) FROM PanelBundle:Issue x LEFT JOIN PanelBundle:IssueMessages im WITH x.id = im.idIssue';
Does anyone could give me a hand?
THANKS!
You want to use assication mapping; this will have Doctrine manage all the joins for you.
Once in place, $issue will always have the other associated models available automatically without you having to worry about joins.
For the example below (assuming you use annotation), to get messages for an issue just get the issue objects and then use $issue->getMessages();.
<?php
/** #Entity */
class issue
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
// ...
/**
* #OneToMany(targetEntity="issueMessages", mappedBy="issue")
*/
private $messages;
// ...
public function __construct()
{
$this->messages = new Doctrine\Common\Collections\ArrayCollection();
}
}
/** #Entity */
class issueMessages
{
// ...
/**
* #ManyToOne(targetEntity="issue", inversedBy="messages")
* #JoinColumn(name="issue_id", referencedColumnName="id")
*/
private $issue;
// ...
}
If you using yml format for schema orm files than
first you need to write schema and mention oneToMany, manyToOne relationship with table fields & generate entity, repository class.
Than you can use join with two or more tables as below example:
Example of repository class file function:
----------------------------------------------------
public function getReportInfo($idUserDetail)
{
$query = $this->createQueryBuilder('UR')
->select("UR.report_period_start_date, UR.report_period_end_date")
->leftJoin('UR.UserReportDetail', 'URD')
->andWhere('UR.id_user_detail = :id')
->setParameter('id', $id)
->orderBy('UR.report_year', 'DESC')
->addOrderBy('UR.report_month', 'DESC')
->setMaxResults(1);
$resultArray = $query->getQuery()->getArrayResult();
return $resultArray;
}
You can call this function from controller action as below:
-------------------------------------------------------------
public function getUserDetailAction($idUserDetail)
{
$em = $this->getDoctrine()->getManager();
$userDetail = $em->getRepository(
'DemoBundle:UserDetail')
->getReportInfo($idUserDetail);
return $userDetail;
}
I hope this would be useful to you.
I think the problem reside in the DQL syntax (+ missing inverse relation?).
By writing this:
SELECT x, COUNT(im.id) FROM PanelBundle:Issue x
LEFT JOIN PanelBundle:IssueMessages im WITH x.id = im.idIssue
you are joining two "random" table based on the condition provided in the WITH clause. This should usually be ok, but it may confuse the Hydrator component.
In your case you should configure the OneToMany side of the relation in Issue entity, then write something like this:
SELECT x, COUNT(im.id) FROM PanelBundle:Issue x
LEFT JOIN x.issueMessages im
Hope it helps!
I'm developing a social network in which users can follow and have followers. Followers and users being followed are implemented as collections using doctrine. I want to be able to filter this collections without loading the whole collection, since doctrine 2.5 this should be posible using criteria and matching, the filtering i want to do should be prety simple i want to hide blocked users. So lets say user A blocks user B, and user B is in the follower list of user C then user B should be hidded so user A can't see it in the follower list of user C.
This was my first approach using criteria:
public function getFollowerUsers(User $user, $page){
$filter_ids = array_merge((array)$user->getBlockedUserIds(), (array)$user->getBlockingUserIds());
$criteria = Criteria::create()
->where(Criteria::expr()->notIn('id', $filter_ids))
->setFirstResult($page * User::USERS_PER_PAGE)
->setMaxResults(User::USERS_PER_PAGE);
return $this->followers->matching($criteria);
}
This should work, but the SQL being executed is the following:
SELECT te.id AS id, te.user_login AS user_login, te.user_pass AS user_pass, te.user_nicename AS user_nicename, te.user_email AS user_email, te.user_url AS user_url, te.user_registered AS user_registered, te.user_activation_key AS user_activation_key, te.user_status AS user_status, te.display_name AS display_name FROM users te JOIN followers t ON t.following_user_id = te.id WHERE t.user_id = ? AND te.ids = ?' with params ["1", ["7","37"]]
Note that i changed Criteria::expr()->notIn('id', $filter_ids) for Criteria::expr()->notIn('ids', $filter_ids) so I could see the SQL being executed, the important thing here is that doctrine is using te.ids = when it should use te.ids NOT LIKE, it doesn't matter which operator i use doctrine always change it to =, so it seems like it only works with Criteria::expr()->eq('id', 1), am I doing anything wrong or this is a bug?. If i change the sql generated by doctrine for not in it works as I expect to work!
My current solution was creating a service so the entity doesn't know anything about the EntityManager:
class UserService {
/* $em EntityManager */
private $em;
public function __construct(EntityManager $em) {
$this->em = $em;
}
public function getFollowingUsers(\models\Users $user, \models\Users $user_querying, $page, $users_per_page){
$filter_ids = implode(",", array_merge((array)$user_querying->getBlockedUserIds(), (array)$user_querying->getBlockingUserIds()));
//var_dump($filter_ids);
$user_following = $this->em->createQuery("SELECT u,f FROM \models\WpUsers u JOIN u.following f WHERE u.id = :user_id AND f.id NOT IN($filter_ids)")
->setParameter('user_id', $user->getId())
->setFirstResult($page * $users_per_page)
->setMaxResults($users_per_page)
->getResult();
return $user_following[0]->getFollowingUsers();
}
}
And the call it this way:
$service = new \services\UserService($this->em);
$following_users = $service->getFollowingUsers($user_list, $user);
This works properly and it seems like I'm not loading the whole collection to filter, but i would like to be able to do it the other way since it is much clear and more elegant
I've found this to be a problem as well. Any comparison ("neq", "lt", etc.) turns out to be "=" in the SQL call. I'm using Doctrine v2.5.2.
Searching many-to-many relationships with Doctrine\Common\Collections\Criteria was unsupported in versions <2.5, so the new functionality must still be in development.
I'm doing a join between two tables using the doctrine that comes bundled in the current symfony release. This is my controller code:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Acme\GearDBBundle\Entity\TbGear;
use Acme\GearDBBundle\Entity\TbDships;
class DefaultController extends Controller
{
public function indexAction()
{
$repository = $this->getDoctrine()
->getRepository('AcmeGearDBBundle:TbGear');
$query = $repository->createQueryBuilder('p')
->select('p', 'q')
->innerJoin('p.fkShip', 'q', 'WITH', 'p.fkShip = q.id')
->getQuery();
$result = $query->getResult();
foreach ( $result as $p ) {
$gear[] = array('shortname' => $p->getGearShortName(), 'name' => $p->getGearName(), 'shipname' => $p->getShipName /* Does not work, since the getter is in a different entity */);
}
return $this->render('AcmeGearDBBundle::index.html.twig', array('gear' => $gear));
}
}
The query generated by this is correct and delivers the expected fields if I execute it in phpmyadmin.
SELECT t0_.GEAR_NAME AS GEAR_NAME0, t0_.GEAR_SHORT_NAME AS GEAR_SHORT_NAME1, t0_.STATUS AS STATUS2, t0_.ID AS ID3, t1_.SHIP_NAME AS SHIP_NAME4, t1_.CONTACT_NAME AS CONTACT_NAME5, t1_.CONTACT_EMAIL AS CONTACT_EMAIL6, t1_.ID AS ID7, t0_.FK_SHIP_ID AS FK_SHIP_ID8, t0_.FK_TYPE AS FK_TYPE9
FROM tb_gear t0_
INNER JOIN tb_dships t1_ ON t0_.FK_SHIP_ID = t1_.ID
AND (t0_.FK_SHIP_ID = t1_.ID)
However, I have no clue how do access those fields in the returned result set. The way I expected it to work ( by accessing the getter of the joined table entity ) does not work. The error message reads: FatalErrorException: Error: Call to undefined method Acme\GearDBBundle\Entity\TbGear::getShipName() in /var/www/symfony/src/Acme/GearDBBundle/Controller/DefaultController.php line 24
which makes sense since the TbGear entity doesn't have a getter method called getShipName() , since that's a method from the joined entity. But how do I access those values? This probably is a stupid question, but I just can't figure it out. Any help is appreciated.
$p->getFkShip()->getShipName() maybe?
This should work since it will retrieve only TbGear that satisfies you relationship. So you could be able to access to all FkShip (I suppose that is a many-to-one relation) that should be only one, and then .... you got it!
EDIT
Of course I suppose that you have correctly designed your class so that you have a getter from TbGear to access the relation with FkShip
Can you add that custom getter: getShipName()?
public function getShipName(){
if ( $this->ship != null ){
return $this->ship->getName();
}
return null; // or an empty string
}
I'm new to doctrine and I'm running into a problem. Here it is:
I have the following model/entity:
<?php
namespace models;
/** #Entity #Table(name="teams") #HasLifecycleCallbacks */
class Team
{
...
/** #OneToMany(targetEntity="Teammember", mappedBy="team") */
private $members;
...
function getTeamsILeadForGame($user, $game)
{
$q = $this->doctrine->em->createQuery("SELECT t, tm FROM models\Team t JOIN t.members tm WHERE tm.user = ?1 AND t.game = ?2 AND tm.is_leader = ?3 ORDER BY t.name ASC");
$q->setParameter(1, $user);
$q->setParameter(2, $game);
$q->setParameter(3, 1);
try {
return $q->getResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
}
AS you can see, there is a link to the Teammember entity. In the function I wrote, I'm trying to get all the teams where the current user has the is_leader flag set to 1.
This query executes just fine and the result is what I expect it to be.
Now onto the problem. Further down in my controller I try to do the following:
$postteam = $this->em->find('models\Team', $this->input->post('team'));
The team data it returns is correct, but when I call $postteam->getMembers() it just returns 1 row (the one where is_leader = 1) instead of all the members of that team.
So it seems like doctrine is keeping my other function in the back of its head? I'm really confused as to why this is.
So like I said, my controller looks like this:
$teams = models\Team::getTeamsILeadForGame($this->user->getId(), $tournament->getGame()->getId());
// Do some checks on the returned teams
$postteam = $this->em->find('models\Team', $this->input->post('team'));
$postteam->getMembers();
When I remove the $teams = models....... line, everything works fine again. So it seems to me like doctrine filters its internal resultset by that line, and then only searches in that resultset from then on.
Any ideas on how to fix this? Thnx
I figured it out finaly :D
It turns out it had to do with lazy loading. Once I set 'fetch=eager' at the link towards the members, everything worked fine.
Hope this is of any help for people having the same problem...