1

I am trying to display a product on each category starting from the top parent category all the way down to the category. I have my db setup like this:

CATEGORY TABLE:
id  |  parent_id   |  root_cat   |  name
5       37              0            bulbs
45      5               0            standard auxiliary
289     45              5            standard
297     289             5            5W

Now this is the products table table:

id    |   name    |   cat
470       bulb 5w      297

And this is happening, when i click on the bulbs category i see the product just fine, but when i click in the sub category standard auxiliary i do not see the product. But if i go another level to standard i can see the product again and also if i click on the 5W cat i also see the product. So the problem is only on the standard auxiliary category.

This is the method i am using to retrieve the data: $table_2 is the products table and $table is the category table.

public function getProductsWhereParentIdis($cat) {
        $check = $this->checkCategoryChildren($cat);
        if($check) {
            $query = "
            SELECT * 
            FROM categories 
            INNER JOIN products 
            ON products.category = categories.id 
            WHERE categories.id = '".$this->db->escape($cat)."' 
            OR categories.parent_id = '".$this->db->escape($cat)."' 
            OR categories.root_category = '".$this->db->escape($cat)."'";   

            return $this->db->fetchAll($query);
        } else {
            $query = "SELECT * FROM {$this->table_2} WHERE category = '".$this->db->escape($cat)."'";

            return $this->db->fetchAll($query);
        }


    }

and this method is just to check if a product has a parent:

public function checkCategoryChildren($id = null) {
        if(!empty($id)) {
            $query = "SELECT * FROM {$this->table} WHERE parent_id = '".$this->db->escape($id)."' ORDER BY view_order ASC";

            return $this->db->fetchAll($query);
        }
    }

and this is the fetchAll method:

public function query($query) {
        $this->last_query = $query;
        $result = mysqli_query($this->connection, $query);
        $this->confirm_query($result);
        return $result;
    }

    public function confirm_query($result) {
        if(!$result) {
            $output  = "Database query failed<br />";
            $output .= "Last SQL query: ". $this->last_query;
            die($output);
        } else {
            $this->affected_rows = mysqli_affected_rows($this->connection);
        }
    }

    public function fetchAll($query) {
        $result = $this->query($query);
        $output = array();
        while($row = mysqli_fetch_assoc($result)) {
            $output[] = $row;
        }
        mysqli_free_result($result);
        return $output;
    }

Really looking forward to anyones suggestion as to why i can see the product in all the categories but one, thank you.

