Deal with authorship properly, in a future-sustainable fashion
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / InflateColumn / File.pm
CommitLineData
5acaa54e 1package DBIx::Class::InflateColumn::File;
4740bdb7 2
3use strict;
4use warnings;
5use base 'DBIx::Class';
6use File::Path;
7use File::Copy;
26ddc864 8use Path::Class;
70c28808 9use DBIx::Class::Carp;
9c1700e3 10use namespace::clean;
11
3814fdad 12carp 'InflateColumn::File has entered a deprecation cycle. This component '
13 .'has a number of architectural deficiencies that can quickly drive '
14 .'your filesystem and database out of sync and is not recommended '
15 .'for further use. It will be retained for backwards '
16 .'compatibility, but no new functionality patches will be accepted. '
17 .'Please consider using the much more mature and actively maintained '
18 .'DBIx::Class::InflateColumn::FS. You can set the environment variable '
19 .'DBIC_IC_FILE_NOWARN to a true value to disable this warning.'
20unless $ENV{DBIC_IC_FILE_NOWARN};
21
9c1700e3 22
23
28d4067a 24__PACKAGE__->load_components(qw/InflateColumn/);
4740bdb7 25
28d4067a 26sub register_column {
26ddc864 27 my ($self, $column, $info, @rest) = @_;
28 $self->next::method($column, $info, @rest);
29 return unless defined($info->{is_file_column});
30
31 $self->inflate_column($column => {
8273e845 32 inflate => sub {
23f067d1 33 my ($value, $obj) = @_;
26ddc864 34 $obj->_inflate_file_column($column, $value);
35 },
36 deflate => sub {
23f067d1 37 my ($value, $obj) = @_;
26ddc864 38 $obj->_save_file_column($column, $value);
39 },
40 });
4740bdb7 41}
42
26ddc864 43sub _file_column_file {
44 my ($self, $column, $filename) = @_;
45
4006691d 46 my $column_info = $self->result_source->column_info($column);
26ddc864 47
48 return unless $column_info->{is_file_column};
49
2053211a 50 # DO NOT CHANGE
51 # This call to id() is generally incorrect - will not DTRT on
52 # multicolumn key. However changing this may introduce
53 # backwards-comp regressions, thus leaving as is
26ddc864 54 my $id = $self->id || $self->throw_exception(
55 'id required for filename generation'
56 );
57
58 $filename ||= $self->$column->{filename};
59 return Path::Class::file(
60 $column_info->{file_column_path}, $id, $filename,
61 );
62}
4740bdb7 63
64sub delete {
65 my ( $self, @rest ) = @_;
66
4006691d 67 my $colinfos = $self->result_source->columns_info;
68
69 for ( keys %$colinfos ) {
70 if ( $colinfos->{$_}{is_file_column} ) {
26ddc864 71 rmtree( [$self->_file_column_file($_)->dir], 0, 0 );
72 last; # if we've deleted one, we've deleted them all
4740bdb7 73 }
74 }
75
26ddc864 76 return $self->next::method(@rest);
4740bdb7 77}
78
26ddc864 79sub insert {
4740bdb7 80 my $self = shift;
d4daee7b 81
26ddc864 82 # cache our file columns so we can write them to the fs
83 # -after- we have a PK
4006691d 84 my $colinfos = $self->result_source->columns_info;
85
26ddc864 86 my %file_column;
4006691d 87 for ( keys %$colinfos ) {
88 if ( $colinfos->{$_}{is_file_column} ) {
26ddc864 89 $file_column{$_} = $self->$_;
90 $self->store_column($_ => $self->$_->{filename});
4740bdb7 91 }
92 }
26ddc864 93
94 $self->next::method(@_);
95
96 # write the files to the fs
97 while ( my ($col, $file) = each %file_column ) {
98 $self->_save_file_column($col, $file);
99 }
100
101 return $self;
4740bdb7 102}
103
4740bdb7 104
26ddc864 105sub _inflate_file_column {
106 my ( $self, $column, $value ) = @_;
4740bdb7 107
26ddc864 108 my $fs_file = $self->_file_column_file($column, $value);
4740bdb7 109
26ddc864 110 return { handle => $fs_file->open('r'), filename => $value };
4740bdb7 111}
112
113sub _save_file_column {
26ddc864 114 my ( $self, $column, $value ) = @_;
115
116 return unless ref $value;
117
118 my $fs_file = $self->_file_column_file($column, $value->{filename});
119 mkpath [$fs_file->dir];
f6ace689 120
121 # File::Copy doesn't like Path::Class (or any for that matter) objects,
122 # thus ->stringify (http://rt.perl.org/rt3/Public/Bug/Display.html?id=59650)
123 File::Copy::copy($value->{handle}, $fs_file->stringify);
26ddc864 124
125 $self->_file_column_callback($value, $self, $column);
126
127 return $value->{filename};
4740bdb7 128}
129
130=head1 NAME
131
5847820e 132DBIx::Class::InflateColumn::File - DEPRECATED (superseded by DBIx::Class::InflateColumn::FS)
133
134=head2 Deprecation Notice
135
3814fdad 136 This component has a number of architectural deficiencies that can quickly
137 drive your filesystem and database out of sync and is not recommended for
138 further use. It will be retained for backwards compatibility, but no new
139 functionality patches will be accepted. Please consider using the much more
140 mature and actively supported DBIx::Class::InflateColumn::FS. You can set
141 the environment variable DBIC_IC_FILE_NOWARN to a true value to disable
142 this warning.
4740bdb7 143
4740bdb7 144=head1 SYNOPSIS
145
146In your L<DBIx::Class> table class:
147
d88ecca6 148 use base 'DBIx::Class::Core';
149
150 __PACKAGE__->load_components(qw/InflateColumn::File/);
d4daee7b 151
4740bdb7 152 # define your columns
153 __PACKAGE__->add_columns(
154 "id",
155 {
156 data_type => "integer",
157 is_auto_increment => 1,
158 is_nullable => 0,
159 size => 4,
160 },
161 "filename",
162 {
163 data_type => "varchar",
164 is_file_column => 1,
165 file_column_path =>'/tmp/uploaded_files',
8273e845 166 # or for a Catalyst application
4740bdb7 167 # file_column_path => MyApp->path_to('root','static','files'),
168 default_value => undef,
169 is_nullable => 1,
170 size => 255,
171 },
172 );
d4daee7b 173
4740bdb7 174
175In your L<Catalyst::Controller> class:
176
0876072c 177FileColumn requires a hash that contains L<IO::File> as handle and the file's
178name as name.
4740bdb7 179
8273e845 180 my $entry = $c->model('MyAppDB::Articles')->create({
4740bdb7 181 subject => 'blah',
8273e845 182 filename => {
183 handle => $c->req->upload('myupload')->fh,
184 filename => $c->req->upload('myupload')->basename
4740bdb7 185 },
186 body => '....'
187 });
188 $c->stash->{entry}=$entry;
d4daee7b 189
4740bdb7 190
191And Place the following in your TT template
d4daee7b 192
4740bdb7 193 Article Subject: [% entry.subject %]
8273e845 194 Uploaded File:
4740bdb7 195 <a href="/static/files/[% entry.id %]/[% entry.filename.filename %]">File</a>
196 Body: [% entry.body %]
d4daee7b 197
0876072c 198The file will be stored on the filesystem for later retrieval. Calling delete
199on your resultset will delete the file from the filesystem. Retrevial of the
200record automatically inflates the column back to the set hash with the
201IO::File handle and filename.
202
203=head1 DESCRIPTION
204
205InflateColumn::File
206
207=head1 METHODS
208
209=head2 _file_column_callback ($file,$ret,$target)
210
48580715 211Method made to be overridden for callback purposes.
0876072c 212
213=cut
214
26ddc864 215sub _file_column_callback {}
4740bdb7 216
217=head1 AUTHOR
218
219Victor Igumnov
220
221=head1 LICENSE
222
223This library is free software, you can redistribute it and/or modify
224it under the same terms as Perl itself.
225
226=cut
227
2281;