ugrás a tartalomhoz

PHP fa-szerkezet

vtsoftware · 2014. Dec. 13. (Szo), 13.10
Üdv mindenkinek!

Adott a következő tömbszerkezet:
$prods = array("Főkategória"=>
  array(
    "url"=>"fokategoria",
    "sub"=>array(
      "Gyártó"=>array(
        "url"=>"gyarto",
        "sub"=>array(
          "Termékcsalád"=>array(
            "url"=>"termekcsalad"
          )
        )
      )
    )
  )
);
Ez alapján szeretnék valahogy egy mysql adatbázisba fa-szerkezetes formában egy menüt eltárolni ahol a következő a struktúra.
category_id | parent_id | title       | url
1           | 0         | Főkategória | fokategoria
2           | 1         | Gyártó      | gyarto
3           | 2         | Család      | csalad


Erre van számtalan példa a neten, de nem az Én problémámra adnak megoldást.
Vagy Ul-Li kódot hoz létre, vagy adatbázisba illeszt, Én viszont az elején akadok el, a tömbön való végigmászással, a parent_id meghatározásával.
Amit találtam eddig, ott mindegyikben meg volt adva a parent_id.
Nos, ez a problémám, a parent_id-t nem tudom, hogy számoljam ki a tömbön mászkálva.

A továbbiakkal nincs gond, kézzel létrehozott tömbön végigmegyek és táblába is szúrom, de ezen az alaptömbön végigmenni és a parent_id-t megadni, valahogy nem megy.

Ehhez kérnék segítséget...
Előre is köszönöm!
 
1

rekurzió

Pepita · 2014. Dec. 13. (Szo), 23.55
Írj egy rekurzív fv-t.
Ami meghívja saját magát, ha van 'sub' kulccsal eleme az aktuális elemnek.
Így át tudod adni a szülőt is.

Vigyázni kell, hogy ne kerülhessen túl nagy mélységű ciklusba.

Ha jól emlékszem, Poetro-nak van fent ilyesmi cikke. Próbáld meg, ha nem megy, segítünk.
2

Rosszul emlékszel. Poetronak

pp · 2014. Dec. 14. (V), 06.22
Rosszul emlékszel.

Poetronak nincs ilyesmi cikke. Egy nagyon jó SitePoint-os cikket fordított és az jelent itt meg a weblaboron. A fordírtás és az eredeti cikk sem ad választ arra a kérdésre, amit feltett a kérdező.
4

sorry

Pepita · 2014. Dec. 14. (V), 14.20
Telefonról csak a saját memóriámra hagyatkoztam, amit nem ártana bővíteni. :)

Viszont abban nagyon egyetértünk, hogy ilyen és hasonló fa-problémáknál érdemes végigolvasni.
3

A kérdést így nem lehet megválaszolni.

pp · 2014. Dec. 14. (V), 07.00
Az van, hogy neked van a memóriában egy nagy halom összefüggő adathalmazról egy reprezentációd, és azt kell elmentened adatbázisba. Igen ám, de szükséged van az egymással összefüggő elemek adatbázisban tárolt egyedi azonosítójára, ahhoz, hogy elmentsd. De amíg nincs adatbázis reprezentációd, addig nem tudod azokat.

Lehet azt, hogy elmented az összes adatot az adatbázisba, így megkapod azok azonosítóját(category_id), majd még egyszer végigmész az elemeken és beállítod a kapcsolódó azonosítókat (parent_id).

Lehet azt is, hogy úgy mész végig a fán, hogy amikor egy elemet elmentesz, a szülő elem már el volt mentve, így tudod az azonosítóját. Az egyik lehetséges bejárás a Pepita által javasolt rekurzív bejárás, mely a legegyszerűbben implementálható, de nagyon sok erőforrást ehet. De ezen ne aggódj, kizárt, hogy olyan mélységű lenne a menü, hogy azt ne tudd feldolgozni. (Ezt abból gondolom, hogy eleve már a memóriában van)

Van egyéb bejárási módszer is, de nem akkora az adathalmaz, hogy ezzel kelljen most foglalkoznod, bár ha fejlődni akarsz, akkor érdemes azokkal is eljátszanod.

A másik kérdés, hogy hogyan tárold az adatbázisban az adatokat.

Az általad mutatott tárolási módszer az egyik legegyszerűbb, aminek a hátránya, hogy pl. morzsamenüt (útvonal egy adott levélig) nehéz generálni vele, meg részfákat se olyan egyszerű előállítani egy darab sql lekérdezéssel. A Pepita által említett cikkben ezt a kérdést járják körbe, szerintem érdemes elolvasnod.

pp
5

Gondom a kulcs

vtsoftware · 2014. Dec. 15. (H), 12.47
Sziasztok!

Köszönöm a válaszokat, amiket írtatok mind kipróbáltam...

Ha egy rekurzív tömbön kell végigjárni, aminek kulcsai számok, értékük pedig a cím/url-ből álló tömb, valamint maga az alkategória, rendben lenne a dolog.
Ami megakaszt, hogy itt a kategória címe a tömb kulcsa.

