Hoe kan ik alle producten tellen binnen categorieen die ook subcategorieen hebben

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Ventilatiesysteem Productontwikkelaar HBO WO Verwa

Samengevat: Zij bieden flexibele ventilatiematerialen, geluidsdempers, rookgasafvoer producten en industrieslangen. Ben jij een technisch productontwikkelaar? Heb jij ervaring met het ontwikkelen van nieuwe producten? Vaste baan: Technisch Productontwikkelaar HBO WO €3.000 - €4.000 Zij bieden een variëteit aan flexibele ventilatiematerialen, geluiddempers, rookgasafvoer producten, industrieslangen en ventilatieslangen voor de scheepsbouw. Met slimme en innovatieve materialen zorgen wij voor een gezonde en frisse leefomgeving. Deze werkgever is een organisatie die volop in ontwikkeling is met hardwerkende collega's. Dit geeft goede ontwikkelingsmogelijkheden. De branche van dit bedrijf is Techniek en Engineering. Functie: Voor de vacature als Technisch Productontwikkelaar Ede Gld HBO WO ga

Bekijk vacature »

Snelle Jaap

Snelle Jaap

09/04/2018 13:08:03
Quote Anchor link
Ik heb een site met producten die binnen categorieeen hangen. Deze categorieen kunnen ook weer binnen subcategorieen hangen. In een zijmenu met alle toplevel categorieen heb ik een cijfer staan per categorie die het aantal producten laat zien binnen deze categorie.

Afbeelding

Dit telt alleen de producten binnen de toplevel categorie. Terwijl er ook producten binnen subcategorieen kunnen staan, deze worden niet meegeteld.

Mijn structuur is nu als volgt:

categorie:
id - categorie id
parent_id - id van parent categorie (topcategory is altijd 1), dit is hetzelfde als het id van zijn parent categorie.


artikel(product)
id - id van het product
catid - id van de categorie waar hij onder hangt (zelfde als id van de categorie)


Dus als mijn data er zo uitziet:

categorie - wastafels - 2 producten
subcategorie - wastafelssub - 5 producten
subsubcategorie - wastafelssubsub - 2 producten

Met mijn huidige code krijg ik naast Wastafels een 2, maar ik zou willen dat hij alles optelt, dus dat er 9 komt te staan.

Dit is nu mijn code:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Haal alle toplevel categorieen op
$pcat             = "SELECT * FROM `snm_categories` WHERE published = 1 and level = 1 and id NOT IN (1) order by rgt ";
$pcatcon          = $conn->query($pcat);
$catids           = '';
while ($pcat      = $pcatcon->fetch_assoc()){
    $catids[] = $pcat['id'];
    // Alle producten binnen bovenstaande categorieen
    $aantal         = "SELECT DISTINCT id FROM `snm_content` WHERE catid = ".$pcat['id']." and state = 1";
    $aantalcon      = $conn->query($aantal);
    $aantal         = $aantalcon->fetch_assoc();

    if(is_null($aantal)){
        $totaal = '';
    }else{
        $totaal = $aantalcon->num_rows;
    }
    if($totaal != 0){
        $amount = '('.$totaal.')';
    }else{
        $amount = $totaal;
    }

    $productcatoverzicht .= '
    <li class="cat-item"><a href="'.$pcat['alias'].'">'.$pcat['title'].'</a><span class="count">'.$amount.'</span></li>';
}
echo productcatoverzicht;


Moet ik dit net als mijn menu code recursief oplossen? Mijn menu code ziet er zo uit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?PHP
    $alias
= $_GET['alias'];
    //Haal alle categorieen en check gelijk of de desbetreffende categorie artikelen onder zich heeft hangen.
    $menu = "
    SELECT cat.id as cat_id, cat.level, cat.parent_id, cat.title as cat_title, cat.alias as cat_alias, cat.published, cat.rgt, cnt.state, cnt.id as content_id, cnt.catid, cnt.title as content_title, cnt.alias as content_alias
    FROM snm_categories cat
    LEFT JOIN snm_content cnt
    ON cnt.catid = cat.id
    WHERE cat.id NOT IN (1, 2, 3, 4, 5, 7)
    AND cat.published = 1
    GROUP BY cat.id
    ORDER BY cat.rgt ASC"
