Doctrine ResultSetMapping ignores entity - php

In doctrine, I want to fetch multiple entities from a native query. But I can't workout how to do it.
I have 3 entities: WBSOProject, Employee and WBSOBooking. Employees can log their work hours through a WBSOBooking entity which couples the Employee with a WBSOProject and it has an extra field for the logged hours.
To generate an overview of the worked hours per employee per project I've written the following code:
$query = "
select
project.id as project_id,
project.name,
employee.id as employee_id,
employee.bsn,
employee.name,
sec_to_time(sum(time_to_sec(wbsoBooking.total))) as balance
from wbso_projects project
inner join wbso_bookings as wbsoBooking on wbsoBooking.project_id = project.id
inner join employees as employee on employee.id = wbsoBooking.employee_id
group by project.year, project.name, employee.id, employee.name
";
$rsm = new ResultSetMapping();
$rsm
->addEntityResult("Kloktijden\\Model\\Entities\\WBSOProject", "project")
->addFieldResult("project", "project_id", "id")
->addFieldResult("project", "name", "name")
->addEntityResult("Kloktijden\\Model\\Entities\\Employee", "employee")
->addFieldResult("employee", "employee_id", "id")
->addFieldResult("employee", "bsn", "bsn")
->addFieldResult("employee", "name", "name")
->addScalarResult("balance", "balance");
$result = Model::getEntityManager()
->createNativeQuery($query, $rsm)
->getResult();
My desired result would be an array like this:
array(
[0] => array(
[0] => Kloktijden\\Model\\Entities\\WBSOProject,
[1] => Kloktijden\\Model\\Entities\\Employee,
"balance" => "00:00"
)
)
But somehow the Employee entity gets ignored, so my result looks like this:
array(
[0] => array(
[0] => Kloktijden\\Model\\Entities\\WBSOProject,
"balance" => "00:00"
)
)
So, my question is: why doesn't my resultset contain the Employee entity? And how can I fix this?

Related

Laravel DB::select() does not return "correct" data

