1 package Reaction::UI::ViewPort::ObjectView;
5 use aliased 'Reaction::UI::ViewPort::DisplayField::Text';
6 use aliased 'Reaction::UI::ViewPort::DisplayField::Number';
7 use aliased 'Reaction::UI::ViewPort::DisplayField::Boolean';
8 use aliased 'Reaction::UI::ViewPort::DisplayField::String';
9 use aliased 'Reaction::UI::ViewPort::DisplayField::DateTime';
10 use aliased 'Reaction::UI::ViewPort::DisplayField::RelatedObject';
11 use aliased 'Reaction::UI::ViewPort::DisplayField::List';
12 use aliased 'Reaction::UI::ViewPort::DisplayField::Collection';
14 class ObjectView is 'Reaction::UI::ViewPort', which {
16 isa => 'Reaction::InterfaceModel::Object', is => 'ro', required => 1
19 has field_names => (isa => 'ArrayRef', is => 'rw', lazy_build => 1);
22 isa => 'HashRef', is => 'rw', init_arg => 'fields',
23 predicate => '_has_field_map', set_or_lazy_build('field_map'),
27 ( is => 'rw', isa => 'ArrayRef', required => 1, default => sub{ [] } );
29 sub fields { shift->_field_map }
31 implements BUILD => as {
32 my ($self, $args) = @_;
33 unless ($self->_has_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) {
38 push(@field_map, $self->build_fields_for($attr => $args));
41 my %field_map = @field_map;
42 my @field_names = @{ $self->sort_by_spec(
43 $args->{column_order}, [keys %field_map] )};
45 $self->_field_map(\%field_map);
46 $self->field_names(\@field_names);
50 implements build_fields_for => as {
51 my ($self, $attr, $args) = @_;
52 my $attr_name = $attr->name;
53 my $builder = "build_fields_for_name_${attr_name}";
55 if ($self->can($builder)) {
56 @fields = $self->$builder($attr, $args); # re-use coderef from can()
57 } elsif ($attr->has_type_constraint) {
58 my $constraint = $attr->type_constraint;
59 my $base_name = $constraint->name;
61 CONSTRAINT: while (defined($constraint)) {
62 my $name = $constraint->name;
63 if (eval { $name->can('meta') } && !$tried_isa++) {
64 foreach my $class ($name->meta->class_precedence_list) {
65 my $mangled_name = $class;
66 $mangled_name =~ s/:+/_/g;
67 my $builder = "build_fields_for_type_${mangled_name}";
68 if ($self->can($builder)) {
69 @fields = $self->$builder($attr, $args);
75 unless (defined($base_name)) {
76 $base_name = "(anon subtype of ${name})";
78 my $mangled_name = $name;
79 $mangled_name =~ s/:+/_/g;
80 my $builder = "build_fields_for_type_${mangled_name}";
81 if ($self->can($builder)) {
82 @fields = $self->$builder($attr, $args);
86 $constraint = $constraint->parent;
88 if (!defined($constraint)) {
89 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";
92 confess "Can't build field ${attr} without $builder method or type constraint";
97 implements build_field_map => as {
98 confess "Lazy field map building not supported by default";
101 implements build_simple_field => as {
102 my ($self, $class, $attr, $args) = @_;
103 my $attr_name = $attr->name;
105 if (my $config = $args->{Field}{$attr_name}) {
108 my $field = $class->new(
109 object => $self->object,
112 location => join('-', $self->location, 'field', $attr->name),
116 return ($attr_name => $field);
119 implements build_fields_for_type_Num => as {
120 my ($self, $attr, $args) = @_;
121 return $self->build_simple_field(Number, $attr, $args);
124 implements build_fields_for_type_Int => as {
125 my ($self, $attr, $args) = @_;
126 return $self->build_simple_field(Number, $attr, $args);
129 implements build_fields_for_type_Bool => as {
130 my ($self, $attr, $args) = @_;
131 return $self->build_simple_field(Boolean, $attr, $args);
134 implements build_fields_for_type_Password => as { return };
136 implements build_fields_for_type_Str => as {
137 my ($self, $attr, $args) = @_;
138 return $self->build_simple_field(String, $attr, $args);
141 implements build_fields_for_type_SimpleStr => as {
142 my ($self, $attr, $args) = @_;
143 return $self->build_simple_field(String, $attr, $args);
146 implements build_fields_for_type_DateTime => as {
147 my ($self, $attr, $args) = @_;
148 return $self->build_simple_field(DateTime, $attr, $args);
151 implements build_fields_for_type_Enum => as {
152 my ($self, $attr, $args) = @_;
153 return $self->build_simple_field(String, $attr, $args);
157 implements build_fields_for_type_ArrayRef => as {
158 my ($self, $attr, $args) = @_;
159 return $self->build_simple_field(List, $attr, $args)
162 implements build_fields_for_type_Reaction_InterfaceModel_Collection => as {
163 my ($self, $attr, $args) = @_;
164 return $self->build_simple_field(Collection, $attr, $args)
167 implements build_fields_for_type_Reaction_InterfaceModel_Object => as {
168 my ($self, $attr, $args) = @_;
169 return $self->build_simple_field(RelatedObject, $attr, $args);
176 delete ${__PACKAGE__ . '::'}{inner};