PHP Doctrine toArray problem - php

I have a problem with the toArray() method in Doctrine. Its doesn't get my relations:
First query :
$q = Doctrine::getTable('posts')->find(1);
debug($q->toArray(true));
Print the postid=1 with out the relations
$q = Doctrine::getTable('posts')->find(1);
$q->Tags->toArray();
debug($q->toArray(true));
...prints the results with tag relation.
But i want to do:
Doctrine::getTable('posts')->findAll()->toArray(true);
...and get all of relations of posts , instead I got an array of post row.
Any idea about how to make it work with the relations?
(notice i added toArray(true) for deep property.
thanks for any help

You could create named query for this table with all relations attached:
Doctrine::getTable('posts')->addNamedQuery('get.by.id.with.relations', 'DQL here...');
And then just use something like this:
Doctrine::getTable('posts')->find('get.by.id.with.relations', array(123));

I beleive you need to do a Join with the query. Otherwise it doesnt hydrate the realated data.
$q = Doctrine_Query::create()
->from('Post p')
->leftJoin('p.RelatedModel1 rm1')
->leftJoin('p.RelatedModel2 rm2');
$q->findAll()->toArray(true);

$q = Doctrine_Query::create()
->from('Post p')
->leftJoin('p.RelatedModel1 rm1')
->leftJoin('p.RelatedModel2 rm2');
$q->findAll()->toArray(true);
Can i Add ->limit()->offset()
to the query ?
I guss that if i first create the query then findAll will act the same as execute right ?

Related

Yii2 How to get all values from column (DB)

I've been sitting for hours trying to find how to get values from table's iab_categories column category_name. I've found only the way to echo all table names:
$connection = Yii::app()->db;//get connection
$dbSchema = $connection->schema;
//or $connection->getSchema();
$tableNames = $dbSchema->getTableNames();//returns array of tbl schema's
var_export($tableNames);
Can anyone help me?
You can use query builder to do that:
$categories = (new \yii\db\Query())
->select(['category_name'])
->from('iab_categories')
->column();
The select() method sets what columns should be included in result.
The from() method sets what table should be queried.
And the column() method executes the query and return first column from result set as array.
EDIT: now, I've realized that even though you've mentioned Yii 2 in title the code you've included in question looks more like Yii 1.x.
So there is query builder version for Yii 1.x:
$categories = Yii::app()->db->createCommand()
->select('category_name')
->from('iab_categories')
->queryColumn();

Laravel Eloquent - "whereNotIn" using a subquery?

I'm struggling to figure out how I can use this SQL with eloquent methods.
SELECT * FROM artists WHERE artists.id NOT IN
(SELECT artist_id FROM artist_issues WHERE issue = 'update_images')
I see that the "whereNotIn" method takes a column, and then an array as the second parameter, so it's not possible to pass a subquery.
Any ideas how I could do this?
Thanks.
Assuming you have the correct relationships set, it should be something like this:
$artists = Artist::whereHas('artist_issues', function(q) {
$q->where('issue', '<>', 'update_images');
});
I guess you have something like this in your Artist model:
public function artist_issues()
{
return $this->belongsTo('App\ArtistIssue');
}

Symfony 2 OneToMany relations - wrong results in association

I have two tables in DB with OneToMany relations. Using 'createQueryBuilder()' method in 'EntityRepository' i try to select some objects with conditions. There is my method:
$query = $this->getEntityManager()->createQueryBuilder();
$query->select("parent")
->from('TestAppBundle:Parent', 'parent')
->leftJoin("parent.children", 'child', 'WITH', 'child.IdP = parent.id')
->where('child.date < :date')
->andWhere('child.status = :null')
->setParameter('date', new DateTime())
->setParameter('null', 0);
And it works almost good. I get Parent Objects with Children Objects in ArrayCollections. Methods select the Parent Objects with conditions but the problem is I get also Children Objects which don't keep the conditions.
I want to get only Parent Objects which keep conditions and Children Objects which also keep conditions. At this time a have to filter results after query and remove Children Object manualy.
I hope you will understand the problem :)
Basically, if you don't select the entities at query time you'll lazy load all children for the parent when you call getChildren(). Select both children and parents like this to avoid lazy loading:
$query->select("parent, child")
For more information please see my answer to a similar question.
Could you try something like this:
$query = $this->getEntityManager()->createQueryBuilder();
$query->select("parent")
->from('TestAppBundle:Parent', 'parent')
->leftJoin("parent.children", 'child', 'WITH', 'child.status = 0');
As far as I understand your needs you should not use leftJoin - with this field you will get parents that don't have children. Use innerJoin instead.
Assuming that child.IdP refers to the parent.id in your model definition you don't have to use WITH clause in this way. So the queryBuilder would be:
$query = $this->getEntityManager()->createQueryBuilder();
$query->select("parent")
->from('TestAppBundle:Parent', 'parent')
->innerJoin("parent.children", 'child')
->where('child.date < :date and child.status = :null')
->setParameter('date', new DateTime())
->setParameter('null', 0);
Regards.

How to 'order_by' on second table when using eloquent one-to-many

