无法理解str_repeat以及如何在视图模板中删除/重构

时间:2014-04-18 20:30:58

标签: php concrete5

我尝试使用替代语法重构一些php模板,以便设计师(比如我)更具可读性:http://getkirby.com/blog/php-templates

但是我没有为具体的导航块 - autonav重构一个视图模板。这就是我的工作......

<ul class="main-nav-left">
<? foreach($navItems as $ni) : ?>
  <li class="dropdown <?= ($ni->classes) ? $ni->classes : '' ?>">

  <? if ($ni->isEnabled) : ?>
    <a class="dropdown-toggle <?= $ni->classes ?>" href="<?= $ni->url ?>"><?= $ni->name ?></a>
  <? else : ?>
    <span class="<?= $ni->classes ?>"><?= $ni->name ?></span>
  <? endif ?>

  <? if ($ni->hasSubmenu) : ?>
    <ul class="dropdown-menu">
  <? else : ?>
    </li><?= str_repeat('</ul></li>', $ni->subDepth); ?>
  <? endif ?>

  </li>
<? endforeach ?>
</ul>

但我不明白为什么</ul></li>不能一次又一次地获得输出。在str_repeat结束之前,我不会$ni->subDepth重复这些结束标记吗?

问题:

如何开放<li>&amp;子菜单项的<a>标签会输出吗?

有没有办法将str_repeat行重构为foreach循环,以便子菜单部分更具可读性?

任何指向正确方向的人都会非常感激 - 我对PHP BTW知之甚少。

干杯

1 个答案:

答案 0 :(得分:1)