;
    $menuconn = $conn->query($menu);
    // Maak een nieuwe array om te vullen met onderstaand resultaat
    $menuData = array(
        'items' => array(),
        'parents' => array()
    );

    // Maak een nieuwe array met simpelweg items en parents, welke gekoppeld zitten aan cat_id/parent_id
    while($menu = $menuconn->fetch_assoc())
    {

        $menuData['items'][$menu['cat_id']] = $menu;
        $menuData['parents'][$menu['parent_id']][] = $menu['cat_id'];
    }


    // Functie om menu te maken, $parentId is 1 (de categorieen die geen parent hebben)
    function buildMenu($parentId, $menuData)
    {

        $html = '';
        if (isset($menuData['parents'][$parentId]))
        {

            //Als parent_id gelijk is aan 1 gooi een li eromheen (want het is geen subcat) anders een ul
            if($parentId == '1'){
              $html = '<li>';
            }
else{
              $html = '<ul class="sub-menu">';
            }

            foreach ($menuData['parents'][$parentId] as $itemId)
            {

                $html .= '<li class="menu-item"><a href="'.$menuData['items'][$itemId]['cat_alias'].'">'.$menuData['items'][$itemId]['cat_title'].'</a>';

                // Voer deze functie uit binnen de functie loop (recursief)
                $html .= buildMenu($itemId, $menuData);

                $html .= '</li>';
            }

            //Als parent_id gelijk is aan 1 gooi een li eromheen (want het is geen subcat)
            if($parentId == '1'){
              $html .= '</li>';
            }
else{
              $html .= '</ul>';
            }
        }

        return $html;
    }

    // Echo het resultaat van de functie en geef 1 mee als parent_id
    echo buildMenu(1, $menuData);
    ?>


Hoe kan ik dit het beste oplossen?
 
PHP hulp

PHP hulp

05/11/2024 15:40:53
 
Ben van Velzen

Ben van Velzen

09/04/2018 13:41:07
Quote Anchor link
Op exact dezelfde manier als buildMenu werkt. Gewoon data in 1 keer ophalen en in PHP verwerken. Als je een wat geavanceerdere database gebruikte kon je een recursieve query schrijven maar dat is hier niet van toepassing. Overigens, waarom noem je je resultsets $xxxcon? Het is geen verbinding maar een resultaat.
Gewijzigd op 09/04/2018 13:41:53 door Ben van Velzen
 
Ivo P

Ivo P

09/04/2018 16:35:00
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
    SELECT cat.id as cat_id, cat.level, cat.parent_id, cat.title as cat_title, cat.alias as cat_alias, cat.published, cat.rgt, cnt.state, cnt.id as content_id, cnt.catid, cnt.title as content_title, cnt.alias as content_alias
    FROM snm_categories cat
    LEFT JOIN snm_content cnt
    ON cnt.catid = cat.id
    WHERE cat.id NOT IN (1, 2, 3, 4, 5, 7)
    AND cat.published = 1
    GROUP BY cat.id
    ORDER BY cat.rgt ASC";


wat doet die group by daar?
Je gebruikt nergens een aggregatie functie (zoals sum(), count()) dus waarom dan group by?
En als je dat al toepast: dan staan achter group-by alle kolommen die niet een aggregatie functie. Dus gewoon alle kolommen in jouw geval, dus netto zou dat niets doen.
 
Thomas van den Heuvel

Thomas van den Heuvel

09/04/2018 16:42:57
Quote Anchor link
Wat @Ben zegt, de recursie werkt precies hetzelde, alleen het werk wat je verzet tijdens een iteratie (stap) is anders.

In feite is het zaak dat je een optelsom van de "children" maakt.

Nu heb je e.e.a. als volgt gestructureerd:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
while($menu = $menuconn->fetch_assoc())
{

    $menuData['items'][$menu['cat_id']] = $menu;
    $menuData['parents'][$menu['parent_id']][] = $menu['cat_id'];
}

?>

(waarbij "parents" eigenlijk "children" zou moeten zijn?)
Maar je zou het ook als volgt kunnen doen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// @todo maak hier een onzichtbaar root-element, in wezen initialiseer je $menuItems hier
$menuItems[0] = array(
    'data'     => array(/* zet hier bijvoorbeeld een label in */),
    'parent'   => false,
    'children' => array(),
);

