Experts is there any option to automatically increase +1 in category_level
for ex: $cond_cat=" where category_level='1' and ID='$sleads' "; than $cond_cat=" where category_level='2' and parent_id ='$sleads' ";
my code is given below.
<?php
include('classes/global.php');
$CT=new Product();
$AdminObj=new Admin();
$sleads=$_REQUEST['sleads'];
$cond_cat=" where category_level='1' and ID='$sleads' ";
$catResult_cond=$CT->getCategory($cond_cat);
$cond_cat=" where category_level='2' and parent_id ='$sleads' ";
$subCatResult_cond=$CT->getCategory($cond_cat);
?>
You may want to try to recursively get subcategories as a child of the subcategory you are into.
<?php
function getSubCategories($level) {
// you should obviously get the $sleads variable in here, for this to work.
$cond_cat = "where category_level='%d' and ID='$sleads' ";
$subcategories = $CT->getCategory(sprintf($cond_cat, $level));
if (count($subcategories) > 0) {
foreach($subcategories as $subcategory) {
$subcategory->subcategories = $CT->getCategory(sprintf($cond_cat, $level+1));
}
}
return $subcategories;
}
$i = 1;
$categories = getSubCategories($i);
?>
This will get you something like:
// $categories // first level
// foreach($categories as $cat) {
// $cat->subcategories // second level categories
// foreach($cat->subcategories as $subcategory) {
// $subcategory->subcategories // third level
// }
// }
// and so on
Please take into account that I assume that your $CT->getCategory function returns an array of category records.
If that is not the case (taking into consideration that you also add an ID="" in your query), you should also alter that function, or use a function that returns multiple category records.
Related
I have a MySQL table with id, parent and comment which I managed to order almost-as-it-should from latest to oldest. If a comment has no parent, this is set to 0.
The comments table: Table Image
Hereby my current code:
<?php
$con = mysqli_connect('host','username','password','database');
if (mysqli_connect_errno($con)) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$comments = array();
$results = mysqli_query($con,"SELECT * FROM comments ORDER BY id DESC");
while ($row = mysqli_fetch_assoc($results)) {
$parent = $row['parent'];
$comments[$parent ? $parent : 0][] = $row;
}
function thread($parent,$comments) {
foreach ($comments[$parent] as $post) {
echo "<div>";
echo $post['comment'];
$id = $post['id'];
if (isset($comments[$id])) {
thread($id,$comments);
}
echo "</div>";
}
}
thread(0,$comments);
?>
The above results in the following order (turned into a list for readability, you can do this in the code by turning the div tags into li and echoing ul tags around the foreach loop):
Third comment
Second comment
Another reply to the second comment
And another one
Reply to the second comment
Reply to a reply
First comment
Reply to the first comment
Notice that replies are ordered in a descending manner as well, just like the comments. Other than that it's completely fine and working like a charm. But this is what it's supposed to be like:
Third comment
Second comment
Reply to the second comment
Reply to a reply
Another reply to the second comment
And another one
First comment
Reply to the first comment
Shortly said: comments should be in descending order, replies in ascending. That is where I got stuck completely. Thanks a lot for your help!!
You can use the array_reverse function to reverse the order of the items in an array:
$results = mysqli_query($con,"SELECT * FROM comments ORDER BY id DESC");
while ($row = mysqli_fetch_assoc($results)) {
// ...
}
// Important bit: Reverse all threads except the main thread (id=0):
foreach ($comments as $key => $value) {
if ($key !== 0) {
$comments[$key] = array_reverse($value);
}
}
function thread($parent,$comments) {
// And so on...
I have a sidebar with categories. when i click on one categorie it shows me the factories who are located in that category.
I did this using joins in codeigniter.
Now i want to show how much factories are in a category. so for example:
Categories.
Cars (2)
Books (7)
Animals (45)
So it simple has to show how much factories have that specific category.
i tried to do a simple count_all_results but then i get the total count of factories. but i want them to count by the specific id of categories.
my model function:
function categorieen_getall($segment3)
{
$this->db->where('categorieen.idcategorieen', $segment3);
$this->db->select('*');
$this->db->from('bedrijfcategorieen');
$this->db->join('categorieen', 'categorieen.idcategorieen = bedrijfcategorieen.idcategorieen');
$this->db->join('bedrijven', 'bedrijven.idbedrijven = bedrijfcategorieen.idbedrijven');
$query = $this->db->get();
$result = $query->result();
/*
echo '<pre>';
print_r($result);
*/
return $result;
}
My controller function:
function get_All()
{
$data['cat'] = $this->categorieen_model->categorieen_getall($segment3);
$this->load->view('views/sidebar', $data);
}
My view:
<div id="sidebar">
<?php
echo '<h3>Categorieën</h3>';
echo ($this->db->count_all_results('categorieen'));
?>
<hr>
<br/>
<?php
echo '<ul>';
if(isset($cat) && is_array($cat)){
foreach($links as $k => $value){
echo '<li>';
echo '<br>';
echo '' .$value->Categorie. '';
echo '</li>';
}
}
echo '<ul>';
/*
if(isset($cat ) && is_array($cat )){
foreach($cat as $key => $row){
echo "Categorie:"; echo $row->Categorie;
echo "<br />";
echo $row->idcategorieen;
echo "<br />";
echo $row->Bedrijfsnaam;
}
}
*/
?>
</div>
My database scheme:
Factories
--------
idfactories
factoryname
adress
email
...
Categories
----------
idcategories
Category
Factorycategories
-----------------
idfactorycategories
idcategories
idfactories
This is not quite suitable because I know there is a better way to do this, but this will do the work for you:
// Get categories
$categories = array();
$query = $this->db->query("select * from `Categories` order by `idcategories`");
if($query->num_rows() > 0)
{
foreach($query->result_array() as $row)
{
$query_count = $this->db->query("select `idfactorycategories` from `Factorycategories` where `idcategories` = {$row['idcategories']}");
$factory_count = $query_count->num_rows();
$categories[] = array(
'count' => $factory_count
);
}
}
For ease, you can first get categories in a foreach loop and then for each of them submit a query for the factories table to get relevant count of factories with that related category id.
I asked another question. with the same problem and i solved it.
Look at my own answer with the solution i got!
Count results in joined table and show between () in sidebar
Thanks for the people who helped me :)
I am trying to make un-order list for parent child categories where if there is any child category than it will create another un-order list ( like indented text) so user can understand properly.
I have fetch sql but with foreach I don't understand how to set so where child category only will display under parent category by creating another un-order list under the parent category.
Here is my code
$query_cat = "SELECT * FROM ^categories";
$query = qa_db_query_sub($query_cat);
$catsid = qa_db_read_all_assoc($query);
echo '<UL>';
foreach ($catsid as $catid){
echo '<LI>'. $catid['title'].' '. $catid['categoryid'].'</LI>';
}
echo '</UL>';
So final result would be
First Category
Sub Category1
Second Category
EDIT:
After modified code with #vlcekmi3 answer https://stackoverflow.com/a/13451136/1053190 I am getting this result
Now how to exclude subcategory from parent list?
There's no really easy solution for this with your design. The most effective way would be to add column like order_in_list (and maybe depth_in_list).
They would be pre calculated in loop (pseudocode):
START TRANSACTION
UPDATE t1 SET order_in_list = 0 // Restart whole loop
$ids = array(0);
while $id = array_shift($ids){
$record = SELECT * FROM t1 WHERE id = $id // Get id details, order_in_list is important
$children = SELECT * FROM t1 WHERE parent_id = $id // get list of all childs
// If it's root element, start indexing from 0
$root_order = ($record ? $record->order_in_list : 1)
$child_no = count($children) // How many child will be adding
// No children, nothing to do:
if $child_no < 1{
continue;
}
append_to_array($ids, $children) // Store ids to process
// Shift all later records, we'll be creating gap in order_in_list 1,2,3,4,5
// To 1,2,5,6,7 to insert items on places 3,4
UPDATE t1 SET order_in_list = (order_in_list + $child_no)
WHERE order_in_list > $record->order_in_list
// Okay, set IDs for direct children
foreach( $children as $child){
UPDATE t1 SET order_in_list = $root_order, depth_in_list = $record->depth_in_list+1
WHERE id = $child->id
$root_order++;
}
}
COMMIT
This way you'll get records like:
First category, 1, 1
Second category 3, 1
Sub category, 2, 2
Which you could display with simple loop:
$last_depth = 0;
foreach( (SELECT * FROM t1 ORDER by `order_in_list`) as $row){
if( $last_detph > $row['depth_in_list'])){
// Close level </ul>
} else if($last_detph < $row['depth_in_list']){
// Opening level <ul>
} else {
// The same depth
}
$last_depth = $row['depth_in_list'];
}
Without modifying database
It would be probably most effective to build two arrays containing root elements and all elements:
$root_elements = array();
$all_elements = array();
foreach( (SELECT * FROM t1) as $row){
// Store details into all_elements, note that entry may have already be created when
// processing child node
if( isset( $all_elements[$row['id']])){
// set details
} else {
$all_elements[$row['id']] = $row;
$all_elements[$row['id']]['children'] = array(); // Array of child elements
}
if( $row['parent_id'] == NULL){
$all_elements[] = $row['id']; // Add row element
} else {
if( isset( $all_elements[ $row[ 'parent_id']])){
$all_elements[ $row[ 'parent_id']]['children'][] = $row['id'];
} else {
// Create new record:
$all_elements[ $row[ 'parent_id']] = array();
$all_elements[ $row[ 'parent_id']]['children'] = array($row['id']);
}
}
}
And then write it as:
foreach( $root_elements as $element_id){
write_recursive( $all_elements[ $element_id]);
}
// And display
function write_recursive( $element)
{
echo '<ul>...';
if( count( $element['children'])){
foreach( $element['children'] as $child){
write_recursive( $all_elements[ $child]);
}
}
echo '</ul>';
}
You better create class for that (to replace using global variables), but you should have a solid way to do this. Anyway try avoid using this with large number of records (I wouldn't go past 2000-5000 menu entries), try to at least cache it.
Note: solutions are oriented towards minimal number of requests on database when displaying list.
you can use complicated query or something like this
foreach ($catsid as $catid) {
...
$subquery_cat = "SELECT * FROM ^categories WHERE parentid='".$catid['categoryid']."'";
$query = qa_db_query_sub($subquery_cat);
$subcatsid = qa_db_read_all_assoc($query);
// wrap into html
...
}
On a product page I want to show 4 other products selected randomly, but never the product that is already being displayed. The product id of the displayed one is $_product->getId() and all the products go into a $result[] array like this:
foreach($collection as $product){
$result[]=$product->getId();
}
I'm using $need = array_rand($result, 4); to get the ids of the 4 random products, but it might include the id of the product on display. How do I exclude $_product->getId() from the $need[] array? Thank you.
Don't put id of the product you don't want to show into $result:
$currentProductId = $_product->getId();
foreach ($collection as $product) {
if ($product->getId() != $currentProductId) $result[] = $product->getId();
}
Is it acceptable to just not put the current product ID in the array?
foreach($collection as $product) {
if( $product != $_product) $result[] = $product->getId();
}
You might generate your random numbers first, like so:
$rands = array();
while ($monkey == false){
$banana = rand(0,4);
if (in_array($banana, $rands) && $banana != $_product->getId()){ $rands[] = $banana; }
if (sizeOf($rands) == 4){
$monkey = true;
}
}
Then you could pipe them through your product grabber. Obviously, you'd need to figure out the bounds for rand yourself but you know more about your app than I do. Picking your numbers first is much cheaper computationally than pulling records and THEN checking to make sure that they're unique.
Of course, if this is database-backed, you could solve it much more elegantly by writing a new query.
If you use the product id as the index $result[] in result, you can remove the current product from the $result array with unset() before making the call to array_rand() like so:
foreach($collection as $product){
$result[$product->getId()] = $product->getId();
}
unset($result[$_product->getId()]);
$need = array_rand($result, 4);
This approach saves you from having to use the values in $need to look up the product id in your $result[] array, since the values in $need will be your product ids.
I have two tables.
The chapters table has the columns id and name.
The chapters_chapter table has columns id, master_id, and slave_id.
Lets say that the chapters table has 7 records:
id name
1 test01
2 test02
3 test03
4 test04
5 test05
6 test06
7 test07
And in the chapters_chapters table I have these records:
id master_id slave_id
1 1 5
2 1 6
3 6 7
4 7 2
Given that data, how can I extract the hierarchy of that data so that it looks like this?
test01
test05
test06
test07
test02
test03
test04
So this was kind of a pain because of the fact that we had to have the hierarchy stored in the DB. Because of this, each item can have multiple children, and each child can have multiple parents.
This second part means we cannot simply loop through the list once and be done with it. We might have to insert an item in multiple places in the hierarchy. While you probably won't actually structure your data that way, the database schema you've described supports this scenario, so the code must support it too.
Here's a high-level version of the algorithm:
Query both tables
Create a map (array) of a parent (number) to its children (another array)
Create a set of items that are children (array of numbers)
Create a function that displays a single item, indenting it to the desired depth.
If that item has children, this function increases the depth by one, and calls itself recursively
Loop through all items that aren't children (root items).
Call the function for each of those items, with a desired depth of 0 (no indent).
Here's two hours work. Enjoy :)
Note that I stuck it within a <pre> block, so you might have to mess with how the indentation is done (output something other than two spaces, mess with the style of the divs, etc).
<?php
$con = mysql_connect("localhost", "test_user", "your_password");
if(!$con)
{
die("could not connect to DB: " . mysql_error());
}
mysql_select_db("your_db", $con);
// get chapters
$chapters = array();
$result = mysql_query("SELECT * FROM chapters");
while($row = mysql_fetch_array($result))
{
$id = $row["id"];
$name = $row["name"];
$chapters[$id] = $name;
}
// get chapters_chapters - We'll call it "parent/child" instead of "master/slave"
$parent_child_map = array();
$is_child = array();
$result = mysql_query("SELECT master_id, slave_id FROM chapters_chapters");
while($row = mysql_fetch_array($result))
{
$parent_id = $row["master_id"];
$child_id = $row["slave_id"];
$children = $parent_child_map[$parent_id];
if($children == null)
{
$children = array();
}
$children[] = $child_id;
$parent_child_map[$parent_id] = $children;
$is_child[$child_id] = true;
}
// display item hierarchically
$display_item_and_children = function($id, $name, $depth)
use ($chapters, $parent_child_map, &$display_item_and_children)
{
echo "<div><pre>";
// indent up to depth
for($i = 0; $i < $depth; $i++)
{
echo " ";
}
echo "id: " . $id
. " name: " . $name
. "</pre></div>";
// if there are children, display them recursively
$children = $parent_child_map[$id];
if($children != null)
{
foreach($children as $child_id)
{
$child_name = $chapters[$child_id];
$display_item_and_children($child_id, $child_name, $depth + 1);
}
}
};
// display all top-level items hierarchically
foreach($chapters as $id => $name)
{
// if it is a top-level item, display it
if($is_child[$id] != true)
{
$display_item_and_children($id, $name, 0);
}
}
mysql_close($con);
?>
And here's a screenshot:
The question becomes how complex you want your solution to be. I'd do it with the following pseudo code.
SELECT all the chapters
SELECT all the *chapters_chapters*
loop over the chapters to create an array chapter objects
loop over the `chapters_chapters* and create the relationships using the chapter objects
Essentially you're creating a link-list.