I am using Laravel 8.12
I am doing a DB::select() call with DB::raw() method filtering. But for convenience I will post full statement with values as well.
Here is the PHP code for query
$sql = "SELECT `medium_info`.* , `postings`.`posting_timestamp` FROM `postings` INNER JOIN `medium_info` ON `postings`.`medium_info_id` = `medium_info`.`id` INNER JOIN `accounts` ON `accounts`.`id` = `postings`.`account_id` INNER JOIN `merchants` ON `merchants`.`account_holder_id` = `accounts`.`account_holder_id` INNER JOIN `medium_types` ON `medium_types`.`id` = `accounts`.`medium_type_id` WHERE `merchants`.`account_holder_id` = :merchant_account_holder_id AND `medium_info`.`id` = :medium_info_id AND `medium_types`.`id` = :medium_types_id";
$result = DB::select ( DB::raw($sql), ['merchant_account_holder_id'=>230124, 'medium_info_id'=>551678, 'medium_types_id'=>1] );
When I print $result it gives me data like this:
[0] => stdClass Object
(
[id] => 230124
[purchase_date] => 2020-11-22
[redemption_date] =>
[expiration_date] =>
[hold_until] => 2021-05-07 02:30:08
...more medium_info data here
[posting_timestamp] => 2020-11-25 23:27:13
...merchants table data which I did not request
[account_holder_id] => 230124
[name] => Best Buy
[logo] => /cdn/merchants/230124/logo.png
If I do the following, results are still same:
$sql = "SELECT `medium_info`.* , `postings`.`posting_timestamp` FROM `postings` INNER JOIN `medium_info` ON `postings`.`medium_info_id` = `medium_info`.`id` INNER JOIN `accounts` ON `accounts`.`id` = `postings`.`account_id` INNER JOIN `merchants` ON `merchants`.`account_holder_id` = `accounts`.`account_holder_id` INNER JOIN `medium_types` ON `medium_types`.`id` = `accounts`.`medium_type_id` WHERE `merchants`.`account_holder_id` = 230124 AND `medium_info`.`id` = 551678 AND `medium_types`.`id` = 1";
$result = DB::select ( $sql));
However when I run this query in phpMyAdmin it gives me 'correct' results with "id" from medium_info table. Here is a screenshot:
I want to add here that results received via DB::select() query has "merchants" row attached which I did not request in my query. Even if I just do SELECT `postings`.`posting_timestamp` FROM... request it would give me this result:
Array
(
[0] => stdClass Object
(
[posting_timestamp] => 2020-11-25 23:27:13
[account_holder_id] => 230124
[id] => 230124
[name] => Best Buy
[logo] => /cdn/merchants/230124/logo.png
[description] => <p>When technology meets life, they come together at Best Buy®. Best Buy has the technology that’s fun and functional, from tablets and videogames, to appliances and big screen TVs. Use your gift card at BestBuy.com® or at any US Best Buy store.</p>
[website] => http://www.bestbuy.com
[merchant_code] => BES
[is_premium] => 1
[large_icon] => /cdn/merchants/230124/large_icon.png
[status] => 1
[get_gift_codes_from_root] => 0
[website_is_redemption_url] => 0
[cost_to_program] => 0
[toa_name] =>
)
)
So obviously it is attaching "merchants" row no matter what I "SELECT". Also, notice that there is [id] => 230124 which is coming from "nowhere", there is no field id in merchants table. There is an id field in medium_info table but it should have returned 551678 not 230124 which is merchant id with field name account_holder_id in merchants table.
Edit: Just want to add that it does not attach merchants data when I run it in phpMyAdmin.
I am still trying to figure this out. If you need more info I am ready to provide. This must be something to do with Laravel DB::select conventions which I am not understanding, since it works in phpMyAdmin? Any help is appreciated.
Try this mate, using query builder :
\DB::table('postings')
->join('medium_info', 'postings.medium_info_id', '=', 'medium_info.id')
->join('accounts', 'postings.account_id', '=', 'accounts.id')
->join('merchants', 'merchants.account_holder_id', '=', 'accounts.account_holder_id')
->join('medium_types', 'medium_types.id', '=', 'accounts.medium_type_id')
->where('merchants.account_holder_id', 230124)
->where('medium_info.id', 551678)
->where('medium_types.id', 1)
->select('medium_info.*', 'postings.posting_timestamp')
->get();
It may help to check which SQL Laravel is actually running on your database.
The snippet bellow allows you to see just that.
<?php
DB::listen(function ($query) {
var_dump($query->sql);
});
Route::get('/', function () {
DB::select('SELECT * FROM users');
});
Also check barryvdh/laravel-debugbar extension.

Php mysql join to subarray with field names

I trying to join table using ONE query into sub array with column name => column value..
Short table(1) "users" structure with data:
user_id email ...
1 xxx#xx.xx ...
2 yyy#yy.yy ...
Short table(2) "users_permissions" structure with data:
user_id plugin_enter offers_view ...
1 1 0 ...
2 1 1 ...
If i use classic method - join left
SELECT `uperms`.*, `u`.*
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
I get classic output
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'plugin_enter' => 1,
'offers_view' => 0
),
[1] = array(
'user_id' => 2,
'email' => yyy#yy.yy,
'plugin_enter' => 1,
'offers_view' => 1,
...
),
All i need is output into subarray as this:
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'permissions => array(
'plugin_enter' => 1,
'offers_view' => 0
),
),
...
Is this possible to do with ONE query?
Table2 (permissions) contains about 60 columns. Is possible to CONCAT column's names with column value, if is joined to Table1 only one row?
MySQL doesn't have arrays or nested structures, so it's not possible to do this in SQL.
Change your query so you give all the fields from users_permissions a consistent naming style. Then you can use a PHP loop to collect all the array elements whose keys match that pattern into the permissions array.
Query:
SELECT u.*, up.plugin_enter AS perm_plugin_enter, up.offers_view AS perm_offers_view, ...
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
PHP:
foreach ($all_results as &$row) {
$permissions = array();
foreach ($row as $key => $value) {
if (strpos($key, 'perm_') === 0) {
$permission[substr($key, 5)] = $value;
unset($row[$key]);
}
}
$row['permissions'] = $permissions;
}
You could do it by concatenating all the column names and values in the table:
SELECT u.*, CONCAT_WS(',', CONCAT('plugin_enter:', plugin_enter), CONCAT('offers_view:', offers_view), ...) AS permissions
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
Then your PHP code can use explode() to split $row['permissions'] into array of name:value pairs, and then convert those to key=>value in the PHP array.
Another solution is to redesign your users_permissions table:
user_id permission_type value
1 plugin_enter 1
1 offers_view 0
...
2 plugin_enter 1
2 offers_view 1
...
Then you can query:
SELECT u.*, GROUP_CONCAT(permission_type, ':', value) AS permission
FROM users AS u
JOIN users_permissions AS up on u.user_id = up.user_id
Another possible sollution is to add prefixes to query.
Inspired by post: https://stackoverflow.com/a/9926134/2795923
SELECT `u`.*, ':prefix_start:', `uperms`.*, ':prefix_end:'
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
Output array looks like this:
[0] => array(
'user_id' => 1
'email' => xxx#xx.xx,
'prefix_start' =>
'plugin_enter' => 1,
'offers_view' => 0
'prefix_end' =>
)
...
Then easy PHP script to add all array data between prefix_start and prefix_end into own subarray.

