Model associations for CakePHP - php

I'm new to CakePHP and having a bit of trouble figuring out how to set up model associations.
Say I have 3 tables: payments, reservations and reservation_details with the following data
table reservations
id | confirmation_number | guest_id
1 123 1
table reservation_details -a reservation can have multiple entries (multiple rooms)
id | reservation_id | date | time | room_id | rate
2 1 2014-18-04 13:00 1 9.99
3 1 2014-18-04 13:00 2 4.99
table payments - many payments for one reservation can be made
id | reservation_id | payment_amount | payment_type | guest_id
4 1 14.98 Cash 1
Here are my model Associations
//Reservation model
public $hasMany = array('ReservationDetail', 'Payment');
//ReservationDetail model
public $belongsTo = array('Reservation');
//Payment model
public $belongsTo = array('Reservation');
public $hasMany = array('ReservationDetail' => array('foreignKey' => 'reservation_id'));
What I'm trying to do is be able to search for a payment and it would return the corresponding reservation and reservation_details for that payment. So it would grab any records from reservation_details that share the same reservation_id. Right now the reservation is returned, but the reservation_details is returned empty
The following search returns information from payments and reservations, but an empty array from reservation_details.
$payment = $this->Payment->find('all',array(
'conditions' => array(
'Payment.guest_id' => '1'
)
));
I'm almost positive it's joining the reservation_details table on payments.id = payments.reservation_id rather than payments.reservation_id = reservation_details.reservation_id. When I manually change payments.id to 1 (the reservation_id value), then the reservation_details are returned.
I believe the MySQL query that I'm trying to achieve would be something like
SELECT reservations.*, reservation_details.*, payments.* from payments
INNER JOIN reservations on reservations.id = payments.reservation_id
INNER JOIN reservation_details on reservation_details.reservation_id = payments.reservation_ID
WHERE payments.guest_id = '1'

Payment.php
add containable behavior as-
public $actsAs = array('Containable');
PaymentsController.php
$payments = $this->Payment->find('all', array(
'conditions' => array(
'Payment.guest_id' => '1'
),
'contain' => array(
'Reservation' => array(
'ReservationDetail'
)
)
));
debug($payments);

Related

Cakephp 4: FIND_IN_SET not returning result