我实际上写了该版本的模板。我也太在意让设计师(和开发人员)对标记具有可读性,并且不管你相信与否,你所看到的可能是最简单的。 (如果你想让你的眼睛流血,请查看它的外观:https://github.com/concrete5/concrete5/blob/bbdd9cb9acd31b6595c665cc1316eb76712f0e0b/web/concrete/blocks/autonav/view.php)。

它之所以不简单的高级原因是:因为autonav块的默认模板必须适应很多不同站点的大量不同情况。因为它是每个Concrete5站点的默认导航菜单结构,所以它必须足够通用以处理任何可能的站点结构(在Concrete5中,表示任意数量的级别和子级别,别名页面,重定向到其子站点的页面, “导航&#34;隐藏的页面”,在新窗口中打开的页面等。)

具体而言,str_repeat行用于促进站点地图结构中可能存在的任意数量的子级别。无论站点地图的深度多少都不重要... 2级,3级,10级,无论如何......一行代码关闭所有子菜单,无论它们有多深。

您链接到的示例Kirby文档中显示的方法肯定更容易阅读和理解:

<?php if($page->hasChildren()): ?>
    <ul>
        <?php foreach($page->children() as $child): ?>
            <li><a href="<?php echo $child->url() ?>"><?php echo $child->title() ?></a></li>
        <?php endforeach ?>
    </ul>
<?php endif ?>

...但是,如果网站的深度为1级或2级,它们仅限于工作。如果您知道您的用户只会在站点地图中添加1个子级别的页面,那么您可以完全放弃(完全应该 - C5的一个好处就是它的设计为每个站点覆盖和自定义导航菜单之类的东西,这样做比在其他CMS中更容易。但是,只要有人添加子子页面,现在您的菜单将无效。您可以通过向该代码添加另一个级别来解决此问题:

<?php if($page->hasChildren()): ?>
    <ul>
        <?php foreach($page->children() as $child): ?>
            <li>
                <a href="<?php echo $child->url() ?>"><?php echo $child->title() ?></a>
                <?php if ($child->hasChildren()): ?>
                    <ul>
                        <?php foreach ($child->children() as $grandchild): ?>
                            <li>
                                <a href="<?php echo $grandchild->url() ?>"><?php echo $grandchild->title() ?></a>
                            </li>
                        <?php endforeach; ?>
                    </ul>
                <?php endif; ?>
            </li>
        <?php endforeach ?>
    </ul>
<?php endif ?>

但是如果有另一个子级别会发生什么?你结束了这个:

<?php if($page->hasChildren()): ?>
    <ul>
        <?php foreach($page->children() as $child): ?>
            <li>
                <a href="<?php echo $child->url() ?>"><?php echo $child->title() ?></a>
                <?php if ($child->hasChildren()): ?>
                    <ul>
                        <?php foreach ($child->children() as $grandchild): ?>
                            <li>
                                <a href="<?php echo $grandchild->url() ?>"><?php echo $grandchild->title() ?></a>
                                <?php if ($grandchild->hasChildren()): ?>
                                    <ul>
                                        <?php foreach ($grandchild->children() as $greatgrandchild): ?>
                                            <li>
                                                <a href="<?php echo $greatgrandchild->url() ?>"><?php echo $greatgrandchild->title() ?></a>
                                            </li>
                                        <?php endforeach; ?>
                                    </ul>
                                <?php endif; ?>
                            </li>
                        <?php endforeach; ?>
                    </ul>
                <?php endif; ?>
            </li>
        <?php endforeach ?>
    </ul>
<?php endif ?>

你可以看到这里有很多重复,这就是为什么Concrete5 autonav模板的结构是这样的。那个str_repeat调用替换了理论上无限数量的嵌套菜单!

为冗长的介绍道歉(我真的很喜欢这些问题,感谢您的提问!)...以下是您具体问题的答案:

  

我不明白为什么</ul></li>不能一次又一次地获得输出。在$ ni-&gt; subDepth结束之前,str_repeat不会重复那些结束标记吗?

是的,str_repeat 输出结束标记,直到$ni->subDepth结束,这就是它的确切目的。这里的根本问题是,虽然站点地图是一个嵌套的层次结构,但&#34;导航项列表&#34;在代码中循环的是一个单独的列表。所以这个&#34;平面列表&#34;页面需要具有表示列表中每个项目在站点地图结构中所处的级别(或深度)的信息。这样做的方法是使用$ni->subDepth变量(它不是内置的PHP函数,也不是内置的Concrete5东西......而是自定义这个autonav模板并在块中设置& #39; s控制器,它位于另一个文件中)。 &#34; subDepth&#34;表示&#34;这个&#34;之间的等级数页面和&#34; next&#34;导航菜单中的页面。对于大多数菜单项,差异是&#34; 0&#34; (如果列表中的下一个项目与当前项目处于同一级别)。但是对于子菜单的最后一项,差异是&#34; 1&#34; (因为下一个导航菜单项比当前导航菜单项高1级...因为当前导航菜单项是下拉菜单中的最后一项,因此下一项启动新的顶级菜单)。偶尔差异可能是2或3(或更多),如果您有一个子菜单,其最后一项是另一个子菜单,则会发生这种情况...然后是子子菜单的最后一项与下一项之间的差异项目可能是&#34; 2&#34; (因为它是子子列表中的最后一项,所以下一个项目将启动一个新的顶级菜单)。所以... str_repeat是一种输出正确数量的结束标记的方法,无论当前导航项与列表中的下一个标记有多少级别。

  

如何开放<li>&amp;子菜单项的<a>标签会输出吗?

它们的输出方式与输出顶级菜单项的开始标记的方式相同!这是&#34;魔术&#34;这个模板...这是一种使用&#34; flat&#34;输出分层导航菜单的方法。列表并且不会为每个可能的子级别反复重复您的标记。因此,您可以使用开头<li>标记的一行:

<li class="dropdown <?= ($ni->classes) ? $ni->classes : '' ?>">

...以及<a>标记的一行:

<a class="dropdown-toggle <?= $ni->classes ?>" href="<?= $ni->url ?>"><?= $ni->name ?></a>

...用于菜单中的每个项目,无论什么&#34;深度&#34;该项目是。整齐! (但最初确实令人困惑:)

  

有没有办法将str_repeat行重构为foreach循环,以便子菜单部分更具可读性?

是的,有可能 IF 您知道站点地图层次结构只有1级或2级。但随着越来越多的关卡开始出现,代码气球失控,然后str_repeat事物变得更具可读性(至少在我看来......但是&#34;可读&#34;在眼睛里读者所以一定要做对你有用的事情。)

所以你有它...对Concrete5 autonav模板进行深入分析:)我希望我不会让你感到无聊,并且它至少在某种程度上是可以理解的。为了记录,我认为&#34;小型CMS&#34;像Kirby,Perch,Couch等都是非常好的系统,但在简单性和灵活性之间存在权衡,因此不同的工具将更适合不同的工作。

祝你好运!