diff options
author | groditi <groditi@03d0b0b2-0e1a-0410-a411-fdb2f4bd65d7> | 2007-11-16 21:20:55 +0000 |
---|---|---|
committer | groditi <groditi@03d0b0b2-0e1a-0410-a411-fdb2f4bd65d7> | 2007-11-16 21:20:55 +0000 |
commit | 89b70ba768f30857a6f8a10e689a89563a29364a (patch) | |
tree | 4efdda00c1b08984a822dc35cad651e5d73cf754 | |
parent | 59836a9d2708930cbed59fd9c7e654368c035bd4 (diff) | |
download | reaction-89b70ba768f30857a6f8a10e689a89563a29364a.tar.gz reaction-89b70ba768f30857a6f8a10e689a89563a29364a.zip |
fixed Bar Controller, tons of bugs everywhere, restructured controller namespace
-rw-r--r-- | lib/ComponentUI/Controller/Root.pm | 2 | ||||
-rw-r--r-- | lib/ComponentUI/Controller/TestModel/Bar.pm | 2 | ||||
-rw-r--r-- | lib/ComponentUI/Controller/TestModel/Baz.pm | 2 | ||||
-rw-r--r-- | lib/ComponentUI/Controller/TestModel/Foo.pm | 2 | ||||
-rw-r--r-- | lib/ComponentUI/TestModel.pm | 4 | ||||
-rw-r--r-- | lib/Reaction/UI/CRUDController.pm | 169 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Collection.pm | 69 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Collection/CRUD.pm | 111 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Root.pm (renamed from lib/Reaction/UI/RootController.pm) | 6 | ||||
-rw-r--r-- | lib/Reaction/UI/ViewPort/GridView/Entity.pm | 11 | ||||
-rw-r--r-- | lib/Reaction/UI/Widget/Field/ChooseOne.pm | 2 |
11 files changed, 202 insertions, 178 deletions
diff --git a/lib/ComponentUI/Controller/Root.pm b/lib/ComponentUI/Controller/Root.pm index 567cf3b..a4d42ee 100644 --- a/lib/ComponentUI/Controller/Root.pm +++ b/lib/ComponentUI/Controller/Root.pm @@ -2,7 +2,7 @@ package ComponentUI::Controller::Root; use strict; use warnings; -use base 'Reaction::UI::RootController'; +use base 'Reaction::UI::Controller::Root'; use Reaction::Class; use aliased 'Reaction::UI::ViewPort'; diff --git a/lib/ComponentUI/Controller/TestModel/Bar.pm b/lib/ComponentUI/Controller/TestModel/Bar.pm index f3140ee..f7859b7 100644 --- a/lib/ComponentUI/Controller/TestModel/Bar.pm +++ b/lib/ComponentUI/Controller/TestModel/Bar.pm @@ -1,6 +1,6 @@ package ComponentUI::Controller::TestModel::Bar; -use base 'Reaction::UI::CRUDController'; +use base 'Reaction::UI::Controller::Collection::CRUD'; use Reaction::Class; __PACKAGE__->config( diff --git a/lib/ComponentUI/Controller/TestModel/Baz.pm b/lib/ComponentUI/Controller/TestModel/Baz.pm index a49c452..f1d7c8b 100644 --- a/lib/ComponentUI/Controller/TestModel/Baz.pm +++ b/lib/ComponentUI/Controller/TestModel/Baz.pm @@ -1,6 +1,6 @@ package ComponentUI::Controller::TestModel::Baz; -use base 'Reaction::UI::CRUDController'; +use base 'Reaction::UI::Controller::Collection::CRUD'; use Reaction::Class; __PACKAGE__->config( diff --git a/lib/ComponentUI/Controller/TestModel/Foo.pm b/lib/ComponentUI/Controller/TestModel/Foo.pm index 3477e0f..cc821c5 100644 --- a/lib/ComponentUI/Controller/TestModel/Foo.pm +++ b/lib/ComponentUI/Controller/TestModel/Foo.pm @@ -1,6 +1,6 @@ package ComponentUI::Controller::TestModel::Foo; -use base 'Reaction::UI::CRUDController'; +use base 'Reaction::UI::Controller::Collection::CRUD'; use Reaction::Class; __PACKAGE__->config( diff --git a/lib/ComponentUI/TestModel.pm b/lib/ComponentUI/TestModel.pm index 2559776..e13c31c 100644 --- a/lib/ComponentUI/TestModel.pm +++ b/lib/ComponentUI/TestModel.pm @@ -11,7 +11,9 @@ $reflector->reflect_schema ( model_class => __PACKAGE__, schema_class => 'RTest::TestDB', - sources => [qw/Foo Bar Baz/], + sources => [qw/Foo Baz/, + [ Bar => {attributes => [[-exclude => 'avatar']] } ], ## for now.... + ], ); diff --git a/lib/Reaction/UI/CRUDController.pm b/lib/Reaction/UI/CRUDController.pm deleted file mode 100644 index 47b4531..0000000 --- a/lib/Reaction/UI/CRUDController.pm +++ /dev/null @@ -1,169 +0,0 @@ -package Reaction::UI::CRUDController; - -use strict; -use warnings; -use base 'Reaction::UI::Controller'; -use Reaction::Class; - -use aliased 'Reaction::UI::ViewPort::ListView'; -use aliased 'Reaction::UI::ViewPort::ActionForm'; -use aliased 'Reaction::UI::ViewPort::ObjectView'; - -has 'model_name' => (isa => 'Str', is => 'rw', required => 1); -has 'collection_name' => (isa => 'Str', is => 'rw', required => 1); - -has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1); -has action_viewport_args => (isa => 'HashRef', is => 'rw', lazy_build => 1); - -sub _build_action_viewport_map { - return { - list => ListView, - view => ObjectView, - create => ActionForm, - update => ActionForm, - delete => ActionForm, - delete_all => ActionForm, - }; -} - -sub _build_action_viewport_args { - my $self = shift; - return { list => - { action_prototypes => - [ { label => 'Create', action => sub { - [ '', 'create', $_[1]->req->captures ] } }, - { label => 'Delete all', action => sub { - [ '', 'delete_all', $_[1]->req->captures ] } }, - ], - Entity => - { action_prototypes => - [ { label => 'View', action => sub { - [ '', 'view', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, - { label => 'Edit', action => sub { - [ '', 'update', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, - { label => 'Delete', action => sub { - [ '', 'delete', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, - ], - }, - }, - }; -} - -sub base :Action :CaptureArgs(0) { - my ($self, $c) = @_; -} - -#XXX candidate for futre optimization, should cache reader? -sub get_collection { - my ($self, $c) = @_; - my $model = $c->model( $self->model_name ); - my $attr = $model->meta->find_attribute_by_name( $self->collection_name ); - my $reader = $attr->get_read_method; - return $model->$reader; -} - -sub get_model_action { - my ($self, $c, $name, $target) = @_; - - if ($target->can('action_for')) { - return $target->action_for($name, ctx => $c); - } - - #can we please kill this already? - my $model_name = "Action::${name}".$self->model_name; - my $model = $c->model($model_name); - confess "no such Model $model_name" unless $model; - return $model->new(target_model => $target, ctx => $c); -} - - - -sub list :Chained('base') :PathPart('') :Args(0) { - my ($self, $c) = @_; - $c->forward(basic_page => { collection => $self->get_collection($c) }); -} - -sub create :Chained('base') :PathPart('create') :Args(0) { - my ($self, $c) = @_; - my $vp_args = { - next_action => 'list', - on_apply_callback => sub { $self->after_create_callback($c => @_); }, - }; - $c->forward( basic_model_action => $vp_args); -} - -sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) { - my ($self, $c) = @_; - $c->forward(basic_model_action => { next_action => 'list'}); -} - -sub after_create_callback { - my ($self, $c, $vp, $result) = @_; - return $self->redirect_to - ( $c, 'update', [ @{$c->req->captures}, $result->id ] ); -} - - - -sub object :Chained('base') :PathPart('id') :CaptureArgs(1) { - my ($self, $c, $key) = @_; - my $object :Stashed = $self->get_collection($c)->find($key); - confess "Object? what object?" unless $object; # should be a 404. -} - -sub update :Chained('object') :Args(0) { - my ($self, $c) = @_; - #this needs a better solution. currently thinking about it - my @cap = @{$c->req->captures}; - pop(@cap); # object id - my $vp_args = { next_action => [ $self, 'redirect_to', 'list', \@cap ]}; - $c->forward(basic_model_action => $vp_args); -} - -sub delete :Chained('object') :Args(0) { - my ($self, $c) = @_; - #this needs a better solution. currently thinking about it - my @cap = @{$c->req->captures}; - pop(@cap); # object id - my $vp_args = { next_action => [ $self, 'redirect_to', 'list', \@cap ]}; - $c->forward(basic_model_action => $vp_args); -} - -sub view :Chained('object') :Args(0) { - my ($self, $c) = @_; - my $object :Stashed; - $c->forward(basic_page => {object => $object}); -} - - - - -sub basic_model_action :Private { - my ($self, $c, $vp_args) = @_; - - my $target = exists $c->stash->{object} ? - $c->stash->{object} : $self->get_collection($c); - - my $cat_action_name = $c->stack->[-2]->name; - my $im_action_name = join('', (map{ uc } split('_', $cat_action_name))); - return $self->push_viewport - ( - $self->action_viewport_map->{$cat_action_name}, - action => $self->get_model_action($c, $im_action_name, $target), - %{ $vp_args || {} }, - %{ $self->action_viewport_args->{$cat_action_name} || {} }, - ); -} - -sub basic_page : Private { - my ($self, $c, $vp_args) = @_; - my $action_name = $c->stack->[-2]->name; - return $self->push_viewport - ( - $self->action_viewport_map->{$action_name}, - %{ $vp_args || {} }, - %{ $self->action_viewport_args->{$action_name} || {} }, - ); -} - -1; diff --git a/lib/Reaction/UI/Controller/Collection.pm b/lib/Reaction/UI/Controller/Collection.pm new file mode 100644 index 0000000..d7d727b --- /dev/null +++ b/lib/Reaction/UI/Controller/Collection.pm @@ -0,0 +1,69 @@ +package Reaction::UI::Controller::Collection; + +use strict; +use warnings; +use base 'Reaction::UI::Controller'; +use Reaction::Class; + +use aliased 'Reaction::UI::ViewPort::ListView'; +use aliased 'Reaction::UI::ViewPort::ObjectView'; + +has 'model_name' => (isa => 'Str', is => 'rw', required => 1); +has 'collection_name' => (isa => 'Str', is => 'rw', required => 1); + +has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1); +has action_viewport_args => (isa => 'HashRef', is => 'rw', lazy_build => 1); + +sub _build_action_viewport_map { + return { + list => ListView, + view => ObjectView, + }; +} + +sub _build_action_viewport_args { + return { }; +} + +sub base :Action :CaptureArgs(0) { + my ($self, $c) = @_; +} + +#XXX candidate for futre optimization, should cache reader? +sub get_collection { + my ($self, $c) = @_; + my $model = $c->model( $self->model_name ); + my $attr = $model->meta->find_attribute_by_name( $self->collection_name ); + my $reader = $attr->get_read_method; + return $model->$reader; +} + +sub list :Chained('base') :PathPart('') :Args(0) { + my ($self, $c) = @_; + $c->forward(basic_page => [{ collection => $self->get_collection($c) }]); +} + +sub object :Chained('base') :PathPart('id') :CaptureArgs(1) { + my ($self, $c, $key) = @_; + my $object :Stashed = $self->get_collection($c)->find($key); + confess "Object? what object?" unless $object; # should be a 404. +} + +sub view :Chained('object') :Args(0) { + my ($self, $c) = @_; + my $object :Stashed; + $c->forward(basic_page => [{object => $object}]); +} + +sub basic_page : Private { + my ($self, $c, $vp_args) = @_; + my $action_name = $c->stack->[-2]->name; + return $self->push_viewport + ( + $self->action_viewport_map->{$action_name}, + %{ $vp_args || {} }, + %{ $self->action_viewport_args->{$action_name} || {} }, + ); +} + +1; diff --git a/lib/Reaction/UI/Controller/Collection/CRUD.pm b/lib/Reaction/UI/Controller/Collection/CRUD.pm new file mode 100644 index 0000000..8a2dcd0 --- /dev/null +++ b/lib/Reaction/UI/Controller/Collection/CRUD.pm @@ -0,0 +1,111 @@ +package Reaction::UI::Controller::Collection::CRUD; + +use strict; +use warnings; +use base 'Reaction::UI::Controller::Collection'; +use Reaction::Class; + +use aliased 'Reaction::UI::ViewPort::ActionForm'; + +sub _build_action_viewport_map { + my $map = shift->next::method(@_); + map{ $map->{$_} = ActionForm } qw/create update delete delete_all/; + return $map; +} + +sub _build_action_viewport_args { + my $args = shift->next::method(@_); + $args->{list} = + { action_prototypes => + [ { label => 'Create', action => sub { + [ '', 'create', $_[1]->req->captures ] } }, + { label => 'Delete all', action => sub { + [ '', 'delete_all', $_[1]->req->captures ] } }, + ], + Entity => + { action_prototypes => + [ { label => 'View', action => sub { + [ '', 'view', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, + { label => 'Edit', action => sub { + [ '', 'update', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, + { label => 'Delete', action => sub { + [ '', 'delete', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, + ], + }, + }; + return $args; +} + +sub get_model_action { + my ($self, $c, $name, $target) = @_; + + if ($target->can('action_for')) { + return $target->action_for($name, ctx => $c); + } + + #can we please kill this already? + my $model_name = "Action::${name}".$self->model_name; + my $model = $c->model($model_name); + confess "no such Model $model_name" unless $model; + return $model->new(target_model => $target, ctx => $c); +} + +sub create :Chained('base') :PathPart('create') :Args(0) { + my ($self, $c) = @_; + my $vp_args = { + next_action => 'list', + on_apply_callback => sub { $self->after_create_callback($c => @_); }, + }; + $c->forward( basic_model_action => [$vp_args]); +} + +sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) { + my ($self, $c) = @_; + $c->forward(basic_model_action => [{ next_action => 'list'}]); +} + +sub after_create_callback { + my ($self, $c, $vp, $result) = @_; + return $self->redirect_to + ( $c, 'update', [ @{$c->req->captures}, $result->id ] ); +} + +sub update :Chained('object') :Args(0) { + my ($self, $c) = @_; + #this needs a better solution. currently thinking about it + my @cap = @{$c->req->captures}; + pop(@cap); # object id + my $vp_args = { next_action => [ $self, 'redirect_to', 'list', \@cap ]}; + $c->forward(basic_model_action => [$vp_args]); +} + +sub delete :Chained('object') :Args(0) { + my ($self, $c) = @_; + #this needs a better solution. currently thinking about it + my @cap = @{$c->req->captures}; + pop(@cap); # object id + my $vp_args = { next_action => [ $self, 'redirect_to', 'list', \@cap ]}; + $c->forward(basic_model_action => [$vp_args]); +} + +sub basic_model_action :Private { + my ($self, $c, $vp_args) = @_; + + my $target = exists $c->stash->{object} ? + $c->stash->{object} : $self->get_collection($c); + + my $cat_action_name = $c->stack->[-2]->name; + my $im_action_name = join('', (map{ ucfirst } split('_', $cat_action_name))); + $c->log->debug($cat_action_name); + $c->log->debug($self->action_viewport_map->{$cat_action_name}); + $c->log->debug(keys %{$self->action_viewport_map}); + return $self->push_viewport + ( + $self->action_viewport_map->{$cat_action_name}, + action => $self->get_model_action($c, $im_action_name, $target), + %{ $vp_args || {} }, + %{ $self->action_viewport_args->{$cat_action_name} || {} }, + ); +} + +1; diff --git a/lib/Reaction/UI/RootController.pm b/lib/Reaction/UI/Controller/Root.pm index 89f1a0f..2760ec8 100644 --- a/lib/Reaction/UI/RootController.pm +++ b/lib/Reaction/UI/Controller/Root.pm @@ -1,4 +1,4 @@ -package Reaction::UI::RootController; +package Reaction::UI::Controller::Root; use base qw/Reaction::UI::Controller/; use Reaction::Class; @@ -33,12 +33,12 @@ sub end :Private { =head1 NAME -Reaction::UI::RootController - Base component for the Root Controller +Reaction::UI::Root - Base component for the Root Controller =head1 SYNOPSIS package MyApp::Controller::Root; - use base 'Reaction::UI::RootController'; + use base 'Reaction::UI::COntroller::Root'; # Create UI elements: $c->stash->{focus_stack}->push_viewport('Reaction::UI::ViewPort'); diff --git a/lib/Reaction/UI/ViewPort/GridView/Entity.pm b/lib/Reaction/UI/ViewPort/GridView/Entity.pm index 3011f7f..98a55f5 100644 --- a/lib/Reaction/UI/ViewPort/GridView/Entity.pm +++ b/lib/Reaction/UI/ViewPort/GridView/Entity.pm @@ -173,6 +173,17 @@ class Entity is 'Reaction::UI::ViewPort', which { ); return $self->_build_simple_field(String, $obj, $attr, $args); }; + + implements _build_fields_for_type_Reaction_InterfaceModel_Object => as { + my ($self, $obj, $attr, $args) = @_; + $args->{Field}{$attr->name}{layout} = 'value/string' + unless( exists $args->{Field}{$attr->name} && + exists $args->{Field}{$attr->name}{layout} && + defined $args->{Field}{$attr->name}{layout} + ); + return $self->_build_simple_field(RelatedObject, $obj, $attr, $args); + }; + }; 1; diff --git a/lib/Reaction/UI/Widget/Field/ChooseOne.pm b/lib/Reaction/UI/Widget/Field/ChooseOne.pm index 9754e71..280c9f3 100644 --- a/lib/Reaction/UI/Widget/Field/ChooseOne.pm +++ b/lib/Reaction/UI/Widget/Field/ChooseOne.pm @@ -5,7 +5,7 @@ use Reaction::UI::WidgetClass; class ChooseOne is 'Reaction::UI::Widget::Field', which { field renders [ option over func('viewport', 'value_choices') ], - { is_required => sub{ $_{viewport}->attribute->required } }; + { is_required => sub{ $_{viewport}->attribute->is_required } }; option renders [string {"DUMMY"}], { |