Welcome Guest!

If you do not have an account yet on The Web Squeeze forums, please Register! It’s FREE and there are many benefits:

  • Receive Fast Advice
  • Learn Programming Languages
  • Get Professional Website Reviews
  • Quick Troubleshooting Assistance

> Foreach Problem -- Table Of Contents Script

This is a discussion on Foreach Problem -- Table Of Contents Script, within the PHP section. This forum and the thread "Foreach Problem -- Table Of Contents Script" are both part of the Programming Your Website category.

 
Reply to this topicStart new topic
> Foreach Problem -- Table Of Contents Script, I have a shaky grasp of variables/arrays/foreach loops
MikeHopley
post Apr 3 2008, 08:29 AM
Post #1


Squeeze Machine
*****

Group: Mentor
Posts: 600
Joined: 15-February 08
From: UK
Member No.: 143



I'm writing some PHP to generate a table of contents. The idea is for me to write the minimum code each time I make a TOC.

So normally, a single entry might look like this:

CODE
   <li><a  href=\"".$host."/articles/serving-guide/badminton-serve-types.php\">The  four types of serve</a></li>
Instead, I want PHP to create this code from (part of) a variable like this:

CODE
$tocArray = "||badminton-serve-types|The four types of badminton  serve";
Here, I use the "||" to separate items and the "|" to separate the URL from the anchor text.

With me so far? That bit is okay, but I also need to nest lists to create subsections (one level of nesting). I do this by adding the signal characters "+" and "-" onto the end of the title. "+" signals "opening a nested list" and "-" signals "closing a nested list".

This part -- the nested lists -- is causing problems with my foreach loop. It only applies the test for the last entry; all other signalled entries are being ignored by the loop. Here's my full code:

CODE
   <?php
       $tocArray =
           "|Introduction
           ||basic-technique/|Basic serving technique+
               ||backhand-low-serve-technique|Backhand low serve
               ||backhand-flick-serve-technique|Backhand flick serve-
           ||tactics|Serving tactics";
          
      
       $tocList=explode("||", $tocArray);
       $directory = "";        // placeholder empty string;
       foreach($tocList as $value) {
           $temp = explode("|",$value);
           $temp3 = trim($temp[1]); $temp4 = rtrim($temp3, "+-");            // removes nesting-signal characters from anchor text
           if ( (substr($temp[0], -1) != "/") && ( strlen($temp[0])  > 0) ) {$temp[0] .= ".php";}            // adds .php for all  non-directory URLs
           $tocURL = $host."/articles/".$article."/".$directory.$temp[0];                               // creates a URL
           if ($tocURL == ($host.$path)) { $entry ="<li  class=\"here\"><span>".$temp4."</span>"; }        //  "you are here" formatting
           else { $entry = "<li><a href=\"".$tocURL."\">".$temp4."</a>"; }        // normal link
          
           $temp2 = substr($temp[1], -1);
           if ($temp2 == "+") {                // for the start of a section
               $directory = $temp[0];        // capturing the directory string for later
               echo $entry."<ol>\n\t";     // starting a nested list
               echo "DEBUG: I dont understand PHP";
           }
           if ($temp2 == "-") {                                // for the end of a section
               echo $entry."</li>\n\t</ol></li>";     // ending nested list
               $directory = "";        // resetting directory
           }
           if ($temp2 != "-" && $temp2 != "+") { echo $entry."</li>\n"; }
       }
       ?>
The only way to activate my debug text is by changing the last item to have a signal "+", like this:

CODE
$tocArray =
           "|Introduction
           ||basic-technique/|Basic serving technique+
               ||backhand-low-serve-technique|Backhand low serve
               ||backhand-flick-serve-technique|Backhand flick serve-
           ||tactics|Serving tactics+;
If I do this, then if ($temp2 == "+") evaluates as true, and the debug text appears.

What's going on?

This post has been edited by MikeHopley: Apr 3 2008, 09:38 AM
Go to the top of the page
 
+Quote Post
c010depunkk
post Apr 3 2008, 09:31 AM
Post #2


Rapid Squeezer
****

Group: Advisors
Posts: 176
Joined: 14-February 08
From: Willich, Germany
Member No.: 56



Grrrrr! That's a tricky one.... I can't find your error, and in an attempt to write a recursive function i only succeeded in frying some brain cells.... i'll have another look at this later.....


--------------------
www.c010depunkk.com ~ the hangout of a web developer
Go to the top of the page
 
+Quote Post
MikeHopley
post Apr 3 2008, 09:37 AM
Post #3


Squeeze Machine
*****

Group: Mentor
Posts: 600
Joined: 15-February 08
From: UK
Member No.: 143



