Autor Zpráva
Pavlii
Profil *
Zdravím Vás,

Našla by se tu nějaká dobrá duše, která by rozlouskla pro mě velkou záhadu? Hledal jsem řešení po celém fóru, asi špatně, protože jsem nenašel. Tvořím takový přehled - databázi poskytovatelů internetového připojení, kdy (jak je známo) signál se šíří od souseda k sousedovi, proto jsem využil MySQL a v PHP se snažím do WHILE includovat WHILE až do několikáté úrovně. Tedy řešil jsem to tak:

První soubor je index.php
$l = 0;   //nastavení počáteční úrovně
$ref[$l] = "provider";  //array pro uložení vyhledávacího identifikátoru
include "config.php";   //spojení s databází + nastavení kódování atd.
include "select.php";   //výpis z databáze


a druhý soubor select.php vypadá takhle:
$dotaz = mysql_query("SELECT * FROM users WHERE poskytovatel = '$ref[$l]'");   //dotaz na MySQL
while($vypis = mysql_fetch_array($dotaz))
    {
    echo "<p style=\"text-indent: " . $indent . "px; background-color: " . $barva . "\">" . $vypis[id] . "&nbsp;&nbsp;&nbsp;" . $vypis[name] . "&nbsp;&nbsp;&nbsp;" . $vypis[poskytovatel] . "</p>";
    $dalsi = mysql_query("SELECT * FROM users WHERE poskytovatel = '$vypis[name]'");   //dotaz na další napojené subjekty
    $pocet = mysql_num_rows($dalsi);   //počet napojených subjektů
        {
        if ($pocet > 0)
            {
            $l++;   // Povýšení úrovně o 1
            $ref[$l] = $vypis[surname];  //přiřadí vyhledávací klíč
            include "select.php";  //načte opět sám sebe
            }
        }     
    }

Script vypíše poskytovatele až do poslední úrovně a tam se zastaví. Nevím proč, nevrátí se o úroveň výš, aby dopsal zbývající poskytovatele, takže výpis vypadá třeba takhle:

Výpis poskytovatelů:
Ostrava - provider
    Mošnov - Ostrava
        Krmenín - Mošnov
            ABC plast s.r.o. - Krmelín
            MŠ Beruška - Krmelín
            Bartošovice - Krmelín
                Zámek - Bartošovice
                Obecní úřad - Bartošovice
                    Dvořák - Obecní úřad
                    Matějíčkovi - Obecní úřad
                    Brda - Obecní úřad
                        Chadima - Brda

Taže pod Mošnovem je dalších 8 "odběratelů", pod Krmelínem 22 a k nim už se ve výpise neumím dostat. :-(
Kde dělám chybu?
DJ Miky
Profil
Vkládaný skript používá stejné proměnné, takže si výsledek dotazu (proměnná $dotaz) vyšší úrovně přepíšeš výsledkem dotazu nižší úrovně, tedy po návratu na vyšší úroveň zůstane v $dotaz výsledek dotazu nižší úrovně (který už neobsahuje žádné další záznamy). Navíc by to nejspíš nefungovalo správně ještě z jednoho důvodu, a sice kvůli proměnné $l, kterou sice inkrementuješ, ale už nevracíš zpět při návratu z nižší úrovně.

Obvykle se takovýto problém místo rekurzivního vkládání souborů řeší rekurzivním voláním funkce. U funkce ti problém se stejně pojmenovanou proměnnou nevznikne, protože lokální proměnné ve funkci nejsou vidět jinde.

Ještě jedna věc: Pokud bude úrovní a záznamů hodně, bude výrazně narůstat počet SQL dotazů, což může negativně ovlivnit rychlost webu. Proto se vyplatí např. vytáhnout všechny záznamy najednou, uložit je do pole (kde klíčem bude třeba ID) a rekurzivní výpis provádět až nad polem. Tím se vykoná vždy pouze jediný dotaz bez ohledu na počet záznamů a úrovní.
Pavlii
Profil *
DJ Miky:
Děkuji, zkoušel jsem (předtím, než jsem vůbec o radu psal) i snižování úrovní, ale to mi záhadně způsobuje binec v poli. Tedy $ref[6] by se mělo rovnat "Chadima", ale proměnná mi vypíše "ChadimaChadimaChadimaChadimaChadimaChadima". Takže jsem již ztracen. Teď jsem se ještě pokusil to přepsat do function, ale to jsem už nerozběhal vůbec :-( Jsem prostě lama.
Alphard
Profil
Prohledávání stromu nění nijak unikátní úloha, existuje hromada hotových řešení. Zpaměti znám jenom interval.cz/clanky/metody-ukladani-stromovych-dat-v-relacnich-databazich ale několikrát sem někdo dával i hotovou verzi se stažením dat do pole a rekurzí jen na úrovní PHP. Ale opatrně vzhledem k celkové velikosti databáze, jak tady vidím členění až na úroveň jednotlivých obcí, mám obavy, jestli by načtení všeho do pole byl dobrý nápad.
Pavlii
Profil *
Alphard:
Děkuji Ti Alphard, tohle by mi jako nakopnutí mělo stačit. Tři hodinky jsem pospal a hned mám čistější hlavu :-) Takže jdu to vyzkoušet!
Kcko
Profil
Alphard: To jsem byl možná já.

Pavlii:
http://sandbox.rjwebdesign.cz/dbmenu/pg.php
http://sandbox.rjwebdesign.cz/dbmenu/source.phps
Pavlii
Profil *
Tak jsem to zkusil hodit do funkce, běží, ale asi jen do 3. úrovně, pak to začne dělat blbosti. Jakože záznam z 1. úrovně mi vrazí do 3. a nevím proč. :-(

function getTree($parent, $level)
    {
//    include "config.php"; 
    $result = mysql_query("SELECT * FROM users WHERE poskytovatel='$parent'");
    while ($row = mysql_fetch_array($result))
        {
        $odsazeni = $level * 30;
        echo "<p style=\"text-indent: " . $odsazeni . "pt\">" . $level . "&nbsp;" .$row['name']. "&nbsp;" .$row['poskytovatel']. "<br />";
        getTree($row['poskytovatel'], $level++);
        }
    }

getTree("ostrava", 1);

navíc potřebuji vypsat celý strom, i když to bude velký...
DJ Miky
Profil
Chyba je v $level++, inkrementace ti změní původní hodnotu, takže v dalším průchodu cyklem už bude nesprávně o jedničku zvýšená, tím se ti druhý záznam první úrovně vykreslí na druhou úroveň, třetí záznam první úrovně na třetí apod. (a jejich podstromy budou stejným způsobem posunuté na nižší úroveň, než by měly). Místo inkrementace bys měl použít $level + 1, tak se aktuální úroveň nezmění.
Pavlii
Profil *
DJ Miky:
Skvěle Miky, teď to běží jak má :-)
Díkz moc za pomoc

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: