[Catalyst-commits] r8711 - trunk/examples/CatalystAdvent/root/2008/pen

dhoss at dev.catalyst.perl.org dhoss at dev.catalyst.perl.org
Thu Dec 4 11:50:24 GMT 2008


Author: dhoss
Date: 2008-12-04 11:50:24 +0000 (Thu, 04 Dec 2008)
New Revision: 8711

Added:
   trunk/examples/CatalystAdvent/root/2008/pen/AdventPhotoGallery.pod
Log:
added PhotoGallery advent calendar


Added: trunk/examples/CatalystAdvent/root/2008/pen/AdventPhotoGallery.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2008/pen/AdventPhotoGallery.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2008/pen/AdventPhotoGallery.pod	2008-12-04 11:50:24 UTC (rev 8711)
@@ -0,0 +1,448 @@
+=head1 Super Simple Photo Gallery
+
+Let's create an extremely simple (but fun!) photogallery.
+First things first, we need to make sure we have everything.
+
+=head2 Our packing list:
+
+=over 12
+
+=item C<DBIx::Class::InflateColumn::FS>
+
+This will be used to store our file pointer in the database, write the image to the file system, and later, give us a
+Path::Class::File object to manipulate our images later on.
+
+=item C<Imager>
+
+The all and the everything for our image manipulation needs.  If not installed already, make sure you install libjpeg so that
+JPEG files can be manipulated by Imager.
+
+
+=item C<MIME::Types>
+
+=item C<File::Mimeinfo>
+
+=item C<DateTime>
+
+=back
+
+Once you have installed these two things with great success, move on to the next step.
+
+=head1 Let's get started already!
+
+Ok.  So here comes the fun stuff.  We're going to assume you know how to create a Catalyst application skeleton, controllers, and models
+at the very least.  If not, you have some documentation to read first :-)
+
+Create a controller in your application called Photos.  Something like this:
+
+    perl script/*create.pl controller Photos
+    
+Next, you'll want to set up a table called Photos in your RDBMS of choice.  Here, we use MySQL because I've yet to learn Postgres.
+The necessary columns you will need are as follows:
+
+=over 12
+
+=item photoid
+
+type: INT
+size: 11
+null: no
+other: PRIMARY KEY auto_increment
+
+=item name
+
+type: VARCHAR
+size: 255
+null: no
+other:
+
+=item uploaded
+
+type: DATETIME
+size: 
+null: no
+other: 
+(If you so desire, include the InflateColumn::DateTime component to be able to manipulate this column as if it were
+a DateTime object)
+
+=item path
+
+type: TEXT
+size: 
+null: no
+other: 
+
+
+=item caption
+
+type: TEXT
+size:
+null: no
+other:
+
+
+=back
+
+So now you have your basic tables set up.  Next, we need to generate our Schema files so DBIx::Class can interact with our
+database objects.  I use this script to update/create my schema definition from the database.
+Copy/paste this script into a file called myapp_update_schema.pl (replace "myapp" with whatever you named this application) and stick it
+in the script/ directory of your application:
+
+    #!/usr/bin/perl 
+
+
+    use FindBin;
+    use DBIx::Class::Schema::Loader qw| make_schema_at |;
+    make_schema_at(
+    	"MyApp::Schema",
+    	{
+		    debug          => 1,
+		    use_namespaces => 0,
+		    components     => [qw/ InflateColumn::DateTime InflateColumn::FS PK::Auto/],
+		    dump_directory => "$FindBin::Bin/../lib"
+	    },
+	    [ "dbi:mysql:myapp", "narf", "blarf" ]
+    );
+    
+now run perl script/*update*.  If there are no errors, proceed!
+
+=head2 Adding the InflateColumn::FS magic
+
+Open up Schema/Photos.pm.  Since we used ::Loader, there will be a good portion of the file that you're not supposed to manually
+edit.  This is marked by these lines:
+
+    # Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-12-01 02:57:02
+    # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:A/YrsvGDAWKpDaGlJ3Dwqg
+    
+You can safely modify anything below this though.  Add these lines to the file:
+
+    use MyApp;
+    __PACKAGE__->add_columns(
+	    "path",
+	    {
+	        data_type      => 'TEXT',
+            is_fs_column   => 1,
+            fs_column_path => MyApp->path_to( 'root', 'static', 'photos' ) . ""
+	    }
+    );
+    
+This tells DBIx::Class that the column "path" is now a Path::Class::File object and we can call Path::Class::File methods on it upon retrieval.
+
+Great! Now let's edit our controller.
+
+=head1 The Photos Controller
+
+Edit Controller/Photos.pm to match this file:
+
+    package MyApp::Controller::Photos;
+
+    use strict;
+    use warnings;
+    use parent 'Catalyst::Controller::HTML::FormFu';
+    use DateTime;
+    use Imager;
+    use MIME::Types;
+    use File::MimeInfo ();
+    use BoyosPlace;
+
+    __PACKAGE__->mk_accessors(qw(thumbnail_size));
+
+    =head1 NAME
+
+     MyApp::Controller::Photos - Catalyst Controller
+
+    =head1 DESCRIPTION
+
+    Catalyst Controller.
+
+    =head1 METHODS
+
+    =cut
+
+    =head2 index 
+  
+      display the photos
+
+    =cut
+
+    sub index : Path : Args(0) {
+	    my ( $self, $c ) = @_;
+
+	    my @photos = $c->model('DB::Photos')->all;
+
+	    $c->stash->{photos}   = \@photos;
+    	$c->stash->{template} = "photos/index.tt2";
+
+    }
+
+    =head2 get_photos
+
+      set up photo stash
+  
+    =cut
+
+    sub get_photos : Chained('/') PathPart('photo') CaptureArgs(1) {
+	    my ( $self, $c, $photoid ) = @_;
+
+	    my $photo = $c->model('DB::Photos')->find($photoid);
+
+    	if ( $photo == undef ) {
+
+		    $c->stash->{error_msg} = "No such photo.";
+
+	    }
+	    else {
+
+    		$c->stash->{photo} = $photo;
+
+    	}
+
+    }
+
+    =head2 add_photo
+
+      Add a photo to the database
+
+    =cut
+
+    sub add_photo : Path('/photo/add') FormConfig('photos/add.yml') {
+	    my ( $self, $c ) = @_;
+
+	    $c->stash->{template} = "photos/add.tt2";
+	    my $form = $c->stash->{form};
+	    my $mime = MIME::Types->new;
+ 
+        ## comment out this block if you're not using the Authorization plugin
+	    unless ( $c->check_user_roles('admin') ) {
+
+		    $c->flash->{error_msg} =
+		      "You don't have the proper permissions to add photos here";
+		    $c->res->redirect( $c->uri_for('/photos') );
+
+	    } 
+
+	    if ( $form->submitted_and_valid ) {
+
+		    my $photo = $c->model('DB::Photos')->create(
+		    	{
+	    			name     => $form->param('photo_name'),
+				    path     => $c->req->upload('photo')->fh,
+				    caption  => $form->param('caption'),
+				    uploaded => DateTime->now,
+				    mime => $mime->mimeTypeOf( $c->req->upload('photo')->basename ),
+			    }
+		    );
+
+		    $c->stash->{status_msg} = "Successfully uploaded!";
+	    	$c->stash->{photo}      = $photo;
+    		$c->detach;
+ 
+    	}
+ 
+    }
+
+    =head2 generate_thumbnail
+
+      this method generates a thumbnail of a 
+      given image
+
+    =cut
+
+    sub generate_thumbnail : Chained('get_photos') PathPart('thumbnail') Args(0) {
+	    my ( $self, $c ) = @_;
+
+	
+	    my $photo = $c->stash->{photo};
+	    my $size  = $self->thumbnail_size;
+
+	    my $mimeinfo = File::MimeInfo->new;
+ 
+	    my $data = $photo->path->open('r') or die "Error: $!";
+	    my $img = Imager->new;
+	    $img->read( fh => $data ) or die $img->errstr;
+	    my $scaled = $img->scale( xheight => $size );
+	    my $out;
+	    $scaled->write(
+		    type => $mimeinfo->extensions( $photo->mime ),
+		    data => \$out
+	      )
+	      or die $scaled->errstr;
+	    $c->res->content_type( $photo->mime );
+	    $c->res->content_length( -s $out );
+	    $c->res->header( "Content-Disposition" => "inline; filename="
+		      . $mimeinfo->extensions( $photo->mime ) );
+
+	    binmode $out;
+	    $c->res->body($out);
+
+    }
+
+    =head2 view_image
+
+      hackish method to view
+      an image full-size
+
+    =cut
+
+    sub view_image : Chained('get_photos') PathPart('generate') Args(0) {
+	    my ( $self, $c ) = @_;
+
+	    my $photo = $c->stash->{photo};
+
+	    my $mimeinfo = File::MimeInfo->new;
+
+	    my $data = $photo->path->open('r') or die "Error: $!";
+	    my $img = Imager->new;
+	    $img->read( fh => $data ) or die $img->errstr;
+
+	    my $out;
+	    $img->write(
+		    type => $mimeinfo->extensions( $photo->mime ),
+		    data => \$out
+	      )
+	      or die $img->errstr;
+	    $c->res->content_type( $photo->mime );
+	    $c->res->content_length( -s $out );
+	    $c->res->header( "Content-Disposition" => "inline; filename="
+    		  . $mimeinfo->extensions( $photo->mime ) );
+
+	    binmode $out;
+	    $c->res->body($out);
+
+    }
+
+    =head2 view_photo
+
+      view an individual photo
+
+    =cut
+
+    sub view_photo : Chained("get_photos") PathPart('view') Args(0) {
+	    my ( $self, $c ) = @_;
+
+	    my $photo = $c->stash->{photo};
+
+	    $c->stash->{template} = "photos/view.tt2";
+
+    }
+
+    =head2 delete_photo
+
+      delete a photo or photos
+  
+    =cut
+
+    sub delete_photo : Chained("get_photos") PathPart('delete') Args(0) {
+    	my ( $self, $c ) = @_;
+ 
+    	my $photo = $c->stash->{photo};
+	    $c->stash->{template} = 'photos/delete.tt2';
+
+	    if ( $c->check_user_roles("admin") ) {
+
+		    if ( $c->req->param('delete') eq 'yes' ) {
+
+			    $photo->delete;
+		    	$c->stash->{status_msg} = "Photo " . $photo->photoid . " deleted!";
+	    		$c->detach;
+    
+    		}
+
+	    }
+	    else {
+
+		    $c->flash->{error_msg} =
+		      "You don't have proper permissions to delete images.";
+	    	$c->res->redirect("/");
+   
+    	}
+
+    }
+
+The view:
+
+=over 12
+
+=item add.tt2
+
+    <h2>Upload your photos</h2>
+    [% UNLESS form.submitted_and_valid %]
+     [% form %]
+
+    [% ELSE %]
+
+    <p>Success!</p>
+    <p>Here's your image: <img src="[% c.uri_for("/photo/$photo.photoid/thumbnail") %]" />
+
+    [% END %]
+
+=item delete.tt2
+
+    [% UNLESS c.req.param('delete') %]
+    <h2>Deleting [% photo.name %]</h2>
+    <div id="photo">
+    <img src="[% c.uri_for("/photo/$photo.photoid/generate") %]" alt="[% photo.name %]" />
+    </div>
+    <p>ARE YOU SURE YOU WANT TO DELETE THIS PHOTO?</p>
+    <p><a href="[% c.uri_for("/photo/$photo.photoid/delete", { delete=> 'yes' } ) %]">yes</a> I do</p>
+    <p><a href="[% c.uri_for("/photos") %]">no</a> I don't</p>
+    <div>&laquo;<a href="[% c.uri_for("/photos") %]">back</a>
+    [% ELSE %]
+    <p>Deleted!</p>
+    [% END %]
+
+=item index.tt2
+
+    [% USE table (photos, rows=3) %]
+    <h2>Puppy Photos</h2>
+
+    <div id="puppy-list">
+    <table>
+    [% FOREACH column = table.cols %]
+    <tr>
+    [% FOREACH photo = column %]
+    <td>
+      [% IF photo %]
+      <a href="[% c.uri_for("/photo/$photo.photoid/view") %]">
+         <img src="[% c.uri_for("/photo/$photo.photoid/thumbnail")%]" />
+      </a>
+      [% ELSE %]
+      <img src="[% c.uri_for("/static/photos/blank.gif")%]" width="150" height="100"/>
+      [% END %]
+    </td>
+    [% END %]
+    </tr>
+    [% END %]
+    <table>
+    </div>
+
+
+=item view.tt2
+
+    <h2>[% photo.name %]</h2>
+    <div id="photo">
+    <img src="[% c.uri_for("/photo/$photo.photoid/generate") %]" alt="[% photo.name %]" />
+    </div>
+    <p>[% photo.caption %]</p>
+    <div>&laquo;<a href="[% c.uri_for("/photos") %]">back</a>
+
+
+Voila! There you have it. Go nuts.
+
+=head1 AUTHOR
+
+Devin Austin
+devin.austin at gmail.com
+http://www.codedright.net
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;
+
+
+




More information about the Catalyst-commits mailing list