fef825a39a0261a010db9746caed717b197eeb41
[catagits/Reaction.git] / lib / Reaction / UI / ViewPort / Collection.pm
1 package Reaction::UI::ViewPort::Collection;
2
3 use Reaction::Class;
4 use Scalar::Util qw/blessed/;
5 use aliased 'Reaction::InterfaceModel::Collection' => 'IM_Collection';
6 use aliased 'Reaction::UI::ViewPort::Object';
7
8 use namespace::clean -except => [ qw(meta) ];
9 extends 'Reaction::UI::ViewPort';
10
11 has members => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
12
13 has collection         => (is => 'ro', isa => IM_Collection, required   => 1);
14 has current_collection => (is => 'rw', isa => IM_Collection, lazy_build => 1);
15
16 has member_args  => ( is => 'rw', isa => 'HashRef', lazy_build => 1);
17 has member_class => ( is => 'ro', isa => 'Str',     lazy_build => 1);
18
19 sub BUILD {
20   my ($self, $args) = @_;
21   if( my $member_args = delete $args->{Member} ){
22     $self->member_args( $member_args );
23   }
24 }
25
26 sub _build_member_args { {} }
27
28 sub _build_member_class { Object };
29
30 after clear_current_collection => sub{
31   shift->clear_members; #clear the members the current collection changes, duh
32 };
33
34 sub _build_current_collection {
35   return $_[0]->collection;
36 }
37
38 #I'm not really sure why this is here all of a sudden.
39 sub model { shift->current_collection }
40
41 sub _build_members {
42   my ($self) = @_;
43   my (@members, $i);
44   my $args = $self->member_args;
45   my $builders = {};
46   my $field_orders = {};
47   my $ctx = $self->ctx;
48   my $loc = join('-', $self->location, 'member');
49   my $class = $self->member_class;
50
51   #replace $i with a real unique identifier so that we don't run a risk of
52   # events being passed down to the wrong viewport. for now i disabled event
53   # passing until i fix this (groditi)
54   for my $obj ( $self->current_collection->members ) {
55     my $type = blessed $obj;
56     my $builder_cache = $builders->{$type} ||= {};
57     my @order;
58     if( exists $args->{computed_field_order} ){
59       @order = (computed_field_order => $args->{computed_field_order});
60     } elsif( exists $field_orders->{$type} ) {
61       @order = (computed_field_order => $field_orders->{$type});
62     }
63
64     my $member = $class->new(
65       ctx => $ctx,
66       model => $obj,
67       location => join('-', $loc, $i++),
68       builder_cache => $builder_cache,
69       @order, %$args,
70     );
71
72     #cache to prevent the sort function from having to be run potentially
73     #hundreds of times
74     $field_orders->{$type} ||= $member->computed_field_order unless @order;
75     push(@members, $member);
76   }
77   return \@members;
78 };
79
80 __PACKAGE__->meta->make_immutable;
81
82
83 1;
84
85 __END__;
86
87 =head1 NAME
88
89 Reaction::UI::ViewPort::Collection
90
91 =head1 DESCRIPTION
92
93 Creates, from an InterfaceModel::Collection, a list of viewports representing each
94 member of the collection.
95
96 =head1 ATTRIBUTES
97
98 =head2 collection
99
100 =head2 current_collection
101
102 =head2 member_args
103
104 =head2 member_class
105
106 =head1 INTERNAL METHODS
107
108 These methods, although stable, are subject to change without notice. These are meant
109 to be used only by developers. End users should refrain from using these methods to
110 avoid potential breakages.
111
112 =head2 BUILD
113
114 =head2 get_builder_for
115
116 =head2 model
117
118 =head1 AUTHORS
119
120 See L<Reaction::Class> for authors.
121
122 =head1 LICENSE
123
124 See L<Reaction::Class> for the license.
125
126 =cut