Hogy részletesebb legyek...
Egy xlsx fájlt kell feldolgozni, amiben laponként vannak a gyártók.
A termékcsaládok és a kategóriák pedig egy-egy oszlopban.
Először pedig ugyebár a lapokon tudok végigmenni (legalábbis a SimpleXLSX-et használva), de a menü struktúrájában a kategória a legfelső szint, alatta a gyártók, ez alatt pedig a családok.

Sajnos az xlsx-en nem lehet módosítani...
A táblázat felépítése:
id  |  kategória  |  család  |  megnevezés . . .
0   |  kateg1     |  csalad1 |  krémes
1   |  kateg1     |  csalad1 |  kávé
2   |  kateg1     |  csalad2 |  üdítő
3   |  kateg2     |  csalad1 |  pogácsa
4   |  kateg2     |  csalad2 |  kifli
----------------
gyártó1 | gyártó2 | gyártó3


Lehet rossz oldalról közelítem meg a dolgot, de a jelenlegi állás szerint:
- végigmegyek a lapokon
- végigmegyek a sorokon

Soronként:
- Létrehozok egy tömböt, kulcsa a kategória, megadom az url értékét.
$categories[_KATEGÓRIA_]['url'] = 'kategoria';
- Ezen tömbbe szúrok egy sub tömböt, ezen belül pedig egy gyártó kulccsal rendelkező tömböt, melynek ugyancsak megadok egy url értéket.
$categories[_KATEGÓRIA_]['sub'][_GYÁRTÓ_]['url'] = array('url'=>'gyarto');
- Majd folytatva a dolgot, ugyan ezt a termékcsaládhoz is...
$categories[_KATEGÓRIA_]['sub'][_GYÁRTÓ_]['sub'][_CSALÁD_] = array('url'=>'csalad');
Nem épp a legjobb megoldás, de ez tűnt logikusnak, így gondoltam elkerülni az ismétlődést.
Rekurzívan terveztem végigmenni rajta, megadva a parent_id-t, de nem tudom hogy számoljak... stb.

Ezen felül próbálkoztam a következővel is.
$categories[_KATEGÓRIA_][_GYÁRTÓ_][_CSALÁD_] = '';
Ezzel ugyebár nem lenne gond az ismétlődés, a szülő tömb is megvan, de a végigmászás...
function recu($arr, $step=0) {
  $res=array();
  foreach ($arr as $key=>$val) {
    if (is_array($val)) {
      $res[]=recu($val, ++$step);
    } else {
      $res[]=array('title'=>$key, 'url'=>urlencode($key));
    }
  }
  return $res;
}
var_dump(recu($categories));
De rosszak az indexek, ami alapján a parent meglehetne...
array() {
  0=>array() {
    'title'=>'Kategória',
    'url'=>'kategoria',
    'parent_id'=> 0,
    'sub'=>array() {
      0=>array() {
        'title'=>'Gyártó',
        'url'=>'gyarto',
        'parent_id'=> 1,
        'sub'=>array() {
          0=>array() {
            'title'=>'Család',
            'url'=>'csalad',
            'parent_id'=> 2
          }
        }
      }
    }
  }
}


Mit javasoltok?

Előre is köszönöm...
6

Minek építed fel a memóriában

pp · 2014. Dec. 15. (H), 15.59
Minek építed fel a memóriában is a dolgot?

Végigmész a lapokon, ami ugye úgy néz ki, hogy végigmész a sorokon, és minden sorra a következőt teszed:
1. Lekérdezed a kategória adatait az adatbázisból, ha nincs akkor létrehozod.
2. Lekérdezed a gyártó adatait az adatbázisból, ha nincs akkor létrehozod.
3. Lekérdezed a család adatait az adatbázisból, ha nincs akkor létrehozod. (ha ez nem unique akkor a gyártót is át kell adni a lekérdezésnek, nem csak a nevét)
4. Elmented a terméket az adatbázisba, a megfelelő család (gyártó, kategória) adatokkal együtt.

Import done.

pp
7

Rendben is lenne, de...

vtsoftware · 2014. Dec. 15. (H), 16.31
Amit írsz, rendben is volna.
De itt annyi a probléma, hogy elég sok adatról van szó ami kb. 25 lapot, laponként 20 - 1.000 sort jelent.

Az általad leírtakat mind-mind soronként végigvinni túl sokáig tartana.
... vagy félreértettem valamit. :)
És gondolnom kell a jövőre is, ennél csak több adat lesz.

Amiatt gondoltam tömbökre, mert hamarabb tudom ellenőrizni azt, hogy létezik-e a rekord, avagy sem, gondolok itt a kulcsokra.
Az általad írt módszer és a tömbök közt ahogy Én gondolom van futásidő beli különbség... ami esetemben sokat számít.

