|
Smarty
WARNING: All discussion is moving to https://reddit.com/r/smarty, please go there! This forum will be closing soon. |
|
View previous topic :: View next topic |
Author |
Message |
simon3z Smarty n00b
Joined: 08 Dec 2007 Posts: 2
|
Posted: Sat Dec 08, 2007 6:00 pm Post subject: One-to-many tables relationship |
|
|
Hi all, I'm wondering what's the best practice to retrieve and display the data of a one-to-many relationship.
Let's take a common case as example: product_category has-many products. How can I display the categories along with the products?
Let's assume I have a large number of product categories and I paginate them with 20 results per page, that would become 20 queries on the products table to find the related items.
I could perform a join on the two tables but I dont want to repeat the product_category for each product I display; I would like the name of the product_category followed by the list of products. Example:
_ Category1
__ Prod1Cat1
__ Prod2Cat1
_ Category2
__ Prod1Cat2
_Categotry3
__ Prod1Cat3
[...]
Is there a common practice for this?
Thank you in advance. |
|
Back to top |
|
czarnowski Guest
|
Posted: Sun Dec 09, 2007 11:40 am Post subject: |
|
|
assign a blank value to smarty variable oldcat before the beginning of the foreach
compare the actual cat with oldcat
if not the same value assign the new one to oldcat and print it out |
|
Back to top |
|
master_kaos Smarty Regular
Joined: 02 Aug 2007 Posts: 54
|
Posted: Tue Dec 11, 2007 3:45 pm Post subject: |
|
|
I am actually working on exactly this this morning (just taking my morning break)
this is how I am doing it (sqlFunctions is my own SQL helper class)
Code: |
class category
{
var $id = null;
var $name = null;
var $sql;
var $products;
function category(id)
{
global $db;
$this->sql = new sqlFunctions($db);
$results = $sql->select("SELECT * FROM category WHERE id = '" . $this->sql->clean($id) . "'");
$this->id = $results[0]['id'];
$this->name = $results[0]['name'];
$this->products = product::getByCategoryID($this->id);
}
function getAll()
{
global $db;
$sql = new sqlFunctions($db);
$categories = array();
$results = $sql->select("SELECT id FROM category");
foreach($results as $result)
{
$categories[] = new category($result['id']);
}
return $categories;
}
}
class product
{
var $id = null;
var $name = null;
var $sql;
function product(id)
{
global $db;
$this->sql = new sqlFunctions($db);
$results = $sql->select("SELECT * FROM product WHERE id = '" . $this->sql->clean($id) . "'");
$this->id = $results[0]['id'];
$this->name = $results[0]['name'];
}
function getByCategoryID($id)
{
global $db;
$sql = new sqlFunctions($db);
$products = array();
results = $sql->select("SELECT id FROM product WHERE id = '" . $sql->clean($id). "'");
foreach($results as $result)
{
$products[] = new product($result['id']);
}
return $products
}
}
now php code could be like this
$smarty->assign('categories', category::getAll());
then template would be like this
{foreach from=$categories item=category}
{$category->name}<br>
{assign var=products value=$categories->products}
{foreach from=$products item=product}
{$product->name}<br>
{/foreach}
{/foreach}
|
I haven't actually tested this code, but it will work, might be 1 or two small typos though |
|
Back to top |
|
simon3z Smarty n00b
Joined: 08 Dec 2007 Posts: 2
|
Posted: Tue Dec 11, 2007 4:19 pm Post subject: |
|
|
Thank you very much! Your code is very clean and I really like the getAll and getByCategoryID idea. Very well implemented!
I have to say that I am quite concerned about the amount of the sql queries it would generate:
1 query: SELECT id FROM category;
N queries: SELECT * FROM category WHERE id = '?';
N queries: SELECT id FROM product WHERE id = '?';
M queries: SELECT * FROM product WHERE id = '?';
Where N is the number of the categories and M is the number of the products in each category.
To retrieve just 1 product in 1 category I would have 4 sql queries. To retrieve 2 products in 2 different categories would be 7 sql queries. (Please correct me if my math is wrong).
Do you think this would be scalable? Can we trade performances for clean code?
Do you think that your solution would scale even on a high traffic site?
Thank you for your answer. |
|
Back to top |
|
master_kaos Smarty Regular
Joined: 02 Aug 2007 Posts: 54
|
Posted: Tue Dec 11, 2007 5:07 pm Post subject: |
|
|
I have never really worked on an application that has high load, so (extreme) performance tweaks was never really an issue.
One thing you could do however, is take out the $products variable, and then just do a manual call on getByCategoryID.
(Smarty can't call a static function on a class, so I just assign a blank product)
Code: |
$smarty->assign('product', new product(null));
{foreach from=$categories item=category}
{$category->name}<br>
{assign var=products value=$product->getByCategoryID($smarty.get.id)}
{foreach from=$products item=product}
{$product->name}<br>
{/foreach}
{/foreach}
|
This way it won't preload the class, so you won't have the extra overhead if you don't need it
But yeah, still a lot of sql queries. I have never had to worry about it because I haven't had much load on my web apps, but if I did and I saw performance dropping, I may seek another solution.
What you could maybe do to drop a few queries is have a function that JUST returns raw sql results
so something like
Code: |
//can't think of a good name right now
function getAllRaw()
{
global $db;
$sql = new sqlFunctions($db);
return $sql->select("SELECT * FROM category");
}
|
This will be WAY quicker, and way less sql queries.
You can then access the data by doing
{$product.name}
You just wont have all the class information available, just the raw results. BUt if all you are doing is just displaying it, it probably doesn't matter.
edit::: Now that I think about it , I actually did do this solution a couple projects back. A client wanted to display 6000 products on their screen at once without pagination. And creating all the classes and running all the SQL queries took a while (only a second or two, but still that is way too slow)
so I did this solution and it was really fast. |
|
Back to top |
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|