代码分离悖论:从多维数组创建HTML树并将HTML保留在递归函数之外

时间:2022-12-20 21:35:32

This working code seems to be the typical solution to this problem.

这个工作代码似乎是这个问题的典型解决方案。

It takes a multi-dimensional array that holds categories and their subcategories (with no implied limitation on how many levels deep it goes) and creates an HTML unordered list from it, echoing it out onto the page from inside a recursive function.

它需要一个包含类别及其子类别的多维数组(没有暗示它深入多少级别),并从中创建一个HTML无序列表,从递归函数内部回显到页面。

Sub-levels are traversed by passing the value for each array element's 'children' key to array_walk() recursively, from inside the original callback function named _category_list()_.

通过从名为_category_list()_的原始回调函数内部递归地将每个数组元素的'children'键的值传递给array_walk()来遍历子级别。

How can this method of output be modified so that all HTML code would exist in the template, outside the function?

如何修改这种输出方法,以便在函数外部的模板中存在所有HTML代码?

Here's the rundown of the code:

This multi-dimensional array holds the multi-level category tree.

该多维数组包含多级别类别树。

Important keys to use in the HTML are 'category_id', 'name', and 'children'. Other keys have been purged from the array below for simplicity sake, but if they are useful they are: 'parent_id' and 'level' (starting with level 1).

在HTML中使用的重要键是'category_id','name'和'children'。为简单起见,其他键已从下面的数组中清除,但如果它们有用,它们是:'parent_id'和'level'(从1级开始)。

<?php

// the array containing the tree
$categories = array (
  'category_id' => '2',
  'name' => 'Top Category Name',
  'children' => array (
    0 => array (
      'category_id' => '188',
      'name' => 'Category Name',
      'children' => array (
        0 => array (
          'category_id' => '159',
          'name' => 'Category Name',
          'children' => array (),
        ),
        1 => array (
          'category_id' => '160',
          'name' => 'Category Name',
          'children' => array (),
        ),
        2 => array (
          'category_id' => '166',
          'name' => 'Category Name',
          'children' => array (),
        ),
      ),
    ),
    1 => array (
      'category_id' => '4',
      'name' => 'Category Name',
      'children' => array (
        0 => array (
          'category_id' => '141',
          'name' => 'Category Name',
          'children' => array (),
        ),
        1 => array (
          'category_id' => '142',
          'name' => 'Category Name',
          'children' => array (),
        ),
      ),
    ),
  ),
)

?>

.

This next function produces the majority of the HTML output, but it locks the HTML inside itself.

下一个函数生成大部分HTML输出,但它将HTML锁定在自身内部。

However, instead of echoing it right from the function, I'm looking for a way to pass this data back to the view template in a manner that is friendly for designers to customize.

但是,我没有直接从函数中回显它,而是寻找一种方法将这些数据以一种友好的方式传递回视图模板,供设计人员自定义。

<?php

// separate the HTML from this function,
// passing $v to the view template for handling
function category_list($v, $k){
  switch ($k) {
    case 'category_id':
      echo "<li id="$v">";
      break;
    case 'name':
      echo "$v";
      break;
    case 'children':
      if(count($v) > 0){
        echo "<ul>";
        foreach($v as $k=>$v)
        array_walk($v, 'category_list');
        echo "</ul>";
      }
      echo "</li>";
      break;
  }
}

?>

.

The next block of code is the current template html/php with the call to traverse the first level of the array via array_walk() and referencing the recursive function above. The function itself then handles the recursion and iteration of deeper categories with 1 or more child. Of course, this is the typical approach.

下一个代码块是当前模板html / php,调用通过array_walk()遍历数组的第一级并引用上面的递归函数。然后,函数本身处理具有1个或更多子节点的更深层类别的递归和迭代。当然,这是典型的方法。

This code should have all HTML tags, rather than just the outer tags.

此代码应包含所有HTML标记,而不仅仅是外部标记。

<ul>
<?php array_walk($tree,'category_list'); ?>
</ul>

.

The Ideal Solution:

理想的解决方案:

The end goal here is to find a way for template designers to create their ideal navigation structure without having to create or modify the recursion function (which isn't accessible), nor require use of a foreach loop for each level of the multi-dimensional array. The solution should not be tied to any specific depth limitations.

这里的最终目标是为模板设计者找到一种方法来创建理想的导航结构,而无需创建或修改递归函数(不可访问),也不需要为多维的每个级别使用foreach循环阵列。解决方案不应与任何特定的深度限制相关联。

Examples of HTML customizations could range from placing additional attributes inside the ul/li tags, or even wrapping new tags around the output text, such as span tags, which are commonly used in navigations to achieve a sliding-doors effect with CSS. So I think the appropriate solution will need to support those case scenarios at a minimum.

HTML自定义的示例包括在ul / li标记内放置其他属性,甚至在输出文本周围包装新标记,例如span标记,这些标记通常用于导航以实现CSS的滑动门效果。所以我认为适当的解决方案至少需要支持这些案例场景。

Iterating through the array from the template using array_walk() would still be okay, as long as it can be used in such a way that the callback function passes the desired vars back to the template for use with the designer's HTML.

使用array_walk()从模板中迭代数组仍然可以,只要它可以以回调函数将所需的vars传递回模板以便与设计者的HTML一起使用的方式使用。

Ideally, if array_walk_recursive() knew how many levels deep its iterator actually is, I think this feat would be much easier to solve. But unless someone knows a workaround to that issue, the solution may be different entirely.

理想情况下,如果array_walk_recursive()知道它的迭代器实际上有多少级别,我认为这个专长将更容易解决。但除非有人知道该问题的解决方法,否则解决方案可能完全不同。

I also want to avoid using javascript methods of building the tree. And if there's a way to avoid using the switch, I'm open to suggestions there too.

我也想避免使用构建树的javascript方法。如果有办法避免使用开关,我也愿意接受建议。

1 个解决方案

#1


Have you thought of writing a Class that manages and stores the info you want to pass back. You function could alter an instance of that class as it goes though and in the end pass back the filled object.

您是否考虑过编写一个管理和存储您想要传回的信息的类。你的函数可以改变该类的实例,并最终传回填充的对象。

Your content would be encapsulated inside the class and you can write all the methods and utilities for the user to manipulate and output the data. Utility methods can also be written inside the class to show the number of levels, etc.

您的内容将封装在类中,您可以编写用户操作和输出数据的所有方法和实用程序。也可以在类中编写实用方法来显示级别数等。

I haven't tried it myself but this is where I would start since the Class allows me to refine and expand on what my users would want and they wouldn't need to know the internal details of what was happening.

我自己没有尝试过,但这是我要开始的地方,因为Class允许我改进和扩展我的用户想要的东西,他们不需要知道发生了什么的内部细节。

#1


Have you thought of writing a Class that manages and stores the info you want to pass back. You function could alter an instance of that class as it goes though and in the end pass back the filled object.

您是否考虑过编写一个管理和存储您想要传回的信息的类。你的函数可以改变该类的实例,并最终传回填充的对象。

Your content would be encapsulated inside the class and you can write all the methods and utilities for the user to manipulate and output the data. Utility methods can also be written inside the class to show the number of levels, etc.

您的内容将封装在类中,您可以编写用户操作和输出数据的所有方法和实用程序。也可以在类中编写实用方法来显示级别数等。

I haven't tried it myself but this is where I would start since the Class allows me to refine and expand on what my users would want and they wouldn't need to know the internal details of what was happening.

我自己没有尝试过,但这是我要开始的地方,因为Class允许我改进和扩展我的用户想要的东西,他们不需要知道发生了什么的内部细节。