Doctrine: select rows that are related to another table - doctrine

I have two tables: assignment and file that is related to assignment. I would like to get rows of assignment that are related to any row of file applying the where sentence.
$querybuilder = $this->createQueryBuilder('query');
$querybuilder
->select('assignment')
->from(AssignmentReadModel::class, 'assignment')
->innerJoin('assignment.files', 'files')
->where('files.name=:archivo')
->setParameter('archivo', 'practica');
$data = $querybuilder->getQuery()->getResult();
$files = $data[0]->files();
var_export($files->count());
With this query I'm getting all the files when it should only get only one file "practica". When I execute "$files->count()" doctrine is doing a extra query to get all the files.

In query, no columns of the files entity are selected, so this is not part of the result rows and thus the relation is not hydrated.
To get the filtered files, select also the files relation:
$querybuilder
->select('assignment')
->addSelect('files')
A word of caution
Once a relation has been hydrated, this hydrated collection is used for this entity for other queries(reference all result row doesn't fetch in object, unless you choose to
1) refresh the collection:
$em->refresh($assignment);
and also include refrech option on cascade operations of the relation definition:
#OneToMany(targetEntity="File", mappedBy="assignment", cascade={"refresh"})
or
2) when using query builder to set:
use Doctrine\ORM\Query;
$querybuilder->setHint(Query::HINT_REFRESH, true); // <-- Tell the hydrator to refresh

Related

How to get the list of inserted ids from the insert() method to use with the syncWithoutDetaching() method?

I have Files and Folders models that are related by a many-to-many relationship with a folder_file pivot table.
I want to insert files in bulk using the insert() method, then use the list of inserted ids with the syncWithoutDetaching() method to update the pivot table, | first create the $data_array in a foreach loop that does other things as well:
$data_array = [];
foreach (...) {
// ...
$data_array[] = $row;
}
then I want to insert the data and update the pivot table:
File::insert($data_array);
$folder->files()->syncWithoutDetaching($array_of_inserted_ids);
Is it possible to get the list of inserted ids from the insert() method?
Or maybe there is a more efficient way for better DB performance?
At first I just wanted to create the record and update the pivot table inside the foreach loop that creates the $data_array so that on every iteration it would create and update the tables, but that could be bad for performance with that many queries?
You could use the createMany() here. Instead of inserting the files then get the ids of inserted data. It will accept an array of data so that you could directly insert your array of files then connecting them to the folder.
$folder->files()->createMany($data_array);

Partial select of left joined table with doctrine query builder

When querying one table using the doctrine query builder a partial select can be written like this:
$queryBuilder = $this->createQueryBuilder('person');
$queryBuilder->addSelect('partial person.{id, name}');
How can one write a partial select be written for a left joined table? I tried something like this, but can't figure out the correct syntax:
$queryBuilder = $this->createQueryBuilder('person');
$queryBuilder->join('person.address');
$queryBuilder->addSelect('partial person.{id, name} person.address.city'); // ???
My goal would be to select only parts of the Person and the Address object when executing the query to be more memory efficient.
Your syntax is off for your join operation. You have to give an alias when using join. From there, you can just use the same syntax to query your partial Address object:
// In a method of PersonRepository
$qb = $this->createQueryBuilder('person')
->select(['partial person.{id, name}', 'partial address.{id, city}'])
->join('person.address', 'address');
Notice that I added id to the fields retrieved for Address. If you don't, Doctrine will give you the following error:
Error: The partial field selection of class Path\To\Entity\Address must contain the identifier
As a side note, you said you wanted to write this select for a left joined table. If you want to perform a LEFT JOIN, you need to use leftJoin instead of join (the signature of both methods is the same).

Laravel query builder - Select elements unique or null on specific column

