Jump to content

Recursion Function, Trying to get my head around this one..


ChemicalBliss

Recommended Posts

It's not usual I ask questions on here ;) - I usually help rather than be helped but alas, this is really confusing  :confused:!

 

Short Story (You can skip this to "Your Mission")

Without going into unnecessary detail i'll try to explain what i'm trying to do;

 

[*]Take an array (example provided...)

  • 	Array(
    	// These must be here, they are initially read by the template parser to get a starting point.
    	"data"=>Array(
    		"template"=>"main",													// Template to start from (base template)
    		"content"=>"%custom_topmenu% <Br/>Table<Br/> %bigtablecustom1%",	// replace %content% tag,Shows 2 Examples, A Custom Menu, and Main Table with Smaller Tables inside
    	),
    	// Below is numerically indexed arrays of content that will replace tags in the above "content" item
    	0=>Array(
    		"data"=>Array(
    			"rkey"=>"%bigtablecustom1%",		// MUST have this item
    			"template"=>"bigtable_single",	// MUST have this item
    			0=>Array(
    				"%title%"=>"Some Table Heading",
    				"%footer%"=>"Some Table Footer Message (author?)",
    				"%content%"=>"Some Content for the table with another rkey: %smalltablecustom1% --- %smalltablecustom2%",
    				"%title_note%"=>"Some Time and Date"
    			)
    		),
    		0=>Array(
    			"data"=>Array(
    				"rkey"=>"%smalltablecustom1%",
    				"template"=>"smalltable_single",
    				0=>Array(
    					"%title%"=>"Small Title",
    					"%content%"=>"Some Small Content or Note"
    				)
    			)
    		),
    		1=>Array(
    			"data"=>Array(
    				"rkey"=>"%smalltablecustom2%",
    				"template"=>"smalltable_single",
    				0=>Array(
    					"%title%"=>"Small Title 2",
    					"%content%"=>"Some Small Content or Note"
    				)
    			)
    		)
    )
    1=>Array(
    	// The menu is dynamically created by the module using it's inherited protected methods.
    	"data"=>Array(
    		"rkey"=>"%custom_topmenu%",
    		"template"=>"custom_topmenu",
    		0=>Array(
    			"%item1_name%"=>"Sub-Link 1",
    			"%item1_link%"=>"#",
    			"%item2_name%"=>"Sub-Link 2",
    			"%item2_link%"=>"#",
    			"%item3_name%"=>"Sub-Link 3",
    			"%item3_link%"=>"#",
    			"%item4_name%"=>"Sub-Link 4",
    			"%item4_link%"=>"#"
    		)
    	)
    )
    )
    

 

[*]Turn this array into a single document, basically collpase all items with their children in the parent code.

 

The Problem (You can skip this to "Your Mission")

Now to make it easier and to (try) to prevent cross-tag contamination (so templates dont replace content that is supposed to be there from other template files...) I have wrote a recursion function that fills out all the content and removes the content sub-array from the data arrays (half the job).

 

So now I have a multi-dimensional array that needs collapsing into a single document (variable), I am getting confused with how to go through this array (below - not above) so that all the template items are "inserted" inside their parent array items.

 

The Function I made

	// Recursive, goes through an array and converts any "data" into actual templates. (Puts the content into a template)
private function parse_template_data_array($array){

	// First let's count how many items are in the array that was passed to us
	$item_count = count($array);

	// This should never happen, each array should have at least a "data" array inside.
	if($item_count < 1){
		// Template Parser Fatal Object Syntax Error
		exit("FATAL PARSER ERROR1");

	// If there is only one item, we don't need to recurse (There are no "child" elements) and so we skip the recursive section.
	}else if($item_count == 1){
		// No items to parse, move on

	// So there are some child elements we must recurse through.
	}else{
		// So this loops each "Child" element and passes that array to this function (recurse), Once it's finished it saves the array (result).
		for($i=0;$i<($item_count-1);$i++){	// -1 from the count, 1 to get rid of the data array.
			$array[$i] = $this->parse_template_data_array($array[$i]);
		}
	}

	// This part does the initial "template expansion", it finds the template needed for this item and saves it with the content to this item.

	// So we count how many data items we have
	$dcount = count($array['data']); // Count Data Items (minimum of 2 - Each data array must have "rkey" and "template")

	// If there isn't at least two items then someone made a booboo.
	if($dcount < 2){
		// Template Parser Fatal Object Syntax Error
		exit("FATAL PARSER ERROR2");

	// Otherwise let's sort this content out (We don't check if we only have the 2 minimum items since templates might not have Tags to replace).
	}else{
		// Load Template file using the "template" item in the data array.
		$template = $this->get_file($array['data']['template']);

		// Count the amount of data items (content) to replace tags inside the loaded template (If there is no content sub-array then put to 0 to skip the below part).
		$dstrcount = (isset($array['data'][0]))? count($array['data'][0]) : 0;

		// No template content, maybe no tags, just give the template content back.
		if($dstrcount < 1){
			// No items to parse

		// We have some content to replace.
		}else{

			// We need the keys of the content sub-array so we can use (a neat feature of) the str_replace function.
			$akeys = array_keys($array['data'][0]);
			$template = str_replace($akeys ,$array['data'][0],$template);
		}

		// Save the result into this array item so we can pass the whole item back (This is also what happens when it recurses above)
		$array['data']['content'] = $template;
	}

	// Return the result array.
	return $array;
}

 

