CakePhp3 select() in query more than one tier - php

Is it possible to get columns of tables which are two or more tables remote by using select()?
$rooms = TableRegistry::get('Rooms')
->find()
->contain(['Levels.Buildings'])
->toArray();
... this works, but returns ervery column of the three tables
$rooms = TableRegistry::get('Rooms')
->find()
->select(['Buildings.name'])
->contain(['Levels.Buildings'])
->toArray();
... this returns nothing, althought the generated select statement seems to be correct

You can only select fields in the primary query if you are handling a one-to-one relationship (i.e. hasOne or belongsTo). This is presumably your issue. In which case you need to specify the fields to include from your has-many relationship in the contain itself:-
$rooms = TableRegistry::get('Rooms')
->find()
->contain([
'Levels' => [
'Buildings' => [
'fields' => 'name'
]
]
])
->toArray();
This is because CakePHP will perform a second separate query to retrieve the has-many associated model data for which you need to specify the query conditions within the contain.

Related

Laravel with([]) select only some columns of the relation

Edit
This question is unique because it poses unique problems such as:
relations within the with components. (items.product.stockManagement).
A large amount of components, this causes the accepted answers of the linked question to not apply.
Suppose you have a large with() like the following:
$order = Order::with([
'company',
'complaints',
'person',
'items',
'items.product',
'items.product.stockManagement',
'status',
])->findOrFail($id);
How can I then select with all their relations but specific columns for some of them?
$order = Order::with([
'company', // select only id,name, size
'complaints', // select only id, name , body
'person',
'items',
'items.product', // select only id, name , price
'items.product.stockManagement',
'status', // select only id
'items.product.media',
'items.product.mainProduct',
'items.product.mainProduct.media'
])->findOrFail($id);
Like this:
$order = Order::with([
'company:id,name,size',
'complaints:id,name,body',
'person',
'items',
'items.product:id,name,price',
'items.product.stockManagement',
'status:id',
'items.product.media',
'items.product.mainProduct',
'items.product.mainProduct.media'
])->findOrFail($id);
The documentation is very brief about the loading of specific columns (you even have to scroll down a bit to the heading that says "Eager Loading Specific Columns").
You may not always need every column from the relationships you are retrieving. For this reason, Eloquent allows you to specify which columns of the relationship you would like to retrieve:
$books = App\Book::with('author:id,name')->get();
Note:
When using this feature, you should always include the id column and any relevant foreign key columns in the list of columns you wish to retrieve.
You can also provide a callback for some more advanced relation querying.
Order::with([
'company' => function ($q) {
$q->select('id', 'name');
}
])
I faced the same problem. You need to specify the foreign id not id (primary key).
For example:
Data::with('other:id,name')->get();
It won't be working if you customize the foreign name.
So, you need to add your foreign column name completely.
Data::with('other:foreign_id,name')->get();
And that will work!
$order = Order::with(
['company' => function($query) {
$query->select('id','name','size')
}),
'complaints' => function($query) {
$query->select('id','name','body')
}),
'person',
'items',
'items.product' => function($query) {
$query->select('id','name','price')
}), 'items.product.stockManagement','status'=> function($query) {
$query->select('id')
}),'items.product.media', 'items.product.mainProduct', 'items.product.mainProduct.media'])->findOrFail($id);

Laravel query a model in a nested query?

I have an Appointment model that has a relation to Employee and an Employee to a User. I am trying to query a list of appointments between specific dates ($weekStart and $weekEnd) and retrieve the appointments as well as the related Employees and Users.
So far this works, it returns all my Clients with all appointments and the assigned Employees/Users (Employees belong to User).
'clients' => Client::with('careType','appointments.employees.user')->get(),
However I wish to specify between dates on the appointments model. So I have this:
$data = [
'clients' => Client::with(['appointments' => function ($query) use ($weekStart, $weekEnd) {
$query->whereBetween('starts_at', [$weekStart, $weekEnd]);
}])->get(),
];
In the above what is the syntax to also retrieve the employees and user models when I have a sub query?
You just add your other models in your Client's with() array.
$data = [
'clients' => Client::with(['appointments' => function ($query) use ($weekStart, $weekEnd) {
$query->whereBetween('starts_at', [$weekStart, $weekEnd]);
}, 'appointments.employees.user'])->get(),
];

Limit fields in result of Propel v2 query with left join

