shallow copying req->params
[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
94 each member of the collection.
95
96 =head1 ATTRIBUTES
97
98 =head2 collection
99
100 Required read-only L<InterfaceModel::Collection|Reaction::InterfaceModel::Collection>
101 This is the original collection.
102
103 =head2 current_collection
104
105 Read-only, lazy-building
106 L<InterfaceModel::Collection|Reaction::InterfaceModel::Collection>
107 This is the collection that will be used to create C<members> and should be
108 altered to reflect any ordering, paging, etc. By default this is the
109 same thing as C<collection>.
110
111 =head2 member_args
112
113 A read-write HASH ref of additional parameters to pass to the C<member_class>
114 constructor as items are instantiated.
115
116 =head2 member_class
117
118 The class to use when instantiating items to represent the member items.
119
120 See: L<Object|Reaction::UI::ViewPort::Object>,
121 L<Member|Reaction::UI::ViewPort::Grid::Member>,
122 L<Member::WithActions|Reaction::UI::ViewPort::Grid::Member::WithActions>,
123
124 =head1 INTERNAL METHODS
125
126 These methods, although stable, are subject to change without notice.
127 Extend at your own risk, APIs may change in the future.
128
129 =head2 BUILD
130
131 Intercept a parameter with the key C<Member> amd store it in C<member_args>
132
133 =head2 model
134
135 Returns the C<current_collection>
136
137 =head2 _build_members
138
139 Build individual viewports for each member of the collection,
140
141 =head2 _build_member_args
142
143 Defaults to an empty HASH ref.
144
145 =head2 _build_member_class
146
147 Defaults to L<Reaction::UI::ViewPort::Object>
148
149 =head1 AUTHORS
150
151 See L<Reaction::Class> for authors.
152
153 =head1 LICENSE
154
155 See L<Reaction::Class> for the license.
156
157 =cut