PDO: group a property instead of duplicate lines

Good morning,
I have a request that return me several information for a reservation and each reservation can be linked to several room.
Is it possible to have an array of room instead of duplicate the line each time they are multiple rooms for a reservation.
What I want:
[
idReservation1 => [
"client_name" => "kévin titi",
"checkin" => "2017-08-08",
"d_checkout" => "2017-08-10",
"email" => "titi#gmail.com",
room_id => [1,2,3,9]//here I want an array
],
idReservation2 => [
"client_name" => "firstname lastname",
"checkin" => "2017-08-18",
"d_checkout" => "2017-08-20",
"email" => "toto#gmail.com",
"room_id" => [1,12,13,9]//here I want an array
]
]
if the idReservation is not the key does not matter, the important here is to have an array for room_id
I have looked all PDO fetch modes but they don't seems to match to my problem.
My request:
$prep = $this->pdo->prepare("
SELECT re.id as resId, re.client_name, re.d_checkin, re.d_checkout, re.mail, ro_re.room_id as room
FROM Reservation re
JOIN Room_Reservation ro_re ON ro_re.reservation_id = re.id
WHERE re.confirmed = false
");
Thanks
Assuming that you are working with MySql: the solution using GROUP_CONCAT function(to group room ids for each reservation):
$stmt = $this->pdo->prepare("
SELECT
re.id as resId, re.client_name, re.d_checkin, re.d_checkout, re.mail,
GROUP_CONCAT(ro_re.room_id SEPARATOR ',') AS room_ids
FROM
Reservation re
INNER JOIN Room_Reservation ro_re ON ro_re.reservation_id = re.id
WHERE re.confirmed = false
GROUP BY re.id
");
$stmt->execute();
// `room_ids` column will contain a string like "1,2,3,9"
$result = [];
foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) {
$row['room_ids'] = explode(',', $row['room_ids']); // converting string with room ids into array
$result[] = $row;
}

Retrieving result from multiple many to many relation tables with limit [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Table relations image is in this link http://www.serofero.net/mvb-table-relation.png
I am using php as server side programming language and MySQL as database.
Problem Description
User adds a new venue. One venue may have multiple beverages, events, features so on and so forth. Now , I want such a query or magic so that I could collect all the beverages, events, features, foods, styles, types, event_options and space_requirements related to each venue along with its venue_id, name, description, capacity, min_rate, max_rate, location (from locations table). Also I need to offset and limit the result so that I could implement pagination in backend. But the challange is that the limit should limit the number of venues not its beverages, foods, styles etc.
I am also wondering to collect the result in php array as below:
$result = array(
0=> array(
"name" => "Venue A",
"description" => "Venue A description",
"capacity" => "Venue A capacity",
"location" => "Venue A location",
"beverages" => array('beverage1','beverage23','beverage7',...),
"events" => array('event8','event17','event19','event4',...),
"features" => array('features1',...),
"foods" => array(),
"styles" => array(),
"types" => array('type7', 'type14', 'type23',...),
"event_options" => array(),
"space_requirements" => array()
)
,
1=> array(
"name" => "Venue B",
"description" => "Venue B description",
"capacity" => "Venue B capacity",
"location" => "Venue B location",
"beverages" => array('beverage1'),
"events" => array('event2','event7','event9','event4',...),
"features" => array(),
"foods" => array(),
"styles" => array('style1', 'style2',...),
"types" => array('type47', 'type4', 'type3',...),
"event_options" => array(),
"space_requirements" => array()
)
);
Today is 5th day I am trying to figure out the solution but I have been failed all the time. Below is the snippet of MySQL Query that I could write till now.
SELECT v.name, e.event, t.type, s.style
FROM venues v
LEFT JOIN venue_events ve ON v.venue_id = ve.venue_id
LEFT JOIN events e ON e.event_id = ve.event_id
LEFT JOIN venue_types vt ON v.venue_id = vt.venue_id
LEFT JOIN types t ON t.type_id = vt.type_id
LEFT JOIN venue_styles vs ON v.venue_id = vs.venue_id
LEFT JOIN styles s ON s.style_id = vs.style_id
WHERE v.venue_id IN (SELECT venue_id FROM venues) LIMIT 0,5
/* I want to limit the number of "venues" but the LIMIT 0,5 limits the number of 'events', 'types' , 'styles' the "venue" have. And this is the main problem.
I have also tried :
WHERE v.venue_id IN (SELECT venue_id FROM venues LIMIT 0,5) but it raises the MySQL error.
*/
But I dont know what to do next to get the result as I mentioned above.
Please help me.
Thankyou.
SELECT DISTINCT ven.venue_id, ven.name, e.event_id, e.event, t.type_id, t.type, s.style_id, s.style
FROM (SELECT * FROM venues v LIMIT 0,5) ven /*This line does magic for me*/
LEFT JOIN venue_events ve ON ven.venue_id = ve.venue_id
LEFT JOIN events e ON e.event_id = ve.event_id
LEFT JOIN venue_types vt ON ven.venue_id = vt.venue_id
LEFT JOIN types t ON t.type_id = vt.type_id
LEFT JOIN venue_styles vs ON ven.venue_id = vs.venue_id
LEFT JOIN styles s ON s.style_id = vs.style_id

Cakephp custom query with left join table rows as nested arrays

I'm trying to get nested arrays for my Cakephp custom query below:
$this->query("
SELECT *
FROM group_buys GroupBuy
LEFT JOIN products Product
ON Product.id = GroupBuy.product_id
LEFT JOIN group_buy_users GroupBuysUser
ON GroupBuysUser.group_buy_id = GroupBuy.id
LEFT JOIN group_buy_images GroupBuyImage
ON GroupBuyImage.group_buy_id = GroupBuy.id
LEFT JOIN product_details ProductDetail
ON ProductDetail.product_id = Product.id
LEFT JOIN specifications Specification
ON Specification.id = ProductDetail.specification_id
LEFT JOIN specification_categories SpecificationCategory
ON SpecificationCategory.id = Specification.specification_category_id
WHERE GroupBuy.id = {$id}
");
Problem with this is that it comes up with redundant data obviously with GroupBuy table row values repeating which I don't want.
Is there a way we can have nested arrays if LEFT JOINED table has more rows than the former table with Cake's custom query?
I know this can be done with find recursive = 2 but would like to achieve this with custom query.
Have you tried using containable?
$this->GroupBuy->Behaviors->attach('Containable');
$this->GroupBuy->find('all', array(
'conditions' => array('GroupBuy.id' => $id),
'contain' => array(
'Product' => array(
'ProductDetail' => array(
'Specification' => array(
'SpecificationCategory'
)
)
),
'GroupBuysUser',
'GroupBuyImage'
),
));

Categories