Blu3
  • 143
  • 2
  • 19
  • How many combinations are there? – Strawberry Aug 26 '19 at 22:35
  • i tried 3 getting id, parent_id and another root_parent which i have not typed down but it still does not get the desired effect – Blu3 Aug 26 '19 at 22:37
  • dont worry Dharman, i escape every query but you just do not see it because i call a method from a different class, the escape method i call on each input relieves me of any sql injections – Blu3 Aug 26 '19 at 22:40
  • @Strawberry i removed the inner from the statement but it has not different effect – Blu3 Aug 26 '19 at 22:45
  • 5
    It's not about escaping, manual escaping is the problem. Use prepared statements with placeholder values. It means far less code and far fewer problems as a bonus. – tadman Aug 26 '19 at 22:50
  • ok thank you but if you could help me with my problem that would be great – Blu3 Aug 26 '19 at 22:50
  • @Dharman do you have any idea how i can achieve this – Blu3 Aug 27 '19 at 08:11
  • @Blu3 in the category table, why doesn't the category id = 45 has the root_cat value = 0. It should be 5. – Madhur Bhaiya Aug 29 '19 at 04:11
  • it doesnt have it because it is coming right from the root in this case and even when i put it, it does not make a difference – Blu3 Aug 29 '19 at 06:31
  • So what you want you want bulb product no matter which category user clicked right? @Blu3 – Dhaval Purohit Aug 29 '19 at 10:59
  • Another question, Is product always mapped with the last children or it may mapped with root or intermediate categories? @Blu3 – Dhaval Purohit Aug 29 '19 at 11:00
  • Take a look at this [question](https://stackoverflow.com/questions/20215744/how-to-create-a-mysql-hierarchical-recursive-query) – Michal Hynčica Aug 29 '19 at 21:19

2 Answers2

2

Here is the solution i think you are looking for the main problem is you are only seeing category data which are only one level up or one level down

I have also mentioned some comments in the code kindly check it. And i also don't know how your fetchAll() function return the data. eg. object or array.

Edited: So in this code fetchAll() function return the data in array format because you have used mysqli_fetch_assoc()

public function getProductsWhereParentIdis($cat)
{
    $check = $this->checkCategories($cat);
    if (!empty($check)) {
        $query = "
        SELECT * 
        FROM categories 
        INNER JOIN products 
        ON products.category = categories.id 
        WHERE categories.id in (".(implode(",", $check)).")";
        return $this->db->fetchAll($query);
    } else {
        $query = "SELECT * FROM {$this->table_2} WHERE category = '".$this->db->escape($cat)."'";

        return $this->db->fetchAll($query);
    }
}

public function checkCategories($cat_id)
{
    $query = "SELECT * FROM {$this->table} WHERE id = '".$this->db->escape($cat_id)."' ORDER BY view_order ASC";
    $catObj = $this->db->fetchAll($query);
    $childs = $this->getChildCategoryIds($cat_id);
    $childs[] = $cat_id;
    // you can remove the parents from here if you don't want to get all
    // products which have parents categories associated in it.
    // eg. while user click on standard then if you don't want to get the products which
    // is assigned with bulbs or standard auxiliary then return only childs.
    $parents = $this->getParentCategoryIds($catObj[0]['parent_id']);
    return array_merge($childs, $parents);
}

public function getChildCategoryIds($cat_id)
{
    $cat_array = [];
    $q = "SELECT * FROM {$this->table} WHERE parent_id = '".$this->db->escape($cat_id)."' ORDER BY view_order ASC";
    $result = $this->db->fetchAll($q);
    foreach ($result as $value) {
        $tmp_array = $this->getChildCategoryIds($value['id']);
        $cat_array[] = $value['id'];
        if (!empty($tmp_array)) {
            $cat_array = array_merge($cat_array, $tmp_array);
        }
    }
    return $cat_array;
}

public function getParentCategoryIds($cat_id)
{
    $cat_array = [];
    $q = "SELECT * FROM {$this->table} WHERE id = '".$this->db->escape($cat_id)."' ORDER BY view_order ASC";
    $result = $this->db->fetchAll($q);
    if (!empty($result[0]['parent_id'])) {
        $tmp_array = $this->getParentCategoryIds($result[0]['parent_id']);
        $cat_array[] = $result[0]['parent_id'];
        if (!empty($tmp_array)) {
            $cat_array = array_merge($cat_array, $tmp_array);
        }
    }

    return $cat_array;
}
Dhaval Purohit
  • 1,270
  • 10
  • 28
  • i have included the fetchAll method as well for you to see, i took your code and tested it but unfortunately it did not work. in the checkCategories method you wrote $q and i changed it to $query to match the $catObj varible because it was throwing an error – Blu3 Aug 29 '19 at 13:03
  • then all access to the result would be like `$result[0]['parent_id']` Let me edit the answer – Dhaval Purohit Aug 29 '19 at 13:06
  • @Blu3 Check now – Dhaval Purohit Aug 29 '19 at 13:11
  • no now it does not work correctly at all. keep in mind when i click on bulbs i see the product in the last child category and the products assigned to each other category under the top main category, the only problem is in the second tier, here let me add some photos for you to see the results with my code – Blu3 Aug 29 '19 at 13:22
  • done, just added them, tell me if you understand it completely – Blu3 Aug 29 '19 at 13:32
  • Ok give me 2 min i will get back to you @Blu3 – Dhaval Purohit Aug 29 '19 at 13:38
  • I have updated the code and test it locally with the data structure you given and i am able to get bulb if the category is `standard auxiliary` @Blu3 – Dhaval Purohit Aug 29 '19 at 13:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/198663/discussion-between-dhaval-purohit-and-blu3). – Dhaval Purohit Aug 29 '19 at 13:57
  • so based on what i can see here i no longer need the root_category at all for this to work – Blu3 Aug 30 '19 at 15:44
  • thank you very much, it is amazing what you did and i will definitely learn a lot from this, thank you again – Blu3 Aug 31 '19 at 16:31
0

FWIW, I find this easier to read...

SELECT c.olumms
     , i.actually
     , w.ant
  FROM categories c
  JOIN products p
    ON p.category = c.id 
 WHERE :mystring IN (c.root_category,c.parent_id,c.id);
Strawberry
  • 33,750
  • 13
  • 40
  • 57
  • what is the :mystring IN.... i do not understand how i should type this – Blu3 Aug 26 '19 at 23:22
  • See about placeholders for prepared and bound queries – Strawberry Aug 26 '19 at 23:24
  • but this does not work because when i enter the first sub like fiat it does not show anything unless i go to hatchback or saloon, you understand? – Blu3 Aug 26 '19 at 23:38
  • This comes back to my first comment – Strawberry Aug 26 '19 at 23:42
  • it goes like this: Auto -> Bulbs - > Standard Auxiliary - > Standard - > 1.2W – Blu3 Aug 26 '19 at 23:45
  • when clicking on bulbs i see everything from 1.2W but when i click on standard auxiliary it does not show anything unless i go one more level to standard, then i can see the 1.2W. Hope this is clear – Blu3 Aug 26 '19 at 23:47
  • did this answer your first comment? – Blu3 Aug 27 '19 at 00:24
  • No. I was expecting a number. – Strawberry Aug 27 '19 at 06:10
  • could you please help me out as i do not understand what you are seeking. for example in my case you can start from the bulbs part and if we go all the way down to 1.2W. it means it is 3. is this the number you are expecting? – Blu3 Aug 27 '19 at 06:32
  • strawberry please help me out – Blu3 Aug 27 '19 at 08:08
  • around 3k of products and less than 300 for categories – Blu3 Aug 27 '19 at 08:31
  • Well, you can probably hold 3k in memory quite efficiently, so I would be tempted to push everything into json and parse it with some javascript - but that doesn't help you with your organizational problem, which (although you can solve it with your present model), I'd instead be tempted to solve with a different model. Maybe take a look at nested sets. – Strawberry Aug 27 '19 at 08:40
  • so you have no suggestions how i can achieve this with a sql query? – Blu3 Aug 27 '19 at 08:41
  • i ask because every category works except one which tells me that everything is fine i just need to figure out why only one category the product is not being displayed – Blu3 Aug 27 '19 at 08:43