r62507@cain (orig r402): groditi | 2007-11-14 18:33:11 +0000
[catagits/Reaction.git] / lib / Reaction / UI / ViewPort / ObjectView.pm
CommitLineData
7adfd53f 1package Reaction::UI::ViewPort::ObjectView;
2
3use Reaction::Class;
4
5use aliased 'Reaction::UI::ViewPort::DisplayField::Text';
6use aliased 'Reaction::UI::ViewPort::DisplayField::Number';
7use aliased 'Reaction::UI::ViewPort::DisplayField::Boolean';
8use aliased 'Reaction::UI::ViewPort::DisplayField::String';
9use aliased 'Reaction::UI::ViewPort::DisplayField::DateTime';
10use aliased 'Reaction::UI::ViewPort::DisplayField::RelatedObject';
11use aliased 'Reaction::UI::ViewPort::DisplayField::List';
12use aliased 'Reaction::UI::ViewPort::DisplayField::Collection';
e22de101 13use aliased 'Reaction::InterfaceModel::Object';
14
7adfd53f 15
16class ObjectView is 'Reaction::UI::ViewPort', which {
e22de101 17 has object => (isa => Object, is => 'ro', required => 1);
18 has ordered_fields => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
7adfd53f 19
7adfd53f 20 has _field_map => (
7b78a39d 21 isa => 'HashRef', is => 'rw', init_arg => 'fields', lazy_build => 1,
7adfd53f 22 );
23
24 has exclude_fields =>
25 ( is => 'rw', isa => 'ArrayRef', required => 1, default => sub{ [] } );
26
e22de101 27
7b78a39d 28
7b78a39d 29 implements fields => as { shift->_field_map };
7adfd53f 30
31 implements BUILD => as {
32 my ($self, $args) = @_;
33 unless ($self->_has_field_map) {
34 my @field_map;
35 my $object = $self->object;
36 my %excluded = map{$_ => 1} @{$self->exclude_fields};
37 for my $attr (grep { !$excluded{$_->name} } $object->parameter_attributes) {
89939ff9 38 push(@field_map, $self->_build_fields_for($attr => $args));
7adfd53f 39 }
40
6ab43711 41 my %field_map = @field_map;
42 $self->_field_map( \%field_map );
7adfd53f 43 }
44 };
45
89939ff9 46 implements _build_fields_for => as {
7adfd53f 47 my ($self, $attr, $args) = @_;
48 my $attr_name = $attr->name;
89939ff9 49 my $builder = "_build_fields_for_name_${attr_name}";
7adfd53f 50 my @fields;
51 if ($self->can($builder)) {
52 @fields = $self->$builder($attr, $args); # re-use coderef from can()
53 } elsif ($attr->has_type_constraint) {
54 my $constraint = $attr->type_constraint;
55 my $base_name = $constraint->name;
56 my $tried_isa = 0;
57 CONSTRAINT: while (defined($constraint)) {
58 my $name = $constraint->name;
de48f4e6 59 $name = $attr->_isa_metadata if($name eq '__ANON__');
7adfd53f 60 if (eval { $name->can('meta') } && !$tried_isa++) {
61 foreach my $class ($name->meta->class_precedence_list) {
62 my $mangled_name = $class;
63 $mangled_name =~ s/:+/_/g;
89939ff9 64 my $builder = "_build_fields_for_type_${mangled_name}";
7adfd53f 65 if ($self->can($builder)) {
66 @fields = $self->$builder($attr, $args);
67 last CONSTRAINT;
68 }
69 }
70 }
71 if (defined($name)) {
72 unless (defined($base_name)) {
73 $base_name = "(anon subtype of ${name})";
74 }
75 my $mangled_name = $name;
76 $mangled_name =~ s/:+/_/g;
89939ff9 77 my $builder = "_build_fields_for_type_${mangled_name}";
7adfd53f 78 if ($self->can($builder)) {
79 @fields = $self->$builder($attr, $args);
80 last CONSTRAINT;
81 }
82 }
83 $constraint = $constraint->parent;
84 }
85 if (!defined($constraint)) {
89939ff9 86 confess "Can't build field ${attr_name} of type ${base_name} without $builder method or _build_fields_for_type_<type> method for type or any supertype";
7adfd53f 87 }
88 } else {
89 confess "Can't build field ${attr} without $builder method or type constraint";
90 }
91 return @fields;
92 };
93
7b78a39d 94 implements _build_field_map => as {
7adfd53f 95 confess "Lazy field map building not supported by default";
96 };
97
89939ff9 98 implements _build_ordered_fields => as {
7b78a39d 99 my $self = shift;
6ab43711 100 my $ordered = $self->sort_by_spec($self->column_order, [keys %{$self->_field_map}]);
101 return [@{$self->_field_map}{@$ordered}];
7b78a39d 102 };
103
89939ff9 104 implements _build_simple_field => as {
7adfd53f 105 my ($self, $class, $attr, $args) = @_;
106 my $attr_name = $attr->name;
107 my %extra;
108 if (my $config = $args->{Field}{$attr_name}) {
109 %extra = %$config;
110 }
111 my $field = $class->new(
112 object => $self->object,
113 attribute => $attr,
114 name => $attr->name,
115 location => join('-', $self->location, 'field', $attr->name),
116 ctx => $self->ctx,
117 %extra
118 );
119 return ($attr_name => $field);
120 };
121
89939ff9 122 implements _build_fields_for_type_Num => as {
7adfd53f 123 my ($self, $attr, $args) = @_;
89939ff9 124 return $self->_build_simple_field(Number, $attr, $args);
7adfd53f 125 };
126
89939ff9 127 implements _build_fields_for_type_Int => as {
7adfd53f 128 my ($self, $attr, $args) = @_;
89939ff9 129 return $self->_build_simple_field(Number, $attr, $args);
7adfd53f 130 };
131
89939ff9 132 implements _build_fields_for_type_Bool => as {
7adfd53f 133 my ($self, $attr, $args) = @_;
89939ff9 134 return $self->_build_simple_field(Boolean, $attr, $args);
7adfd53f 135 };
136
89939ff9 137 implements _build_fields_for_type_Password => as { return };
7adfd53f 138
89939ff9 139 implements _build_fields_for_type_Str => as {
7adfd53f 140 my ($self, $attr, $args) = @_;
89939ff9 141 return $self->_build_simple_field(String, $attr, $args);
7adfd53f 142 };
143
89939ff9 144 implements _build_fields_for_type_SimpleStr => as {
7adfd53f 145 my ($self, $attr, $args) = @_;
89939ff9 146 return $self->_build_simple_field(String, $attr, $args);
7adfd53f 147 };
148
89939ff9 149 implements _build_fields_for_type_DateTime => as {
7adfd53f 150 my ($self, $attr, $args) = @_;
89939ff9 151 return $self->_build_simple_field(DateTime, $attr, $args);
7adfd53f 152 };
153
89939ff9 154 implements _build_fields_for_type_Enum => as {
7adfd53f 155 my ($self, $attr, $args) = @_;
89939ff9 156 return $self->_build_simple_field(String, $attr, $args);
7adfd53f 157 };
158
89939ff9 159 implements _build_fields_for_type_ArrayRef => as {
7adfd53f 160 my ($self, $attr, $args) = @_;
89939ff9 161 return $self->_build_simple_field(List, $attr, $args)
7adfd53f 162 };
163
89939ff9 164 implements _build_fields_for_type_Reaction_InterfaceModel_Collection => as {
7adfd53f 165 my ($self, $attr, $args) = @_;
89939ff9 166 return $self->_build_simple_field(Collection, $attr, $args)
7adfd53f 167 };
168
89939ff9 169 implements _build_fields_for_type_Reaction_InterfaceModel_Object => as {
7adfd53f 170 my ($self, $attr, $args) = @_;
89939ff9 171 return $self->_build_simple_field(RelatedObject, $attr, $args);
7adfd53f 172 };
173
7adfd53f 174 no Moose;
175
176 no strict 'refs';
177 delete ${__PACKAGE__ . '::'}{inner};
178
179};
180
1811;