Howto make this relation work in MYSQL or Laravel - php

I'm no amazing with MYSQL at all, however laravel framework has made it very easy for me to get what i need as long as i know the basics.
So this question will first aim towards the MYSQL people, because i would rather figure out how to achieve this in plain MYSQL, and then convert it into laravel queries after.
I have 4 tables that need to be used in this query, as seen below:
1. products
id | name | description | price
2. customers
id | fname | lname | email | telephone
3. orders
id | customer_id | total_price | status
4. order_items
id | order_id | product_id | quantity | price
So i am creating an orders page on my web application. On this page it will show a list of all orders, including the order_items to that particular order. It will also include which customer this order belongs to.
I have managed to achieve the above using laravel, and i get the array seen below:
Array
(
[0] => Array
(
[id] => 9
[customer_id] => 16
[total_price] => 103.96
[status] => new
[created_at] => 2016-02-24 03:06:41
[customer] => Array
(
[id] => 16
[fname] => firstname
[lname] => lastname
[email] => firstname.lastname#gmail.com
[telephone] => 07707707707
[address_line_1] => Warstone Rd, walsall
[address_line_2] => Wolverhampton
[postcode] => WV10 7LX
)
[order_item] => Array
(
[0] => Array
(
[id] => 1
[order_id] => 9
[product_id] => 44
[quantity] => 1
[price] => 50.00
)
[1] => Array
(
[id] => 2
[order_id] => 9
[product_id] => 46
[quantity] => 2
[price] => 31.98
)
[2] => Array
(
[id] => 3
[order_id] => 9
[product_id] => 48
[quantity] => 1
[price] => 7.99
)
[3] => Array
(
[id] => 4
[order_id] => 9
[product_id] => 51
[quantity] => 1
[price] => 13.99
)
)
)
)
Now the part i am having trouble with is getting the products that relate to the order_items.
So far it has worked for me because i have been doing thinking like this
$order = Order::find($id)->with('customer','orderItem')->get()->toArray();
This works easy because an order has a customer_id field and an order_items has an order_id. But for me to get the products i need to join products to order_items.
If any one is good at MYSQL and can provide me a query to study and then convert into laravel that would be great.
If anyone knows laravel 5, well this is all the laravel stuff below:
Order.php
public function customer(){
return $this->belongsTo('App\Customer');
}
public function orderItem(){
return $this->hasMany('App\OrderItem');
}
OrderItem.php
public function order(){
$this->belongsTo('App\Order');
}
public function product(){
$this->hasOne('App\Product');
}
Product.php
public function orderitem(){
$this->hasOne('App\OrderItem');
}
Customer.php
public function orders(){
$this->belongsTo('App\Order');
}
As you can see above are my modal relationships i have set up.
This is my controller where i try to get the full array.
public function show($id)
{
$order = Order::find($id)->with('customer','orderItem','product')->get()->toArray();
echo "<pre>";
print_r($order);
echo "</pre>";
}
The error i receive is:
call to undefined method Illuminate\Database\Query\Builder::product()
If i remove the ->with('customer','orderItem','product') and change it to ->with('customer','orderItem') i get the array posted above.
Does anyone know how i can achieve this please?

You are on the right part the only mistake you are doing is you are calling product on the order model which has no direct relation with it. You have to call the product model through the orderitem model like this
Order::find($id)->with('customer','orderItem.product')->get()->toArray()

Related

Retrieve multiple rows from multiple tables