// haal hier *alle* items in de goede volgorde op, inclusief root-elementen
while($menu = $menuconn->fetch_assoc())
{

    $parentId = $menu['parent_id'] === NULL ? 0 : $menu['parent_id'];
    $menuItems[$menu['cat_id']] = array(
        'data'     => $menu,
        'parent'   => $parentId,
        'children' => array(),
    );

    // voeg item toe als child van parent
    $menuItems[$parentId]['children'][] = $menu['cat_id'];
}

?>

Hierbij helpt het als je dus in de query de root-elementen toevoegt, en hierboven nog een soort van "onzichtbare" root zet waaraan alle root-elementen verbonden zijn. Op die manier krijg je een echte boom (met één hoofd-root) waar je makkelijk doorheen kunt lopen.
Gewijzigd op 09/04/2018 16:49:39 door Thomas van den Heuvel
 
Snelle Jaap

Snelle Jaap

09/04/2018 16:51:57
Quote Anchor link
Die onzichtbare root is er eigenlijk al, alle topcategorieen hebben parent_id 1, die 1 is de categorie ROOT in mijn database. Ik ga hier is wat mee proberen, zelf kwam ik op dit uit (niet werkend en waarschijnlijk nog vol fouten):

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function getProdsInCat($cat, $conn){
        global $prods;
        // Tell alle producten binnen de doorgegeven categorie
        $countproducts    = "SELECT COUNT(`id`) FROM `snm_content` WHERE `catid` = '".$cat."'";
        $countproductscon = $conn->query($countproducts);
        $countproducts    = $countproductscon->fetch_assoc();

        // Haal alle categorieen op waar parent_id gelijk is aan het meegestuurde id
        $countcats       = "SELECT * FROM snm_categories WHERE parent_id = '".$cat."'";
        $countcatscon    = $conn->query($countcats);
        while($countcats = $countcatscon->fetch_assoc()){
            getProdsInCat($countcats['id'],$conn);
        }
    }
    // Loop alle categorieen en stop de functie in de loop zodat deze alle ids doorgeeft aan de functie
    $allcats = "SELECT * FROM snm_categories WHERE published = 1";
    $allcatsconn = $conn->query($allcats);
    while($allcats = $allcatsconn->fetch_assoc()){
      $allprods = getProdsInCat($allcats['id'], $conn);
    }
 
Thomas van den Heuvel

Thomas van den Heuvel

09/04/2018 17:45:36
Quote Anchor link
Misschien heb ik het niet goed uitgelegd. Het is hier weer een kwestie van problemen opsplitsen denk ik.

Eerst bouw je een datastructuur in de vorm van een boom, en vervolgens laat je op deze boom recursieve functies los. Op het moment dat je voldoende informatie in deze datastructuur hebt zitten kun je daarmee de dataverrijking uitvoeren (bijvoorbeeld het tellen van het totaal aantal children van een categorie) zonder verdere tussenkomt van een database.
 
Ward van der Put
Moderator

Ward van der Put

09/04/2018 17:53:29
Quote Anchor link
Thomas van den Heuvel op 09/04/2018 17:45:36:
Het is hier weer een kwestie van problemen opsplitsen denk ik.

Eens. En het eerste probleem is dan: wáárom moet er überhaupt een telling in een menu worden getoond? ;-)
 
Snelle Jaap

Snelle Jaap

11/04/2018 15:23:03
Quote Anchor link
Ward van der Put op 09/04/2018 17:53:29:
Thomas van den Heuvel op 09/04/2018 17:45:36:
Het is hier weer een kwestie van problemen opsplitsen denk ik.

Eens. En het eerste probleem is dan: wáárom moet er überhaupt een telling in een menu worden getoond? ;-)

Waarom niet?
 
Ramon van Dongen

Ramon van Dongen

12/04/2018 07:59:11
Quote Anchor link
Snelle Jaap op 11/04/2018 15:23:03:
Waarom niet?


Ah, nu komen we ergens. Door dit soort inhoudelijke vragen is het probleem snel opgelost :-)
 
Rob Doemaarwat

Rob Doemaarwat

12/04/2018 18:01:52
Quote Anchor link
Gewoon recursief doen:
- vanuit je "root" genereer je de sub-menus
- vanuit de sub-menus geef je naast de resulterende HTML ook het aantal items terug (en tel je die op bij de items in het menu zelf - en die geef je weer terug, enz).
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.