The Array returned by the above function

Array
(
    [data] => Array
        (
            [rkey] => %cdb_res_tpl_blk%
            [template] => main
            [content] => <html><head></head><body>%custom_topmenu%<br />%bigtablecustom1%</body></html>
        )

    [0] => Array
        (
            [data] => Array
                (
                    [rkey] => %bigtablecustom1%
                    [template] => bigtable_single
                    [content] => "Some Table Heading"=>"Some Table Heading",
			"Some Table Footer Message (author?)"=>"Some Table Footer Message (author?)",
			"Some Content for the table with another rkey: %smalltablecustom1% --- %smalltablecustom2%"=>"Some Content for the table with another rkey: %smalltablecustom1% --- %smalltablecustom2%",
			"Some Time and Date"=>"Some Time and Date"


                )

            [0] => Array
                (
                    [data] => Array
                        (
                            [rkey] => %smalltablecustom1%
                            [template] => smalltable_single
                            [content] => "Small Title"=>"Small Title",
			"Some Small Content or Note"=>"Some Small Content or Note"



                        )

                )

            [1] => Array
                (
                    [data] => Array
                        (
                            [rkey] => %smalltablecustom2%
                            [template] => smalltable_single
                            [content] => "Small Title 2"=>"Small Title",
			"Some Small Content or Note"=>"Some Small Content or Note"



                        )

                )

        )

    [1] => Array
        (
            [data] => Array
                (
                    [rkey] => %custom_topmenu%
                    [template] => custom_topmenu
                    [content] => "Sub-Link 1"=>"Sub-Link 1",
			"#"=>"#",
			"Sub-Link 2"=>"Sub-Link 2",
			"#"=>"#",
			"Sub-Link 3"=>"Sub-Link 3",
			"#"=>"#",
			"Sub-Link 4"=>"Sub-Link 4",
			"#"=>"#"



                )

        )

)

 

Your mission

(Should you choose to accept ofc ;)), is to take the above array and turn it into a single html variable, with all the child elements inside their parent templates by replacing the tags in the array. All the data required is in the array, all that is needed is to "collapse" the array.

 

Things to bear in mind:

[*]%cdb_res_tpl_blk% - This is in the original template file, so the result of a successfull collapse will replace this tag with the result. Dont worry about this one :P

[*][rkey] - This is the "Tag" to replace in the "parent" content.

[*][template] - This is the template file.

[*][content] - This is the content that needs to go inside the parent item.

 

Expected Result

<html><head></head><body>"Sub-Link 1"=>"Sub-Link 1",
"#"=>"#",
"Sub-Link 2"=>"Sub-Link 2",
"#"=>"#",
"Sub-Link 3"=>"Sub-Link 3",
"#"=>"#",
"Sub-Link 4"=>"Sub-Link 4",
"#"=>"#"<br />"Some Table Heading"=>"Some Table Heading",
"Some Table Footer Message (author?)"=>"Some Table Footer Message (author?)",
"Some Content for the table with another rkey: "Small Title"=>"Small Title","Some Small Content or Note"=>"Some Small Content or Note" --- "Small Title 2"=>"Small Title","Some Small Content or Note"=>"Some Small Content or Note""=>"Some Content for the table with another rkey: %smalltablecustom1% --- %smalltablecustom2%",
"Some Time and Date"=>"Some Time and Date"</body></html>

 

 

I will be working on this myself and if I find a solution I will post here. It is just that the way I code is I put my idea in my head, then try to code it in my head categorically, but when I think I find a solution it seems there is a bug, such as it will only collpase the main element, the bigtable, and the first small table, it wont do the other small table and not the menu either so basically it doesnt recurse items in the same array, only those underneath it. I'm so close but yet...so far...

 

THANK YOU for ANY light you can shed on this situation it's been bugging me for a few days now (admittely have not coded since my first attempt - so tired.)

 

My Code

I won't provide the code I've done for it now since it just flat-out doesn't work, I've lost the code that I mentioned earlier that was bugged I modified and to be perfectly honest can't be bothered to reproduce it (it won't get me anywhere).

Link to comment
Share on other sites

Just to let you know, I sorted it.

 

