A couple of typos, and general whitespace cleanup (ick)
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / InflateColumn / File.pm
index 1d76bef..1901187 100644 (file)
-package DBIx::Class::File;
+package DBIx::Class::InflateColumn::File;
 
 use strict;
 use warnings;
 use base 'DBIx::Class';
 use File::Path;
 use File::Copy;
-use IO::File;
+use Path::Class;
 
 __PACKAGE__->load_components(qw/InflateColumn/);
 
-
 sub register_column {
-  my ($self, $column, $info, @rest) = @_;
-  $self->next::method($column, $info, @rest);
-  return unless defined($info->{is_file_column});
-    $self->inflate_column(
-      $column =>
-        {
-          inflate => $self->_inflate_file_column,
-          deflate => sub {
-              my ( $file, @column_names ) = $self->_load_file_column_information;
-              $self->_save_file_column( $file, $self, @column_names );
-          },
-        }
-    );
+    my ($self, $column, $info, @rest) = @_;
+    $self->next::method($column, $info, @rest);
+    return unless defined($info->{is_file_column});
+
+    $self->inflate_column($column => {
+        inflate => sub { 
+            my ($value, $obj) = @_;
+            $obj->_inflate_file_column($column, $value);
+        },
+        deflate => sub {
+            my ($value, $obj) = @_;
+            $obj->_save_file_column($column, $value);
+        },
+    });
 }
 