Persze nem elvetendő ötlet, sok adat van, ami a gondot okozza, az az ismétlődés a sorokban...
A másik ami miatt szükségem van a tömbökre, az, hogy az url-eket php függvénnyel formázom meg.
8

nem egy megoldás a problémádra..

EL Tebe · 2014. Dec. 15. (H), 17.06
..de érdemes átnézni ezt, mert megkönnyíti a tömbön való végigfutkosást:

RecursiveArrayIterator class
9

Megvolt, az akadás oka ugyanaz...

vtsoftware · 2014. Dec. 15. (H), 17.11
Már átnéztem, de végül mindig ugyan oda jutok.

A parent_id-t nem tudom a kulcsok felhasználtságával azokból szerezni, egyébként pedig nem tudom hogy-s-mint tudnám kiszámolni, hol kell ++-olni... :D
10

Legalább próbáld meg. :)

pp · 2014. Dec. 16. (K), 08.44
Nem értelek.

"Az általad leírtakat mind-mind soronként végigvinni túl sokáig tartana."

Az adatbázis azonosítót, csak azután kapod meg, miután elmentetted. Hogyan lehetne gyorsabban? Egyébként ha egy kategóriát egyszer beolvastál/létrehoztál, tarthatod a memóriában, attól a fenti megoldás még működni fog.

function get_category($nev) {
  static $categories = array();
  if (!isset($categories[$nev])) {
    $categories[$nev] = ...adatbazis műveletek...;
  }
  return $categories[$nev];
}
"A másik ami miatt szükségem van a tömbökre, az, hogy az url-eket php függvénnyel formázom meg."
Ennek mi köze az importhoz?

Úgy érzem teljesen rossz fele indultál el. Az első, hogy beimportálod az excelt az adatbázisba(ami akár egy var_export is lehet egy fájlban) és után foglalkozol a megjelenítéssel, de ekkor az xls-t már el lehet felejteni.

pp
11

pontosan

Pepita · 2014. Dec. 16. (K), 09.00
Igaza van pp-nek, elobb a nyers adatokat toldd be egy (v. Több) tablaba, utana azzal mar konnyebben vegzel barmi muveletet.

probald ki amiket irt.
12

Jogos...

vtsoftware · 2014. Dec. 16. (K), 15.57
Igazat kell adnom nektek, de nem erről van szó, még az excel importálásnál tartok...
A megjelenítés majd ez után, bár az elmélet már megvan rá, de előbb legyen valami az adatbázisban. :)

Adott az excel táblázat.
Azt tömbként tudom csak feldolgozni, SimpleXLSX használatával...
include('../simplexlsx.class.php');
$xlsx = new SimpleXLSX('_XLSXFÁJL_');
$gyartok = $xlsx->sheetNames();

foreach ($gyartok as $gyi=>$gyartonev) {
  $rows = $xlsx->rows($gyi);
  foreach ($rows as $i=>$row) {
    $categories[$row[_KATEGCOL]][$gyartonev][$row[_CSALADCOL]] = '';
  }
}
A megjelenítéssel nem lesz gondom, az már adatbázisból megy.
De most az excelben található adatokat szeretném valahogy a szülő-gyermek kapcsolatok megállapításával az adatbázisba írni.

A fenti kóddal a szülő-gyermek kapcsolatok megvannak.
Az okoz gondot, hogy ami alapján a végigjáráskor be tudnám azonosítani a szülő-tömböt, az szöveg, nem pedig szám.

A fentebb létrejövő tömbön szeretnék valahogy úgy végigjárni-kelni, hogy közben tudom számolni a kategóriákat, a gyártók parent_id-jének megadni, s így tovább, közben mindegyik elemnek megadni a címét és az url-jét.

A feldolgozásához valahogy így kezdenék neki: (elméletben)
foreach ($categories as $categ_row) {
  $db->prepare("INSERT INTO `categories` (`categ_id`, `parent_id`, `title`, `url`) VALUES (:categ_id, :parent_id, :title);");
  $db->bindParam(':categ_id', $categ_row['categ_id']);
  $db->bindParam(':parent_id', $categ_row['parent_id']);
  $db->bindParam(':title', $categ_row['title']);
  $db->bindParam(':url', UrlEncode($categ_row['title']));
  $db->execute();
}
A feldolgozandó tömb létrehozásával van az igazi problémám...

Előre is köszönöm és elnézést...
13

Még mindig nem értem mi okoz

pp · 2014. Dec. 17. (Sze), 07.00
Még mindig nem értem mi okoz problémát.

"Az okoz gondot, hogy ami alapján a végigjáráskor be tudnám azonosítani a szülő-tömböt, az szöveg, nem pedig szám."

Nem az a kérdés, hogy szám-e vagy sem, hanem, hogy egyedi-e, vagyis egyértelműen azonosítja-e az adott elemet, avagy sem. Ha a név ilyen akkor tökéletes erre.

Még mindig nem értem, hogy minek építed fel a tömböt, amin nem tudsz végigiterálni.

pp