Just getting into the whole MVC developing style.
Using CI I think I got the initial hang on the controllers, models and views. But, I run into a problem which was an easy-peasy for me in "my own" way of coding.
I have a single DB table to drive dynamic menu. The design is:
With sample data being:
The logic, in my head anyway, would be:
select * where active=1, then
if row's parent_id==0 check the retrieved data-set for rows where
parent_id==id of the current row
if not found, generate <li class="no_subs"></li> element
if found, generate <li class="subs"> element, open new <ul>
generate <li></li> for all items that matched, close <ul>, close
"subs" <li>
So, based on the above sample data the resulting html would be:
<li class="no_subs">Home</li>
<li class="no_subs">News</li>
<li class="subs">Training
<ul>
<li>Materials</li>
<li>Tests</li>
</ul>
</li>
<li class="subs">Other
<ul>
<li>Usefull links</li>
</ul>
</li>
So far all I can do is generate the top level menu.
Any ideas how to tackle this?
Thanks,
You can join the same table twice to achieve your goal
grub the data where parent_id == 0 and active == 1, so you will get the only menu titles.
join the data with the same table where id == parent_id. so you will get the this table.
id | name | parent_id | active | link | as_id | as_name | as_parent_id | as_active | as_link
**this 2 steps can be done in single sql query.
then i think this code will help you...
$sub_menu_started = false;
for ($i=0; $i < count($result); $i++) {
if (empty($result[$i]['as_name'])) {
echo '<li class="no_subs">'.$result[$i]['name'].'</li>';
}
else {
if(!$sub_menu_started) {
echo '<li class="subs">'.$result[$i]['name'];
echo '<ul><li>'.$result[$i]['as_name'].'</li>';
$sub_menu_started = true;
}
else {
if ($result[$i]['id'] == $result[$i-1]['id']) {
echo '<li>'.$result[$i]['as_name'].'</li>';
if($result[$i]['id'] != $result[$i+1]['id']) {
echo '</ul></li>';
$sub_menu_started = false;
}
}
}
}
}
if ($sub_menu_started) {
echo '</ul></li>';
}
Related
I'm having doubts about manipulating the child menu items to improve the display style.
I am currently generating according to documentation:
function index()
{
$list = $this->Categorias->find('threaded')->toArray();
$this->set('list', $list);
}
$renderItems = function($items) use (&$renderItems)
{
echo '<ul>';
foreach ($items as $item) {
echo '<li>';
echo h($item->name);
if ($item->children) {
$renderItems($item->children); // < recursion
}
echo '</li>';
}
echo '</ul>';
};
$renderItems($list);
But the display is in error.. The display is in this format:
I appreciate any comments!
As mentioned in the tree behavior docs, if you want to use threaded results, then you need some kind of recursive functionality to iterate not only over the top level items (which your example is doing), but also over the nested child items.
Also note that using the children finder as in your example, will only retrieve the children of the node with the specified primary key, ie it won't retrieve their parent node, also if the table contains multiple root nodes, they wouldn't be retrieved either. So depending on your data you might need to use only the threaded finder.
That being said, the children of an item are nested under the children property/key, so a basic example could look like this:
$renderItems = function($items) use (&$renderItems)
{
echo '<ul>';
foreach ($items as $item) {
echo '<li>';
echo h($item->name);
if ($item->children) {
$renderItems($item->children); // < recursion
}
echo '</li>';
}
echo '</ul>';
};
$renderItems($list);
That would create a nested list like this (without the formatting/indenting of course):
<ul>
<li>
Fun
<ul>
<li>
Sport
<ul>
<li>Surfing</li>
<li>Skating</li>
</ul>
</li>
</ul>
</li>
<li>
Trips
<ul>
<li>National</li>
<li>International</li>
</ul>
</li>
</ul>
See also
Cookbook > Database Access & ORM > Behaviors > Tree
I am developing a website using PHP and this is the 1st time I am trying a dynamic menu.
What I am doing is I have created a table for pages.
The table structure is as follows:
____________________________________________________________________________
|page_id|title|url|content|menu_title|show_on_navuigation|is_sub|parent_page|
|_______|_____|___|_______|__________|___________________|______|___________|
Here is_sub indicates whether it is a dropdown menu of some main menu. and parent_page is the main menu of the sub menu.
Now, what I want is, like
I have created 2 parent pages:
About Us and Test
and 2 sub menu's: Test aboutus and testsub,
Test aboutus is sub of About Us and testsub is sub of test.
How actually should the query and the loop, so that the menu renders perfectly.
Thanks in advance.
This is my menu structure:
<ul>
<li class='has-sub'><a href='#'><span>About Us</span></a>
<ul>
<li><a href='corporateprofile'><span>Corporate Profile</span></a></li>
<li class='last'><a href='visionandmission'><span>Vision & Mission</span></a></li>
</ul>
</li>
<li class='has-sub'><a href='#'><span>Business Services</span></a>
<ul>
<li><a href='recruitment'><span>Recruitment</span></a></li>
<li><a href='training'><span>Training</span></a></li>
<li><a href='executivesearch'><span>Executive Search</span></a></li>
<li><a href='payroll'><span>Payroll</span></a></li>
<li class='last'><a href='backgroundverification'><span>Background Verification</span></a></li>
</ul>
</li>
<li class='has-sub'><a href='#'><span>Employers</span></a>
<ul>
<li><a href='enquiry'><span>Enquiry</span></a></li>
<li><a href='jobdescription'><span>Job Description</span></a></li>
<li><a href='employercontract'><span>Employer Contract</span></a></li>
<li class='last'><a href='feedback'><span>Feedback</span></a></li>
</ul>
</li>
<li class='has-sub'><a href='javascript:;'><span>Job Seeker</span></a>
<ul>
<li><a href='applyforjob'><span>Apply For Job/Register</span></a></li>
<li><a href='careertips'><span>Career Tips</span></a></li>
<li><a href='interview Questions'><span>Interview Questions</span></a></li>
<li><a href='interviewprocess'><span>Interview Process</span></a></li>
<li class='last'><a href='corporatedress'><span>Corporate Dress</span></a></li>
</ul>
</li>
<li class='has-sub'><a href='#'><span>Franchise</span></a>
<ul>
<li class='last'><a href='#'><span>Franchise Enquiry Form</span></a></li>
</ul>
</li>
<li class='last'><a href='#'><span>Contact us</span></a></li>
</ul>
<?php
function displayMenu($parent_page_id) {
$sql = "SELECT * FROM `pages` WHERE `parent_page` = '$parent_page_id'"; // sql
$result = mysql_query($sql);
if( mysql_num_rows($result) === 0 ) { // mysql_num_rows() is deprecated, but you are using mysql extension so that's why I show it here
return true; // exit function
} // else, continue to rest of function
echo '<ul>';
while($row = mysql_fetch_assoc($result)) { // deprecated mysql php function here for simplicity
echo '<li>' . $result['menu_title'] . ''; // no closing </li> yet
displayMenu($row['page_id']); // this is the recursive part
echo '</li>'; // close the <li> from before the recursion
}
echo '</ul>';
}
$get_base_menu = mysql_query("SELECT * FROM pages WHERE parent_page = 0");
while($fetch_base_menu = mysql_fetch_array($get_base_menu))
{
$parent_page_id = $fetch_base_menu['page_id'];
displayMenu($parent_page_id);
}
?>
I highly suggest trying to get away from using an Adjacency List model and move toward a much easier to manage solution, such as a nested set. Using an MPTT type solution should help you manage your hierarchical data much easier. Using an Adjacency List model you are limited at a certain point.
I'd suggest looking into using something along the lines of Zebra_MPTT, or some other form of MPTT library. Please checkout this article on Managing Hierarchical data in MySQL.
I think the simplest thing for you to code will be something like this recursive function. All you have to do is put it on your page and make sure you have parent_page_id = 0 for the base level menu items. (I'm using parent_page_id instead of parent_page because I assume that is what you mean and it is more clear for the answer.)
Calling the function with an argument of "0" should give you the full menu tree.
$trace = array();
function displayMenu($parent_page_id) {
$sql = "SELECT * FROM `tbl_menu` WHERE `parent_page_id` = $parent_page_id"; // sql
$result = mysql_query($sql);
if( mysql_num_rows($result) === 0 ) { // mysql_num_rows() is deprecated, but you are using mysql extension so that's why I show it here
$trace[] = "Page_id $parent_page_id has no children";
return true; // exit function
} // else, continue to rest of function
echo '<ul>';
while($row = mysql_fetch_assoc($result)) { // deprecated mysql php function here for simplicity
$trace[] = "Entered while loop for page_id = $parent_page_id"; // not an error, just tracking
echo '<li>' . $row['menu_title'] . ''; // no closing </li> yet
displayMenu($row['page_id']); // this is the recursive part
echo '</li>'; // close the <li> from before the recursion
}
echo '</ul>';
}
displayMenu(0); // call function for base level
var_dump($trace);
More info:
I have researched the topic before and had a nice link to a page on mysql.com with an in-depth exploration of hierarchical relational database structures. But when I checked, the link was broken!
But, I think I found it on another site, here:
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
I thought to implement advanced commenting system in my website using PHP-MySql. I finally settled for a 3-level comment-reply system for this purpose.
Well, for that purpose I came across this article to implement the data-structure of the SQL database.
I planned to use nested set mdoel for the feature I want to use. The structure of the comments are like this-
<ul>
<li>Parent comment</li>
<ul>
<li>First reply of parent comment</li>
<ul>
<li>reply of the previous reply</li>
<ul>
<li>reply of the previous reply</li>
<li>another reply of the previous reply</li>
</ul>
<li>another reply of the previous comment</li>
</ul>
<li>second reply of the parent comment</li>
</ul>
</ul>
For this type of structure, I have been playing around with PHP to show the query detecting the parents and its child uniquely(for fetching user details associated with each comment) and produce the output in the manner if shown above. Do anyone have idea how to do it. Please help me out.
EDIT :
I have a seperate user table in SQL linked to the comment table as user.id=comment.id. So considering this, what would be the recommended approach to detect user activity for each comment? I mean, for ex- I want to fetch user name and email for a sub-comment of parent comment 2. Hoow could it be done?
Use the query from "Finding the Depth of the Nodes", and this PHP code will create the nested lists.
$cur_depth = -1;
while ($row = mysqli_fetch_assoc($query)) { // Loop through results of query
if ($row['depth'] > $cur_depth) {
echo "<ul>\n";
$cur_depth = $row['depth'];
}
else while ($cur_depth > $row['depth']) {
echo "</ul>\n";
$cur_depth--;
}
echo "<li>" . $row['comment'] . "</li>\n";
}
while ($cur_depth > -1) {
echo "</ul>\n";
$cur_depth--;
}
I have a categories table that looks like this:
----------------------------------------
| id | parentId | Name |
----------------------------------------
1 0 Cat 1
2 0 Cat 2
3 0 Cat 3
4 2 Cat 4
5 3 Cat 5
6 5 Cat 6
Basically I need to iterate through the categorys creating a UL LI html list like the following:
<ul id="categories">
<li id="1">Cat 1</li>
<li id="2">Cat 2
<ul>
<li id="4">Cat 4</li>
</ul>
</li>
<li id="3">Cat 3
<ul>
<li id="5">Cat 5
<ul>
<li id="6">Cat 6</li>
</ul>
</li>
</ul>
</li>
</ul>
Im having major issues trying to iterate over this trying to create the above html. The id's maybe any number of levels deep within parentId's. Im donig this in PHP. Because there are nth number of levels deep I think I need to do some kind of array_walk funuction but not surch how. Also to make things just a little harder the machine it sists on runs PHP4 and I know it needs upgrading but it cant at the min so I need a php 4 solution ideally. How should I go about doing this?
Try the left/right tree method for storing hierarchical information in a database.
http://blogs.sitepoint.com/hierarchical-data-database/
This is what I do in my website, where I have multi-level LIs that need to open at 1:6 and have children 2:3,4:5 where the first number is the 'left' and the second is the 'right'. I have about 5 levels deep at the moment, but you could have many more. It's just a matter of developing an interface for setting the correct left/right values based on the position you add it to.
You just have to add a 'lft' and 'rgt' column to your table (as explained in that article).
First create a tree structure and insert your categories into the tree using id and parent_id. Then try Depth-first_search using either a list of references to arrays to be processed or recursion.
function printRecList($tree){
// exit condition
if (is_string($tree))
echo "<li>$tree</li>";
echo "<ul>";
foreach ($tree as $subtree)
printRecList($subtree); // recursion step
echo "</ul>";
}
The way your database is structured, you cannot do that with a single mysql query and you should do it recursively. Something in line with:
function print_children ($id) {
$children = query("SELECT * FROM `table` WHERE `parentId` = " . (int)$id);
if (!empty($children)) {
echo '<ul>';
foreach ($children as $child) {
echo '<li>' . $child['name'];
print_children($child['id']);
echo '</li>';
}
echo '</ul>';
}
}
print_children(0);
Replace query with something that gets results for your database query.
function writelevel($id, $txt, $children) {
if (isset($txt[$id]))
echo "<li id=\"$id\">".$txt[$id];
if (isset($children[$id])) {
echo "<ul>";
foreach ($children[$id] as $child)
writelevel($child, $txt, $children);
echo "</ul>";
}
if (isset($txt[$id]))
echo "</li>";
}
//Assuming your query is done and the result is in $qry
$txt=array();
$children=array();
//Fetch and structure data
while (true) {
//Fetch next row
$row=mysql_fetch_row($qry);
if (!$row) break;
//Store text
$txt[$row[0]]=$row[2];
//Store child relationships
if (!isset($children[$row[1]])) $children[$row[1]]=array();
$children[$row[1]]=$row[0];
}
//Writeout
writelevel(0);
i want to display the mysql's fetched results with php and html in unordered list and list format as like http://www.miniclip.com/games/en/. you can see in the all games categories in the footer in alphabetical order. the same requirement i do have. i guess i have written the logic its working fine. but i am unable to represent it properly. you can see in the following link above the footer. http://www.playtoongames.com/play1...
code:
<?php
$gameQuery = mysql_query ("SELECT name, LEFT(name, 1) AS first_char FROM games WHERE UPPER(name) BETWEEN 'A' AND 'Z' OR name BETWEEN '0' AND '9' ORDER BY name");
$current_char = '';
while ($gameRow = mysql_fetch_assoc($gameQuery)){
if ($_SESSION['lang'] == 'fr'){
$description = $gameRow['description_fr'];
}else{
$description = $gameRow['description'];
}
?>
<div style='float:left' title="<img src='<?php echo $gameRow['sitePath'];?>games/images/<?php echo $gameRow['img_100x75'];?>' width='230' height='112' class='thumb' alt='<?php echo $gameRow['name'];?>'/>" class='tooltip'>
<ul>
<li>
<a href='<?php echo $gameRow['sitePath'];?>play/<?php echo str_replace(' ','_',$gameRow['name']);?>'><?php echo $gameRow['name'];?></a>
</li>
</ul>
</div>
can anybody look into this...
Regards,
sam.
On the Playtoons site, each <li> is in its' own individual <ul> - this means you're creating a new list for each item:
<ul>
<li>13 More Days</li>
</ul>
<ul>
<li>A Bikers Heaven</li>
</ul>
What you should be doing is using one <ul> which contains all the items as <li>s:
<ul>
<li>13 More Days</li>
<li>A Bikers Heaven</li>
</ul>
Well, I think the key is that there are 6 columns, which just means you'll need to break your array into 6 different parts.
Here's some psuedocode:
$pArr = $from_sql_array; // I'll let you take care of that.
$itmCount = count($pArr);
$itmsPerCol = ceil($itmCount / 6.0);
for ($ii=0; $ii < 6; $ii++)
{
$pCol = array_slice($pArr, $itmsPerCol * $ii, $itmsPerCol);
echo '<ul class="floatleft"><li>'.implode("</li>\n<li>",$pCol).'</li></ul>';
}