+sub _file_column_file {
+    my ($self, $column, $filename) = @_;
 
-sub delete {
-    my ( $self, @rest ) = @_;
+    my $column_info = $self->column_info($column);
 
-    my @column_names = $self->columns;
-    for (@column_names) {
-        if ( $self->column_info($_)->{is_file_column} ) {
-            my $path =
-              File::Spec->catdir( $self->column_info($_)->{file_column_path},
-                $self->id );
-            rmtree( [$path], 0, 0 );
-        }
-    }
+    return unless $column_info->{is_file_column};
 
-    my $ret = $self->next::method(@rest);
+    my $id = $self->id || $self->throw_exception(
+        'id required for filename generation'
+    );
 
-    return $ret;
+    $filename ||= $self->$column->{filename};
+    return Path::Class::file(
+        $column_info->{file_column_path}, $id, $filename,
+    );
 }
 
-sub _inflate_file_column {
-    my $self = shift;
+sub delete {
+    my ( $self, @rest ) = @_;
 
-    my @column_names = $self->columns;
-    for(@column_names) {
+    for ( $self->columns ) {
         if ( $self->column_info($_)->{is_file_column} ) {
-            # make sure everything checks out
-            unless (defined $self->$_) {
-                # if something is wrong set it to undef
-                $self->$_(undef);
-                next;
-            }
-            my $fs_file =
-              File::Spec->catfile( $self->column_info($_)->{file_column_path}, 
-                $self->id, $self->$_ );
-            $self->$_({handle => new IO::File($fs_file, "r"), filename => $self->$_});
+            rmtree( [$self->_file_column_file($_)->dir], 0, 0 );
+            last; # if we've deleted one, we've deleted them all
         }
     }
+
+    return $self->next::method(@rest);
 }
 
-sub _load_file_column_information {
+sub insert {
     my $self = shift;
 
-    my $file;
-    my @column_names;
-
-    @column_names = $self->columns;
-    for (@column_names) {
+    # cache our file columns so we can write them to the fs
+    # -after- we have a PK
+    my %file_column;
+    for ( $self->columns ) {
         if ( $self->column_info($_)->{is_file_column} ) {
-            # make sure everything checks out
-            unless ((defined $self->$_) ||
-             (defined $self->$_->{filename} && defined $self->$_->{handle})) {
-                # if something is wrong set it to undef
-                $self->$_(undef);
-                next;
-            }
-            $file->{$_} = $self->$_;
-            $self->$_( $self->$_->{filename} );
+            $file_column{$_} = $self->$_;
+            $self->store_column($_ => $self->$_->{filename});
         }
     }
 
-    return ( $file, @column_names );
-}
+    $self->next::method(@_);
 
-sub _save_file_column {
-    my ( $self, $file, $ret, @column_names ) = @_;
-
-    for (@column_names) {
-        if ( $ret->column_info($_)->{is_file_column} ) {
-            next unless (defined $ret->$_);
-            my $file_path =
-              File::Spec->catdir( $ret->column_info($_)->{file_column_path},
-                $ret->id );
-            mkpath [$file_path];
-            
-            my $outfile =
-              File::Spec->catfile( $file_path, $file->{$_}->{filename} );
-            File::Copy::copy( $file->{$_}->{handle}, $outfile );
-        
-            $self->_file_column_callback($file->{$_},$ret,$_);
-        }
+    # write the files to the fs
+    while ( my ($col, $file) = each %file_column ) {
+        $self->_save_file_column($col, $file);
     }
+
+    return $self;
 }
 
-=head1 METHODS
 
-=cut
+sub _inflate_file_column {
+    my ( $self, $column, $value ) = @_;
 
+    my $fs_file = $self->_file_column_file($column, $value);
 
-=head2 _file_column_callback ($file,$ret,$target)
+    return { handle => $fs_file->open('r'), filename => $value };
+}
 
-method made to be overridden for callback purposes.
+sub _save_file_column {
+    my ( $self, $column, $value ) = @_;
 
-=cut
+    return unless ref $value;
+
+    my $fs_file = $self->_file_column_file($column, $value->{filename});
+    mkpath [$fs_file->dir];
 
-sub _file_column_callback {
-    my ($self,$file,$ret,$target) = @_;
+    # File::Copy doesn't like Path::Class (or any for that matter) objects,
+    # thus ->stringify (http://rt.perl.org/rt3/Public/Bug/Display.html?id=59650)
+    File::Copy::copy($value->{handle}, $fs_file->stringify);
+
+    $self->_file_column_callback($value, $self, $column);
+
+    return $value->{filename};
 }
 
 =head1 NAME
 
 DBIx::Class::InflateColumn::File -  map files from the Database to the filesystem.
 
-=head1 DESCRIPTION
-
-InflateColumn::File
-
 =head1 SYNOPSIS
 
 In your L<DBIx::Class> table class:
 
     __PACKAGE__->load_components( "PK::Auto", "InflateColumn::File", "Core" );
-    
+
     # define your columns
     __PACKAGE__->add_columns(
         "id",
@@ -159,11 +136,12 @@ In your L<DBIx::Class> table class:
             size                => 255,
         },
     );
-    
+
 
 In your L<Catalyst::Controller> class:
 
-FileColumn requires a hash that contains L<IO::File> as handle and the file's name as name.
+FileColumn requires a hash that contains L<IO::File> as handle and the file's
+name as name.
 
     my $entry = $c->model('MyAppDB::Articles')->create({ 
         subject => 'blah',
@@ -174,18 +152,33 @@ FileColumn requires a hash that contains L<IO::File> as handle and the file's na
         body => '....'
     });
     $c->stash->{entry}=$entry;
-    
+
 
 And Place the following in your TT template
-    
+
     Article Subject: [% entry.subject %]
     Uploaded File: 
     <a href="/static/files/[% entry.id %]/[% entry.filename.filename %]">File</a>
     Body: [% entry.body %]
-    
-The file will be stored on the filesystem for later retrieval.
-Calling delete on your resultset will delete the file from the filesystem.
-Retrevial of the record automatically inflates the column back to the set hash with the IO::File handle and filename.
+
+The file will be stored on the filesystem for later retrieval.  Calling delete
+on your resultset will delete the file from the filesystem.  Retrevial of the
+record automatically inflates the column back to the set hash with the
+IO::File handle and filename.
+
+=head1 DESCRIPTION
+
+InflateColumn::File
+
+=head1 METHODS
+
+=head2 _file_column_callback ($file,$ret,$target)
+
+method made to be overridden for callback purposes.
+
+=cut
+
+sub _file_column_callback {}
 
 =head1 AUTHOR