I'm using Propel ORM v2 to retrieve records from a table which is linked to records of another table using foreign key. I'd like to return only certain fields from both the parent table and the child table.
What is the best way to do this?
My table structure looks like this:
Table: User
- Id
- Name
- Age
- MaritalStatus
Table: Profile
- UserId (FK->User.Id)
- Street
- City
- State
- Country
- TelephoneNumber
I have tried the following but the query does not return the desired User object with children Profile objects and only the selected fields of Id, Name for the User object and TelephoneNumber for the Profile child objects:
\UserQuery()::create
->select(array('Id', 'Name', 'Profile.Telephonenumber'))
->leftJoinWithProfile()
->find()
->toArray();
Any advise is greatly appreciated
just took a quick look over Propel.
This select returns what you have asked for, ('Id', 'Name', 'Profile.Telephonenumber').
\UserQuery::create()
->join('Profile')
->select(array('Id', 'Name', 'Profile.Telephonenumber'))
->find()
->toArray();
//returns an array with values for 'Id','Name', 'Profile.Telephonenumber'
If you want all the entries of the 'User' table and entries from 'Profile' as a child array try this:
\UserQuery::create()
->join('User.Profile')
->find()
->toArray();
//returns an array with all the entries from 'User' table and an child array with entries from 'Profile' table.
Sorry if i made any mistakes, is my first answer on Stackoverflow.
Have a nice day,
M.I.
You should probably use withColumn(), e.g.
\UserQuery()::create()
->leftJoinWithProfile()
->withColumn('Profile.TelephoneNumber', 'TelephoneNumber')
->select(['Id', 'Name', 'TelephoneNumber'])
->find()
->toArray();

Condition for related table ORM Kohana

For example I have 3 tables:
songs(id, song_name)
song_category(id, song_id, category_id)
categories(id, name)
I want to get songs which have categories with id higher than 5. I want to do it using ORM, not with simple SQL query. Is it possible to do it with one query like this:
$songs = ORM::factory("songs")->where("category.id > 5")
No, you cannot do this with a single Kohana ORM call.
The best way I have found to do it is something like this, which makes a modification to the SQL query that the ORM will generate:
// Get the basic "song" model
$songs = ORM::factory("songs");
// Get the information about how it is connected to
// the "category" model using the `through` model
$song_relations = $results->has_many();
$category_relation = $song_relations['categories'];
$through = $category_relation['through'];
// Join on `through` model's target foreign key (far_key) and `target` model's primary key
$join_col1 = $through.'.'.$category_relation['foreign_key'];
$join_col2 = $songs->object_name().'.'.$songs->primary_key();
$songs->join($through)->on($join_col1, '=', $join_col2);
// Now, filter on the
$songs->where($through.'.'.$category_relation['far_key'], '>', 5);
$arr = $results->find_all()->as_array();
You could save some code by hardcoding the values in the join method call, but this way leverages the ORM relation definitions that you already have.
This assumes that your Song model has the following code in it:
protected $_has_many = [
'categories' => [
'model' => 'category',
'through' => 'song_category',
'foreign_key' => 'song_id',
'far_key' => 'category_id',
]
];

Kohana 3 ORM: How to get data from pivot table? and all other tables for that matter

I am trying to use ORM to access data stored, in three mysql tables 'users', 'items', and a pivot table for the many-many relationship: 'user_item'
I followed the guidance from Kohana 3.0.x ORM: Read additional columns in pivot tables
and tried
$user = ORM::factory('user',1);
$user->items->find_all();
$user_item = ORM::factory('user_item', array('user_id' => $user, 'item_id' => $user->items));
if ($user_item->loaded()) {
foreach ($user_item as $pivot) {
print_r($pivot);
}
}
But I get the SQL error:
"Unknown column 'user_item.id' in
'order clause' [ SELECT user_item.*
FROM user_item WHERE user_id = '1'
AND item_id = '' ORDER BY
user_item.id ASC LIMIT 1 ]"
Which is clearly erroneous because Kohana is trying to order the elements by a column which doesn't exist: user_item.id. This id doesnt exist because the primary keys of this pivot table are the foreign keys of the two other tables, 'users' and 'items'.
Trying to use:
$user_item = ORM::factory('user_item', array('user_id' => $user, 'item_id' => $user->items))
->order_by('item_id', 'ASC');
Makes no difference, as it seems the order_by() or any sql queries are ignored if the second argument of the factory is given.
Another obvious error with that query is that the item_id = '', when it should contain all the elements.
So my question is how can I get access to the data stored in the pivot table, and actually how can I get access to the all items held by a particular user as I even had problems with that?
Thanks
By default, all of Kohana's ORM models expect the table's primary key to be 'id.' You need to set $_primary_key in your model to something else.
$user_item = ORM::factory('user_item', array('user_id' => $user, 'item_id' => $user->items));
I think you need to provide a single item_id value for this to work, not an array of objects.
Also, to find all entries for a single user you should be able to do this:
$user_items = ORM::factory('user_item', array('user_id' => $user));
Does that answer your question?

Categories