I have a model Form for table forms. There is a column called guid which can be null, or contain some sort of grouping random hash.
I need to select all forms that have column guid either null or unique in current search. In other words, for repeating guid values in current search I select only first occurence of every guid hash.
I tried:
$results = App\Form::where(... some where clauses .. ).groupBy('guid')
and it's almost ok, but for all rows, where guid == NULL it groups them and selects only one (and I need all of them).
How can I get the unique or null rows either by building proper SQL query or filtering the results in PHP?
Note: I need my $results to be an Illuminate\Database\Eloquent\Builder instance
EDIT:
I fount out that SQL version of query I need is:
SELECT * FROM `forms` WHERE .... GROUP BY IFNULL(guid, id)
What would be equivallent query for Laravel's database query builder?
UPDATE: Using DB::raw
App\Form::where(... conditions ...)
->groupBy(DB::raw("IFNULL('guid', 'id')"));
Or the another way could be:
You can also use whereNotNull, whereNull & at last merge both the collections using merge() like this:
First get the results where guid is grouped by (excluding null guid's here):
$unique_guid_without_null = App\Form::whereNotNull('guid')->groupBy('guid')->get();
Now, get the results where guid is null:
$all_guid_with_null = App\Form::whereNull('guid')->get();
and at last merge both the collections using merge() method:
$filtered_collection = $unique_guid_without_null->merge($all_guid_with_null);
Hope this helps!
For your edited question, you can use raw() as;
->groupBy(DB::raw("IFNULL('guid', 'id')"))
So your final query will be as:
$results = App\Form::where(... some where clauses .. )
->groupBy(DB::raw("IFNULL('guid', 'id')"));
By above query, your $results will be an instance of Illuminate\Database\Eloquent\Builder.

Mulitple LIKE db query using associative array- but all from the same column name...?

I'm trying to query my database using CodeIgniter's active record class. I have a number of blog posts stored in a table. The query is for a search function, which will pull out all the posts that have certain categories assigned to them. So the 'category' column of the table will have a list of all the categories for that post in no particular order, separated by commas, like so: Politics, History, Sociology. etc.
If a user selects, say, Politics, and History, The titles of all the posts that have BOTH these categories should be returned.
So, the list of categories queried will be the array $cats. I thought this would work-
foreach ($cats as $cat){
$this->db->like('categories',$cat);
}
By Producing this:
$this->db->like ('categories','Politics');
$this->db->like ('categories','History');
(Which would produce- 'WHERE categories LIKE '%Politics%' AND categories LIKE '%History%')
But it doesn't work, it seems to only produce the first statement. The problem I guess is that the column name is the same for each of the chained queries. There doesn't seem to be anything in the CI user guide about this (http://codeigniter.com/user_guide/database/active_record.html) as they seem to assume that each chained statement is going to be for a different column name.
Of course it is not possible to use an associative array in one statement as it would have to contain duplicate keys- in this case every key would have to be 'categories'...
With regard to MySQL, I just ran the following query on my database and there were no issues.
SELECT *
FROM `TicketUpdates`
WHERE content LIKE '%update%'
AND content LIKE '%footprints%';
Likewise the following code ran as expected:
$this->db->select('*');
$this->db->from('TicketUpdates');
$this->db->like('content', 'update');
$this->db->like('content', 'footprints');
print_r($this->db->get()->result());
If you're using the 'like' function in CI, you have to prefix and postfix them with the proper query functions, example:
$this->db->select('*');
$this->db->from('tablename');
foreach($cats as $cat){
$this->db->like('categories', $cat);
}
$result = $this->db->get();
you can use following code
$this->db->select("*")->from($table);
foreach($cats as $single_name)
$this->db->or_like("categories",$single_name);
$result = $this->db->get();

Doctrine toarray does not convert relations

I followed doctrine documnetation to get started. Here is the documentation.
My code is
$User = Doctrine_Core::getTable("User")->find(1);
when I access relations by $User->Phonenumbers, it works. When I convert User object to array by using toArray() method, it does not convert relations to array. It simply display $User data.
Am I missing something?
By using the find method you've only retrieved the User data which is why the return of toArray is limited to that data. You need to specify the additional data to load, and the best place to do this is usually in the original query. From the example you linked to, add the select portion:
$q = Doctrine_Query::create()
->select('u.*, e.*, p.*') // Example only, select what you need, not *
->from('User u')
->leftJoin('u.Email e')
->leftJoin('u.Phonenumbers p')
->where('u.id = ?', 1);
Then when toArray'ing the results from that, you should see the associated email and phonenumber data as well.
I also noticed an anomaly with this where if you call the relationship first then call the ToArray, the relationship somehow gets included. what i mean is that, taking your own eg,
$User = Doctrine_Core::getTable("User")->find(1);
$num= $User->Phonenumbers->office; // assumed a field 'office' in your phone num table
$userArray = $user->toArray(true);
In the above case, $userArray somehow contains the whole relationship. if we remove the $num assignment it doesn't.
am guessing this is due to doctrine only fetching the one record first, and it's only when you try to access foreign key values that it fetches the other related tables

Resources