QUOTE (c010depunkk @ Apr 3 2008, 10:31 AM) *
Grrrrr! That's a tricky one.... I can't find your error, and in an attempt to write a recursive function i only succeeded in frying some brain cells.... i'll have another look at this later.....


Thanks for looking! smile.gif

I have a feeling it's something fundamental to do with how variables behave inside a loop, but I'm completely out of my depth here...
Go to the top of the page
 
+Quote Post
c010depunkk
post Apr 3 2008, 10:25 AM
Post #4


Rapid Squeezer
****

Group: Advisors
Posts: 176
Joined: 14-February 08
From: Willich, Germany
Member No.: 56



OK, here's a recursive function that can handle endlessly nested toc's biggrin.gif

I didn't add all your extra stuff like highlighting the current link and so, but hopefully you can modify it to fit your needs:

CODE
<?php

$tocArray =
           "|Introduction
           ||basic-technique/|Basic serving technique+
               ||backhand-low-serve-technique|Backhand low serve
               ||basic-technique/|Basic serving technique+
                   ||backhand-low-serve-technique|Backhand low serve
                   ||backhand-flick-serve-technique|Backhand flick serve-
               ||backhand-flick-serve-technique|Backhand flick serve-
               ||basic-technique/|Basic serving technique+
               ||backhand-low-serve-technique|Backhand low serve
               ||backhand-flick-serve-technique|Backhand flick serve-
           ||tactics|Serving tactics";

echo('<ul>'.make_menu($tocArray).'</ul>');

function make_menu(&$str) {
    $rs='';
    //$str=trim($str,"\t");
    $last_char='';
    do {
        $vpp=strpos($str,'||'); // find first vertical pipe pair
        $ss=($vpp?substr($str,0,$vpp):$str); // get sub-text (the inline if is for the very last link
        $str=substr($str,$vpp+2); // chop the original string
        $p=explode('|',$ss); // explode link and text
        $n=rtrim($p[1]); // kill any crapp on the end
        $ln=strlen($n)-1; // get the length
        $last_char=$n[$ln]; // get the last char
        $lt=(($last_char=='+'||$last_char=='-')?substr($n,0,$ln-2):$n); // clean up the link text
        $rs.='<li><a href="'.$p[0].'">'.$lt.'</a>'; // make the link
        if($last_char=='+') { // check if we should do a nested list
            $rs.='<ul>'.make_menu($str).'</ul>'; // call this function recursively for the nested list
        }
        $rs.='</li>'."\n"; // end this item
    } while($vpp&&($last_char!='-')); // keep going as long as no minus or the end of the string comes
    return $rs; // return the list
}

?>


--------------------
www.c010depunkk.com ~ the hangout of a web developer
Go to the top of the page
 
+Quote Post
MikeHopley
post Apr 3 2008, 10:43 AM
Post #5


Squeeze Machine
*****

Group: Mentor
Posts: 600
Joined: 15-February 08
From: UK
Member No.: 143



QUOTE (c010depunkk @ Apr 3 2008, 11:25 AM) *
OK, here's a recursive function that can handle endlessly nested toc's biggrin.gif

I didn't add all your extra stuff like highlighting the current link and so, but hopefully you can modify it to fit your needs:


Wow, thank you so much! That's better than just fixing the problem -- you're also helping me learn better coding. biggrin.gif

I'll have to stop working on this now, but I'll check out your function tomorrow to test it and see if I can understand it.

Thanks again!
Go to the top of the page
 
+Quote Post
Rakuli
post Apr 3 2008, 10:45 AM
Post #6


Squeeze Machine
*****

Group: Administrators
Posts: 643
Joined: 13-February 08
From: Catching the squeezed drips downunder.
Member No.: 13



Well, c010depunkk already gave his code but I'll show you mine...

Just a matter of adding an extra couple of bars around your plus and minus signs -- makes for less conditional checks and string functions.

I think the problem you had mike was that your conditionals were coming up in the wrong order and skipping at the incorrect places.

