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...
Related
So I have a database setup like this.
Phone numbers belong to groupings. And users belong to groupings as well. I'm trying to figure out how to get all users that belong to a grouping but through the entity object instead of just a query if this is possible.
For example I'm aware I could do a query like this...
<?php
/**
* Auto generated by MySQL Workbench Schema Exporter.
* Version 3.0.3 (doctrine2-annotation) on 2017-03-27 04:09:37.
* Goto https://github.com/johmue/mysql-workbench-schema-exporter for more
* information.
*/
namespace Entity;
use Doctrine\ORM\Mapping as ORM;
use Entity\BaseGrouping;
/**
* Entity\Grouping
*
* #ORM\Entity()
*/
class Grouping extends BaseGrouping
{
public function getUsersByPriority(){
global $entityManager;
$users = $entityManager->getRepository('Entity\User')->findBy(array(),array('priority' => 'ASC'));
return $users;
}
}
With a little modification I could add another filter perhaps so that only the correct results pertaining to that group are shown instead of everything. Right now this will result in just every user showing instead of those that should belong to just the group.
What I'm looking for is something kind of like this...
$results = $entityManager->getRepository('entity\Phonenumber')->findBy(array('number' => '+'.$numberCalled));
if(count($results)<=0 || count($results)>1){
sendEmail('Error Occured', 'There was duplicate phone numbers in the database, used fallbacknumber<br/><br/>'.print_r($_REQUEST,true),"joe#poolserviceusa.com");
return $fallbacknumber;
}else{
$phonenumber = $results[0];
$group = $phonenumber->getGrouping(); //#JA - Returns the group object and stores it to variable group in scope
}
//Get list of all users in the group
$users = $group->getUsersByPriority(); //#JA - Returns all users associated with the group
//Find the first active and not busy user
foreach($users as $user){
echo '<test>'.$user->getUserName().'<test>';
}
Since I mapped correctly all the doctrine classes I'm able to just say $phonenumber->getGroupings(); and it returns me only the groupings that belong to that phonenumber which is perfect!
What I need now however is all the users that belong to that particular group?
Easy enough if we do $group->getUsers(); The problem here is I need the users sorted by priority and there is no sorting when I use these default methods.
How do I get all the users of just the group while sorting by priority?
I think I found the answer but I don't know if this is the best answer or not. I modified the function getUsersByPriority to this.
public function getUsersByPriority(){
global $entityManager;
$grouping_id = $this->getId();
$users = $entityManager->getRepository('Entity\User')->findBy(array('grouping_id' => $grouping_id),array('priority' => 'ASC'));
//#JA - Get reference to the users of just this grouping.
$users = $this->users;
return $users;
}
I didn't realize I could use $this->getId(); to get reference to the current instance in this case.
I have some problem that, I am using criteria to customize a number column query
$criteria=new CDbCriteria();
$criteria->select =array('CompanyName', 'CompanyCountCoupon','CompanyDes', 'CompanyLogo');
$models = Company::model()->findAll($criteria);
After I put it to array and echo result
$rows = array();
foreach($models as $i=>$model1) {
$rows[$i] = $model1->attributes;
}
echo CJSON::encode($rows)
My problem is that the results contains all attributes of table, and attributes not in criteria->select will set = null
{"CompanyName":"abc","CompanyCountCoupon":"0","CompanyDes":"Hello","CompanyLogo":"\/upload\/company\/abc.jpg",**"CompanyID":null,"CompanyWebSite":null,"CompanyAdrress1":null,"CompanyAdrress2":null,"CompanyPhone1":null,"CompanyPhone2":null**}
Please help me.
Thanks to all
if you go with findAll() (using ActiveRecord) you won't be able to control that part, the way to go is a custom query :
$results = Yii::app()->db->createCommand()
->select('CompanyName ,CompanyCountCoupon ,CompanyDes ,CompanyLogo')
->from('company')
//->where() // where part
->queryAll();
echo CJSON::encode($results);
now its already good to be JSON encoded and also much faster than regular ActiveRecord
Use getAttributes()
Example
$rows = Company::model()->getAttributes(array('CompanyName','CompanyCountCoupon','CompanyDes', 'CompanyLogo'));
echo CJSON::encode($rows);
This is correct behaviour.
You are asking for specific columns, so this is being correctly provided.
Recall that the attributes is part of the model, not the query.
$model = Company::model()->findByPK();
print_r($model);
...
/* Company points to the TABLE. not the query */
class Company extends CActiveRecord
{
---
}
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.
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 have a query which is returning a sum, so naturally it returns one row.
I need to count the number of records in the DB which made that sum.
Here's a sample of the type of query I am talking about (MySQL):
SELECT
i.id,
i.vendor_quote_id,
i.product_id_requested,
SUM(i.quantity_on_hand) AS qty,
COUNT(i.quantity_on_hand) AS count
FROM vendor_quote_item AS i
JOIN vendor_quote_container AS c
ON i.vendor_quote_id = c.id
LEFT JOIN company_types ON company_types.company_id = c.company_id
WHERE company_types.company_type = 'f'
AND i.product_id_requested = 12345678
I have found and am now using the select_min(), select_max(), and select_sum() functions, but my COUNT() is still hard-coded in.
The main problem is that I am having to specify the table name in a tightly coupled manner with something like $this->$db->select( 'COUNT(myDbPrefix_vendor_quote_item.quantity_on_hand) AS count' ) which kills portability and makes switching environments a PIA.
How can/should I get my the count values I am after with CI in an uncoupled way??
If you want a completely decoupled way of dealing with this, just run the query to get all the rows you'd add with SUM() and then add them together in PHP.
$sum = 0;
foreach($query->result() as $row)
{
$sum += $row->quantity_on_hand;
}
Or something like that.
What about defining your table in a var or const and then doing the query like so:
define('VENDOR_QUOTE_ITEM', 'vendor_quote_item');
$this->$db->select( 'COUNT(' . VENDOR_QUOTE_ITEM . '.quantity_on_hand) AS count' );
This should be faster than $query->num_rows() as that would retrieve results and have PHP count them. The above code cuts to the chase and just asks the DB for the count without returning anything else (because it uses mysql's COUNT())
As for why $query->num_rows(); isn't working.. Make sure that var you call num_rows on a CI query result object. You should have something like this:
$your_query = $this->db->query("YOUR QUERY");
$your_query->num_rows()
if you would like to use any MySQL function inside $this->db->select() function pass the second parameter as FALSE.
So it should be $this->$db->select( 'COUNT(myDbPrefix_vendor_quote_item.quantity_on_hand) AS count' , FALSE)
Well ... while it's a different direction than I initially envisioned, I ended up simply extending CI via the directions found HERE.
I added a select_count() method to match the existing select_min(), select_max(), and select_sum() methods.
This addition only applies to MySQL at this time, but it's a solid solution.
In case someone encounters a similar problem in the future, here's what I did:
I dropped Simons "MY_Loader" directly into my "application/core"
directory (didn't need to change a thing).
Then I created a "MY_DB_mysql_driver" in the "application/core" directory,
as per his instructions ... and made it looke like this: (sans comments for brevity)
.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class My_DB_mysql_driver extends CI_DB_mysql_driver {
final public function __construct($params) {
parent::__construct($params);
log_message('debug', 'Extended DB driver class instantiated!');
} /* method: __CONSTRUCT */
final public function select_count($select = '', $alias = ''){
if ( !is_string($select) OR $select == ''){
$this->display_error('db_invalid_query');
}
if ($alias == ''){
$alias = $this->_create_alias_from_table(trim($select));
}
$sql = 'COUNT('.$this->_protect_identifiers(trim($select)).') AS '.$alias;
$this->ar_select[] = $sql;
if ($this->ar_caching === TRUE){
$this->ar_cache_select[] = $sql;
$this->ar_cache_exists[] = 'select';
}
return $this;
} /* method: SELECT_COUNT */
}
Hope it helps.