I've had to do some Conveluded way of recursing the whole thing. A few patches here and there but it works at the moment without flaw (as far as i can tell).

 

Basically I changed the code that made the initial array, the code that made it easier to work with, and managed to formulate a successfull collapse function.

 

Like so;

 

Original Array now comes in like this:

Array
(
    [data] => Array
        (
            [rkey] => %cdb_res_tpl_blk%
            [template] => default_tpl
            [content] => %custom_topmenu% <Br/>Table<Br/> %bigtablecustom1%
        )

    [0] => Array
        (
            [data] => Array
                (
                    [rkey] => %bigtablecustom1%
                    [template] => bigtable_single
                    [0] => Array
                        (
                            [%title%] => Some Table Heading
                            [%footer%] => Some Table Footer Message (author?)
                            [%content%] => Some Content for the table with another rkey: %smalltablecustom1% --- %smalltablecustom2%
                            [%title_note%] => Some Time and Date
                        )

                )

            [0] => Array
                (
                    [data] => Array
                        (
                            [rkey] => %smalltablecustom1%
                            [template] => smalltable_single
                            [0] => Array
                                (
                                    [%title%] => Small Title
                                    [%content%] => Some Small Content or Note
                                )

                        )

                )

            [1] => Array
                (
                    [data] => Array
                        (
                            [rkey] => %smalltablecustom2%
                            [template] => smalltable_single
                            [0] => Array
                                (
                                    [%title%] => Small Title 2
                                    [%content%] => Some Small Content or Note
                                )

                        )

                )

        )

    [1] => Array
        (
            [data] => Array
                (
                    [rkey] => %custom_topmenu%
                    [template] => custom_topmenu
                    [0] => Array
                        (
                            [%item1_name%] => Sub-Link 1
                            [%item1_link%] => #
                            [%item2_name%] => Sub-Link 2
                            [%item2_link%] => #
                            [%item3_name%] => Sub-Link 3
                            [%item3_link%] => #
                            [%item4_name%] => Sub-Link 4
                            [%item4_link%] => #
                        )

                )

        )

)

 

Then the code that makes it easier is now like so:

	// Recursive, goes through an array and converts any "data" into actual templates. (Puts the content into a template)
private function parse_template_data_array($array){

	// First let's count how many items are in the array that was passed to us
	$item_count = count($array);

	// This should never happen, each array should have at least a "data" array inside.
	if($item_count < 1){
		// Template Parser Fatal Object Syntax Error
		exit("FATAL PARSER ERROR1");

	// If there is only one item, we don't need to recurse (Tehre are no "child" elements) and so we skip the recursive section.
	}else if($item_count == 1){
		// No items to parse, move on

	// So there are some child elements we must recurse through.
	}else{
		// So this loops each "Child" element and passes that array to this function (recurse), Once it's finished it saves the array (result).
		for($i=0;$i<($item_count-1);$i++){	// -1 from the count, 1 to get rid of the data array.
			$array[$i] = $this->parse_template_data_array($array[$i]);
		}
	}

	// This part does the initial "template expansion", it finds the template needed for this item and saves it with the content to this item.

	// So we count how many data items we have
	$dcount = count($array['data']); // Count Data Items (minimum of 2 - Each data array must have "rkey" and "template")

	// If there isn't at least two items then someone made a booboo.
	if($dcount < 2){
		// Template Parser Fatal Object Syntax Error
		exit("FATAL PARSER ERROR2");

	// Otherwise lets sort this content out (We don't check if we only have the 2 minimum items since templates might not have Tags to replace).
	}else{
		// Load Template file using the "template" item in the data array.
		$template = $this->get_file($array['data']['template']);

		// Count the amount of data items (content) to replace tags inside the loaded template (If tehre is no content sub-array then put to 0 to skip the below part).
		$dstrcount = (isset($array['data'][0]))? count($array['data'][0]) : 0;

		// No template content, maybe no tags, just give the template content back.
		if($dstrcount < 1){
			// No items to parse

		// We have some content to replace.
		}else{

			// We need the keys of the content sub-array so we can use (a neat feature of) the str_replace function.
			$akeys = array_keys($array['data'][0]);
			$template = str_replace($akeys ,$array['data'][0],$template);
		}

		// Save the result into this array item so we can pass the whole item back (This is also what happens when it recurses above)
		if($array['data']['template'] != "default_tpl"){
			$array['data']['content'] = $template;
		}
		unset($array['data'][0]);
	}

	// Return the result array.
	return $array;
}

private function get_file($name){
	return implode("",file(CDB_DOC_ROOT."cdb_includes/templates/".$name.".tpl"));
}

 

And finally the modified "easy" array:

