简体   繁体   English

在Perl的Template Toolkit中访问作为匿名哈希的数组项

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

I have this piece of code as part of a foreach loop in my controller: 我将这段代码作为控制器中foreach循环的一部分:

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

In @$groups array I want to store anonymous hashes where the key element is the group object and the value element is the admin of that group object. 在@ $ groups数组中,我想存储匿名哈希,其中的关键元素是组对象,而值元素是该组对象的管理员。 Then in the template I want to show the list of different groups that the admin can log in, for that I have this code: 然后在模板中,我想显示管理员可以登录的不同组的列表,为此我有以下代码:

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

I know that the p IN partners is not right but is to show you what I want to achieve. 我知道p IN合作伙伴不正确,而是向您展示我想要实现的目标。 Any suggestions on the template code? 关于模板代码有什么建议吗?

You will need to rework your code significantly to make this possible. 您将需要对代码进行大量重做才能使其成为可能。

Keys in Perl hashes are strings , not scalars. Perl哈希中的键是字符串 ,而不是标量。 Using anything that isn't a string as a key in a hash (eg, $gr in the expression { $gr => $gra } will cause it to be stringified, just as if you had interpolated it into a string or printed it. Unless you have explicitly overloaded the "" operator on the My::Model::Group object, the key will end up being stored as a literal string along the lines of: 使用任何不是一个字符串作为哈希键(例如, $gr在表达{ $gr => $gra }将导致它被字符串化,就好像你已经插入它变成一个字符串或打印它。除非您在My::Model::Group对象上显式重载了""运算符,否则该键最终将作为文字字符串存储在以下行中:

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

This string cannot be converted back to the original object -- in fact, the original object was probably garbage-collected as soon as it went out of scope, so it no longer exists at all. 该字符串不能转换回原始对象-实际上,原始对象可能在超出范围后立即被垃圾回收,因此它根本不存在。

Consider storing the pair as an array reference instead, eg 考虑将其存储为数组引用,例如

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

duskwuff already explains in their answer that you can't use objects as hash keys as they get serialized and you'll lose the object-ness. duskwuff已经在他们的答案说明 ,当对象被序列化时,您不能将它们用作哈希键,并且会失去对象的特性。 My answer builds on that. 我的答案基于此。

Let's say you have an array of arrays instead, where each inner array holds a pair of objects. 假设您有一个数组数组,每个内部数组都包含一对对象。 I've created Moo classes to illustrate. 我创建了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' )
    ],
];

There are four pairs. 有四对。 Two admins, four groups. 两个管理员,四个小组。 Three of the groups belong to the foo admin, and one to bar . 其中三个组属于foo admin,另一个属于bar Now let's look at the template. 现在让我们看一下模板。

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 -%]

The relevant part obviously is the DATA section. 显然相关的部分是DATA部分。 We need to reorganize the array data structure into a hash that has the admins, and then each group sorted into one of the admin slots. 我们需要将数组数据结构重组为具有管理员的哈希,然后将每个组分类到一个管理员插槽中。

We don't need to create the by_admin variable. 我们不需要创建by_admin变量。 It will be created globally implicitly. 它将在全局隐式创建。 But we do need to set a default value for $by_admin->{$item[0]->name} (I'm using Perl syntax now, to make it easier to understand). 但是我们确实需要为$by_admin->{$item[0]->name}设置默认值(为了易于理解,我现在正在使用Perl语法)。 It seems like Template Toolkit does not know autovivification , and the DEFAULT keyword is similar to the //= assignment operator in Perl . 似乎Template Toolkit不知道自动生存能力 ,并且DEFAULT关键字类似于Perl中//=赋值运算符

We can then push the first element of item into the array ref we just created (if it didn't exist yet) inside the hash ref element with the key item.1.name inside by_name . 然后,我们可以push的第一个元素item到我们刚刚创建的数组引用与键(如果还不存在的话)的哈希ref元素内item.1.nameby_name

Once we're done preparing, the rest is just a simple loop. 一旦准备就绪,剩下的就是一个简单的循环。 We iterate the sort ed keys of by_admin , and then iterate the array ref that's behind that key. 我们迭代by_adminsort keys ,然后迭代该键后面的数组ref。

Here's the output: 这是输出:

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

It would make sense to do the preprocessing not in a template, but in your controller instead. 最好不要在模板中而是在控制器中进行预处理。 As normal Perl code it should be easier to read. 作为正常的Perl代码,它应该更易于阅读。

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

Note that I have omitted use strict and use warnings for brevity. 请注意,为简洁起见,我省略了use strictuse warnings

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM