I have a list of about 100 articles, and within each article is a list of clauses. The clauses are a list of varying levels deep.
$clauses = array(
[
'Fields' => ['Clause' => 'clause 1', 'Status' => 'Draft']
],
[
'Fields' => ['Clause' => 'clause 2', 'Status' => 'Draft'],
'SubClauses' => [
[
'Fields' => ['Clause' => 'clause 2_a', 'Status' => 'Draft'],
'SubClauses' => [
[
'Fields' => ['Clause' => 'clause 2_a_1', 'Status' => 'Draft']
],
[
'Fields' => ['Clause' => 'clause 2_a_2', 'Status' => 'Draft']
]
]
]
]
],
[
'Fields' => ['Clause' => 'clause 3', 'Status' => 'Draft']
]
);
echo PHP_EOL;
To create an html ordered list out of the $clauses array, I built this:
function htmlList ( $clauses, $depth = 0 ) {
if ( $depth == 0 ) {
echo '<ol type="1">';
} elseif ( $depth == 1 ) {
echo '<ol type="i">';
} else {
echo '<ol type="a">';
}
foreach ( $clauses as $key => $clause ) {
if ( isset($clauses[$key]['SubClauses']) ) {
echo ' <li>' . $clauses[$key]['Fields']['Clause'];
htmlList ( $clauses[$key]['SubClauses'], ++$depth );
} elseif ( isset($clauses[$key]['Fields']) ) {
echo ' <li>' . $clauses[$key]['Fields']['Clause'] . '</li>';
}
}
$depth--;
echo ' </li>';
echo '</ol>';
}
htmlList ( $clauses );
echo PHP_EOL;
It only builds the list for a single article. When the code loops to the next article, i get a error because the function is already defined.
I want to keep the html in the template and not put it inside the code files, so I have the function in the template where it can write the html there.
I need to make the name of the function change when the next article loops, so I converted this to a closure and assigned it to a variable. I am passing the function since I need it to recurse.
$htmlList = function ( $clauses, $depth = 0 ) use ( &$htmlList ) {
if ( $depth == 0 ) {
echo '<ol type="1">';
} elseif ( $depth == 1 ) {
echo '<ol type="i">';
} else {
echo '<ol type="a">';
}
foreach ( $clauses as $key => $clause ) {
if ( isset($clauses[$key]['SubClauses']) ) {
echo ' <li>' . $clauses[$key]['Fields']['Clause'];
$htmlList ( $clauses[$key]['SubClauses'], ++$depth );
} elseif ( isset($clauses[$key]['Fields']) ) {
echo ' <li>' . $clauses[$key]['Fields']['Clause'] . '</li>';
}
}
$depth--;
echo ' </li>';
echo '</ol>';
};
$htmlList ( $clauses );
echo PHP_EOL;
This also works for a single article, but allows the name to be changed dynamically. I then made the name of the variable that holds the name of the function dynamic.
$articles = array(
['Title' => 'title 1', 'Status' => 'Draft'],
['Title' => 'title 2', 'Status' => 'Draft'],
);
for ( $i = 0; $i < sizeof($articles); $i++ ) {
echo $articles[$i]['Title'] . PHP_EOL;
$htmlList = 'htmlList' . '_' . $i;
$$htmlList = function ( $clauses, $depth = 0 ) use ( &$$htmlList ) {
if ( $depth == 0 ) {
echo '<ol type="1">';
} elseif ( $depth == 1 ) {
echo '<ol type="i">';
} else {
echo '<ol type="a">';
}
foreach ( $clauses as $key => $clause ) {
if ( isset($clauses[$key]['SubClauses']) ) {
echo ' <li>' . $clauses[$key]['Fields']['Clause'];
$$htmlList ( $clauses[$key]['SubClauses'], ++$depth );
} elseif ( isset($clauses[$key]['Fields']) ) {
echo ' <li>' . $clauses[$key]['Fields']['Clause'] . '</li>';
}
}
$depth--;
echo ' </li>';
echo '</ol>';
};
$$htmlList ( $clauses );
}
This is where it breaks. It does not like variably named function name inside the use() and errs at the $$ because it is a variable-variable and it only allows 1 $ and I have 2 $$ since the variable name’s value changes.
Would it be better to save the function in the main code outside the template so it doesn’t have to build anew for each article, or would it better to put the function in the template and keep html out of the main code files? All other constructs surrounding html are generally in the template files.
How can I get the clauses to convert to an html list for each article it loops through?
2
Answers
There was a previous valid and accepted answer that was oddly removed. It required saving the function in a variable to pass around though. I am adding the solution back as nuances in the design of the solution may help others with a similar problem in case the other answer(s) won't work for them, which keeps the html within the loop, or in case it might not be a good design to loop over a function declaration.
The primary change is to simply define the function outside of the loop. It can still exist at the top of the template file. Then it won't be called multiple times and it will still work.
Independently of a better code design, you can test if a function already exists before defining it with
function_exists
: