在 Perl 的 Template Toolkit 中访问作为匿名散列的数组项

Access an array item that is an anonymous hash in Template Toolkit in Perl

我将这段代码作为控制器中 foreach 循环的一部分:

my $gr = My::Model::Group->new(id => $gra->gr_id);
$gra = My::Model::Group::Admin->new(id => $gra->id);
push(@$groups, {$gr => $gra});

在@$groups 数组中,我想存储匿名散列,其中键元素是组对象,值元素是该组对象的管理员。然后在模板中我想显示管理员可以登录的不同组的列表,因为我有这个代码:

[%- FOREACH  gr IN groups -%]
  <li><input type="radio" name="group" value="[% gr.id %]">[% gr.name %]</input></li>
[%- END -%]

我知道p IN小伙伴说的不对但是就是想告诉你我想要达到的目的。对模板代码有什么建议吗?

您需要大量修改代码才能实现这一点。

Perl 散列中的键是 字符串 ,而不是标量。使用任何不是字符串的东西作为散列中的键(例如,表达式 { $gr => $gra } 中的 $gr 将导致它被字符串化,就像您将它插入到字符串中或打印出来一样. 除非您在 My::Model::Group 对象上显式重载了 "" 运算符,否则密钥最终将按照以下行存储为文字字符串:

"My::Model::Group=HASH(0x1234567890)"

此字符串无法转换回原始对象 -- 事实上,原始对象可能在超出范围后立即被垃圾回收,因此它根本不存在。

考虑将该对存储为数组引用,例如

push @$groups, [$gr, $gra];

您不能将对象用作散列键,因为它们已序列化,您将失去对象特性。我的回答以此为基础。

假设您有一个数组数组,其中每个内部数组包含一对对象。我创建了 Moo 类 来说明。

package My::Model::Group;
use Moo;
has [qw/id name/] => ( is => 'ro' );

package My::Model::Group::Admin;
use Moo;
has [qw/id name/] => ( is => 'ro' );

package main;

my $groups = [
    [
        My::Model::Group->new( id => 1, name => 'group1' ) =>
            My::Model::Group::Admin->new( id => 1, name => 'foo' )
    ],
    [
        My::Model::Group->new( id => 2, name => 'group2' ) =>
            My::Model::Group::Admin->new( id => 1, name => 'foo' )
    ],
    [
        My::Model::Group->new( id => 3, name => 'group3' ) =>
            My::Model::Group::Admin->new( id => 1, name => 'bar' )
    ],
    [
        My::Model::Group->new( id => 4, name => 'group4' ) =>
            My::Model::Group::Admin->new( id => 1, name => 'foo' )
    ],
];

有四对。两个管理员,四个组。其中三个组属于 foo 管理员,一个属于 bar。现在让我们看一下模板。

use Template;

my $tt = Template->new();
$tt->process( \*DATA, { groups => $groups }, \my $output )
   or die $tt->error;

print $output;
__DATA__
[%- FOREACH item IN groups -%]
    [%- DEFAULT by_admin.${item.1.name} = [] -%]
    [%- by_admin.${item.1.name}.push(item.0) -%]
[%- END -%]

[%- FOREACH admin IN by_admin.keys.sort -%]
    [%- FOREACH group IN by_admin.$admin -%]
        [%- admin %] -> [% group.id %]

    [%- END -%]
[%- END -%]

相关部分显然是 DATA 部分。我们需要将数组数据结构重新组织成一个包含管理员的哈希,然后将每个组排序到一个管理员槽中。

我们不需要创建 by_admin 变量。它将在全局隐式创建。但是我们确实需要为 $by_admin->{$item[0]->name} 设置一个默认值(我现在使用 Perl 语法,以便于理解)。似乎 Template Toolkit 不知道 autovivification, and the DEFAULT keyword is similar to the //= assignment operator in Perl.

然后我们可以 push item 的第一个元素到我们刚刚创建的数组 ref 中(如果它还不存在)在哈希 ref 元素中,键为 item.1.name里面by_name.

准备工作完成后,剩下的就是一个简单的循环。我们迭代 by_adminsorted keys,然后迭代该键后面的数组 ref。

这是输出:

bar -> 3
foo -> 1
foo -> 2
foo -> 4

不在模板中而是在您的控制器中进行预处理是有意义的。作为普通的 Perl 代码,它应该更容易阅读。

my %by_admin;
for my $group (@$groups) {
    push @{ $by_admin{ $group->[1]{name} } }, $group->[0];
}

请注意,为了简洁起见,我省略了 use strictuse warnings