Silverstripe 4中如何向模板传递多组数组并正确遍历
嘿,我来帮你捋清楚这个问题:你想在模板里用两个循环展示不同的列表数据,思路方向是对的,但合并ArrayList的方式犯了个小错误,导致模板里无法正确访问到数据。
先说说你当前代码的问题
你把$SSArrayList和$JSBrandsArray直接push到了新的$mainArray(一个ArrayList)里,这意味着$mainArray里的两个元素就是这两个列表本身,但它们没有对应的键名。当你在模板里<% loop $MainArray %>时,每一次循环的上下文都是其中一个列表(第一次是$SSArrayList,第二次是$JSBrandsArray),这时候你在这个上下文里写<% loop $SSArrayList %>,模板根本找不到名为$SSArrayList的变量——因为当前上下文就是这个列表本身,自然渲染不出来。
虽然var_dump()能看到完整数据,但Silverstripe模板的上下文机制和普通PHP数组访问是不一样的,这就是问题所在。
给你两种可行的解决方案
方案一:直接传递两个独立变量(推荐,更简单直观)
不需要合并成一个ArrayList,直接把两个列表作为独立参数传给模板就行:
控制器代码:
// 先创建好你的$SSArrayList $sqlQuery = new SQLSelect(); $sqlQuery->setFrom('Wine'); $sqlQuery->addWhere($queryArray); $results = $sqlQuery->execute(); $SSArrayList = new ArrayList; foreach($results as $result) { $SSArrayList->push(new ArrayData($result)); } // 重新创建$JSBrandsArray(用ArrayData包装更规范) $JSBrandsArray = new ArrayList; foreach($results as $result) { if (!empty($result['BrandName'])) { $JSBrandsArray->push(new ArrayData([ 'Brandname' => $result['BrandName'] ])); } } // 直接传递两个变量到模板 return $this->customise([ 'WineResults' => $SSArrayList, 'BrandList' => $JSBrandsArray ])->renderWith("Layout/WinesList");
模板代码(WinesList.ss):
<!-- 遍历酒品数据 --> <% loop $WineResults %> <p>酒品品牌:$BrandName,其他字段:$YourOtherField</p> <% end_loop %> <!-- 遍历品牌列表 --> <% loop $BrandList %> <p>品牌:$Brandname</p> <% end_loop %>
方案二:用ArrayData作为容器传递(如果需要统一管理)
如果你一定要用一个变量把两个列表传进去,别用ArrayList(它是用来存同类型列表项的),改用ArrayData——它是Silverstripe用来存键值对数据的容器:
控制器代码:
// 先创建好两个ArrayList(同上) // 用ArrayData包装两个列表 $mainData = new ArrayData([ 'SSArrayList' => $SSArrayList, 'JSBrandsArray' => $JSBrandsArray ]); // 传递这个包装后的变量 return $this->customise(['MainData' => $mainData])->renderWith("Layout/WinesList");
模板代码:
<!-- 直接通过容器访问两个列表,不需要外层loop --> <% loop $MainData.SSArrayList %> <p>酒品信息:$BrandName</p> <% end_loop %> <% loop $MainData.JSBrandsArray %> <p>品牌:$Brandname</p> <% end_loop %>
额外小提示
创建$JSBrandsArray时,最好用ArrayData包装每个元素,虽然普通数组在模板里也能访问,但用Silverstripe的标准数据对象更符合框架的设计规范,避免潜在的上下文访问问题。
内容的提问来源于stack exchange,提问作者mckinselberg