CODE
<?php




       $tocArray =
           "|Introduction
                       ||basic-technique/|Basic serving technique ||+||backhand-low-serve-technique|Backhand low serve
                       ||backhand-flick-serve-technique|Backhand flick serve ||-||tactics|Serving tactics";
          

       $tocList=explode("||", $tocArray);
       $directory = "";        // placeholder empty string;
   foreach($tocList as $key => $value)
   {
       $value = trim($value);
       // First things first
       // if this is the start or end of some nested elements -- close it all up
      
           if ($value == '+')
           {
                echo '<ol>';
                continue;
            } else if ($value == '-') {
                echo '</ol></li>';
                continue;
            }
            
            // Get the two parts of the string now
           $temp = explode("|",$value);
          
           $temp[0] = trim($temp[0]); $temp[1] = trim($temp[1]); // Trip that icky white-space
          
          // Add .php to all non-directory URLs
          $temp[0] = substr($temp[0], -1) != "/" &&  strlen($temp[0])  > 0 ? $temp[0] . '.php' : $temp[0];
          
            // create a noice loitle urelly
           $tocURL = $host."/articles/".$article."/".$directory.$temp[0];
          
           // Okay so here's what I'm going to do
           // we will start the list element
          
          
           //  "you are here" formatting
           if ($tocURL == ($host.$path))
           {
                   echo "<li  class=\"here\"><span>", $temp[1], "</span>";
                
             // normal link
            } else {
                echo "<li><a href=\"", $tocURL, "\">".$temp[1]."</a>";
            }  
            
            // Now we check if this element will be followed by a + sign -- we will close the list only if
            // it is not
            
            if ($tocList[$key+1] != '+')
                echo '</li>';
          
  
       }






?>


--------------------
Luke Dingle . com

Turn Over a Playful Leaf on Web Design -- read about the javascript cat
Go to the top of the page
 
+Quote Post
MikeHopley
post Apr 3 2008, 11:05 AM
Post #7


Squeeze Machine
*****

Group: Mentor
Posts: 600
Joined: 15-February 08
From: UK
Member No.: 143



Thanks Rakuli! It's interesting to see how a slight change in method makes things much simpler -- and hence less likely to fail.

I shall be playing with both of these solutions at some point (though because I'm lazy, I'll probably start with Rakuli's and save c010depunkk's for when I want arbitrary amounts of nesting).

Cheers!

*whispers*
The WebSqueeze left Webforumz in the dust for this problem. wink.gif


QUOTE (Rakuli @ Apr 3 2008, 10:45 AM) *
Well, c010depunkk already gave his code but I'll show you mine...

Just a matter of adding an extra couple of bars around your plus and minus signs -- makes for less conditional checks and string functions.

I think the problem you had mike was that your conditionals were coming up in the wrong order and skipping at the incorrect places.


This post has been edited by MikeHopley: Apr 3 2008, 11:08 AM
Go to the top of the page
 
+Quote Post
Rakuli
post Apr 3 2008, 11:10 AM
Post #8


Squeeze Machine
*****

Group: Administrators
Posts: 643
Joined: 13-February 08
From: Catching the squeezed drips downunder.
Member No.: 13



QUOTE
shall be playing with both of these solutions at some point (though because I'm lazy, I'll probably start with Rakuli's and save c010depunkk's for when I want arbitrary amounts of nesting).


LOL -- My method allows for arbitrary nesting as well wink.gif but c010depunkk has gone for the recursive function which is much more portable..

wink...no problem


--------------------
Luke Dingle . com

Turn Over a Playful Leaf on Web Design -- read about the javascript cat
Go to the top of the page
 
+Quote Post
c010depunkk
post Apr 4 2008, 12:41 AM
Post #9


Rapid Squeezer
****

Group: Advisors
Posts: 176
Joined: 14-February 08
From: Willich, Germany
Member No.: 56



ROFL!!! I love it when me and Rakuli flood the forums with alternate solutions biggrin.gif biggrin.gif biggrin.gif

One of these days we are going to have to stage a "PHP Battle" where me and Rakuli battle it out to decide who is the ober-guru wink.gif
It'll be a huge sponsored event, with tons of publicity for The Squeeze and huge amounts of spectators... How about we do it in Heinz Stadium, in PA? We could sell hot dogs....



*c010depunkk cracks his fingers, cackles evilly, hunches lower over the keyboard and sharpens his parentheses*


--------------------
www.c010depunkk.com ~ the hangout of a web developer
Go to the top of the page
 
+Quote Post
Rakuli
post Apr 4 2008, 12:52 AM
Post #10


Squeeze Machine
*****

Group: Administrators
Posts: 643
Joined: 13-February 08
From: Catching the squeezed drips downunder.
Member No.: 13



** Types message with his spare hand while doing one-armed push-ups **

So, the script has been written? Doesn't mean I can't write a better one biggrin.gif


--------------------
Luke Dingle . com

Turn Over a Playful Leaf on Web Design -- read about the javascript cat
Go to the top of the page
 
+Quote Post
MikeHopley
post Apr 4 2008, 06:16 AM
Post #11


Squeeze Machine
*****

Group: Mentor
Posts: 600
Joined: 15-February 08
From: UK
Member No.: 143



Hurrah! It works -- with a little tweaking to set the directory paths correctly.

