package DBIx::Class::Schema::RestrictWithObject; our $VERSION = '0.0001'; use DBIx::Class::Schema::RestrictWithObject::RestrictComp::Schema; use DBIx::Class::Schema::RestrictWithObject::RestrictComp::Source; # (c) Matt S Trout 2006, all rights reserved # this is free software under the same license as perl itself =head1 NAME DBIx::Class::Schema::RestrictWithObject - Automatically restrict resultsets =head1 SYNOPSYS In your L class: __PACKAGE__->load_components(qw/Schema::RestrictWithObject/); In the L table class for your users: #let's pretend a user has_many notes, which are in ResultSet 'Notes' sub restrict_Notes_resultset { my $self = shift; #the User object my $unrestricted_rs = shift; #restrict the notes viewable to only those that belong to this user #this will, in effect make the following 2 equivalent # $user->notes $schema->resultset('Notes') return $self->related_resultset('notes'); } #it could also be written like this sub restrict_Notes_resultset { my $self = shift; #the User object my $unrestricted_rs = shift; return $unrestricted_rs->search_rs( { user_id => $self->id } ); } Wherever you connect to your database my $schema = MyApp::Schema->connect(...); my $user = $schema->resultset('User')->find( { id => $user_id } ); $resticted_schema = $schema->restrict_with_object( $user, $optional_prefix); In this example we used the User object as the restricting object, but please note that the restricting object need not be a DBIC class, it can be any kind of object that provides the adequate methods. =cut =head1 DESCRIPTION This L component can be used to restrict all resultsets through an appropriately-named method in a user-supplied object. This allows you to automatically prevent data from being accessed, or automatically predefine options and search clauses on a schema-wide basis. When used to limit data sets, it allows simplified security by limiting any access to the data at the schema layer. Please note however that this is not a silver bullet and without careful programming it is still possible to expose unwanted data, so this should not be regarded as a replacement for application level security. =head1 PUBLIC METHODS =head2 restrict_with_object $restricting_obj, $optional_prefix Will restrict resultsets according to the methods available in $restricting_obj and return a restricted copy of itself. ResultSets will be restricted if methods in the form of C are found in $restricting_obj. If the optional prefix is included it will attempt to use C, if that does not exist, it will try again without the prefix, and if that's not available the resultset will not be restricted. =cut sub restrict_with_object { my ($self, $obj, $prefix) = @_; my $copy = $self->clone; $copy->make_restricted; $copy->restricting_object($obj); $copy->restricted_prefix($prefix) if $prefix; return $copy; } =head1 PRIVATE METHODS =head2 make_restricted Restrict the Schema class and ResultSources associated with this Schema =cut sub make_restricted { my ($self) = @_; my $class = ref($self); my $r_class = $self->_get_restricted_schema_class($class); bless($self, $r_class); foreach my $moniker ($self->sources) { my $source = $self->source($moniker); my $class = ref($source); my $r_class = $self->_get_restricted_source_class($class); bless($source, $r_class); } } =head2 _get_restricted_schema_class $target_schema Return the class name for the restricted schema class; =cut sub _get_restricted_schema_class { my ($self, $target) = @_; return $self->_get_restricted_class(Schema => $target); } =head2 _get_restricted_source_class $target_source Return the class name for the restricted ResultSource class; =cut sub _get_restricted_source_class { my ($self, $target) = @_; return $self->_get_restricted_class(Source => $target); } =head2 _get_restrictedclass $type, $target Return an appropriate class name for a restricted class of type $type. =cut sub _get_restricted_class { my ($self, $type, $target) = @_; my $r_class = join('::', $target, '__RestrictedWithObject'); unless (eval { $r_class->can('can') }) { my $r_comp = join( '::', 'DBIx::Class::Schema::RestrictWithObject::RestrictComp', $type ); $self->inject_base($r_class, $r_comp, $target); } return $r_class; } 1; __END__; =head1 SEE ALSO L, L, L, =head1 AUTHORS Matt S Trout (mst) With contributions from Guillermo Roditi (groditi) =head1 LICENSE You may distribute this code under the same terms as Perl itself. =cut