Changeset 752

Show
Ignore:
Timestamp:
11/16/06 16:42:32 (2 years ago)
Author:
bchoate
Message:

Refactored asset classes to have a first-class table. Merged selected vfix updates.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/wheeljack/build/mt-dists/MT.mk

    r731 r752  
    22PRODUCT_CODE = MT 
    33PRODUCT_VERSION = 3.3 
    4 SCHEMA_VERSION = 3.3003 
     4SCHEMA_VERSION = 3.3005 
    55API_VERSION = 3.33 
  • branches/wheeljack/lib/MT.pm.pre

    r748 r752  
    18161816 
    18171817Movable Type has a variety of hook points at which a plugin can attach 
    1818 a callback. The context and calling conventions of each one are 
    1819 documented here. 
     1818a callback. 
    18201819 
    18211820In each case, the first parameter is an L<MT::Callback> object which 
     
    18231822 
    18241823The app-level callbacks related to rebuilding are documented 
    1825 in L<MT::WeblogPublisher>. The specific apps document the callbacks which 
    1826 they invoke. 
     1824in L<MT::WeblogPublisher>. The specific apps document the callbacks 
     1825which they invoke. 
    18271826 
    18281827=head1 LICENSE 
  • branches/wheeljack/lib/MT/App/CMS.pm

    r751 r752  
    887887    my %args = ( sort => 'created_on', direction => 'descend' ); 
    888888 
    889     my $type_filter; 
     889    my $class_filter; 
    890890    my $filter = ($app->param('filter') || ''); 
    891     if ($filter eq 'archive_type') { 
    892         $type_filter = $app->param('filter_val'); 
     891    if ($filter eq 'class') { 
     892        $class_filter = $app->param('filter_val'); 
    893893    } 
    894894 
     
    906906    my %blogs; 
    907907    require File::Basename; 
     908    require JSON; 
    908909    my $auth_prefs = $app->user->entry_prefs; 
    909910    my $tag_delim = chr($auth_prefs->{tag_delim}); 
     
    919920        $row->{blog_name} = $blog ? $blog->name : '-'; 
    920921        $row->{file_name} = File::Basename::basename($row->{file_path}); 
     922        my $meta = $obj->metadata; 
    921923        if (-f $row->{file_path}) { 
    922924            my @stat = stat($row->{file_path}); 
    923925            my $size = $stat[7]; 
    924             $row->{asset_type} = $app->translate($obj->type_name); 
     926            $row->{thumbnail_url} = $meta->{thumbnail_url} = 
     927                $obj->thumbnail_url(Height => 230, Width => 164); 
     928            $row->{asset_class} = $obj->class_label; 
    925929            $row->{file_size} = $size; 
    926             $row->{tags} = MT::Tag->join($tag_delim, $obj->tags); 
    927930            if ($size < 1024) { 
    928931            } elsif ($size < 1024000) { 
     
    935938                $ts = $stat[10]; 
    936939                $ts = epoch2ts($blog, $ts); 
     940            } 
     941            if (my $by = $obj->created_by) { 
     942                my $user = MT::Author->load($by, { cached_ok => 1 }); 
     943                $row->{created_by} = $user ? $user->name : ''; 
    937944            } 
    938945            if ($ts) { 
     
    947954            $row->{file_is_missing} = 1; 
    948955        } 
     956        $row->{metadata_json} = JSON::objToJson($meta); 
    949957    }; 
    950958 
    951     if ($type_filter) { 
    952         my $asset_pkg = MT::Asset->type_class($type_filter); 
    953         $terms{archive_type} = $asset_pkg->types; 
     959    if ($class_filter) { 
     960        my $asset_pkg = MT::Asset->class_handler($class_filter); 
     961        $terms{class} = $asset_pkg->classes; 
    954962    } else { 
    955         $terms{archive_type} = MT::Asset->types; 
     963        $terms{class} = MT::Asset->classes; 
    956964    } 
    957965 
    958966    # identifier => name 
    959     my $types = MT::Asset->type_names; 
    960     my @type_loop; 
    961     foreach my $type (keys %$types) { 
    962         push @type_loop, { 
    963             type_id => $type
    964             type_name => $types->{$type}, 
     967    my $classes = MT::Asset->class_labels; 
     968    my @class_loop; 
     969    foreach my $class (keys %$classes) { 
     970        push @class_loop, { 
     971            class_id => $class
     972            class_label => $classes->{$class}, 
    965973        }; 
    966974    } 
    967975    # Now, sort it 
    968     @type_loop = sort { $a->{type_name} cmp $b->{type_name} } @type_loop; 
     976    @class_loop = sort { $a->{class_label} cmp $b->{class_label} } @class_loop; 
    969977 
    970978    $app->listing({ 
     
    979987                edit_blog_id => $blog_id, 
    980988            ) : ()), 
    981             type_loop => \@type_loop, 
     989            class_loop => \@class_loop, 
    982990            can_delete_files => $app->user->is_superuser, 
    983991            nav_assets => 1, 
     992            has_expanded_mode => 1, 
    984993        }, 
    985994    }); 
     
    22662275        push @class_loop, { 
    22672276            class_name => $_, 
    2268             class_label => $app->translate($MT::Log::Classes{$_}->class_label)
     2277            class_label => $MT::Log::Classes{$_}->class_label
    22692278        }; 
    22702279    } 
     
    27262735                $q->param($col) : $obj->$col(); 
    27272736        } 
     2737        # Make certain any blog-specific element matches the blog we're 
     2738        # dealing with. If not, call shenanigans. 
     2739        if (defined($blog_id) && (exists $param{blog_id}) && ($blog_id != $obj->blog_id)) { 
     2740            return $app->error($app->translate("Invalid parameter")); 
     2741        } 
     2742 
    27282743        # Set type-specific display parameters 
    27292744        if ($type eq 'entry') { 
     
    31103125            $param{core_itemset_action_loop} = $core_actions || []; 
    31113126            $param{has_itemset_actions} = 
    3112                 ($plugin_actions || $core_actions) ? 1 : 0; 
     3127                (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    31133128 
    31143129            # since MT::App::build_page clobbers it: 
     
    31773192            $param{core_itemset_action_loop} = $core_actions || []; 
    31783193            $param{has_itemset_actions} = 
    3179                 ($plugin_actions || $core_actions) ? 1 : 0; 
     3194                (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    31803195        } elsif ($type eq 'author') { 
    31813196            # TODO: Populate permissions / blogs for this user 
     
    52135228    $param{core_itemset_action_loop} = $core_actions || []; 
    52145229    $param{has_itemset_actions} = 
    5215         ($plugin_actions || $core_actions) ? 1 : 0; 
     5230        (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    52165231 
    52175232    $param{saved} = $q->param('saved'); 
     
    55025517 
    55035518        require MT::Asset; 
    5504         my $img_pkg = MT::Asset->type_class('asset:image'); 
     5519        my $img_pkg = MT::Asset->class_handler('image'); 
    55055520        my $asset = new $img_pkg; 
    55065521        $asset->blog_id($blog_id); 
    5507         $asset->url($thumb); 
     5522        #$asset->url($thumb); 
    55085523        $asset->file_path($t_file); 
    55095524        $asset->file_name($basename); 
     
    55135528        $asset->image_width($thumb_width); 
    55145529        $asset->image_height($thumb_height); 
     5530        $asset->created_by($app->user->id); 
    55155531        $asset->save; 
    55165532 
     
    55755591            $url .= $rel_url_ext; 
    55765592 
    5577             my $img_pkg = MT::Asset->type_class('asset:image'); 
     5593            my $img_pkg = MT::Asset->class_handler('image'); 
    55785594            my $asset = new $img_pkg; 
    55795595            $asset->blog_id($blog_id); 
     
    55825598            $asset->file_name($basename); 
    55835599            $asset->file_ext($blog->file_extension); 
     5600            $asset->created_by($app->user->id); 
    55845601            $asset->save; 
    55855602 
     
    60566073    $param->{commenter_table}[0]{core_itemset_action_loop} = $core_actions || []; 
    60576074    $param->{commenter_table}[0]{has_itemset_actions} = 
    6058         ($plugin_actions || $core_actions) ? 1 : 0; 
     6075        (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    60596076    $param->{commenter_table}[0]{plugin_action_loop} = $app->plugin_actions('list_commenters') || []; 
    60606077    \@data; 
     
    63046321    $param->{template_table}[0]{core_itemset_action_loop} = $core_actions || []; 
    63056322    $param->{template_table}[0]{has_itemset_actions} = 
    6306         ($plugin_actions || $core_actions) ? 1 : 0; 
     6323        (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    63076324    \@data; 
    63086325} 
     
    64116428    $param->{comment_table}[0]{core_itemset_action_loop} = $core_actions || []; 
    64126429    $param->{comment_table}[0]{has_itemset_actions} = 
    6413         ($plugin_actions || $core_actions) ? 1 : 0; 
     6430        (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    64146431    \@data; 
    64156432} 
     
    69006917    $param->{ping_table}[0]{core_itemset_action_loop} = $core_actions || []; 
    69016918    $param->{ping_table}[0]{has_itemset_actions} = 
    6902         ($plugin_actions || $core_actions) ? 1 : 0; 
     6919        (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    69036920    \@data; 
    69046921} 
     
    72527269    $param->{entry_table}[0]{core_itemset_action_loop} = $core_actions || []; 
    72537270    $param->{entry_table}[0]{has_itemset_actions} = 
    7254         ($plugin_actions || $core_actions) ? 1 : 0; 
     7271        (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    72557272    \@data; 
    72567273} 
     
    73647381        $obj = MT::Entry->load($id) 
    73657382            || return $app->error($app->translate("No such entry.")); 
     7383        return $app->error($app->translate("Invalid parameter")) 
     7384            unless $obj->blog_id == $blog_id; 
    73667385        return $app->error($app->translate("Permission denied.")) 
    73677386            unless $perms->can_edit_entry($obj, $author); 
     
    78077826    $param{core_itemset_action_loop} = $core_actions || []; 
    78087827    $param{has_itemset_actions} = 
    7809         ($plugin_actions || $core_actions) ? 1 : 0; 
     7828        (scalar(@$plugin_actions) || scalar(@$core_actions)) ? 1 : 0; 
    78107829    $param{nav_categories} = 1; 
    78117830    $app->add_breadcrumb($app->translate('Categories')); 
     
    92739292    $param{is_image} = defined($w) && defined($h); 
    92749293    require File::Basename; 
    9275     $basename = File::Basename::basename($local_file); 
     9294    my $local_basename = File::Basename::basename($local_file); 
    92769295    my $ext = ''; 
    92779296    if ($local_file =~ m/\.([A-Za-z]+)$/) { 
     
    92809299 
    92819300    require MT::Asset; 
    9282     my $img_pkg = MT::Asset->type_class($param{is_image} ? 'asset:image' : 'asset'); 
     9301    my $img_pkg = MT::Asset->class_handler($param{is_image} ? 'image' : 'file'); 
    92839302    my $asset = new $img_pkg; 
    92849303    $asset->blog_id($blog_id); 
    92859304    $asset->url($url); 
    92869305    $asset->file_path($local_file); 
    9287     $asset->file_name($basename); 
     9306    $asset->file_name($local_basename); 
    92889307    $asset->file_ext($ext); 
    92899308    if ($param{is_image}) { 
     
    92919310        $asset->image_height($h); 
    92929311    } 
     9312    $asset->created_by($app->user->id); 
    92939313    $asset->save; 
    92949314 
     
    95209540    ## on it if it's there. 
    95219541    if (defined $search) { 
     9542        my $enc = MT::ConfigMgr->instance->PublishCharset; 
     9543        $search = MT::I18N::encode_text($search, 'utf-8', $enc) if ($enc !~ m/utf-?8/i) && ('dialog_grant_role' eq $app->param('__mode')); 
    95229544        $search = quotemeta($search) unless $is_regex; 
    95239545        $search = '(?i)' . $search unless $case; 
     
    95359557            $terms{'type'} = MT::Author::AUTHOR(); 
    95369558            if ('dialog_grant_role' eq $app->param('__mode')) { 
    9537                 @cols = qw(name)
     9559                @cols = qw(name nickname email url)
    95389560            } elsif ($blog_id) { 
    95399561                $args{'join'} = MT::Permission->join_on('author_id', { blog_id => $blog_id } ); 
  • branches/wheeljack/lib/MT/App/Comments.pm

    r717 r752  
    633633    my %params = @_; 
    634634    require MT::Author; 
    635     my $cmntr = MT::Author->load({ name => $params{nickname}, 
     635    my $cmntr = MT::Author->load({ name => $params{name}, 
    636636                                   type => MT::Author::COMMENTER }); 
    637637    if (!$cmntr) { 
     
    647647    } else { 
    648648        $cmntr->set_values({email => $params{email}, 
    649                             nickname => $params{name}, 
     649                            nickname => $params{nickname}, 
    650650                            password => "(none)", 
    651651                            type => MT::Author::COMMENTER, 
  • branches/wheeljack/lib/MT/Asset.pm

    r734 r752  
    99use strict; 
    1010use MT::Tag; 
    11 use base qw(MT::FileInfo MT::Taggable); 
     11use base qw(MT::Object MT::Taggable); 
     12 
     13__PACKAGE__->install_properties({ 
     14    column_defs => { 
     15        'id' => 'integer not null auto_increment', 
     16        'class' => 'string(255)', 
     17        'blog_id' => 'integer not null', 
     18        'label' => 'string(255)', 
     19        'url' => 'string(255)', 
     20        'description' => 'text', 
     21        'file_path' => 'string(255)', 
     22        'file_name' => 'string(255)', 
     23        'file_ext' => 'string(20)', 
     24        'mime_type' => 'string(255)', 
     25        'image_width' => 'integer', 
     26        'image_height' => 'integer', 
     27        'duration' => 'integer', 
     28        'parent' => 'integer', 
     29    }, 
     30    indexes => { 
     31        blog_id => 1, 
     32        url => 1, 
     33        label => 1, 
     34        file_path => 1, 
     35        class => 1, 
     36        parent => 1, 
     37        created_by => 1, 
     38        created_on => 1, 
     39    }, 
     40    audit => 1, 
     41    datasource => 'asset', 
     42    primary_key => 'id', 
     43}); 
    1244 
    1345# A registry of mappings between asset identifiers and packages. 
    1446our %Classes = ( 
    15     'MT::Asset::Image' => 'asset:image', 
     47    'image' => 'MT::Asset::Image', 
     48    'file' => 'MT::Asset', 
    1649); 
    1750our %Types = ( 
    18     'asset:image' => 'MT::Asset::Image', 
     51    'MT::Asset::Image' => 'image', 
     52    'MT::Asset' => 'file', 
    1953); 
     54 
     55sub set_defaults { 
     56    my $obj = shift; 
     57    my $pkg = ref $obj; 
     58    $obj->class($pkg->class); 
     59} 
     60 
     61sub class { 
     62    my $pkg = shift; 
     63    return $pkg->SUPER::class(@_) if ref $pkg; 
     64    $Types{ref $pkg || $pkg} || 'file'; 
     65} 
    2066 
    2167# Returns the list of registered asset identifiers for this class 
    2268# and those that derive from it. Also includes the type of the package 
    2369# invoked. 
    24 sub types { 
    25     my $pkg = shift; 
    26     my $this_type = $pkg->type; 
    27     my @types = keys %Types; 
    28     @types = grep { m/^\Q$this_type\E:/ } @types; 
    29     push @types, $this_type; 
    30     \@types; 
     70sub classes { 
     71    my $pkg = shift; 
     72    my $this_class = $pkg->class; 
     73    my @classes = values %Types; 
     74    if ($this_class ne 'file') { 
     75        @classes = grep { m/^\Q$this_class\E:/ } @classes; 
     76        push @classes, $this_class; 
     77    } 
     78    \@classes; 
    3179} 
    3280 
    3381# Allows registration (or replacement) of an asset type. 
    34 sub add_type { 
    35     my $pkg = shift; 
    36     my ($type, $class) = @_; 
    37     if (exists $Types{$type}) { 
    38         delete $Classes{$Types{$type}}; 
    39     } 
    40     $Types{$type} = $class; 
    41     $Classes{$class} = $type; 
     82sub add_class { 
     83    my $pkg = shift; 
     84    my ($ident, $package) = @_; 
     85    if (exists $Classes{$ident}) { 
     86        delete $Types{$Classes{$ident}}; 
     87    } 
     88    $Classes{$ident} = $package; 
     89    $Types{$package} = $ident; 
     90
     91 
     92sub extensions { 
     93    undef; 
     94
     95 
     96# This property is a meta-property. 
     97sub url { 
     98    my $asset = shift; 
     99    my $url = $asset->SUPER::url(@_); 
     100    return $url if defined $url; 
     101 
     102    return $asset->cache_property(sub { 
     103        my $blog = $asset->blog or return undef; 
     104        my $url = $blog->site_url; 
     105        $url .= '/' unless $url =~ m!/$!; 
     106        my $path = $asset->file_path; 
     107        $path =~ s!\\!/!g; 
     108        $url .= $path; 
     109        $url; 
     110    }, @_); 
    42111} 
    43112 
     
    48117# available, this will at least offer the generic package to access the 
    49118# asset.) 
    50 sub type_class { 
    51     my $pkg = shift; 
    52     my ($type) = @_; 
    53     return 'MT::Asset' if $type eq 'asset'; 
    54     my $class = $Types{$type}; 
    55     if ($class) { 
    56         eval "use $class;"; 
    57         return $class unless $@; 
     119sub class_handler { 
     120    my $pkg = shift; 
     121    my ($class) = @_; 
     122    my $package = $Classes{$class}; 
     123    if ($package) { 
     124        if (defined *{$package.'::'}) { 
     125            return $package; 
     126        } else { 
     127            eval "use $package;"; 
     128            return $package unless $@; 
     129        } 
    58130    } 
    59131    __PACKAGE__; 
     
    61133 
    62134# Returns a hashref of asset identifiers mapped to the localized string 
    63 # used to name them. (Ie, asset:image => 'Image'). 
    64 sub type_names { 
    65     my $pkg = shift; 
    66     my %names = ($pkg->type => $pkg->type_name)
    67     foreach (keys %Types) { 
    68         my $class = $pkg->type_class($_); 
    69         $names{$class->type} = $class->type_name
     135# used to name them. (Ie, image => 'Image'). 
     136sub class_labels { 
     137    my $pkg = shift; 
     138    my %names
     139    foreach (keys %Classes) { 
     140        my $class = $pkg->class_handler($_); 
     141        $names{$class->class} = $class->class_label
    70142    } 
    71143    \%names; 
    72 } 
    73  
    74 # Initializes the MT::Asset object (which is actually a MT::FileInfo object), 
    75 # assigning a generic asset_type to it. 
    76 sub init { 
    77     my $asset = shift; 
    78     $asset->SUPER::init(@_); 
    79     my $type = $asset->type; 
    80     $asset->archive_type($asset->type); 
    81     $asset; 
    82 } 
    83  
    84 # Returns the asset type identifier; for generic MT::Asset, this is just 
    85 # 'asset' 
    86 sub type { 
    87     'asset'; 
    88144} 
    89145 
    90146# Returns a localized name for the asset type. For MT::Asset, this is simply 
    91147# 'File'. 
    92 sub type_name
     148sub class_label
    93149    MT->translate('File'); 
    94150} 
     
    99155    my $obj = shift; 
    100156    $obj->SUPER::set_values(@_); 
    101     my $at = $obj->archive_type
    102     if (my $pkg = $obj->type_class($at)) { 
     157    my $t = $obj->class
     158    if (my $pkg = $obj->class_handler($t)) { 
    103159        bless $obj, $pkg; 
    104160    } 
    105161    $obj; 
    106 } 
    107  
    108 # Calls the standard MT::Object::load routine, but sets the 
    109 # archive_type, if unset. This restricts the load to include only 
    110 # the assets that match the package requested. Note that this will 
    111 # exclude by default all other asset types, even if you use 
    112 # MT::Asset->load. To include all asset types, the archive_type 
    113 # load term should be set to the value of MT::Asset->types. 
    114 sub load { 
    115     my $pkg = shift; 
    116     my ($terms, $args) = @_; 
    117     if ($terms && (!ref($terms))) { 
    118         $terms = { id => $terms }; 
    119     } else { 
    120         $terms ||= {}; 
    121     } 
    122     $terms->{archive_type} ||= $pkg->type; 
    123     $pkg->SUPER::load(@_); 
    124 } 
    125  
    126 # See notes for the load method. 
    127 sub load_iter { 
    128     my $pkg = shift; 
    129     my ($terms, $args) = @_; 
    130     if ($terms && (!ref($terms))) { 
    131         $terms = { id => $terms }; 
    132     } else { 
    133         $terms ||= {}; 
    134     } 
    135     $terms->{archive_type} ||= $pkg->type; 
    136     $pkg->SUPER::load_iter(@_); 
    137162} 
    138163 
     
    147172 
    148173# Removes the asset, associated tags and related file. 
     174# TBD: Should we track and remove any generated thumbnail files here too? 
    149175sub remove { 
    150176    my $asset = shift; 
     
    160186} 
    161187 
     188sub blog { 
     189    my $asset = shift; 
     190    $asset->cache_property(sub { 
     191        my $blog_id = $asset->blog_id or return undef; 
     192        require MT::Blog; 
     193        MT::Blog->load($blog_id, { cached_ok => 1 }); 
     194    }); 
     195} 
     196 
     197# Returns a true/false response based on whether the active package 
     198# has extensions registered that match the requested filename. 
     199sub can_handle { 
     200    my $pkg = shift; 
     201    my ($filename) = @_; 
     202    my $ext = lc $filename; 
     203    $ext =~ s/.*\.//; 
     204    my $extensions = $pkg->extensions or return 0; 
     205    foreach my $this_ext (@$extensions) { 
     206        if (ref $this_ext eq 'Regexp') { 
     207            return 1 if $ext =~ m/$this_ext/; 
     208        } elsif ($this_ext eq $ext) { 
     209            return 1; 
     210        } 
     211    } 
     212    0; 
     213} 
     214 
     215# Given a filename, returns an appropriate MT::Asset class to associate 
     216# with it. This lookup is based purely on file extension! If none can 
     217# be found, it returns MT::Asset. 
     218sub handler_for_file { 
     219    my $pkg = shift; 
     220    my ($filename) = @_; 
     221    my $classes = $pkg->classes || []; 
     222    foreach my $class (@$classes) { 
     223        my $this_pkg = $pkg->class_handler($class); 
     224        if ($this_pkg->can_handle($filename)) { 
     225            return $this_pkg; 
     226        } 
     227    } 
     228    __PACKAGE__; 
     229} 
     230 
     231sub metadata { 
     232    my $asset = shift; 
     233    return { 
     234        MT->translate("Tags") => MT::Tag->join(',', $asset->tags), 
     235        url => $asset->url, 
     236        file => $asset->file_path, 
     237        name => $asset->file_name, 
     238        'class' => $asset->class, 
     239        ext => $asset->file_ext, 
     240        mime_type => $asset->mime_type, 
     241        duration => $asset->duration, 
     242    }; 
     243} 
     244 
     245sub thumbnail_file { 
     246    undef; 
     247} 
     248 
     249sub stock_icon_url { 
     250    undef; 
     251} 
     252 
     253sub thumbnail_url { 
     254    my $asset = shift; 
     255    my $file_path = $asset->thumbnail_file(@_); 
     256    if ((defined $file_path) && (-f $file_path)) { 
     257        require File::Basename; 
     258        my ($base) = File::Basename::basename($file_path); 
     259        my $url = $asset->url; 
     260        my $file = $asset->file_name; 
     261        $url =~ s/%([A-F0-9]{2})/chr(hex($1))/gei; 
     262        $url =~ s!\Q$file\E$!$base!; 
     263        return $url; 
     264    } 
     265    # Use a stock icon 
     266    return $asset->stock_icon_url(@_); 
     267} 
     268 
    1622691; 
     270 
     271__END__ 
     272 
     273=head1 NAME 
     274 
     275MT::Asset 
     276 
     277=head1 SYNOPSIS 
     278 
     279    use MT::Asset; 
     280 
     281    # Example 
     282 
     283=head1 DESCRIPTION 
     284 
     285This module provides an object definition for a file that is placed under 
     286MT's control for publishing. 
     287 
     288=head1 METHODS 
     289 
     290=head2 MT::Asset->new 
     291 
     292Constructs a new asset object. The base class is the generic asset object, 
     293which represents a generic file. 
     294 
     295=head2 MT::Asset->handler_for_file($filename) 
     296 
     297Returns a I<MT::Asset> package suitable for the filename given. This 
     298determination is typically made based on the file's extension. 
     299 
     300=head1 AUTHORS & COPYRIGHT 
     301 
     302Please see the I<MT> manpage for author, copyright, and license information. 
     303 
     304=cut 
  • branches/wheeljack/lib/MT/Asset/Image.pm

    r733 r752  
    99use base 'MT::Asset'; 
    1010 
    11 sub type { 
    12     'asset:image'; 
     11# List of supported file extensions (to aid the stock 'can_handle' method.) 
     12sub extensions { 
     13    ['gif', 'jpg', 'jpeg', 'png']; 
    1314} 
    1415 
    15 sub type_name
     16sub class_label
    1617    MT->translate('Image'); 
    1718} 
     
    1920sub metadata { 
    2021    my $obj = shift; 
    21     { height => $obj->image_height, width => $obj->image_width }; 
     22    my $meta = $obj->SUPER::metadata(@_); 
     23    $meta->{MT->translate("Dimensions")} = MT->translate("[_1] wide, [_2] high", 
     24        $obj->image_width, $obj->image_height); 
     25    $meta; 
     26
     27 
     28sub thumbnail_file { 
     29    my $asset = shift; 
     30    my (%param) = @_; 
     31    my $file_path = $asset->file_path; 
     32    my @imginfo = stat($file_path); 
     33    return undef unless @imginfo; 
     34 
     35    my $h = $param{Height}; 
     36    my $w = $param{Width}; 
     37    require File::Basename; 
     38    my $path = File::Basename::dirname($file_path); 
     39    my $file = $asset->file_name; 
     40    $file =~ s!\.[a-z]+$!!i; 
     41    $thumbnail = File::Spec->catfile($path, $file . '-thumb-' . $h . 'x' . $w . '.' . $asset->file_ext); 
     42    my @thumbinfo = stat($thumbnail); 
     43 
     44    # thumbnail file exists and is dated on or later than source image 
     45    if (@thumbinfo && ($thumbinfo[9] >= $imginfo[9])) { 
     46        return $thumbnail; 
     47    } 
     48 
     49    # stale or non-existent thumbnail. let's create one! 
     50    my $blog = $param{Blog}; 
     51    $blog ||= MT::Blog->load($asset->blog_id, { cached_ok => 1 }); 
     52    return undef unless $blog; 
     53    my $fmgr = $blog->file_mgr; 
     54    return undef unless $fmgr; 
     55 
     56    # create a thumbnail for this file 
     57    require MT::Image; 
     58    my $img = new MT::Image(Filename => $file_path) 
     59        or return $asset->error(MT::Image->errstr); 
     60 
     61    # 100000px wide image, 10px tall => 164x230 
     62    #     scale the horizontal to fit 
     63    # 100000px tall image, 10px wide => 164x230 
     64    #     scale the vertical to fit 
     65    # 100000px wide/tall => 164x230 
     66    #     scale the horizontal to fit 
     67 
     68    # find the longest dimension of the image: 
     69    my ($i_h, $i_w) = ($img->{height}, $img->{width}); 
     70    my ($n_h, $n_w) = ($i_h, $i_w); 
     71    my $scale = ''; 
     72    if ($i_h > $i_w) { 
     73        # scale, if necessary, by height 
     74        if ($i_h > $h) { 
     75            $scale = 'h'; 
     76        } elsif ($i_w > $w) { 
     77            $scale = 'w'; 
     78        } 
     79    } else { 
     80        # scale, if necessary, by width 
     81        if ($i_w > $w) { 
     82            $scale = 'w'; 
     83        } elsif ($i_h > $h) { 
     84            $scale = 'h'; 
     85        } 
     86    } 
     87    if ($scale eq 'h') { 
     88        # scale by height 
     89        $n_w = int($i_h * $h / $i_h); 
     90        $n_h = $h; 
     91    } elsif ($scale eq 'w') { 
     92        # scale by width 
     93        $n_w = $w; 
     94        $n_h = int($i_h * $w / $i_w); 
     95    } 
     96 
     97    my ($data) = $img->scale(Height => $n_h, Width => $n_w) 
     98        or return $asset->error(MT->translate("Error scaling image: [_1]", $img->errstr)); 
     99    $fmgr->put_data($data, $thumbnail, 'upload') 
     100        or return $asset->error(MT->translate("Error creating thumbnail file: [_1]", $fmgr->errstr)); 
     101    return $thumbnail; 
    22102} 
    23103 
    241041; 
     105 
     106__END__ 
     107 
     108=head1 NAME 
     109 
     110MT::Asset::Image 
     111 
     112=head1 SYNOPSIS 
     113 
     114    use MT::Asset::Image; 
     115 
     116    # Example 
     117 
     118=head1 DESCRIPTION 
     119 
     120=head1 METHODS 
     121 
     122=head2 MT::Asset::Image->class 
     123 
     124Returns 'image', the identifier for this particular class of asset. 
     125 
     126=head2 MT::Asset::Image->class_label 
     127 
     128Returns the localized descriptive name for this type of asset. 
     129 
     130=head2 MT::Asset::Image->extensions 
     131 
     132Returns an arrayref of file extensions that are supported by this 
     133package. 
     134 
     135=head2 $asset->metadata 
     136 
     137Returns a hashref of metadata values for this asset. 
     138 
     139=head2 $asset->thumbnail_file(%param) 
     140 
     141Creates or retrieves the file path to a thumbnail image appropriate for 
     142the asset. If a thumbnail cannot be created, this routine will return 
     143undef. 
     144 
     145=head1 AUTHORS & COPYRIGHT 
     146 
     147Please see the I<MT> manpage for author, copyright, and license information. 
     148 
     149=cut 
  • branches/wheeljack/lib/MT/Entry.pm

    r751 r752  
    178178    my $entry = shift; 
    179179    $entry->cache_property('trackback', sub { 
    180         MT::Trackback->load({ entry_id => $entry->id }); 
     180        if ($entry->id) { 
     181            return scalar MT::Trackback->load({ entry_id => $entry->id }); 
     182        } 
    181183    }); 
    182184} 
  • branches/wheeljack/lib/MT/FileInfo.pm

    r736 r752  
    1414        'id' => 'integer not null auto_increment', 
    1515        'blog_id' => 'integer not null', 
     16        'entry_id' => 'integer', 
    1617        'url' => 'string(255)', 
    17         'file_path' => 'string(255)', 
    18         'file_name' => 'string(255)', 
    19         'file_ext' => 'string(20)', 
    20         'entry_id' => 'integer', 
     18        'file_path' => 'text', 
    2119        'templatemap_id' => 'integer', 
    2220        'template_id' => 'integer', 
     
    2523        'startdate' => 'string(80)', 
    2624        'virtual' => 'boolean', 
    27         'image_width' => 'integer', 
    28         'image_height' => 'integer', 
    2925    }, 
    3026    indexes => { 
     
    3430        templatemap_id => 1, 
    3531        url => 1, 
    36         file_path => 1, 
    37         archive_type => 1, 
    3832    }, 
    39     audit => 1, 
    4033    datasource => 'fileinfo', 
    4134    primary_key => 'id', 
  • branches/wheeljack/lib/MT/Image.pm

    r717 r752  
    5353    my $image = shift; 
    5454    eval { require Image::Magick }; 
    55     return $image->error(MT->translate("Can't load Image::Magick: [_1]", $@)) 
    56         if $@; 
     55    if (my $err = $@) { 
     56        return $image->error(MT->translate("Can't load Image::Magick: [_1]", $err)); 
     57    } 
    5758    1; 
    5859} 
     
    102103    my $image = shift; 
    103104    eval { require IPC::Run }; 
    104     return $image->error(MT->translate("Can't load IPC::Run: [_1]", $@)) 
    105         if $@; 
     105    if (my $err = $@) { 
     106        return $image->error(MT->translate("Can't load IPC::Run: [_1]", $err)); 
     107    } 
    106108    my $pbm = $image->_find_pbm or return; 
    107109    1; 
  • branches/wheeljack/lib/MT/Object.pm

    r751 r752  
    342342sub cache_property { 
    343343    my $obj = shift; 
    344     my ($key, $code) = @_; 
    345     return $obj->{__cache}{$key} if exists $obj->{__cache}{$key}; 
    346     return undef unless $code; 
    347     $obj->{__cache}{$key} = $code->(); 
     344    my $key = shift; 
     345    my $code = shift; 
     346    if (ref $key eq 'CODE') { 
     347        ($key, $code) = ($code, $key); 
     348    } 
     349    $key ||= (caller(1))[3]; 
     350 
     351    if (@_) { 
     352        $obj->{__cache}{$key} = $_[0]; 
     353    } else { 
     354        if ((!defined $obj->{__cache}{$key}) && $code) { 
     355            $obj->{__cache}{$key} = $code->($obj, @_); 
     356        } 
     357    } 
     358    return exists $obj->{__cache}{$key} ? $obj->{__cache}{$key} : undef; 
    348359} 
    349360 
  • branches/wheeljack/lib/MT/ObjectDriver/DBM.pm

    r742 r752  
    657657        $driver->run_callbacks($class . "::pre_update", $obj, $original); 
    658658    } 
    659     my $class = ref $obj; 
    660659    delete $object_cache{$class}->{$id} if $id && exists $object_cache{$class}->{$id}; # invalidate the cache 
    661660    $original->id($id); 
  • branches/wheeljack/lib/MT/Template/Context.pm

    r717 r752  
    160160 
    161161    if ($cat_expr) { 
     162        my @cols = $cat_expr =~ m!/! ? qw(category_label_path label) : qw(label); 
    162163        my %cats_used; 
    163         # sort in descending order by length 
    164         if ($cat_expr =~ m!/!) { 
    165             # add extra 'path' expression categories 
    166             my @path_cats; 
     164        foreach my $col (@cols) { 
     165            my %cats_replaced; 
     166            @$cats = sort {length($b->$col) <=> length($a->$col)} @$cats; 
     167 
    167168            foreach my $cat (@$cats) { 
    168                 my $catp = $cat->category_label_path; 
    169                 push @path_cats, { label => $catp, id => $cat->id, obj => $cat }; 
    170             } 
    171             @path_cats = sort {length($b->{label}) <=> length($a->{label})} @path_cats; 
    172             foreach (@path_cats) { 
    173                 my $cat = $_->{obj}; 
    174                 my $catp = $_->{label}; 
    175 </