Now I need to add one more element to the script, and then I'll post my completed solution.
Go to the top of the page
 
+Quote Post
MikeHopley
post Apr 4 2008, 06:37 AM
Post #12


Squeeze Machine
*****

Group: Mentor
Posts: 600
Joined: 15-February 08
From: UK
Member No.: 143



Finished! Here's my complete code, which also allows for setting skill levels by appending the title with *IA (intermediate and advanced) or *A (advanced only). The really neat thing about this is that, if I mark a section as *A, then all the subsection pages are also affected (because the whole subsection list is contained within the section <li>).

CODE
$tocList=explode("||", $tocArray);
        $directory = "";        // placeholder empty string;
    foreach($tocList as $key => $value)
    {
        $value = trim($value);
        // First things first
        // if this is the start or end of some nested elements -- close it all up
              
             // Get the two parts of the string now
            $temp = explode("|",$value);
            
           $temp[0] = trim($temp[0]); $temp[1] = trim($temp[1]); // Trim white-space
          
          
           // Apply skill classes (hides some pages from beginners)
          
           $skills = explode("*", $temp[1]);
           if ($skills[1] == "IA") {
                   $skillClass = "intermediate advanced";
                 $temp[1] = $skills[0];    // Removing skill tokens from anchor text
             } else if ($skills[1] == "A") {
                 $skillClass = "advanced";
                 $temp[1] = $skills[0];      // Removing skill tokens from anchor text
             } else { $skillClass = ""; }        
          
           if ($tocList[$key-1] == '+') {
                 $tempDir = explode("|", $tocList[$key-2]);
                 $directory = $tempDir[0];
           }
          
            if ($value == '+')
            {
                 echo "<ol>\n";
                 continue;
             } else if ($value == '-') {
                 echo '</ol></li>';
                 $directory = "";
                 continue;
             }          
      
           // Add .php to all non-directory URLs
           $temp[0] = substr($temp[0], -1) != "/" &&  strlen($temp[0])  > 0 ? $temp[0] . '.php' : $temp[0];
          
             // create a URL
            $tocURL = $host."/articles/".$article."/".$directory.$temp[0];              
          
            //  "you are here" formatting
            if ($tocURL == ($host.$path))
            {
                    echo "<li  class=\"here\"><span>", $temp[1], "</span>";
                
             // normal link
             } else {
                 echo "<li class=\"".$skillClass."\"><a href=\"".$tocURL."\">".$temp[1]."</a>";
             }  
            
             // Now we check if this element will be followed by a + sign -- we will close the list only if
             // it is not
            
             if ($tocList[$key+1] != '+')
                 echo "</li>\n";
        }


...and here's an example TOC file:

CODE
<?php $tocArray =

    "|Introduction
    ||grip-principles|Grip principles
    ||racket-bevels|Badminton racket bevels
    ||grips/|Fundamental badminton grps
        ||+||basic-grip|Basic grip
        ||panhandle-grip|Panhandle grip
        ||thumb-grip|Thumb grip
        ||bevel-grip|Bevel grip*IA
    ||-||changing-grip|Changing grip
    ||grip-adjustments/|Adjusting your grip*IA
        ||+||grip-length|Grip length
        ||late-forehand-grip-adjustment|Late forehand
        ||late-backhand-grip-adjustment|Late backhand
        ||smash-grip-adjustment|Smash*A
    ||-||which-grip/|Which badminton grip?*IA
        ||+||serve|Which grip for serving?
        ||serve-return|Which grip for returning serve?
        ||net-shot|Which grip for net shots?
        ||net-kill|Which grip for net kills?
        ||drive-push|Which grip for drives and pushes?
        ||lift|Which grip for lifts?
        ||smash-defence|Which grip for smash defence?
        ||clear-smash-drop|Which grip for clears, smashes, and drops?
    ||-||background/|Background information
        ||+||old-grips|What happened to the old grips?
        ||grip-size|Grip size
        ||marking-the-racket-handle|Marking the racket handle
        ||alternative-views|Alternative views*A
        ||mechanics-of-grip-length|Mechanics of grip length*A||-    
";?>


This has made writing TOC's much easier, and has also allowed me to cut out reliance on javascript for the current-page-highlighting effect. smile.gif

This post has been edited by MikeHopley: Apr 4 2008, 06:40 AM
Go to the top of the page
 
+Quote Post
If you found The Web Squeeze to be helpful, please donate so we can keep this site FREE, FRESH, and fortified with Web Design & Development info!
Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 

Collapse

> Similar Topics

    Topic Title Replies Topic Starter Views Last Action
No New Posts   10 jackfranklin 308 17th February 2008 - 01:44 PM
Last post by: Rakuli
No New Posts