I have an array, $submenus, in my app that I implode to a delimited string:
$subs = implode(',', $submenus);
The string will look something like this: 'ml_,nc_,msr_'. These values are stored in a field called group_prefix in my submenus table. Each submenu row has a unique group_prefix.
The following code builds menus and submenus from a database:
$menus = $this->Menus->find('all', [
'order' => ['Menus.display_order ASC'],
'conditions' => $conditions,
'contain' => [
'Submenus' => [
'conditions' => [
'Submenus.status' => 1,
'FIND_IN_SET("' . $subs . '", Submenus.group_prefix)'
],
]
]
]);
$this->set('menus', $menus);
It works fine until I add the FIND_IN_SET condition on Submenus. When I do, I get no submenus returned, just the main menus. Debug confirms that the string is formatted propery. Doesn't error out, I just get no resultset.
When I run the submenus query in MySQL, it works.
set #prefixes = 'ml_,nc_,msr_';
SELECT `id`, `name` FROM `submenus` WHERE `status` = 1 AND FIND_IN_SET(`submenus`.`group_prefix`, #prefixes);
+----+---------------------------+
| id | name |
+----+---------------------------+
| 4 | Mission Lessons Module |
| 5 | MSR Module |
| 8 | Work Authorization Module |
+----+---------------------------+
What am I missing?
Answer was to reverse the order of arguments in FIND_IN_SET.

(Laravel/PHP) SQL Query that selects all orders from table that matches product_id and variation_id in array

Im trying to build a SQL Query that will select all orders from a table that matches options that i defined.
Databse i use: Mysql
Language: PHP
Basicly i have a array that looks like this.
[
[
"user_id" => 1,
"product_id" => 5548,
"variation_id" => 14
],
[
"user_id" => 1,
"product_id" => 5548,
"variation_id" => 15
],
[
"user_id" => 1,
"product_id" => 4422,
"variation_id" => 4
]
]
This means that the user(id: 1) has one product with the "id" of 5548, and then he also has 2 variations of that product that are "id" 14 and 15. You can also see that the same user owns the product(id:4422) that has variation(id:4).
I then have a "order_lines" table that looks like this
order_lines
+----+-----+---------+-----------------------------+
| id | uid | user_id | product_id | variation_id |
+----+-----+---------+-----------------------------+
| 1 | 1 | 1 | 5548 | 14 |
+----+-----+---------+-----------------------------+
| 2 | 2 | 1 | 5548 | 15 |
+----+-----+---------+-----------------------------+
| 3 | 3 | 1 | 4422 | 4 |
+----+-----+---------+-----------------------------+
| . | . | . | .... | .. |
+----+-----+---------+-----------------------------+
I now need a SQL Query that selects all the rows where there is a match between the user_id, product_id and variation_id that are defined in the array.
The output should contain all rows that meet these conditions.
I hope someone can pin me in the right direction.
I'm building in Laravel if you got the query builder just at your hand. Else i very much appreciate an SQL Query.
if I am getting you right, below code will help you, using just Core PHP
foreach($array as $arr){
$user_id = $arr['user_id'];
$prodct_id = $arr['prodct_id'];
$variation_id = $arr['variation_id'];
$query = "SELECT * FROM order_lines WHERE user_id = $userId AND product_id = $productId AND variation_id = $variationId";
$queryResult = mysql_fetch_assoc($query);
$yourCollection[] = $queryResult;
}
print_r($yourCollection);
Try below code to use Laravel Query Builder, below code will help you to get results for multiple users based on product and variation.
$qb_order_lines = DB::table('order_lines');
$where_condition = [
['user_id' => '', 'product_id' => '', 'variation_id' => ''],
];
foreach ($where_condition as $condition) {
$qb_order_lines->orWhere(function($query) use ($condition) {
$query->where('user_id', $condition['user_id'])
->where('product_id', $condition['product_id'])
->where('variation_id', $condition['variation_id']);
});
}
$obj_result = $qb_order_lines->get();
If you want to get it for only one user, use below code
$obj_result = DB::table('order_lines')
->where('user_id', $condition['user_id'])
->where('product_id', $condition['product_id'])
->where('variation_id', $condition['variation_id'])
->get();
You can modify the above query builders based on your requirements like select fields or group by.
Let me know if you need any help.
For anyone interesting.
My problem was that i needed to count of many matches that were between my array and my database.
Instead of selecting and outputting. I eneded up using sql count() function in a query, that did the job.

Codeigniter 4 query builder join display only 1 time from first table

I have done up a query builder using join. I would like to show table 2, 3, 4, 5, 6 and so on based on the user id on table 1. I tried to query the result, it is showing like this :
My Tables
Table users
user_id | username | email
1 | userA | userA#email.com
2 | userB | userB#gmail.com
Table add_game
game_id | user_id | ign | acc_id
1 | 1 | ignA | accA
2 | 1 | ignB | accB
1 | 2 | ignB | accB
3 | 2 | ignD | accD
I will be using foreach loop and I believe it will display out multiple times based on the records in the database. What should I do if I only want to display the information highlighted in the red box (which is from users table) just 1 time and all the records associated with user id in add_game table?
This is my current code :
Controller
public function login()
{
$data = [];
helper(['form']);
$validation = \Config\Services::validation();
$db = db_connect();
$model = new LoginModel($db);
$user = $model->login($this->request->getVar('userlogin'));
$this->setUserSession($user[0]);
echo view('templates/header', $data, $user);
echo view('account/login', $data, $user);
echo view('templates/footer', $data, $user);
}
private function setUserSession($user){
$data = [
'user_id' => $user['user_id'],
'username' => $user['username'],
'email' => $user['email'],
'firstname' => $user['firstname'],
'lastname' => $user['lastname'],
'dob' => $user['dob'],
'country' => $user['country'],
'country_code' => $user['c_code'],
'contact' => $user['contact'],
'game_id' => $user['game_id'],
'ign' => $user['ign'],
'acc_id' => $user['acc_id'],
'isLoggedIn' => true
];
session()->set($data);
return true;
}
Model:
return $this->db->table('users')
->groupStart()
->where('username', $str)
->orWhere('email', $str)
->groupEnd()
->join('add_game', 'add_game.user_id = users.user_id')
->get()
->getResultArray();
I have a few more tables but not yet created for now so I have only joined 1 table for the time being. What am I missing? Or do I have to loop twice? Is there a way that I just need to loop 1 time? Hope someone can help me out here. Thanks in advance guys!
the easiest way to achieve this (display 2 records from add_game table and 1 record from users table) you need to create a foreach loop in your view, and exclude duplicated data from users table to be shown.
controller:
$data['my_data']=$this->Your_model->your_method(); // your query example
$this->load->view('your_view',$data)
view:
<?php $my_id=0;foreach($my_data as $row):?>
<?php if($my_id!=$row->user_id):?>
<div><?=$row->username?></div> <!--data from table user-->
<div><?=$row->created_at?></div> <!--data from table add_game-->
<?php else:?>
<div><?=$row->created_at?></div> <!--only data from table add_game-->
<?php endif;?>
<?php $my_id=$row->user_id;endforeach;?>

CakePHP retrieve data from another Model

I am new to cakephp and I have a little problem about retrieving data from another model.
My table association is like this:
Items hasMany Stocks
Stocks belongsTo Items
Items belongsTo UnitMeasurement
UnitMeasurement hasMany Items
My problem is I want to show UnitMeasurement Name to Stocks index html table view.
Current Html table view:
----------------------------------------------------------------------
Item | Stock Balance| Unit | Created |
----------------------------------------------------------------------
Microprocessor | 12 | DISPLAY UNIT NAME HERE!| 19/1/2014 |
Microcontroller| 20 | DISPLAY UNIT NAME HERE!| 19/1/2014 |
CPU | 12 | DISPLAY UNIT NAME HERE!| 19/1/2014 |
----------------------------------------------------------------------
How do I make the succesful query ?
Thanks.
EDIT:
This is my find query in my StocksController index function:
public function index() {
$this->Stock->recursive = 0;
$order = "Stock.id DESC";
//set orderby
$stock = $this->Stock->find('all',array('order'=>$order));
$this->set('stocks', $stock);
//query to find UnitMeasurement Name for Stocks Item
foreach ($stock as $stocks) {
//debug($stocks);
$this->loadModel('Items');
$unitMeasurement = $this->Items->find('first',array('fields'=>'unit_measurement_id','conditions'=>array('Items.id'=>$stocks['Stock']['item_id'])));
$this->set('units',$unitMeasurement);
}
}
Thanks again.
check this model name always singular please check and let me know if it works !
foreach ($stock as $stocks) {
//debug($stocks);
//$this->loadModel('Items');
$this->loadModel('Item');
$unitMeasurement = $this->Item->find('first',array('fields'=>'unit_measurement_id','conditions'=>array('Item.id'=>$stocks['Stock']['item_id'])));
$this->set('units',$unitMeasurement);
}
You could make a query like this:
$items = $this->Item->find('all', array(
'fields' => array(
'Item.name',
'SUM(Stock.amount) as amount',
'UnitMeasurement.name',
'Item.created',
),
'joins' => array(
array(
'table' => "stocks",
'alias' => "Stock",
'conditions' => "Item.id = Stock.item_id"
),
array(
'table' => 'unit_measurements',
'alias' => 'UnitMeasurement',
'conditions' => 'UnitMeasurement.id = Item.unit_measurement_id',
),
),
'group' => array('Item.id', 'Item.unit_measurement_id'),
));

CakePHP Many to One - single table

I have a Members table:
Members(id, name, gender, head_id)
What I want is to make family relationships based around the head of household (who is a member).
So its like: One member belongs to one Family (defined by a member)
Maybe I could split it into 2 tables, a Members and Families table:
Families(id, head_id)
and the Members table would have a family_id instead of head_id.
The main problem would be on adding new members and modifying the relationships.
EDIT:
All the answers were great.
I ended up doing it manually. Dave's solution is what I was looking for, but didn't workout exactly the way I was hoping.
See "Multiple Relations to the Same Model"
"It is also possible to create self associations as shown below:"
class Post extends AppModel {
public $belongsTo = array(
'Parent' => array(
'className' => 'Post',
'foreignKey' => 'parent_id'
)
);
public $hasMany = array(
'Children' => array(
'className' => 'Post',
'foreignKey' => 'parent_id'
)
);
}
From a Database point of view, I consider you should have 3 tables:
persons (id, passport_number, name, dob, ...)
families (id, father_id, mother_id, surname, number_of_members,... )
families_persons (family_id, person_id)
A family is defined as the union of two persons and might have some other common fields such as surname.
Anyway, if you do it in your way, you can do it with one only table. (father with head_id set to 0, and the rest of the family members with head_id referring to his id.
In case you want to use two tables, controllers can use more than one Model, so it is not a problem to deal with more table in the save action.
You should have two tables. That is the best way, and will offer you the most flexibility and ease of use within your application.
Database Tables
// families
id | name
------------------------------
1 | Smith
2 | Jones
3 | Davis
// members table
id | family_id | name | gender
-----------------------------------
1 | 2 | James | M
2 | 3 | Christine | F
3 | 1 | David | M
4 | 2 | Mark | M
5 | 1 | Simon | M
6 | 1 | Lucy | F
CakePHP Models
Then you just need to define your models so they have the correct relationships.
// app/Model/Family.php
class Family extends AppModel {
public $hasMany = array('Member');
}
// app/Model/Member.php
class Member extends AppModel {
public $belongsTo = array('Family');
}
Then you can retrieve your families like this:
CakePHP Controller
// Find all members that belong to Family 1
$family = $this->Member->find('all', array(
'conditions' => array('family_id' => 1)
));
OR
// Find Family 1 and get all its members
$family = $this->Family->find('first', array(
'conditions' => array('family_id' => 1),
'contain' => array('Member')
));
You shouldn't have any problems with adding new members or modifying the relationships, like you are worried about, but if you run into any specific problems we can likely help you. This kind of model relationship is extremely common.

Categories