[Catalyst-commits] r12442 - in Catalyst-Controller-DBIC-API/1.003: . branches/moosify-validation-configurability branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API branches/moosify-validation-configurability/t/rest

nperez at dev.catalyst.perl.org nperez at dev.catalyst.perl.org
Mon Dec 21 13:32:45 GMT 2009


Author: nperez
Date: 2009-12-21 13:32:44 +0000 (Mon, 21 Dec 2009)
New Revision: 12442

Added:
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Types.pm
Modified:
   Catalyst-Controller-DBIC-API/1.003/
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/Changes
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Base.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/REST.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/RPC.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Request.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/RequestArguments.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/StaticArguments.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/StoredResultSource.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Validator.pm
   Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/t/rest/list.t
Log:
 r5162 at nicklaptop:  nicholas | 2009-12-21 07:30:55 -0600
 Convert DBIC::API::Request into a role and apply it to ->req, move types out into their own package, update the docs and explain new features, bump version to 1.004, correct small problem with setup_list_method, only one begin method in Base instead



Property changes on: Catalyst-Controller-DBIC-API/1.003
___________________________________________________________________
Name: svk:merge
   - 4ad37cd2-5fec-0310-835f-b3785c72a374:/Catalyst-Controller-DBIC-API/1.001:9528
4ad37cd2-5fec-0310-835f-b3785c72a374:/Catalyst-Controller-DBIC-API/1.002:9762
992f488a-d630-404b-95f9-f7d0fdf28443:/local/ccda:4264
   + 4ad37cd2-5fec-0310-835f-b3785c72a374:/Catalyst-Controller-DBIC-API/1.001:9528
4ad37cd2-5fec-0310-835f-b3785c72a374:/Catalyst-Controller-DBIC-API/1.002:9762
992f488a-d630-404b-95f9-f7d0fdf28443:/local/ccda:5162

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/Changes
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/Changes	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/Changes	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,5 +1,13 @@
 Revision history for Catalyst-Controller-DBIC-API
 