I am trying retrieve multiple rows from multiple tables but I think I am not doing it in the right way. The project is kind of a shop online, I have 3 tables in it: orders, orderdetails and services, which all are linked with an ID:
I have Order ID and Service ID in orderdetails' table, it means I inserts a row for each item on the basket linked to Service ID to see which service is, and Order Id to check for which order are. Example:
services table
-
service_id|name |price
------------------------
2 |Tech |100
------------------------
4 |Support|150
------------------------
10 |Mainten|50
------------------------
orders table
-
order_id|customer_id|name|lastname
----------------------------------
10 |16 |John|Smith
----------------------------------
orderdetails table
-
orderdetails_id|order_id|service_id|price|quantity
--------------------------------------------------
1 |10 |2 |100 |4
--------------------------------------------------
2 |10 |4 |150 |2
--------------------------------------------------
3 |10 |10 |50 |1
--------------------------------------------------
I inserts service's price on orderdetails table because maybe the services price can change AFTER a customer order it.
At this moment I have this query:
$query = $this->db->prepare(
'SELECT orders.*, orderdetails.*, services.*
FROM orders
LEFT JOIN orderdetails
ON orderdetails.order_id = orders.order_id
LEFT JOIN services
ON orderdetails.service_id = services.service_id
WHERE orders.order_id = ?
AND orders.customer_id = ?');
And I got this result:
stdClass Object
(
[order_id] => 10
[customer_id] => 16
[name] => Tech
[lastname] => Smith
[orderdetails_id] => 1
[service_id] => 2
[price] => 100
[quantity] => 4
)
stdClass Object
(
[order_id] => 10
[customer_id] => 16
[name] => Support
[lastname] => Smith
[orderdetails_id] => 2
[service_id] => 4
[price] => 150
[quantity] => 2
)
stdClass Object
(
[order_id] => 10
[customer_id] => 16
[name] => Mainten
[lastname] => Smith
[orderdetails_id] => 3
[service_id] => 10
[price] => 50
[quantity] => 1
)
I have two problems. The 1st problem is I have the same column name in orders table and services table. The 2nd is the query returns all the information (because I know I am not querying well), but I expect to receive something like this:
stdClass Object
(
[order_id] => 10
[customer_id] => 16
[name] => John
[lastname] => Smith
[orderdetails_id] => 1
[service_id] => 10
[price] => 50
[quantity] => 1
[service_name] => Mainten
[orderdetails_id2] => 2
[service_id2] => 4
[price2] => 150
[quantity2] => 2
[service_name2] => Support
[orderdetails_id3] => 3
[service_id3] => 2
[price3] => 100
[quantity3] => 4
[service_name3] => Tech
)
I mean, I am not an expert in SQL Queries, and I read a lot, but I think you guys could help me to figure it out this because I have other two tables to link with: customer-service-worker who will get the order to process, and area's table who will receive the order.
I use this code for getting the objects:
$array = array();
while($loop = $result->fetch_object()){ $array[] = $loop; }
return $array;
The problem is that you are using fetch_object() for getting the result but you are not renaming in the query the columns with the same name, and since you can't have two different object attributes with the same name the rest of columns are discarded.
You can either use other method for getting the values like fetch_row() or change the query to rename columns with the same name, for example:
SELECT orders.*, orderdetails_id, service_id, orderdetails.price as detail_price, quantity,
services.name as service_name, services.price as service_price
FROM orders
LEFT JOIN orderdetails ON orderdetails.order_id = orders.order_id
LEFT JOIN services ON orderdetails.service_id = services.service_id
WHERE orders.order_id = ?
As a side note if order_id is the primary key of orders you don't need to use customer_id in the where condition, and if the primary key is composed of both columns (i.e., you can have the same order ID for different customers) I recommend change it and use only order_id.

How to save special array data into Three MySQL table in PHP

I have JSON which need to insert into MySQL table.
What I already did is, convert it to array using:
$json_data = json_decode($geo_json, true);
and get an output of array but I do not know how to inset into second and third MySQL table.
My MySQL Table:
Table 1:
geo_id | user_id | geo_title | geo_description | geo_date |geo_status |geo_action |action_reason | geo_json | remote_ip | map_type |geo_snapshot
I can able to insert into above table easily but problem is in table two and Three listed below.
Table 2:
id | layer_id | map_id | layer_name | user_id | draw_type | latlng | radious
Table 3:
data_id | geo_key | geo_value | map_id | layer_id
Array I am getting:
Array
(
[type] => FeatureCollection
[features] => Array
(
[0] => Array
(
[type] => Feature
[properties] => Array
(
[action] => a
[poi_name] => a
[fac_type] => 17
[ph_number] => a
[hno] => a
[postcode] => a
[mail] => a
[str_nm] => a
[photo] => developer-page.png
[comment] => a
[url] => a
[sub_loc] => a
[employee] => a
)
[geometry] => Array
(
[type] => Point
[coordinates] => Array
(
[0] => 88.434448242188
[1] => 22.510971144638
)
)
)
[1] => Array
(
[type] => Feature
[properties] => Array
(
[action] => b
[poi_name] => b
[fac_type] => 18
[ph_number] => b
[hno] => b
[postcode] => b
[mail] => b
[str_nm] => b
[photo] => 1475131600_developer-page.png
[comment] => b
[url] => b
[sub_loc] => b
[employee] => b
)
[geometry] => Array
(
[type] => Point
[coordinates] => Array
(
[0] => 88.321151733398
[1] => 22.50906814933
)
)
)
)
)
Now problem is to insert above data into two separate tables:
Table 2: This is only require to insert draw_type | latlng from above php array.
Example: draw_ type: point and latlng : coordinates
Table 3:
This is require to insert geo_key | geo_value | map_id | layer_id from above PHP array.
Example:
geo_key : properties [action,poi_name,fac_type,ph_number,hno,postcode,mail,str_nm, photo, comment, url, sub_loc, employee]
geo_value : [properties values ]
map_id :[this will be table 1 insert id]
layer_id : [this can be blank]
Please guide me and show me how to start.
$json_data["features"][$array_index]["geometry"]["type"]
For table2:
foreach($json_data["features"] as $info){
$type = $info["geometry"]["type"];
$latlng_0 = $info["geometry"]["coordinates"][0];
$latlng_1 = $info["geometry"]["coordinates"][1];
// DO INSRET with $type, $latling_0, $latling_1
$sql = "INSERT INTO Table2 (draw_type, latlng0, latlng1) VALUES ('".$type."','".$latlng_0."','".$latlng_1."')";
....
}
For table3:
Is 'map_id' a auto increment key in table1?
You'll need to know map_id first by select * where (conditions)
after successful insert data to table1
And if 'layer_id' can accept blank (null) data, it'll be fine if you don't specific value in INSERT command. Just make sure your table have correct settings.

Insert Array values, multiple rows

I'm trying to record some information on a database. My post looks like this:
Array
(
[Action] => 1000
[Date_Stat] => 07/02/2013
[Date_Final] => 07/02/2013
[Product_Id] => Array
(
[0] => 2
[1] => 6
[2] => 1
)
[Conversion] => Array
(
[0] => 1,20
[1] => 1,00
[2] => 2,03
)
[ValueMin] => Array
(
[0] => 2,00
[1] => 1,58
[2] => 2,70
)
[ValueMax] => Array
(
[0] => 2,50
[1] => 1,98
[2] => 2,90
)
[ValueMedio] => Array
(
[0] => 2,20
[1] => 1,68
[2] => 2,80
)
)
HOW can I insert all this on database the right way?
I'm not sure about the best way to design the tables and store the information. I'm using this to make a PRICE TABLE with starting date, final date and list all products with prices.
Also I'm thinking what is the best method. There are 2 possibilities I think about
Date_Start | Date_End |Product_Id | ValueMin | ValueMax | ValueMedio | Conversion
02-02-2013 02-03-2013 1 1.00 2.00 3.00 4.00
02-02-2013 02-03-2013 2 1.00 2.00 3.00 4.20
02-02-2013 02-03-2013 3 1.00 2.00 2.00 4.40
OR (using implode and putting all values on the same row)
Date_Start | Date_End |Product_Id | ValueMin | ValueMax | ValueMedio | Conversion
02-02-2013 02-03-2013 1,2,3 1,1,1 2, 2,2 3,3,2 4, 4.3, 4.4
Thanks a lot!
Choose the option mentioned first. Selecting Rows will become much easier if you do it that way.
To insert the records, use a simple prepared Statement (PHP Manual) and use a for-Loop.
I'd suggest a little tweak over the first option. If you create a separate table (Something along the lines of "Prices") like this:
id|DateStart|DateEnd|
1|02-02-2013|02-02-2013|
And then, in the table you suggested, you'd replace the date range for the PriceId (Foreign Key to this table). That way it'll be easier for you to maintain the consistency over changes on date ranges.

Redbeanphp - Getting data from foreign key index

Sorry for the vague title, if anyone would like to edit it to reflect more about what I am posting, please do so. Here is the situation. I have 3 tables:
support:
id | contact_id | title | problem | etc
supportlogin:
id | contact_id | login | pass | etc
contact:
id | first_name | last_name | email | etc
I am loading the support bean just fine, and am accessing the contact info:
$support=R::load('support',1);
echo $support->contact->first_name;
I want to echo the supportlogin information similarly:
echo $support->contact->ownSupportlogin->login;
Is this possible, and am I doing it the right way? I have tried the following ways with no success:
echo $support->contact->supportlogin->login;
echo $support->contact->ownSupportlogin->login;
echo $support->contact->ownSupportlogin[0]->login;
EDIT: MORE INFO
I did print_r($support->contact) and was given the data:
RedBean_OODBBean Object
(
[null:RedBean_OODBBean:private] =>
[properties:RedBean_OODBBean:private] => Array
(
[id] => 109
[phone] => 1234580970
[first_name] => Tim
[last_name] => Withers
)
[__info:RedBean_OODBBean:private] => Array
(
[type] => contact
[sys.id] => id
[tainted] =>
)
[beanHelper:RedBean_OODBBean:private] => RedBean_BeanHelperFacade Object
(
)
[fetchType:RedBean_OODBBean:private] =>
)
And then I did print_r($support->contact->ownSupportlogin) and this showed up:
Array
(
[13] => RedBean_OODBBean Object
(
[null:RedBean_OODBBean:private] =>
[properties:RedBean_OODBBean:private] => Array
(
[id] => 13
[link] => fecd4ef67e8c789efa1792f9ee0efff4
[login] =>
[password] =>
[receiveemails] => 1
[contact_id] => 109
[role] => 1
)
[__info:RedBean_OODBBean:private] => Array
(
[type] => supportlogin
[sys.id] => id
[tainted] =>
)
[beanHelper:RedBean_OODBBean:private] => RedBean_BeanHelperFacade Object
(
)
[fetchType:RedBean_OODBBean:private] =>
)
)
I can access it using: echo $support->contact->ownSupportlogin[13]->login;, but doing it dynamically seems to be a problem....
Figured it out, and will leave it up in case anyone else has a similar problem:
This will only work if you have a 1:1 relationship. Redbean populates the ownSupportlogin as an array of all supportlogin rows related to the contact. If one table can have many child tables, then you will need to loop through that array and pull out the data you want. If it is a 1:1 relationship, then you can use PHP's reset() to access the data of the first element in the array:
echo reset($support->contact->ownSupporlogin)->login;

A Select Statement that would do the following

I am just learning how to wrap my head around sql and php. I have 4 tables structured as follows
+-----------+ +------------+ +---------+ +----------+
| Project | | Slide | | Shape | | Points |
+-----------+ +------------+ +---------+ +----------+
| id | | id | | id | | id |
+-----------+ | project_id | | cont_id | | shape_id |
+------------+ +---------+ | x |
| y |
+----------+
As you can see the tables are linked by id all the way down to points meaning a project will contain a number of slides that contain a number of shapes that contain a number of points.
I have a SQL query
SELECT slide.`id`, shape.`id`, points.`x_point`, points.`y_point`
FROM `project`, `slide`, `shape`, `points`
WHERE 1 = slide.`project_id`
AND slide.`id` = shape.`slide_id`
AND shape.`id` = points.`shape_id`
What I want is to take the results of this query that look like this
[0] => stdClass Object
(
[id] => 27
[x] => 177
[y] => 177
)
[1] => stdClass Object
(
[id] => 27
[x] => 178
[y] => 423
)
[2] => stdClass Object
(
[id] => 27
[x] => 178
[y] => 419
)
[3] => stdClass Object
(
[id] => 27
[x] => 178
[y] => 413
)
[4] => stdClass Object
(
[id] => 27
[x] => 181
[y] => 399
)
[5] => stdClass Object
(
[id] => 27
[x] => 195
[y] => 387
)
[6] => stdClass Object
(
[id] => 27
[x] => 210
[y] => 381
)
[7] => stdClass Object
(
[id] => 27
[x] => 231
[y] => 372
)
[8] => stdClass Object
(
[id] => 27
[x] => 255
[y] => 368
)
[9] => stdClass Object
(
[id] => 27
[x] => 283
[y] => 368
)
... AND CONTINUED FOR A LONG TIME
What I want is to convert this beastly array of crap into something that more resembles this
[9] => stdClass Object
(
[id] => ID OF LIKE SHAPES
[x] => Array(ALL THE X POINTS)
[y] => ARRAY(ALL THE Y Points)
)
I cannot for the life of me figure out how to convert this to such an array.
If it cannot be done with the query I designed is there a better query. Maybe one that grabs the points then takes that puts it into an array that of the points... I think I just got an Idea...
New Info,
So I added an answer to this question, I don't know if that's the standard way. To help out other answers if mine is not a good solution I will add my thought process here as well.
Check out my answer bellow for more info.
Also how does an ORM compare to my algorithm bellow?
Using an ORM like Doctrine, you would simply model it like
/**
* #Entity
*/
class Project
{
/**
* #Id #GeneratedValue
* #Column(type="integer")
*/
private $id;
/**
* #OneToMany(targetEntity="Slide", mappedBy="project")
*/
private $slides;
public function __construct()
{
$this->slides = new \Doctrine\Common\Collections\ArrayCollection;
}
}
/**
* #Entity
*/
class Slide
{
/**
* #Id #GeneratedValue
* #Column(type="integer")
*/
private $id;
/**
* #ManyToOne(targetEntity="Project", inversedBy="slides")
* #JoinColumn(name="project_id", referencedColumnName="id")
*/
private $project;
/**
* #OneToMany(targetEntity="Shape", mappedBy="slide")
*/
private $shapes;
}
And so on...
See http://www.doctrine-project.org/docs/orm/2.0/en/reference/association-mapping.html#one-to-many-bidirectional
Of course, there's a fair amount of setup and processing overhead involved but you'll appreciate an ORM as your domain model becomes more complex.
So I have been working on this a while and I came up with my own answer. I would love input because I think it is probably the BAD way to do this.
Here is my thought process. One Query is great but what if we build the results array incrementally. What I mean is we can build the results array by traversing through the tables with designed SELECT statements.
Here is the code I comment it because I am having a hard time describing my algorithm in just words.
/* $cur_project is set above from an input value. Assume any int
The algoritim Traverses a series of results and puts them into the proper places in a usable array.
The algorithim has an query count of NumberOfSlides + 2(NumberOfSlides)+1 which seems really high
For real word application if querying the DB is as bad as everyone says.
*/
// A blank array to build up
$projectArray = Array();
// I just want to see how many queries this thing generates
$queryCount = 0;
// Query 1 - This query will get all slides in a project.
$slide_id = $this->db->query('SELECT slide.`id`
FROM `slide`
WHERE slide.`project_id` = '.$cur_project);
$queryCount++;
//Now traverse the results to Query 1
foreach ($slide_id->result() as $slide_id){
// In the project array add an element with the key that is
// the slide_id for all slides in that project. Then for each
// key also create a new empty array at each added element
$projectArray[$slide_id->id] = Array();
// Query 2 - grab all the shapes that match the current slide in the current project!
// This is where things get inefficient.
$shape_id = $this->db->query('SELECT shape.`id`
FROM `shape`
WHERE shape.`slide_id` = '.$slide_id->id
);
$queryCount++;
// Traverse the results to Query 2
foreach ($shape_id->result() as $shape_id) {
// For every slide now create a key that matches the shape and fill that array with
// info I need such as an array of the points.
$projectArray[$slide_id->id][$shape_id->id] = Array(
'x_points' => Array(),
'y_points' => Array()
);
// Query 3 - Ask the DB for x/y points for the current shape. You can see how for slides with lots of shapes
$points = $this->db->query('SELECT points.`x_point`, points.`y_point`
FROM `points`
WHERE points.`shape_id` = '.$shape_id->id
);
$queryCount++;
// Traverse the Query 3 results
foreach ($points->result() as $point) {
// Populate the final arrays with the points
$projectArray[$slide_id->id][$shape_id->id]['x_points'][] = $point->x_point;
$projectArray[$slide_id->id][$shape_id->id]['y_points'][] = $point->y_point;
}
}
}
The above returns an array that looks like so
Array
(
[1] => Array
(
[27] => Array
(
[x_points] => Array
(
[0] => 177
[1] => 178
[2] => 178
[3] => 178
[4] => 181
...
Which can be interpreted as
Array
(
[SLIDE_ID] => Array
(
[SHAPE_ID] => Array
(
[x_points] => Array
(
[0] => 177
[1] => 178
[2] => 178
[3] => 178
[4] => 181
...
My problem with this solution is what I say in my top comment. I think you could duplicate these results with an array search for the original results as listed in the answer. That seems worse though.
Please for the life of me tell me how to improve this any comments on it will help me.
Thanks a lot.
I hope this help:
<?php
$newStdClass['id'] = $stdClass[$i]['id'];
for($i=0;$i<count($stdClass);$i++)
{
$newStdClass['x'][] = $stdClass[$i]['x'];
$newStdClass['y'][] = $stdClass[$i]['y'];
}
?>
Assuming $sttClass is your array of crap as you said :D.

Categories