Funció recursiva – PHP – Fòrums de SitePoint

estic intentant crear una relació pare-fill amb mysql.

id

parent_id

títol

feliç

1

0

sóc pare no.1

Estic content pel pare núm.1

2

0

sóc pare no.2

Estic content pel pare no.2

3

2

sóc fill del pare núm.2

Estic content pel pare no.2

4

2

sóc fill del pare núm.2

Im contingut infantil per als pares núm.2

5

4

sóc nét del pare núm.2

Im contingut de nét per als pares núm.2

Creo la taula pare i la taula fill per separat, però només vaig poder crear un fill de nivell, així que si he de crear un fill multi-nid, he de crear una taula fill nova per a cada fill imbricat… així que després de fer la cerca de bits, vaig saber-ho Sobre Funció recursiva amb el qual podria crear múltiples fills imbricats sense cap problema.

Utilitzant PDO mysqli com a codi següent

try {
    $host="localhost";
    $dbname="55";
    $user="root";
    $password   = '';

    $conn = new PDO("mysql:host=$host;dbname=$dbname",$user,$password);
    $conn->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    //$e->getMessage();
    die("Something went wrong please contact your adminstrator");
}


function categoryTree($parent_id = 0, $sub_mark = '',$rt=""){
    global $conn ;
    
    $data = $conn->prepare("SELECT * FROM categories WHERE parent_id = :parent_id");
    $data->bindParam(':parent_id', $parent_id);      
    $data->execute();        
    if ($data ->rowCount()) {
        $i=1;
        while($row = $data->fetch(PDO::FETCH_OBJ) ){
            echo '
  • '.$row->name.''; categoryTree($row->id, $sub_mark.'-',$rt.'op'); $i++; } } }
  • Edició núm.1

    Ara el resultat és que tots els pares i els fills estan en el mateix ‘li’(ul>li)
    Vull que cada nen tingui un nou ul>li amb un identificador únic a li
    Vull títol i contingut a les pestanyes perquè necessito un identificador unquie, però em dóna el mateix identificador per al títol infantil

    //Tab-title
    
    • im parent one
    • im parent two arrow icon
      • im first child of parent two
      • im second child of parent two arrow icon
        • im garnd child of parent two
        • im garnd child of parent two

    5
    L’etiqueta span només s’ha de mostrar si tenen fills, si els pares tenen fills i els fills tenen un nét, l’etiqueta span només s’ha de mostrar a pares i fills, si els pares no tenen cap fill, no s’hauria de mostrar l’etiqueta span.

    Problema #2
    Ara, al contingut de la pestanya, el contingut principal només s’hauria de mostrar si té algun fill, si els pares tenen fills, només s’hauria de mostrar el contingut secundari, però si els pares tenen un nét, només s’hauria de mostrar el contingut del nét… a les pestanyes de contingut només s’hauria de mostrar l’últim s’ha de mostrar contingut infantil.

    He aconseguit aquestes opcions fàcilment creant una taula pare i una taula per separat, però amb una funció recursiva creant una taula única, no puc assolir el meu requisit


    Alguna cosa així estaria bé amb JavaScript i Ajax, però em digresso. Primer ho buscaria tot en PHP PDO – una cosa així →

    /*
     * PHP PDO connection
     */
    $db_options = array(
        /* important! use actual prepared statements (default: emulate prepared statements) */
        PDO::ATTR_EMULATE_PREPARES => false
        /* throw exceptions on errors (default: stay silent) */
    , PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        /* fetch associative arrays (default: mixed arrays)    */
    , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    );
    $pdo = new PDO('mysql:host=" . DATABASE_HOST . ";dbname=" . DATABASE_NAME . ";charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD, $db_options);
    
    
    /*
     * Pagination Format
     * Read all the data from the database table in an array format
     */
    function readData($pdo, $table, $page, $perPage, $offset) {
        $sql="SELECT * FROM " . $table . ' WHERE page=:page ORDER BY date_added DESC LIMIT :perPage OFFSET :blogOffset';
        $stmt = $pdo->prepare($sql); // Prepare the query:
        $stmt->execute(['perPage' => $perPage, 'blogOffset' => $offset, 'page' => $page]); // Execute the query with the supplied data:
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    

    No presteu atenció a la part de paginació, és el $stmt->fetchALL(PDO::FETCH_ASSOC) el que és important, llavors només podeu accedir a la matriu. A continuació es mostra un exemple del que estic intentant dir →

    /* Finally, call for the data from the database table to display */
    
    $cms = readData($pdo, 'cms', 'blog', $per_page, $offset);
    
        
        
            
    " alt="article image">

    Created by on

    Record ' . urldecode($record['id']) . '' : null; ?>

    Realment no necessiteu una funció recursiva que faci d’aquesta manera, però haureu de saber quants nivells haureu de baixar. És per això que vaig dir que JavaScript/Ajax seria millor, ja que l’ús de la funció recursiva seria útil, ja que seria el meu dinàmic que no pas estàtic i més fàcil esbrinar quants nivells. (Penso)

    L’execució de consultes dins dels bucles no és eficient, i encara és pitjor per a una funció recursiva, ja que s’està executant per a cada fila de dades, per trobar si aquesta fila té dades secundàries. Fins i tot si traieu la instrucció prepare de la funció i només executeu la consulta ja preparada dins del bucle, no estalviareu el nombre d’execucions i només estalviareu un 5% del temps d’execució total preparant la consulta només una vegada.

    La millor manera de fer-ho és consultar i obtenir totes les dades alhora, indexar/pivotar les dades utilitzant el parent_id com a índex de matriu principal, i després fer que la funció recursiva operi sobre les dades ja obtingudes.

    No estic segur per a què utilitzeu realment les classes sub_mark, rt i html ni per a què haurien de ser (els vostres exemples de dades, el codi i la sortida desitjada no coincideixen), així que els he deixat qualsevol codi. .

    Vegeu el codi d’exemple següent:

    // get all the data at once, indexing/pivoting the data using the parent_id as the main index
    $sql = "SELECT parent_id, id, name FROM your_table ORDER BY parent_id, id";
    $stmt = $pdo->query($sql);
    $menu_data = $stmt->fetchAll(PDO::FETCH_GROUP);
    
    function categoryTree($menu_data, $parent_id = 0, $sub_mark = '',$rt="",$level=0)
    {
    	// if any matching rows, add to output
    	if(isset($menu_data[$parent_id]))
    	{
    		if($level > 0)
    		{
    			// close the previous li
    			echo " arrow iconn";
    		}
    		// start a new ul section here
    		echo "
      n"; foreach($menu_data[$parent_id] as $row) { // produce output // start li here for each piece of data echo "
    • {$row['name']}"; // get any children for the current id and output them categoryTree($menu_data, $row['id'], $sub_mark.'-',$rt.'op',$level++); // close the li for either a piece of data or for a whole ul section echo "
    • n"; } // close the ul here echo "
    n"; } } categoryTree($menu_data);

    Aquest codi ha nomenat la variable de connexió $pdo i ha establert el mode d’obtenció per defecte a assoc quan es va fer la connexió. També hauríeu d’establir el conjunt de caràcters perquè coincideixi amb les taules de la vostra base de dades i establir les consultes preparades emulades com a false.



    1 M’agrada

    Estic d’acord amb mabismad pel que fa a agafar totes les dades d’UNA consulta i fer qualsevol funció recursiva o de bucle a la matriu de dades.

    A la meva versió vaig definir les dades en 2 tipus amb clau 'categories' Tinc totes les dades molt semblants a les de mabismad $menu_data matriu amb el id com a clau de registre que sembla aquest.

    [categories] => Array
            (
                [1] => Array
                    (
                        [id] => 1
                        [parent_id] => 0
                        Recursive function - PHP - SitePoint Forums => Parent No.1
                        [content] => Content for Parent No.1
                    )
    
                [2] => Array
                    (
                        [id] => 2
                        [parent_id] => 0
                        Recursive function - PHP - SitePoint Forums => Parent No.2
                        [content] => Content for Parent No.2
                    )
    ///etc
    

    Per al segon tipus de dades he utilitzat la clau'parent_cats' col·locant el parent_id com a clau, després una clau oberta natural i l’id com a valor. Això dóna lloc a una gran varietat de pares i fills.

    [parent_cats] => Array
            (
                [0] => Array
                    (
                        [0] => 1
                        [1] => 2
                        [2] => 7
                    )
    
                [2] => Array
                    (
                        [0] => 3
                        [1] => 4
                    )
    
                [4] => Array
                    (
                        [0] => 5
                        [1] => 6
                    )
    
                [5] => Array
                    (
                        [0] => 8
                        [1] => 9
                        [2] => 10
                    )
    
                [9] => Array
                    (
                        [0] => 11
                    )
    
                [7] => Array
                    (
                        [0] => 12
                    )
    
            )
    

    Aquestes matrius es van construir així.

    $categoryMulti = array(
        'categories' => array(),
        'parent_cats' => array()
    );	 
    $sql = "SELECT `id`, `parent_id`, `title`, `content` FROM categories";
    $query = $conn->query($sql);
    while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
        $categoryMulti['categories'][$row['id']] = $row;
        $categoryMulti['parent_cats'][$row['parent_id']][] = $row['id'];
    }
    

    Vaig utilitzar la següent funció recursiva per crear la llista de menús.

    function listCategoryTree($parent, $category)
    {
        $css_class = ($parent == 0 ? "parent" : "child");	
    	
    	$html="";
        if (isset($category['parent_cats'][$parent])) {
            $html .= '
      '."n"; foreach ($category['parent_cats'][$parent] as $cat_id) { if (!isset($category['parent_cats'][$cat_id])) { $html .= '
    • ' . $category['categories'][$cat_id]['title'] . '
    • '."r"; } else { $html .= '
    • ' . $category['categories'][$cat_id]['title'] . ' '."r"; $html .= listCategoryTree($cat_id, $category); $html .= '
    • '."r"; } } $html .= '
    '."n"; } return $html; }

    que sembla així.
    arbre de menús
    Per a tots els identificadors d’atribut, vaig utilitzar l’identificador de registre, de manera que cadascun seria una classe css ul única i definida en funció del parent_id i va afegir el teu etiquetes però comentat el arrow icon text per a la demostració… Podeu editar com vulgueu.

    Estic intentant mostrar el títol al títol de la pestanya i el contingut al contingut de la pestanya, de manera que quan feu clic al títol de la pestanya, el contingut corresponent s’hauria de mostrar a la pestanya.

    com esbrinar l’últim fill i mostrar contingut només per a l’últim fill…

    I què tal aquesta versió?

    function listCategoryTree($parent, $category)
    {
        $css_class = ($parent == 0 ? "parent" : "child");	
    	
    	$html="";
        if (isset($category['parent_cats'][$parent])) {
            $html .= '
      '."n"; foreach ($category['parent_cats'][$parent] as $cat_id) { if (!isset($category['parent_cats'][$cat_id])) { $html .= '
    • ' . $category['categories'][$cat_id]['content'] . '
    • '."r"; } else { $html .= '
    • ' . $category['categories'][$cat_id]['title'] . ' '."r"; $html .= listCategoryTree($cat_id, $category); $html .= '
    • '."r"; } } $html .= '
    '."n"; } return $html; }

    arbre del menú 2

    echo listCategoryTree(0, $categoryMulti) (resolt) error resolt

    Aquest és el meu codi de prova complet.

    $categoryMulti = array(
        'categories' => array(),
        'parent_cats' => array()
    );	 
    $sql = "SELECT `id`, `parent_id`, `title`, `content` FROM categories";
    $query = $conn->query($sql);
    while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
        $categoryMulti['categories'][$row['id']] = $row;
        $categoryMulti['parent_cats'][$row['parent_id']][] = $row['id'];
    }
    
    
    function listCategoryTree($parent, $category)
    {
        $css_class = ($parent == 0 ? "parent" : "child");	
    	
    	$html="";
        if (isset($category['parent_cats'][$parent])) {
            $html .= '
      '."n"; foreach ($category['parent_cats'][$parent] as $cat_id) { if (!isset($category['parent_cats'][$cat_id])) { $html .= '
    • ' . $category['categories'][$cat_id]['content'] . '
    • '."r"; } else { $html .= '
    • ' . $category['categories'][$cat_id]['title'] . ' '."r"; $html .= listCategoryTree($cat_id, $category); $html .= '
    • '."r"; } } $html .= '
    '."n"; } return $html; } echo listCategoryTree(0, $categoryMulti);

    estic intentant aconseguir la condició anterior.
    Amb el vostre codi, tinc una llista exitosa de títols de pares i fills de diversos nivells secció de títol de la pestanya

    Ara dins Contingut de la pestanya Estic intentant llistar contingut per al títol que apareix a títol de la pestanya
    A Contingut de la pestanya, si els pares tenen fills multinivells, només s’hauria de mostrar el darrer contingut secundari, però si els pares tenen algun fill, s’hauria de mostrar el contingut principal.

    Però estic rebent contingut per a tots els pares del títol, així com per al fill imbricat aquí, vull el darrer contingut secundari, però si el pare té fill, s’hauria de mostrar el contingut principal

    com comprovar si els pares tenen fills, si els pares tenen fills, mostren contingut només per a l’últim fill, si els pares no tenen fills, mostren el contingut dels pares

    Codi per mostrar el títol secundari de diversos nivells al títol de la pestanya

    
    $categoryMulti = array(
        'categories' => array(),
        'parent_cats' => array()
    );   
    
    $sql = "SELECT `id`, `parent_id`, `name`, `content` FROM categories";
    $query = $conn->query($sql);
    while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
       $categoryMulti['categories'][$row['id']] = $row;
        $categoryMulti['parent_cats'][$row['parent_id']][] = $row['id'];
    }
    
    
    //title for tabs
    function listCategoryTree($parent, $category)
    {
        $css_class = ($parent == 0 ? "parent" : "child");   
        
        $html="";
        if (isset($category['parent_cats'][$parent])) {
            $html .= ''."n";
        }
        return $html;
    }
    
    

    Codi que intenta mostrar el darrer contingut secundari si els pares tenen un fill imbricat en diversos nivells i si el pare té algun fill, mostra contingut principal

    //content for tabs
    $contentTab = array(
        'contentCat' => array(),
        'contentChild' => array()
    );   
    $sql = "SELECT `id`, `parent_id`, `name`, `content` FROM categories";
    $query = $conn->query($sql);
    while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
       $contentTab['contentCat'][$row['id']] = $row;
        $contentTab['contentChild'][$row['parent_id']][] = $row['id'];
    }
    
    //content for tabs
    function listContentTree($parent, $category)
    {
        $css_class = ($parent == 0 ? "parent" : "child");   
        
        $html="";
        if (isset($category['contentChild'][$parent])) {
            $html .= ''."n";
        }
        return $html;
    }
    
    

    Com puc comprovar que l’últim fill mostri contingut només per a l’últim fill i si el pare no té cap fill, mostra el contingut dels pares

    Aquest embolic, per cert, és el motiu pel qual existeix el model de llista d’adjacència.



    2 m’agrada

    al final del dia, la pregunta segueix sent la mateixa… com es pot esbrinar l’últim fill en un nen anidat de diversos nivells i només es mostra el contingut del darrer fill i si el pare no té cap fill, només mostra el contingut dels pares…

    el vostre enllaç suggerit em mostra el procés per enumerar tots els fills imbricats o llista per identificador, però vull mostrar tots els llistats de fills en bucle i comprovar l’últim fill i mostrar només el contingut de l’últim fill… i el contingut dels pares només si el pare no té cap fill

    M’acabo d’adonar que satishinnovstudio no ets el creador original del tema.

    Entenc que @satishinnovstudio i @esu són companys que treballen en el mateix projecte.

    El fil continua en un fil nou:
    Troba l’últim fill en funció recursiva



    1 M’agrada

    Leave a Comment

    Your email address will not be published. Required fields are marked *