Of course I can use order_by with columns in my first table but not with columns on second table because results are partial.
If I use 'join' everything works perfect but I need to achieve this in eloquent. Am I doing something wrong?
This is an example:
//with join
$data = DB::table('odt')
->join('hdt', 'odt.id', '=', 'hdt.odt_id')
->order_by('hdt.servicio')
->get(array('odt.odt as odt','hdt.servicio as servicio'));
foreach($data as $v){
echo $v->odt.' - '.$v->servicio.'<br>';
}
echo '<br><br>';
//with eloquent
$data = Odt::get();
foreach($data as $odt){
foreach($odt->hdt()->order_by('servicio')->get() as $hdt){
echo $odt->odt.' - '.$hdt->servicio.'<br>';
}
}
In your model you will need to explicitly tell the relation to sort by that field.
So in your odt model add this:
public function hdt() {
return $this->has_many('hdt')->order_by('servicio', 'ASC');
}
This will allow the second table to be sorted when using this relation, and you wont need the order_by line in your Fluent join statement.
I would advise against including the order by in the relational method as codivist suggested. The method you had laid is functionally identical to codivist suggestion.
The difference between the two solutions is that in the first, you are ordering odt ( all results ) by hdt.servicio. In the second you are retrieving odt in it's natural order, then ordering each odt's contained hdt by servico.
The second solution is also much less efficient because you are making one query to pull all odt, then an additional query for each odt to pull it's hdts. Check the profiler. Considering your initial query and that you are only retrieving one column, would something like this work?
HDT::where( 'odt_id', '>', 0 )->order_by( 'servico' )->get('servico');
Now I see it was something simple! I have to do the query on the second table and get contents of the first table using the function odt() witch establish the relation "belongs_to"
//solution
$data = Hdt::order_by('servicio')->get();
foreach($data as $hdt){
echo $hdt->odt->odt.' - '.$hdt->servicio.'<br>';
}
The simple answer is:
$data = Odt::join('hdt', 'odt.id', '=', 'hdt.odt_id')
->order_by('hdt.servicio')
->get(array('odt.odt as odt','hdt.servicio as servicio'));
Anything you can do with Fluent you can also do with Eloquent. If your goal is to retrieve hdts with their odts tho, I would recommend the inverse query for improved readability:
$data = Hdt::join('odt', 'odt.id', '=', 'hdt.odt_id')
->order_by('hdt.servicio')
->get(array('hdt.servicio as servicio', 'odt.odt as odt'));
Both of these do exactly the same.
To explain why this works:
Whenever you call static methods like Posts::where(...), Eloquent will return a Fluent query for you, exactly the same as DB::table('posts')->where(...). This gives you flexibility to build whichever queries you like. Here's an example:
// Retrieves last 10 posts by Johnny within Laravel category
$posts = Posts::join('authors', 'authors.id', '=', 'posts.author_id')
->join('categories', 'categories.id', '=', 'posts.category_id')
->where('authors.username', '=', 'johnny')
->where('categories.name', '=', 'laravel')
->order_by('posts.created_at', 'DESC')
->take(10)
->get('posts.*');

Doctrine ORM, two different querys produce the same result set

I'm using Doctrine 1.2 and Symfony 1.4.
In my action, I have two different query that return different result set. Somehow the second query seem to change the result (or the reference?) of the first one and I don't have any clue why..
Here is an example:
$this->categories = Doctrine_Query::create()
->from('Categorie AS c')
->innerJoin('c.Activite AS a')
->where('a.archive = ?', false)
->execute();
print_r($this->categories->toArray()); // Return $this->categories results, normal behavior.
$this->evil_query = Doctrine_Query::create()
->from('Categorie AS c')
->innerJoin('c.Activite AS a')
->where('a.archive = ?', true)
->execute();
print_r($this->categories->toArray()); // Should be the same as before, but it return $this->evil_query results instead!
Why Doctrine behave this way ? It's totally driving me crazy. Thanks!
To make it simple it seem like the Query 2 are hijacking the Query 1 result.
Use something like this between queries ($em - entity manager):
$em->clear(); // Detaches all objects from Doctrine!
http://docs.doctrine-project.org/en/2.0.x/reference/batch-processing.html
In the API docs for the toArray() method in Doctrine_Collection it says:
Mimics the result of a $query->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
I suspect to answer this question to your satisfaction you're going to have to go through the source code.
This seems like it has to be an issue of $this->categories and $this->evil_query pointing to the same place. What are the results of $this->evil_query === $this->categories and $this->evil_query == $this->categories?
Hubert, have you tried storing the query into a separate variable and then calling the execute() method on it?
I mean something like:
$good_query = Doctrine_Query::create()
->from('...')
->innerJoin('...')
->where('...', false)
;
$evil_query = Doctrine_Query::create()
->from('...')
->innerJoin('...')
->where('...', true)
;
$this->categories = $good_query->execute();
$this->evil_query = $evil_query->execute();
It seems like both attributes (categories and evil_query) are pointing at the same object.
Erm, after both queries you print_r the result of the first query - change the last line to print_r($this->evil_query->toArray()); to see the difference :)

Categories