Array
(
    [data] => Array
        (
            [rkey] => %cdb_res_tpl_blk%
            [template] => default_tpl
            [content] => %custom_topmenu% <Br/>Table<Br/> %bigtablecustom1%
        )

    [0] => Array
        (
            [data] => Array
                (
                    [rkey] => %bigtablecustom1%
                    [template] => bigtable_single
                    [content] => 								<div id="_box_gen">
								<img id="_box_hdr_img" alt="sample topic" src="./images/icon_exclamation.png" width="25" height="25" />
								<div id="_box_hdr">
									Some Table Heading
								</div>
								<div id="_box_hdr_rht">
									Some Time and Date
								</div>

								<div id="_box_top">
									<div id="_box_cnt">
										<center>Some Content for the table with another rkey: %smalltablecustom1% --- %smalltablecustom2%</center>
										<div id="_box_lwr">
											<div id="box_lwr_txt">
												Some Table Footer Message (author?)
											</div>
										</div>
									</div>

								</div>
							</div>

							<br />
							<br />

                )

            [0] => Array
                (
                    [data] => Array
                        (
                            [rkey] => %smalltablecustom1%
                            [template] => smalltable_single
                            [content] => <table width="100" height="100" border="5"><tr><td>Small Title</td></tr><tr><td>Some Small Content or Note</td></tr></table>
                        )

                )

            [1] => Array
                (
                    [data] => Array
                        (
                            [rkey] => %smalltablecustom2%
                            [template] => smalltable_single
                            [content] => <table width="100" height="100" border="5"><tr><td>Small Title 2</td></tr><tr><td>Some Small Content or Note</td></tr></table>

                        )

                )

        )

    [1] => Array
        (
            [data] => Array
                (
                    [rkey] => %custom_topmenu%
                    [template] => custom_topmenu
                    [content] => <a href="#" class="custom_menu_link">Sub-Link 1</a> - 
<a href="#" class="custom_menu_link">Sub-Link 2</a> - 
<a href="#" class="custom_menu_link">Sub-Link 3</a> - 
<a href="#" class="custom_menu_link">Sub-Link 4</a><br/>
                )

        )

)

 

As you can probably see i've modified the template files.

 

This is the result:

				<a href="#" class="custom_menu_link">Sub-Link 1</a> - 
<a href="#" class="custom_menu_link">Sub-Link 2</a> - 
<a href="#" class="custom_menu_link">Sub-Link 3</a> - 
<a href="#" class="custom_menu_link">Sub-Link 4</a><br/> <Br/>Table<Br/> 								<div id="_box_gen">

								<img id="_box_hdr_img" alt="sample topic" src="./images/icon_exclamation.png" width="25" height="25" />
								<div id="_box_hdr">
									Some Table Heading
								</div>
								<div id="_box_hdr_rht">
									Some Time and Date
								</div>
								<div id="_box_top">
									<div id="_box_cnt">
										<center>Some Content for the table with another rkey: <table width="100" height="100" border="5"><tr><td>Small Title</td></tr><tr><td>Some Small Content or Note</td></tr></table> --- <table width="100" height="100" border="5"><tr><td>Small Title 2</td></tr><tr><td>Some Small Content or Note</td></tr></table></center>

										<div id="_box_lwr">
											<div id="box_lwr_txt">
												Some Table Footer Message (author?)
											</div>
										</div>
									</div>
								</div>
							</div>

							<br />

							<br />

 

And now the magic recursive function:


private function build($array,$second_iteration=false){
	$this->_tmp_sec_it = (!isset($this->_tmp_sec_it))? true : false;
	$_tmp_sec_it = $this->_tmp_sec_it;
	if($_tmp_sec_it == true){
		$array['data']['content'] = $array[0]['data']['rkey'];
		$array['data']['rkey'] = $array[0]['data']['rkey'];
	}

	$acount = count($array);
	if($acount > 1){
		for($i=0;$i<$acount-1;$i++){
			$content = $this->build($array[$i], ($second_iteration == true)? false : (!isset($this->_tmp_sec_it))? true : false);
			$array['data']['content'] = str_replace($array[$i]['data']['rkey'],$content,$array['data']['content']);
			unset($array[$i]);
		}
	}else{
		// No Array, skip
	}

	if($_tmp_sec_it == true){
		return str_replace("%cdb_res_tpl_blk%",$array['data']['content'],$this->class_page->get_tpl_file());
	}

	return $array['data']['content'];
}

 

So yeah, built in a few hard-coded values necessary to make it work but it works, and shouldn't hamper any usablity as long as i code the rest to hide it ;).

 

Thanks for all who might of thought of a solution, I'm really not suprised I didnt get a response in time because even for me knowing what I was on about took me about 4 hours to figure this one part out!

 

Now I am HAPPY :D

 

--- If your still reading, note:

$this->_tmp_sec_it is a class GLOBAL :(((((((

If ANYONE can make this function WITHOUT that global PLEASE tell me! I could even PAY!!! (Yes, I hate globals that much)

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.