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
20 isa => 'HashRef', is => 'rw', init_arg => 'fields', lazy_build => 1,
24 ( is => 'rw', isa => 'ArrayRef', required => 1, default => sub{ [] } );
26 has ordered_fields => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
28 implements fields => as { shift->_field_map };
30 implements BUILD => as {
31 my ($self, $args) = @_;
32 unless ($self->_has_field_map) {
34 my $object = $self->object;
35 my %excluded = map{$_ => 1} @{$self->exclude_fields};
36 for my $attr (grep { !$excluded{$_->name} } $object->parameter_attributes) {
37 push(@field_map, $self->build_fields_for($attr => $args));
40 $self->_field_map({ @field_map });
44 implements build_fields_for => as {
45 my ($self, $attr, $args) = @_;
46 my $attr_name = $attr->name;
47 my $builder = "build_fields_for_name_${attr_name}";
49 if ($self->can($builder)) {
50 @fields = $self->$builder($attr, $args); # re-use coderef from can()
51 } elsif ($attr->has_type_constraint) {
52 my $constraint = $attr->type_constraint;
53 my $base_name = $constraint->name;
55 CONSTRAINT: while (defined($constraint)) {
56 my $name = $constraint->name;
57 if (eval { $name->can('meta') } && !$tried_isa++) {
58 foreach my $class ($name->meta->class_precedence_list) {
59 my $mangled_name = $class;
60 $mangled_name =~ s/:+/_/g;
61 my $builder = "build_fields_for_type_${mangled_name}";
62 if ($self->can($builder)) {
63 @fields = $self->$builder($attr, $args);
69 unless (defined($base_name)) {
70 $base_name = "(anon subtype of ${name})";
72 my $mangled_name = $name;
73 $mangled_name =~ s/:+/_/g;
74 my $builder = "build_fields_for_type_${mangled_name}";
75 if ($self->can($builder)) {
76 @fields = $self->$builder($attr, $args);
80 $constraint = $constraint->parent;
82 if (!defined($constraint)) {
83 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";
86 confess "Can't build field ${attr} without $builder method or type constraint";
91 implements _build_field_map => as {
92 confess "Lazy field map building not supported by default";
95 implements build_ordered_fields => as {
97 $self->sort_by_spec($self->column_order, [keys %{$self->_field_map_}])};
100 implements build_simple_field => as {
101 my ($self, $class, $attr, $args) = @_;
102 my $attr_name = $attr->name;
104 if (my $config = $args->{Field}{$attr_name}) {
107 my $field = $class->new(
108 object => $self->object,
111 location => join('-', $self->location, 'field', $attr->name),
115 return ($attr_name => $field);
118 implements build_fields_for_type_Num => as {
119 my ($self, $attr, $args) = @_;
120 return $self->build_simple_field(Number, $attr, $args);
123 implements build_fields_for_type_Int => as {
124 my ($self, $attr, $args) = @_;
125 return $self->build_simple_field(Number, $attr, $args);
128 implements build_fields_for_type_Bool => as {
129 my ($self, $attr, $args) = @_;
130 return $self->build_simple_field(Boolean, $attr, $args);
133 implements build_fields_for_type_Password => as { return };
135 implements build_fields_for_type_Str => as {
136 my ($self, $attr, $args) = @_;
137 return $self->build_simple_field(String, $attr, $args);
140 implements build_fields_for_type_SimpleStr => as {
141 my ($self, $attr, $args) = @_;
142 return $self->build_simple_field(String, $attr, $args);
145 implements build_fields_for_type_DateTime => as {
146 my ($self, $attr, $args) = @_;
147 return $self->build_simple_field(DateTime, $attr, $args);
150 implements build_fields_for_type_Enum => as {
151 my ($self, $attr, $args) = @_;
152 return $self->build_simple_field(String, $attr, $args);
156 implements build_fields_for_type_ArrayRef => as {
157 my ($self, $attr, $args) = @_;
158 return $self->build_simple_field(List, $attr, $args)
161 implements build_fields_for_type_Reaction_InterfaceModel_Collection => as {
162 my ($self, $attr, $args) = @_;
163 return $self->build_simple_field(Collection, $attr, $args)
166 implements build_fields_for_type_Reaction_InterfaceModel_Object => as {
167 my ($self, $attr, $args) = @_;
168 return $self->build_simple_field(RelatedObject, $attr, $args);
175 delete ${__PACKAGE__ . '::'}{inner};