Changeset 2852

Show
Ignore:
Timestamp:
07/29/08 03:46:19 (4 months ago)
Author:
arvind
Message:

Initial refactoring to support drivers to store revision history, e.g. subversion. Driver used is defined via the RevisioningDriver config directive, default: Local

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/feature-revision-histories/lib/MT/Core.pm

    r2747 r2852  
    457457            'UseSQLite2'      => { default => 0, }, 
    458458            'UseJcodeModule'  => { default => 0, }, 
     459            'RevisioningDriver' => { default => 'Local' }, 
    459460            'DefaultTimezone' => { 
    460461                default => '0', 
  • branches/feature-revision-histories/lib/MT/Revisable.pm

    r2850 r2852  
    1212 
    1313our $MAX_REVISIONS = 20; 
     14 
     15{ 
     16my $driver; 
     17sub _driver { 
     18    my $driver_name = 'MT::Revisable::' . MT->config->RevisioningDriver; 
     19    eval 'require ' . $driver_name; 
     20    if (my $err = $@) { 
     21        die (MT->translate("Bad RevisioningDriver config '[_1]': [_2]", $driver_name, $err)); 
     22    } 
     23    my $driver = $driver_name->new; 
     24    die $driver_name->errstr 
     25        if (!$driver || (ref(\$driver) eq 'SCALAR')); 
     26    return $driver; 
     27} 
     28 
     29sub _handle { 
     30    my $method = ( caller(1) )[3]; 
     31    $method =~ s/.*:://; 
     32    my $driver = $driver ||= _driver(); 
     33    return undef unless $driver->can($method); 
     34    $driver->$method(@_); 
     35} 
     36 
     37sub release { 
     38    undef $driver; 
     39} 
     40} 
    1441 
    1542sub install_properties { 
     
    4673} 
    4774 
    48 sub revision_pkg { 
    49     my $class = shift; 
    50     my $props = $class->properties; 
    51  
    52     return $props->{revision_pkg} if $props->{revision_pkg}; 
    53  
    54     my $rev = ref $class || $class; 
    55     $rev .= '::Revision'; 
    56      
    57     return $props->{revision_pkg} = $rev; 
    58 
    59  
    60 sub revision_props { 
    61     my $class = shift; 
    62     my $obj_ds = $class->datasource; 
    63     my $obj_id = $obj_ds . '_id'; 
    64     return { 
    65         key         => $class->datasource, 
    66         column_defs => { 
    67             id      => 'integer not null auto_increment', 
    68             $obj_id => 'integer not null', 
    69             $obj_ds => 'blob not null', 
    70             rev_number => 'integer not null', 
    71             changed => 'string(255) not null' 
    72         }, 
    73         indexes => { 
    74             $obj_id => 1 
    75         }, 
    76         defaults => { 
    77             rev_number => 0 
    78         }, 
    79         audit => 1, 
    80         primary_key => 'id', 
    81         datasource  => $class->datasource . '_rev' 
    82     }; 
    83 
    84  
    85 sub install_revisioning { 
    86     my $class = shift; 
    87     my $datasource = $class->datasource; 
    88      
    89     my $subclass = $class->revision_pkg; 
    90     return unless $subclass; 
    91      
    92     my $rev_props = $class->revision_props; 
    93      
    94     no strict 'refs'; ## no critic 
    95     return if defined ${"${subclass}::VERSION"}; 
    96      
    97     ## Try to use this subclass first to see if it exists 
    98     my $subclass_file = $subclass . '.pm'; 
    99     $subclass_file =~ s{::}{/}g; 
    100     eval "# line " . __LINE__ . " " . __FILE__ . "\nno warnings 'all';require '$subclass_file';$subclass->import();"; 
    101     if ($@) { 
    102         ## Die if we get an unexpected error 
    103         die $@ unless $@ =~ /Can't locate /; 
    104     } else { 
    105         ## This class exists.  We don't need to do anything. 
    106         return 1; 
    107     } 
    108  
    109     my $base_class = 'MT::Object'; 
    110  
    111     my $subclass_src = " 
    112         # line " . __LINE__ . " " . __FILE__ . " 
    113         package $subclass; 
    114         our \$VERSION = 1.0; 
    115         use base qw($base_class); 
    116          
    117         1; 
    118     "; 
    119  
    120     ## no critic ProhibitStringyEval  
    121     eval $subclass_src or print STDERR "Could not create package $subclass!\n"; 
    122  
    123     $subclass->install_properties($rev_props);     
    124 
     75sub revision_pkg { _handle(@_); } 
     76sub revision_props { _handle(@_); } 
     77sub init_revisioning { _handle(@_); } 
    12578 
    12679sub revisioned_columns { 
     
    230183} 
    231184 
    232 sub save_revision { 
    233     my $obj = shift; 
    234     return 1 unless $obj->id; 
    235      
    236     my $changed_cols = $obj->{changed_revisioned_cols}; 
    237     return 1 unless scalar @$changed_cols > 0; 
    238      
    239     my $datasource = $obj->datasource;     
    240     my $obj_id = $datasource . '_id'; 
    241     my $packed_obj = $obj->pack_revision();  
    242      
    243     require MT::Serialize; 
    244     my $rev_class = MT->model($datasource . ':revision'); 
    245     my $revision = $rev_class->new; 
    246     $revision->set_values({ 
    247         $obj_id     => $obj->id, 
    248         $datasource => MT::Serialize->serialize(\$packed_obj), 
    249         changed     => join ',', @$changed_cols 
    250     }); 
    251     $revision->rev_number($obj->current_revision); 
    252     $revision->save or return; 
    253      
    254     return 1; 
    255 
    256  
    257 sub object_from_revision { 
    258     my $obj = shift; 
    259     my ($rev) = @_; 
    260     my $datasource = $obj->datasource; 
    261  
    262     my $rev_obj = $obj->clone; 
    263     my $serialized_obj = $rev->$datasource; 
    264     require MT::Serialize; 
    265     my $packed_obj = MT::Serialize->unserialize($serialized_obj); 
    266     $rev_obj->unpack_revision($$packed_obj); 
    267      
    268     # Here we cheat since audit columns aren't revisioned 
    269     $rev_obj->modified_by($rev->created_by); 
    270     $rev_obj->modified_on($rev->modified_on);     
    271      
    272     my @changed = split ',', $rev->changed; 
    273      
    274     return [ $rev_obj, \@changed, $rev->rev_number]; 
    275 
    276  
    277 sub load_revision { 
     185sub save_revision { _handle(@_); } 
     186sub object_from_revision { _handle(@_); } 
     187sub load_revision { _handle(@_); } 
     188 
     189sub apply_revision { 
    278190    my $obj = shift; 
    279191    my ($terms, $args) = @_; 
    280     my $datasource = $obj->datasource;     
    281     my $rev_class = MT->model($datasource . ':revision'); 
    282  
    283     # Only specified a rev_number 
    284     if(defined $terms && ref $terms ne 'HASH') {  
    285         $terms = { rev_number => $_[0] };          
    286     }     
    287     $terms->{$datasource . '_id'} ||= $obj->id;     
    288      
    289     if ( wantarray ) { 
    290         my @rev = map { $obj->object_from_revision($_); } 
    291             $rev_class->load( $terms, $args ); 
    292         unless (@rev) { 
    293             return $obj->error( $rev_class->errstr ); 
    294         } 
    295         return @rev; 
    296     } 
    297     else { 
    298         my $rev = $rev_class->load( $terms, $args ) 
    299             or return $obj->error( $rev_class->errstr ); 
    300         my $o = $obj->object_from_revision($rev); 
    301         return $o; 
    302     }     
    303 
    304  
    305 sub apply_revision { 
    306     my $obj = shift; 
    307     my ( $rev_id ) = @_; 
    308  
    309     my $rev = $obj->load_revision( $rev_id ) 
     192 
     193    my $rev = $obj->load_revision($terms, $args) 
    310194        or return $obj->error( 
    311195            MT->translate('Revision (ID: [_1]) not found.', $rev_id));