2017-05-03 101 views
0

我有這樣一段代碼在我的控制器foreach循環的一部分數組項:訪問在模板工具包一個匿名哈希在Perl

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

在@ $組陣列我想存儲匿名散列,其中關鍵元素是組對象,value元素是該組對象的管理員。然後在模板中我想要展示不同組的列表的管理員可以登錄,對我有這樣的代碼:

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

我知道P IN的合作伙伴是不對的,但要告訴你什麼我想實現。有關模板代碼的任何建議?

+0

'FOREACH item IN list'是正確的。但是你想重新組合它們,對吧?這就像在Excel中的一個關鍵。你有類似'{1 =>'foo',2 =>'bar',3 =>'foo'}'的東西,並且你想要顯示用戶'foo'有'1,3'和'bar'有' 2'。我明白了嗎? – simbabque

+0

是的,這是正確的。你知道它絕對正確 – Albert

+0

是否有多個管理員?我不明白預期的輸出。 – simbabque

回答

3

duskwuff already explains in their answer說,因爲他們得到的序列化,你不能使用對象作爲哈希鍵,你就會失去對象的煩躁。我的答案建立在這個基礎上。

假設您有一個數組數組,而每個內部數組都包含一對對象。我已經創建了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 admin,以及一個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語法,以便更容易理解)。看起來像模板工具包不知道autovivificationthe DEFAULT keyword是類似於//= assignment operator in Perl

我們就可以pushitem第一個元素到我們剛剛創建(如果還不存在的話)的哈希ref元素裏面裏面by_name關鍵item.1.name的數組引用。

一旦我們完成準備,其餘的只是一個簡單的循環。我們遍歷by_adminsortedkeys,然後迭代該鍵後面的數組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贅述。

+0

與我得到它的代碼片段。非常感謝!你們做了我的日子 – Albert

+0

@Albert真正重要的部分是'DEFAULT'。這是我花了一段時間才弄清楚的。 – simbabque

+1

正如你所提到的,這最好在Perl(不是TT)中完成,所以我添加了Perl代碼來完成它。 – ikegami

3

您將需要重新修改代碼以使其成爲可能。

Perl哈希鍵是字符串,而不是標量。使用任何不是字符串的鍵作爲散列中的鍵(例如,$gr{ $gr => $gra }表達式將導致它被字符串化,就像將它插入字符串或打印它一樣。除非您明確地重載了​​""My::Model::Group對象上操作,關鍵最終會被存儲爲沿線的一個字符串:

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

此字符串不能轉換回原來的對象 - 事實上,原來的對象很可能是垃圾 - 一旦它超出範圍收集,所以它不再存在。

考慮將該對存儲爲數組相反,例如

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

好的,但那麼我如何訪問模板中的$ gr的id? – Albert