Laravel Eloquent complex query building - php

I have trouble to achieve my goal to build a filterable complex query.
I have 5 tables. One of them is a time tracking table. To keep that global, I just store the item_id and the time_categories_id to recognize which item it is.
I also need some additional information which is not directly in relation, so for example, I need the client informations which are assigned to a task.
So I have following tables (in short form listed):
times
--------------------------------------------------------
| id | name | description | item_id | time_category_id |
--------------------------------------------------------
time_categories
-------------
| id | name |
-------------
clients
------------------------------------
| id | company| name | description |
------------------------------------
(client has many projects and projects may have many clients)
projects
------------------------------------
| id | company| name | description |
------------------------------------
tasks
----------------------------------------
| id | name | description | project_id |
----------------------------------------
tickets
------------------------------------------------
| id | company| name | description | client_id |
------------------------------------------------
Now I want to create a filter function in which the return should depend on if client or project id is submitted.
For this filter, I created following query:
$timeQuery = Time::select(array(
'times.*',
'time_categories.name as type',
'tasks.name as task_name',
'tasks.description as task_description',
'tickets.name as ticket_name',
'tickets.description as ticket_description'))
->join('time_categories','times.time_category_id','=','time_categories.id')
->leftJoin('tasks',function($join) use ($project){
if(!empty($project))
{
$join->on('times.item_id', '=', 'tasks.id')
->where('tasks.project_id','=',$project);
}else{
$join->on('times.item_id', '=', 'tasks.id');
}
})
->leftJoin('tickets',function($join) use ($client){
if(!empty($client))
{
$join->on('times.item_id','=','tickets.id')
->where('tasks.project_id','=',$client);
}else{
$join->on('times.item_id','=','tickets.id');
}
});
So I ended up here. I don't get an error, but I receive all data instead of filtered data only dependent on client or project id.
Does anyone have an advice?

Related

Summation Query with join codeigniter

I have 2 tables. One with a list of clients and another with a list of data. I am trying to create a table in my view that lists the client name along with the sum of a column(job_total) in the data table. I am able to write a query that works fine in most situations. The problem is, if I have not yet created a record in the data table I need to still display the client name with a balance of zero on my table in my view. Need some direction on how to handle this. I was thinking I need to query my list of clients and loop through that query just not sure how to do it.
I want my view to look like below:
+-------------+---------+
| Client Name | Balance |
+-------------+---------+
| xxx | $75.00 |
| xxx | $100.00 |
| xxx | $0.00 |
+-------------+---------+
Here is a rough layout of the two tables in my database:
cj_clients
+----+-------------+
| id | client name |
+----+-------------+
| 1 | client1 |
| 2 | client2 |
| x | xxx |
+----+-------------+
cj_data
+----+-----------+-----------+
| id | client_id | job_total |
+----+-----------+-----------+
| 1 | 1 | 5.00 |
| 2 | 1 | 10.00 |
| 3 | 1 | 15.00 |
+----+-----------+-----------+
The below code returns the desired results except when no entries have yet been made to the cj_data table. Not sure how to still get the client in the table view with a balance of $0.
$this->db->select('client_name,client_id, sum(job_total) AS balance')
->from('cj_data')
->join('cj_clients','cj_data.client_id = cj_clients.id')
->group_by('client_name');
return $this->db->get()->result();
You need to give left join
$this->db->select('client_name,client_id, IFNULL(sum(job_total),0) AS balance')
->from('cj_data')
->join('cj_clients','cj_data.client_id = cj_clients.id',"left") // here
->group_by('client_name');
return $this->db->get()->result();
I wrote IFNULL condition if record not found or it will show all data for all clients in cj_clients
Note: the Default behaviour of CodeIgniter is it will add inner join
if join not specified

Doctrine mapping many linked tables

I'm working with legacy project in PHP and few of tables in database looks like this:
Table Product:
+----+-------------+----------------+
|id | id_category | id_destination |
+----+-------------+----------------+
|1 | 3 | 1 |
|2 | 2 | 1 |
+----+-------------+----------------+
Table Category:
+-------------+----------------+
| id | category_name |
+-------------+----------------+
| 2 | services |
| 3 | transport |
+-------------+----------------+
Tables "services" and "transport"
+-------------+----------------+ +-------------+----------------+
| id | name | | id | kilometers |
+-------------+----------------+ +-------------+----------------+
| 1 | 'foo' | | 1 | 156 |
| 2 | 'bar' | | 2 | 12 |
+-------------+----------------+ +-------------+----------------+
And now where I want check product with ID 1 it will call:
$info = SELECT * FROM product WHERE ID = 1;
$table = SELECT category_name FROM category WHERE ID = $info['id_category'];
and then:
SELECT * FROM $table WHERE id = $info['id_destination'];
My question is how can I mapped this in Doctrine.
I'm working on Symfony 2.6
You want to look at adding Entity classes in Symfony to handle the data to/from your database; think of these as the database tables themselves.
Then use Doctrine Association Mapping; this handles lookup tables (like MySQL JOIN's) automatically, allowing you to simply get the $product and automatically have access to $product->getCategory() or $product->getServices().
There is an article on this on the Symfony website too which acts as a good introduction:
http://symfony.com/doc/current/book/doctrine.html#relationship-mapping-metadata
Should be enough to get you started.
On a side note, think of upgrading Symfony to v3 or, at least, v2.8, for long term support before you get too deep.

Doctrine multiple 1 to 1 connections

I have task that would be quite simple using regular SQL query but the project is built using doctrine and I am looking for an optimal solution. Maybe someone could advise what would be a good way to approach this.
I have a quite complicated db structure but the simplified version of objects in question look like this:
| Category | | Product | | ProductOption |
------------ --------------- --------------------
| id | | id | | id |
| name | | category_id | | product_id |
------------ | name | | some_data |
--------------- --------------------
Product Option and Product have 1 to 1 connection. But options are created per category (I get 1 entity per category, but need to replicate that entity for every product and store that as 1 to 1 since at some point those options will need to be edited individually. Now there are many ways to do that (the dirty way) , but I would like some advice on how to do that in the most optimal way.

Database design with undetermined data

Recently I have been planning a system that allows a user to customize and add to a web interface. The app could be compared to a quiz creating system. The problem I'm having is how to design a schema that will allow for "variable" numbers of additions to be made to the application.
The first option that I looked into was just creating an object for the additions and then serializing it and putting it in its own column. The content wouldn't be edited often so writing would be minimal, reads however would be very often. (caching could be used to cut down)
The other option was using something other than mysql or postgresql such as cassandra. I've never used other databases before but would be interested in learning how to use them if they would improve the design of the system.
Any input on the subject would be appreciated.
Thank you.
*edit 29/3/14
Some information on the data being changed. For my idea above of using a serialized object, you could say that in the table I would store the name of the quiz, the number of points the quiz is worth and then a column called quiz data that would store the serialized object containing the information on the questions. So overall the object could look like this:
Questions(Array):{
[1](Object):Question{
Field-type(int):1
Field-title(string):"Whats your gender?"
Options(Array):{"Female", "Male"}
}
[2](Object):Question{
Field-type(int):2
Field-title(string):"Whats your name?"
}
}
The structure could vary of course but generally i would be storing integers to determin the type of field in the quiz and then a field to hold the label for the field and the options (if there are any) for that field.
In this scenario I would advise looking at MongoDB.
However if you want to work with MySQL you can think about the entity-attribute-value model in your design. The EAV model allows you to design for entries that contain a variable number of attributes.
edit
Following your update on the datatypes you would like to store, you could map your design as follows:
+-------------------------------------+
| QuizQuestions |
+----+---------+----------------------+
| id | type_id | question_txt |
+----+---------+----------------------+
| 1 | 1 | What's your gender? |
| 2 | 2 | What's your name? |
+----+---------+----------------------+
+-----------------------------------+
| QuestionTypes |
+----+--------------+---------------+
| id | attribute_id | description |
+----+--------------+---------------+
| 1 | 1 | Single select |
| 2 | 2 | Free text |
+----+--------------+---------------+
+----------------------------+
| QuestionValues |
+----+--------------+--------+
| id | question_id | value |
+----+--------------+--------+
| 1 | 1 | Male |
| 2 | 1 | Female |
+----+--------------+--------+
+-------------------------------+
| QuestionResponses |
+----+--------------+-----------+
| id | question_id | response |
+----+--------------+-----------+
| 1 | 1 | 1 |
| 2 | 2 | Fred |
+----+--------------+-----------+
This would then allow you to dynamically add various different questions (QuizQuestions), of different types (QuestionTypes), and then restrict them with different options (QuestionValues) and store those responses (QuestionResponses).

Grabbing individual elements in MySQL Table

I'm attempting to add Breadcrumbs to my website using a MySQL table, and I'm having difficulty at the moment.
I have a table named 'includes' created that stores information about the category, page, subpage, the title, and the ref (url) of the page. Category, Page, and Subpage are all php parameters passed from the page the user is on
My table is laid out like this:
|----------------------------------------------------------------|
| ID | Category | Page | Subpage | Title | Ref |
|----------------------------------------------------------------|
| 0 | | | | Home | ... |
| 1 | Software | | | Software | ... |
| 2 | Software | Desktop | | Desktop Software | ... |
| 3 | Software | Mobile | | Mobile Software | ... |
| 4 | Software | Desktop | Blah | Blah Blah | ... |
| ...
|----------------------------------------------------------------|
What I'm trying to do is make a query that will return only the required steps back to home for the breadcrumbs.
In other words, if the user is on "example.com/software/desktop/blah", the query will return rows 0,1,2, and 4. Or if I was on /software/mobile, it would only return rows 0,1, and 3.
My current attempts have been things like the following:
SELECT * FROM `includes` WHERE
`category` IS NULL AND `page` IS NULL AND `subpage` IS NULL OR
`category`='$category' AND `page` IS NULL AND `subpage` IS NULL OR
`category`='$category' AND `page`='$page' AND `subpage` IS NULL OR
`category`='$category' AND `page`='$page' AND `subpage`='$subpage'
Which not only don't work, but also seem more complex than it should have to be.
I'm probably overcomplicating this, or possibly just doing an entirely wrong method, which is why I've turned here.
Does anyone have a possible solution to this? Should I be looking at a more complex query? (admittedly, SQL is not my forte) Or should I be looking at a new SQL table, or possibly an entirely different method?
What you have is a hierarchical structure. The data is set up with parent-child relationships. There is a good description on how to work with hierarchical data here: http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/
You can make a self relation table like this
id | parent_it | title | Ref
1 | 0 | Home | ...
2 | 1 | Software | ...
3 | 2 | Desktop | ...
4 | 2 | Mobile | ...
5 | 3 | Blah | ...
So your query should get the last element
SELECT * FROM includes WHERE
tilte = 'Blah'
And then get the parent ID title and so on , like this the table structure will be better from my point of view & experience
OR
Generate your query based on the values you get , with simple loop count the arguments and based on that generate the query string then execute it
I hope this can help :)

Categories