setting value for Field::Mutable::DateTime in order to get an error message
[catagits/Reaction.git] / lib / Reaction / UI / ViewPort / Object.pm
CommitLineData
ddccc6a2 1package Reaction::UI::ViewPort::Object;
2
3use Reaction::Class;
4
5use aliased 'Reaction::UI::ViewPort::Field::Text';
6use aliased 'Reaction::UI::ViewPort::Field::Number';
7use aliased 'Reaction::UI::ViewPort::Field::Integer';
8use aliased 'Reaction::UI::ViewPort::Field::Boolean';
9use aliased 'Reaction::UI::ViewPort::Field::String';
10use aliased 'Reaction::UI::ViewPort::Field::DateTime';
11use aliased 'Reaction::UI::ViewPort::Field::RelatedObject';
c8fbb8ad 12use aliased 'Reaction::UI::ViewPort::Field::Array';
ddccc6a2 13use aliased 'Reaction::UI::ViewPort::Field::Collection';
4ed8c1eb 14use aliased 'Reaction::UI::ViewPort::Field::File';
ddccc6a2 15
16use aliased 'Reaction::InterfaceModel::Object' => 'IM_Object';
17
18class Object is 'Reaction::UI::ViewPort', which {
19
20 #everything is read only right now. Later I can make somethings read-write
21 #but first I need to figure out what depends on what so we can have decent triggers
22 has model => (is => 'ro', isa => IM_Object, required => 1);
23 has fields => (is => 'ro', isa => 'ArrayRef', lazy_build => 1);
24
92112f88 25 has field_args => (is => 'rw');
ddccc6a2 26 has field_order => (is => 'ro', isa => 'ArrayRef');
27
28 has builder_cache => (is => 'ro', isa => 'HashRef', lazy_build => 1);
ddccc6a2 29 has excluded_fields => (is => 'ro', isa => 'ArrayRef', lazy_build => 1);
cc44a337 30 has computed_field_order => (is => 'ro', isa => 'ArrayRef', lazy_build => 1);
ddccc6a2 31
32 implements BUILD => as {
33 my ($self, $args) = @_;
504e2c44 34 if( my $field_args = delete $args->{Field} ){
35 $self->field_args( $field_args );
36 }
ddccc6a2 37 };
38
39 implements _build_excluded_fields => as { [] };
40 implements _build_builder_cache => as { {} };
41
42 implements _build_fields => as {
43 my ($self) = @_;
44 my $obj = $self->model;
45 my $args = $self->has_field_args ? $self->field_args : {};
46 my @fields;
cc44a337 47 for my $field_name (@{ $self->computed_field_order }) {
ddccc6a2 48 my $attr = $obj->meta->find_attribute_by_name($field_name);
49 my $meth = $self->builder_cache->{$field_name} ||= $self->get_builder_for($attr);
c03f75a7 50 my $field = $self->$meth($attr, ($args->{$field_name} || {}));
ddccc6a2 51 push(@fields, $field) if $field;
52 }
c8fbb8ad 53 return \@fields;
ddccc6a2 54 };
55
cc44a337 56 implements _build_computed_field_order => as {
ddccc6a2 57 my ($self) = @_;
58 my %excluded = map { $_ => undef } @{ $self->excluded_fields };
59 #treat _$field_name as private and exclude fields with no reader
c8fbb8ad 60 my @names = grep { $_ !~ /^_/ && !exists($excluded{$_})} map { $_->name }
ddccc6a2 61 grep { defined $_->get_read_method } $self->model->meta->parameter_attributes;
c03f75a7 62 return $self->sort_by_spec($self->field_order || [], \@names);
ddccc6a2 63 };
64
65 override child_event_sinks => sub {
36d54b14 66 return ( @{shift->fields}, super());
ddccc6a2 67 };
68
69 #candidate for shared role!
70 implements get_builder_for => as {
71 my ($self, $attr) = @_;
72 my $attr_name = $attr->name;
73 my $builder = "_build_fields_for_name_${attr_name}";
74 return $builder if $self->can($builder);
75 if ($attr->has_type_constraint) {
76 my $constraint = $attr->type_constraint;
77 my $base_name = $constraint->name;
78 my $tried_isa = 0;
2c36a66b 79 my @tried;
ddccc6a2 80 CONSTRAINT: while (defined($constraint)) {
81 my $name = $constraint->name;
82 $name = $attr->_isa_metadata if($name eq '__ANON__');
83 if (eval { $name->can('meta') } && !$tried_isa++) {
84 foreach my $class ($name->meta->class_precedence_list) {
2c36a66b 85 push(@tried, $class);
ddccc6a2 86 my $mangled_name = $class;
87 $mangled_name =~ s/:+/_/g;
88 my $builder = "_build_fields_for_type_${mangled_name}";
89 return $builder if $self->can($builder);
90 }
91 }
92 if (defined($name)) {
2c36a66b 93 push(@tried, $name);
ddccc6a2 94 unless (defined($base_name)) {
95 $base_name = "(anon subtype of ${name})";
96 }
97 my $mangled_name = $name;
98 $mangled_name =~ s/:+/_/g;
99 my $builder = "_build_fields_for_type_${mangled_name}";
100 return $builder if $self->can($builder);
101 }
102 $constraint = $constraint->parent;
103 }
104 if (!defined($constraint)) {
2c36a66b 105 confess "Can't build field ${attr_name} of type ${base_name} without "
106 ."$builder method or _build_fields_for_type_<type> method "
107 ."for type or any supertype (tried ".join(', ', @tried).")";
ddccc6a2 108 }
109 } else {
110 confess "Can't build field ${attr} without $builder method or type constraint";
111 }
112 };
113
114 implements _build_simple_field => as {
115 my ($self, %args) = @_;
116 my $class = delete $args{class};
117 confess("Can not build simple field without a viewport class")
118 unless $class;
119 confess("Can not build simple field without attribute")
120 unless defined $args{attribute};
121
122 my $field_name = $args{attribute}->name;
123 return $class->new(
124 ctx => $self->ctx,
125 model => $self->model,
126 location => join('-', $self->location, 'field', $field_name),
127 %args
128 );
129 };
130
131 implements _build_fields_for_type_Num => as {
132 my ($self, $attr, $args) = @_;
133 $self->_build_simple_field(attribute => $attr, class => Number, %$args);
134 };
135
136 implements _build_fields_for_type_Int => as {
137 my ($self, $attr, $args) = @_;
138 #XXX
139 $self->_build_simple_field(attribute => $attr, class => Integer, %$args);
140 };
141
142 implements _build_fields_for_type_Bool => as {
143 my ($self, $attr, $args) = @_;
144 $self->_build_simple_field(attribute => $attr, class => Boolean, %$args);
145 };
146
147 #XXX
d9a3266f 148 implements _build_fields_for_type_Reaction_Types_Core_Password => as { return };
ddccc6a2 149
150 implements _build_fields_for_type_Str => as {
151 my ($self, $attr, $args) = @_;
152 #XXX
153 $self->_build_simple_field(attribute => $attr, class => String, %$args);
154 };
155
d9a3266f 156 implements _build_fields_for_type_Reaction_Types_Core_SimpleStr => as {
ddccc6a2 157 my ($self, $attr, $args) = @_;
158 $self->_build_simple_field(attribute => $attr, class => String, %$args);
159 };
160
abc28589 161 implements _build_fields_for_type_Reaction_Types_DateTime_DateTime => as {
ddccc6a2 162 my ($self, $attr, $args) = @_;
163 $self->_build_simple_field(attribute => $attr, class => DateTime, %$args);
164 };
165
166 implements _build_fields_for_type_Enum => as {
167 my ($self, $attr, $args) = @_;
168 #XXX
169 $self->_build_simple_field(attribute => $attr, class => String, %$args);
170 };
171
172 implements _build_fields_for_type_ArrayRef => as {
173 my ($self, $attr, $args) = @_;
c8fbb8ad 174 $self->_build_simple_field(attribute => $attr, class => Array, %$args);
ddccc6a2 175 };
176
5ae92ec0 177 implements _build_fields_for_type_Reaction_Types_File_File => as {
4ed8c1eb 178 my ($self, $attr, $args) = @_;
179 $self->_build_simple_field(attribute => $attr, class => File, %$args);
180 };
181
ddccc6a2 182 implements _build_fields_for_type_Reaction_InterfaceModel_Object => as {
183 my ($self, $attr, $args) = @_;
184 #XXX
185 $self->_build_simple_field(attribute => $attr, class => RelatedObject, %$args);
186 };
187
188 implements _build_fields_for_type_Reaction_InterfaceModel_Collection => as {
189 my ($self, $attr, $args) = @_;
190 $self->_build_simple_field(attribute => $attr, class => Collection, %$args);
191 };
192
193};
194
1951;
2dba7201 196
197__END__;
198
199=head1 NAME
200
201Reaction::UI::ViewPort::Object
202
203=head1 DESCRIPTION
204
205=head1 ATTRIBUTES
206
207=head2 model
208
209=head2 fields
210
211=head2 field_args
212
213=head2 field_order
214
215=head2 builder_cache
216
217=head2 excluded_fields
218
219=head2 computed_field_order
220
221=head1 INTERNAL METHODS
222
223These methods, although stable, are subject to change without notice. These are meant
224to be used only by developers. End users should refrain from using these methods to
225avoid potential breakages.
226
227=head2 BUILD
228
229=head2 get_builder_for
230
231=head2 _build_simple_field
232
233=head2 _build_fields_for_type_Num
234
235=head2 _build_fields_for_type_Int
236
237=head2 _build_fields_for_type_Bool
238
239=head2 _build_fields_for_type_Password
240
241=head2 _build_fields_for_type_Str
242
243=head2 _build_fields_for_type_SimpleStr
244
245=head2 _build_fields_for_type_DateTime
246
247=head2 _build_fields_for_type_Enum
248
249=head2 _build_fields_for_type_ArrayRef
250
251=head2 _build_fields_for_type_Reaction_InterfaceModel_Object
252
253=head2 _build_fields_for_type_Reaction_InterfaceModel_Collection
254
255=head1 AUTHORS
256
257See L<Reaction::Class> for authors.
258
259=head1 LICENSE
260
261See L<Reaction::Class> for the license.
262
263=cut