+1.004000
+- Moosify
+- Move validation for *_exposes/*_allows to Data::DPath::Validator
+- Reorganize internals to use Moose and roles
+- Allow maximum configuration for what request parameters are named
+- Properly handle JSON boolean values
+- Earlier and more consistent validation of configuration and request parameters
+
 1.003004
 - Database errors are also handled for searches + tests
 - totalcount isn't included in the response if a db error occurs while fetching data

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Base.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Base.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Base.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,15 +1,18 @@
 package		# hide from PAUSE
 	Catalyst::Controller::DBIC::API::Base;
+our $VERSION = '1.004000';
 
 use Moose;
 
+
 BEGIN { extends 'Catalyst::Controller'; }
 use CGI::Expand ();
 use DBIx::Class::ResultClass::HashRefInflator;
 use JSON::Any;
-use Test::Deep::NoTest ();
+use Test::Deep::NoTest('eq_deeply');
 use MooseX::Types::Moose(':all');
 use MooseX::Aliases;
+use Moose::Util;
 use Try::Tiny;
 use Catalyst::Controller::DBIC::API::Request;
 use namespace::autoclean;
@@ -22,10 +25,17 @@
 has 'object_stash_key' => ( is => 'ro', isa => Str, default => 'object' );
 has 'setup_list_method' => ( is => 'ro', isa => Str, predicate => 'has_setup_list_method');
 has 'setup_dbic_args_method' => ( is => 'ro', isa => Str, predicate => 'has_setup_dbic_args_method');
-has 'active_request' => ( is => 'rw', isa => 'Catalyst::Controller::DBIC::API::Request' );
 
 __PACKAGE__->config();
 
+sub begin :Private {
+    my ($self, $c) = @_;
+    
+    Catalyst::Controller::DBIC::API::Request->meta->apply($c->req)
+        unless Moose::Util::does_role($c->req, 'Catalyst::Controller::DBIC::API::Request');
+    $c->forward('deserialize');
+}
+
 sub setup :Chained('specify.in.subclass.config') :CaptureArgs(0) :PathPart('specify.in.subclass.config') {
 	my ($self, $c) = @_;
 
@@ -43,10 +53,12 @@
 		$req_params = CGI::Expand->expand_hash($c->req->params);
 		foreach my $param (@{[$self->search_arg, $self->count_arg, $self->page_arg, $self->ordered_by_arg, $self->grouped_by_arg, $self->prefetch_arg]}) {
 			# these params can also be composed of JSON
-			eval {
+			try 
+            {
 				my $deserialized = JSON::Any->from_json($req_params->{$param});
 				$req_params->{$param} = $deserialized;
-			};
+			}
+            catch { $c->log->debug("Param '$param' did not deserialize appropriately: $_") if $c->debug }
 		}
 	}
     
@@ -62,24 +74,21 @@
 
     try
     {
-        my $req = Catalyst::Controller::DBIC::API::Request->new
-        (
-            application => $self, 
-            prefetch_allows => $self->prefetch_allows,
-            search_exposes => $self->search_exposes,
-            select_exposes => $self->select_exposes,
-            data => $req_params->{data},
-        );
-        
-        $req->_set_prefetch($req_params->{$self->prefetch_arg});
-        $req->_set_select($req_params->{$self->select_arg});
-        $req->_set_grouped_by($req_params->{$self->grouped_by_arg});
-        $req->_set_ordered_by($req_params->{$self->ordered_by_arg});
-        $req->_set_search($req_params->{$self->search_arg}) if exists $req_params->{$self->search_arg};
-        $req->_set_count($req_params->{$self->count_arg}) if exists $req_params->{$self->count_arg};
-        $req->_set_page($req_params->{$self->page_arg}) if exists $req_params->{$self->page_arg};
+        # set static arguments
+        $c->req->_set_application($self); 
+        $c->req->_set_prefetch_allows($self->prefetch_allows);
+        $c->req->_set_search_exposes($self->search_exposes);
+        $c->req->_set_select_exposes($self->select_exposes);
+        $c->req->_set_request_data($req_params->{data});
 
-        $self->active_request($req);
+        # set request arguments
+        $c->req->_set_prefetch($req_params->{$self->prefetch_arg}) if exists $req_params->{$self->prefetch_arg};
+        $c->req->_set_select($req_params->{$self->select_arg}) if exists $req_params->{$self->select_arg};
+        $c->req->_set_grouped_by($req_params->{$self->grouped_by_arg}) if exists $req_params->{$self->grouped_by_arg};
+        $c->req->_set_ordered_by($req_params->{$self->ordered_by_arg}) if exists $req_params->{$self->ordered_by_arg};
+        $c->req->_set_search($req_params->{$self->search_arg}) if exists $req_params->{$self->search_arg};
+        $c->req->_set_count($req_params->{$self->count_arg}) if exists $req_params->{$self->count_arg};
+        $c->req->_set_page($req_params->{$self->page_arg}) if exists $req_params->{$self->page_arg};
     }
     catch
     {
@@ -98,31 +107,43 @@
     
 	$c->stash->{$self->rs_stash_key} = $c->stash->{$self->rs_stash_key}->search($params, $args);
     # add the total count of all rows in case of a paged resultset
-    eval {
+    try 
+    {
         $c->stash->{_dbic_api}->{totalcount} = $c->stash->{$self->rs_stash_key}->pager->total_entries
             if $args->{page};
-    };
-    if ($@) {
-        $c->log->error($@);
+        $c->forward('format_list');
+    }
+    catch
+    {
+        $c->log->error($_);
         # send a generic error to the client to not give out infos about
         # the database schema
         $self->push_error($c, { message => 'a database error has occured.' });
     }
-    else {
-        $c->forward('format_list');
-    }
 }
 
 sub generate_dbic_search_args :Private {
 	my ($self, $c) = @_;
   
 	my $args = {};
-    my $req = $self->active_request();
+    my $req = $c->req;
+    my $pre_format_params;
 
 	if ( my $action_name = $self->setup_list_method ) {
 		my $setup_action = $self->action_for($action_name);
 		if ( defined $setup_action ) {
-			$c->forward("/$setup_action", [ $req->data, $req ]);
+			$c->forward("/$setup_action", [ $req->request_data, $req ]);
+            if(exists($req->request_data->{$self->search_arg}))
+            {
+                if(!$req->has_search)
+                {
+                    $req->_set_search($req->request_data->{$self->search_arg});
+                }
+                elsif(!eq_deeply($req->has_search, $req->request_data->{$self->search_arg}))
+                {
+                    $req->_set_search($req->request_data->{$self->search_arg});
+                }
+            }
 		} else {
 			$c->log->error("setup_list_method was configured, but action $action_name not found");
 		}
@@ -220,16 +241,9 @@
 	# it still is what they expect (and not inflating to a hash ref)
 	my $rs = $c->stash->{$self->rs_stash_key}->search;
 	$rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
-    eval {
+    try
+    {
 	    $c->stash->{response}->{$self->data_root} = [ $rs->all ];
-    };
-    if ($@) {
-        $c->log->error($@);
-        # send a generic error to the client to not give out infos about
-        # the database schema
-        $self->push_error($c, { message => 'a database error has occured.' });
-    }
-    else {
         # only add the totalcount to the response if also data is returned
         if (my $totalcount = $c->stash->{_dbic_api}->{totalcount}) {
             # numify which is important for JSON
@@ -237,6 +251,13 @@
             $c->stash->{response}->{totalcount} = $totalcount;
         }
     }
+    catch
+    {
+        $c->log->error($_);
+        # send a generic error to the client to not give out infos about
+        # the database schema
+        $self->push_error($c, { message => 'a database error has occured.' });
+    }
 }
 
 sub create :Private {
@@ -299,7 +320,7 @@
 
 sub validate {
 	my ($self, $c, $object) = @_;
-	my $params = $self->active_request->data();
+	my $params = $c->req->request_data();
 
 	my %values;
 	my %requires_map = map { $_ => 1 } @{($object->in_storage) ? [] : $c->stash->{create_requires} || $self->create_requires};
@@ -357,7 +378,8 @@
 sub save_object {
 	my ($self, $c, $object, $params) = @_;
 
-    eval {
+    try
+    {
     	if ($object->in_storage) {
     		foreach my $key (keys %{$params}) {
                 my $value = $params->{$key};
@@ -372,15 +394,16 @@
     		$object->set_columns($params);
     		$object->insert;
     	}
-    };
-    if ($@) {
+    }
+    catch
+    {
         $c->log->error($@);
         # send a generic error to the client to not give out infos about
         # the database schema
         $self->push_error($c, { message => 'a database error has occured.' });
-    }
-
-	return $object;
+    };
+    
+    return $object;
 }
 
 sub end :Private {
@@ -430,6 +453,10 @@
 
 Luke Saunders <luke.saunders at gmail.com>
 
+=head1 LICENSE
+
+You may distribute this code under the same terms as Perl itself.
+
 =cut
 
 1;

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/REST.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/REST.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/REST.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,5 +1,5 @@
 package Catalyst::Controller::DBIC::API::REST;
-
+our $VERSION = '1.004000';
 use Moose;
 BEGIN { extends 'Catalyst::Controller::DBIC::API::Base'; }
 
@@ -73,12 +73,6 @@
 
 =cut 
 
-sub begin :Private {
-	my ($self, $c) = @_;
-
-	$c->forward('deserialize');
-}
-
 sub object :Chained('setup') :Args(1) :PathPart('') :ActionClass('REST') {
 	my ($self, $c, $id) = @_;
 

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/RPC.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/RPC.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/RPC.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,5 +1,5 @@
 package Catalyst::Controller::DBIC::API::RPC;
-
+our $VERSION = '1.004000';
 use Moose;
 BEGIN { extends 'Catalyst::Controller::DBIC::API::Base'; }
 
@@ -84,14 +84,6 @@
 
 =cut 
 
-sub begin :Private {
-	my ($self, $c) = @_;
-
-	$c->forward('deserialize');
-    return if $self->get_errors($c);
-	$c->req->params($self->active_request->data);
-}
-
 sub object :Chained('setup') :CaptureArgs(1) :PathPart('id') {
 	my ($self, $c, $id) = @_;
 

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Request.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Request.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Request.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,14 +1,19 @@
 package Catalyst::Controller::DBIC::API::Request;
-use Moose;
+our $VERSION = '1.004000';
+use Moose::Role;
 use MooseX::Aliases;
-use MooseX::Types::Moose(':all');
+use MooseX::Types::Moose('Object');
 use namespace::autoclean;
 
+### XXX Stupid hack to make role attribute handles work
+sub check_has_relation { }
+sub check_column_relation { }
+
 has 'application' =>
 (
     is => 'ro',
+    writer => '_set_application',
     isa => Object,
-    required => 1,
     handles => 'Catalyst::Controller::DBIC::API::StoredResultSource',
 );
 

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/RequestArguments.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/RequestArguments.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/RequestArguments.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,6 +1,7 @@
 package Catalyst::Controller::DBIC::API::RequestArguments;
+our $VERSION = '1.004000';
 use MooseX::Role::Parameterized;
-use Moose::Util::TypeConstraints;
+use Catalyst::Controller::DBIC::API::Types(':all');
 use MooseX::Types::Moose(':all');
 use Data::Dumper;
 use namespace::autoclean;
@@ -51,14 +52,11 @@
         alias => 'list_page'
     );
 
-    subtype 'OrderedBy' => as Maybe[ArrayRef[Str|HashRef|ScalarRef]];
-    coerce 'OrderedBy' => from Str, via { [$_] };
-
     has 'ordered_by' =>
     (
         is => 'ro',
         writer => '_set_ordered_by',
-        isa => 'OrderedBy',
+        isa => OrderedBy,
         predicate => 'has_ordered_by',
         traits => ['Aliased'],
         coerce => 1,
@@ -66,14 +64,11 @@
         alias => 'list_ordered_by',
     );
 
-    subtype 'GroupedBy' => as Maybe[ArrayRef[Str]];
-    coerce 'GroupedBy' => from Str, via { [$_] };
-    
     has 'grouped_by' =>
     (
         is => 'ro',
         writer => '_set_grouped_by',
-        isa => 'GroupedBy',
+        isa => GroupedBy,
         predicate => 'has_grouped_by',
         traits => ['Aliased'],
         coerce => 1,
@@ -81,16 +76,11 @@
         alias => 'list_grouped_by',
     );
 
-    subtype 'Prefetch' => as Maybe[ArrayRef[Str|HashRef]];
-    coerce 'Prefetch' => 
-        from Str, via { [$_] },
-        from HashRef, via { [$_] };
-    
     has prefetch =>
     (
         is => 'ro',
         writer => '_set_prefetch',
-        isa => 'Prefetch', 
+        isa => Prefetch, 
         default => sub { $p->static ? [] : undef },
         coerce => 1,
         trigger => sub
@@ -125,6 +115,7 @@
     has prefetch_allows =>
     (
         is => 'ro',
+        writer => '_set_prefetch_allows',
         isa => ArrayRef[ArrayRef|Str|HashRef], 
         default => sub { [ ] },
         predicate => 'has_prefetch_allows',
@@ -160,6 +151,7 @@
     has 'search_exposes' =>
     (
         is => 'ro',
+        writer => '_set_search_exposes',
         isa => ArrayRef[Str|HashRef],
         predicate => 'has_search_exposes',
         traits => ['Aliased'],
@@ -186,7 +178,6 @@
             {
                 while( my ($k, $v) = each %$new)
                 {
-                    $DB::single = 1 if $k eq 'cd';
                     local $Data::Dumper::Terse = 1;
                     die qq|{ $k => ${\Dumper($v)} } is not an allowed search term in: ${\join("\n", @{$self->search_validator->templates})}|
                         unless $self->search_validator->validate({$k=>$v})->[0];
@@ -205,6 +196,7 @@
     has 'select_exposes' =>
     (
         is => 'ro',
+        writer => '_set_select_exposes',
         isa => ArrayRef[Str|HashRef],
         predicate => 'has_select_exposes',
         default => sub { [ ] },
@@ -217,14 +209,11 @@
         },
     );
 
-    subtype 'SelectColumns' => as Maybe[ArrayRef[Str|HashRef]];
-    coerce 'SelectColumns' => from Str, via { [$_] };
-    
     has select =>
     (
         is => 'ro',
         writer => '_set_select',
-        isa => 'SelectColumns',
+        isa => SelectColumns,
         default => sub { $p->static ? [] : undef },
         traits => ['Aliased'],
         alias => 'list_returns',
@@ -247,9 +236,10 @@
         },
     );
 
-    has 'data' =>
+    has 'request_data' =>
     (
         is => 'ro',
+        writer => '_set_request_data',
         isa => HashRef,
     );
 };

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/StaticArguments.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/StaticArguments.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/StaticArguments.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,4 +1,5 @@
 package Catalyst::Controller::DBIC::API::StaticArguments;
+our $VERSION = '1.004000';
 use Moose::Role;
 use MooseX::Types::Moose(':all');
 use namespace::autoclean;

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/StoredResultSource.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/StoredResultSource.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/StoredResultSource.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,4 +1,5 @@
 package Catalyst::Controller::DBIC::API::StoredResultSource;
+our $VERSION = '1.004000';
 use Moose::Role;
 use Moose::Util::TypeConstraints;
 use MooseX::Types::Moose(':all');

Added: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Types.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Types.pm	                        (rev 0)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Types.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -0,0 +1,22 @@
+package Catalyst::Controller::DBIC::API::Types;
+our $VERSION = '1.004000';
+
+use warnings;
+use strict;
+
+use MooseX::Types -declare => [qw/OrderedBy GroupedBy Prefetch SelectColumns/];
+use MooseX::Types::Moose(':all');
+
+subtype Prefetch, as Maybe[ArrayRef[Str|HashRef]];
+coerce Prefetch, from Str, via { [$_] }, from HashRef, via { [$_] };
+
+subtype GroupedBy, as Maybe[ArrayRef[Str]];
+coerce GroupedBy, from Str, via { [$_] };
+
+subtype OrderedBy, as Maybe[ArrayRef[Str|HashRef|ScalarRef]];
+coerce OrderedBy, from Str, via { [$_] };
+
+subtype SelectColumns, as Maybe[ArrayRef[Str|HashRef]];
+coerce SelectColumns, from Str, via { [$_] };
+
+1;

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Validator.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Validator.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API/Validator.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -1,4 +1,5 @@
 package Catalyst::Controller::DBIC::API::Visitor;
+our $VERSION = '1.004000';
 use Moose;
 use namespace::autoclean;
 
@@ -92,6 +93,7 @@
 Catalyst::Controller::DBIC::API::Visitor->meta->make_immutable;
 
 package Catalyst::Controller::DBIC::API::Validator;
+our $VERSION = '1.004000';
 use Moose;
 use namespace::autoclean;
 

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API.pm
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API.pm	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/lib/Catalyst/Controller/DBIC/API.pm	2009-12-21 13:32:44 UTC (rev 12442)
@@ -5,11 +5,11 @@
 
 =head1 VERSION
 
-Version 1.003004
+Version 1.004
 
 =cut
 
-our $VERSION = '1.003004';
+our $VERSION = '1.004000';
 
 =head1 NAME
 
@@ -27,16 +27,19 @@
       create_allows => ['nickname'], # additional non-required columns that create allows
       update_allows => ['name', 'age', 'nickname'], # columns that update allows
       update_allows => ['name', 'age', 'nickname'], # columns that update allows
-      list_returns => [qw/name age/], # columns that list returns
-      list_prefetch => ['cds'], # relationships that are prefetched when no prefetch param is passed
-      list_prefetch_allows => [ # every possible prefetch param allowed
+      select => [qw/name age/], # columns that data returns
+      prefetch => ['cds'], # relationships that are prefetched when no prefetch param is passed
+      prefetch_allows => [ # every possible prefetch param allowed
           'cds',
           qw/ cds /,
           { cds => 'tracks' },
           { cds => [qw/ tracks /] }
       ],
-      list_ordered_by => [qw/age/], # order of generated list
-      list_search_exposes => [qw/age nickname/, { cds => [qw/title year/] }], # columns that can be searched on via list
+      ordered_by => [qw/age/], # order of generated list
+      search_exposes => [qw/age nickname/, { cds => [qw/title year/] }], # columns that can be searched on via list
+      data_root => 'data' # defaults to "list" for backwards compatibility
+      use_json_boolean => 1, # use JSON::Any::true|false in the response instead of strings
+      return_object => 1, # makes create and update actions return the object
       );
 
   # Provides the following functional endpoints:
@@ -86,6 +89,18 @@
 
 Whatever you would pass to $c->model to get a resultset for this class. MyAppDB::Track for example.
 
+head2 data_root
+
+By default, the response data is serialized into $c->stash->{response}->{$self->data_root} and data_root defaults to 'list' to preserve backwards compatibility. This is now configuable to meet the needs of the consuming client.
+
+head2 use_json_boolean
+
+By default, the response success status is set to a string value of "true" or "false". If this attribute is true, JSON::Any's true() and false() will be used instead. Note, this does not effect other internal processing of boolean values.
+
+head2 count_arg, page_arg, select_arg, search_arg, grouped_by_arg, ordered_by_arg, prefetch_arg
+
+These attributes allow customization of the component to understand requests made by clients where these argument names are not flexible and cannot conform to this components defaults.
+
 =head2 create_requires
 
 Arrayref listing columns required to be passed to create in order for the request to be valid.
@@ -98,15 +113,19 @@
 
 Arrayref listing columns that update will allow. Columns passed to update that are not listed here will be ignored.
 
-=head2 list_returns
+=head2 select
 
 Arguments to pass to L<DBIx::Class::ResultSet/select> when performing search for L</list>.
 
-=head2 list_prefetch
+=head2 select_exposes
 
+Columns and related columns that are okay to return in the resultset since clients can request more or less information specified than the above select argument.
+
+=head2 prefetch
+
 Arguments to pass to L<DBIx::Class::ResultSet/prefetch> when performing search for L</list>.
 
-=head2 list_prefetch_allows
+=head2 prefetch_allows
 
 Arrayref listing relationships that are allowed to be prefetched.
 This is necessary to avoid denial of service attacks in form of
@@ -116,21 +135,20 @@
 So for three searches, all requiring different prefetch parameters,
 three elements have to be passed to list_prefetch_allows in the controller.
 
-=head2 list_grouped_by
+=head2 grouped_by
 
 Arguments to pass to L<DBIx::Class::ResultSet/group_by> when performing search for L</list>.
 
-=head2 list_ordered_by
+=head2 ordered_by
 
 Arguments to pass to L<DBIx::Class::ResultSet/order_by> when performing search for L</list>.
 
-=head2 list_search_exposes
+=head2 search_exposes
 
 Columns and related columns that are okay to search on. For example if only the position column and all cd columns were to be allowed
 
- list_search_exposes => [qw/position/, { cd => ['*'] }]
+ search_exposes => [qw/position/, { cd => ['*'] }]
 
-
 You can also use this to allow custom columns should you wish to allow them through in order to be caught by a custom resultset. For example:
 
   package RestTest::Controller::API::RPC::TrackExposed;
@@ -159,11 +177,11 @@
     my $rs = $self->SUPER::search(@_);
   }
 
-=head2 list_count
+=head2 count
 
 Arguments to pass to L<DBIx::Class::ResultSet/rows> when performing search for L</list>.
 
-=head2 list_page
+=head2 page
 
 Arguments to pass to L<DBIx::Class::ResultSet/rows> when performing search for L</list>.
 
@@ -216,6 +234,10 @@
 
 Note: see the individual interface classes - L<Catalyst::Controller::DBIC::API::RPC> and L<Catalyst::Controller::DBIC::API::REST> - for details of the endpoints to these abstract methods.
 
+=head2 begin
+
+A begin method is provided to apply the L<Catalyst::Controller::DBIC::API::Request> role to $c->request, and perform deserialization and validation of request parameters
+
 =head2 setup
 
 This action is the chain root of the controller. It must either be overridden or configured to provide a base pathpart to the action and also a parent action. For example, for class MyAppDB::Track you might have
@@ -246,11 +268,11 @@
 
 List level action chained from L</setup>. Checks $c->req->params for each column specified in the L</create_requires> and L</create_allows> parameters of the controller config. If all of the required columns are present then the object is created.
 
-Does not populate the response with any additional information.
+Does not populate the response with any additional information unless the return_object option is set to true, then the created object will be serialized within $c->stash->{response}->{$self->data_root}.
 
 =head2 list
 
-List level action chained from L</setup>. By default populates $c->stash->{response}->{list} with a list of hashrefs representing each object in the class resultset. If the L</list_returns> config param is defined then the hashes will contain only those columns, otherwise all columns in the object will be returned. Similarly L</list_count>, L</list_page>, L</list_grouped_by> and L</list_ordered_by> affect the maximum number of rows returned as well as the ordering and grouping. Note that if list_returns, list_count, list_ordered_by or list_grouped_by request parameters are present then these will override the values set on the class.
+List level action chained from L</setup>. By default populates $c->stash->{response}->{$self->data_root} with a list of hashrefs representing each object in the class resultset. If the L</select> config param is defined then the hashes will contain only those columns, otherwise all columns in the object will be returned. Similarly L</count>, L</page>, L</grouped_by> and L</ordered_by> affect the maximum number of rows returned as well as the ordering and grouping. Note that if select, count, ordered_by or grouped_by request parameters are present then these will override the values set on the class with select becoming bound by the select_exposes attribute.
 
 If not all objects in the resultset are required then it's possible to pass conditions to the method as request parameters. You can use a JSON string as the 'search' parameter for maximum flexibility or use L</CGI::Expand> syntax. In the second case the request parameters are expanded into a structure and then $c->req->params->{search} is used as the search condition.
 
@@ -266,7 +288,7 @@
 
 Note that if pagination is needed, this can be achieved using a combination of the L</list_count> and L</list_page> parameters. For example:
 
-  ?list_page=2&list_count=20
+  ?page=2&count=20
 
 Would result in this search:
  
@@ -276,13 +298,13 @@
 
 =head2 format_list
 
-Used by L</list> to populate response based on class resultset. By default populates $c->stash->{response}->{list} with a list of hashrefs representing each object in the resultset. Can be overidden to format the list as required.
+Used by L</list> to populate response based on class resultset. By default populates $c->stash->{response}->{$self->data_root} with a list of hashrefs representing each object in the resultset. Can be overidden to format the list as required.
 
 =head2 update
 
 Object level action chained from L</object>. Checks $c->req->params for each column specified in the L</update_allows> parameter of the controller config. If any of these columns are found in $c->req->params then the object set by L</object> is updated with those columns.
 
-Does not populate the response with any additional information.
+Does not populate the response with any additional information uness the return_object option is set to true, then the updated object will be serialized within $c->stash->{response}->{$self->data_root}.
 
 =head2 delete
 
@@ -292,17 +314,20 @@
 
 =head2 end
 
-If the request was successful then $c->stash->{response}->{success} is set to 1, if not then it is set to 0 and $c->stash->{response}->{messages} set to an arrayref containing all error messages.
+$c->stash->{response}->{success} is set to 'true' or 'false' (or their respective JSON::Any values for true and false) regarding the success of the request. If the request failed, $c->stash->{response}->{messages} is set to an arrayref containing all error messages.
 
 Then the contents of $c->stash->{response} are serialized using L<Catalyst::Action::Serialize>.
 
 =head1 EXTENDING
 
-By default the create, delete and update actions will not return anything apart from the success parameter set in L</end>, often this is not ideal but the required behaviour varies from application to application. So normally it's sensible to write an intermediate class which your main controller classes subclass from. For example if you wanted create to return the JSON for the newly created object you might have something like:
+By default the create, delete and update actions will not return anything apart from the success parameter set in L</end>, often this is not ideal but the required behaviour varies from application to application. So normally it's sensible to write an intermediate class which your main controller classes subclass from.
 
+For example if you wanted create to return the JSON for the newly created object you might have something like:
+
   package MyApp::ControllerBase::DBIC::API::RPC;
   ...
-  use base qw/Catalyst::Controller::DBIC::API::RPC/;
+  use Moose;
+  BEGIN { extends 'Catalyst::Controller::DBIC::API::RPC' };
   ...
   sub create :Chained('setup') :Args(0) :PathPart('create') {
     my ($self, $c) = @_;
@@ -319,19 +344,36 @@
 
   package MyApp::Controller::API::RPC::Track;
   ...
-  use base qw/MyApp::ControllerBase::DBIC::API::RPC/;
+  use Moose;
+  BEGIN { extends 'MyApp::ControllerBase::DBIC::API::RPC' };
   ...
 
-If you were using the RPC style. For REST the only difference besides the class names would be that create should be :Private rather than an endpoint.
+It should be noted that the L</return_object> attribute will produce the above result for you, free of charge.
 
+For REST the only difference besides the class names would be that create should be :Private rather than an endpoint.
+
 Similarly you might want create, update and delete to all forward to the list action once they are done so you can refresh your view. This should also be simple enough.
 
+If more extensive customization is required, it is recommened to peer into the roles that comprise the system and make use 
+
+=head1 NOTES
+
+It should be noted that version 1.004 and above makes a rapid depature from the status quo. The internals were revamped to use more modern tools such as Moose and its role system to refactor functionality out into self-contained roles.
+
+To this end, internally, this module now understands JSON boolean values (as represented by JSON::Any) and will Do The Right Thing in handling those values. This means you can have ColumnInflators installed that can covert between JSON::Any booleans and whatever your database wants for boolean values.
+
+Validation for various *_allows or *_exposes is now accomplished via Data::DPath::Validator with a lightly simplified, via subclass, Data::DPath::Validator::Visitor. The rough jist of the process goes as follows: Arguments provided to those attributes are fed into the Validator and Data::DPaths are generated. Then, incoming requests are validated against these paths generated. The validator is set in "loose" mode meaning only one path is required to match. for more information, please see L<Data::DPath::Validator> and more specifically L<Catalyst::Controller::DBIC::API::Validator>.
+
+All in all, significant efforts have been made to preserve backwards compatibility with previous versions. This means arguments to config and even internal structures (ie, the stash) should Just Work. This is accomplished by using L<MooseX::Aliases> to provide a mapping from old names to new names. Even the validator behavior /should/ be the same if not a bit more consistent. Internal validation of ->config arguments also happens much, much sooner. And, request parameters are validated as upfront as possible before ->search.
+
 =head1 AUTHOR
 
   Luke Saunders <luke.saunders at gmail.com>
 
 =head1 CONTRIBUTORS
 
+  Nicholas Perez <nperez at cpan.org>
+
   J. Shirley <jshirley at gmail.com>
 
   Zbigniew Lukasiak <zzbbyy at gmail.com>

Modified: Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/t/rest/list.t
===================================================================
--- Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/t/rest/list.t	2009-12-21 09:14:58 UTC (rev 12441)
+++ Catalyst-Controller-DBIC-API/1.003/branches/moosify-validation-configurability/t/rest/list.t	2009-12-21 13:32:44 UTC (rev 12442)
@@ -78,7 +78,6 @@
 
   my @expected_response = map { { $_->get_columns } } $schema->resultset('Artist')->search({ 'cds.title' => 'Forkful of bees' }, { join => 'cds' })->all;
   my $response = JSON::Syck::Load( $mech->content);
-#  use Data::Dumper; warn Dumper($response, \@expected_response);
   is_deeply( { list => \@expected_response, success => 'true' }, $response, 'correct data returned for class with list_returns specified' );
 }
 




More information about the Catalyst-commits mailing list