Changeset 1927

Show
Ignore:
Timestamp:
04/16/08 15:36:30 (6 months ago)
Author:
mpaschal
Message:

Land the new implementation of metadata based on narrow tables
BugzID: 68749

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/release-35/build/mt-dists/default.mk

    r1897 r1927  
    22 
    33PRODUCT_VERSION = 4.15 
    4 SCHEMA_VERSION = 4.0054 
     4SCHEMA_VERSION = 4.0055 
    55API_VERSION = 4.15 
    66 
  • branches/release-35/lib/MT.pm.pre

    r1871 r1927  
    5858            no strict 'refs'; 
    5959            unless ( defined *{ $compat . '::' } ) { 
    60                 eval "require $compat;"; 
     60                eval "# line " . __LINE__ . " " . __FILE__ . "\nrequire $compat;"; 
    6161            } 
    6262        } 
     
    267267        return $object_types{$k} if exists $object_types{$k}; 
    268268 
     269        if ($k =~ m/^(.+):meta$/) { 
     270            my $ppkg = $pkg->model($1); 
     271            my $mpkg = $ppkg->meta_pkg; 
     272            return $mpkg ? $object_types{$k} = $mpkg : undef; 
     273        } 
     274 
    269275        my $model = $pkg->registry( 'object_types', $k ); 
    270276        if ( ref($model) eq 'ARRAY' ) { 
     
    287293        unless ( defined *{ $model . '::__properties' } ) { 
    288294            use strict 'refs'; 
    289             eval "require $model;"; 
     295            eval "# line " . __LINE__ . " " . __FILE__ . "\nrequire $model;"; 
    290296            if ( $@ && ( $k =~ m/^(.+)\./ ) ) { 
    291297 
     
    612618 
    613619    $cb->error();    # reset the error string 
    614     my $result = eval { $cb->invoke(@args) }; 
     620    my $result = eval { 
     621        # line __LINE__ __FILE__ 
     622        $cb->invoke(@args); 
     623    }; 
    615624    if ( my $err = $@ ) { 
    616625        $cb->error($err); 
     
    12621271                    $Plugins{$plugin_sig}{full_path} = $plugin_full_path; 
    12631272                    $timer->pause_partial if $timer; 
    1264                     eval { require $plugin }
     1273                    eval "# line " . __LINE__ . " " . __FILE__ . "\nrequire '$plugin';"
    12651274                    $timer->mark("Loaded plugin " . $sig) if $timer; 
    12661275                    if ($@) { 
     
    12701279                        # the database has been initialized... 
    12711280                        eval { 
     1281                            # line __LINE__ __FILE__ 
    12721282                            require MT::Log; 
    12731283                            $mt->log( 
     
    25882598            if ($method) { 
    25892599                return sub { 
    2590                     eval "require $hdlr_pkg;" 
     2600                    eval "# line " . __LINE__ . " " . __FILE__ . "\nrequire $hdlr_pkg;" 
    25912601                      or Carp::confess( 
    25922602                        "failed loading package $hdlr_pkg for routine $name: $@"); 
     
    25992609            else { 
    26002610                return sub { 
    2601                     eval "require $hdlr_pkg;" 
     2611                    eval "# line " . __LINE__ . " " . __FILE__ . "\nrequire $hdlr_pkg;" 
    26022612                      or Carp::confess( 
    26032613                        "failed loading package $hdlr_pkg for routine $name: $@"); 
     
    26132623        } 
    26142624        else { 
    2615             eval "require $hdlr_pkg;" 
     2625            eval "# line " . __LINE__ . " " . __FILE__ . "\nrequire $hdlr_pkg;" 
    26162626              or Carp::confess( 
    26172627                "failed loading package $hdlr_pkg for routine $name: $@"); 
  • branches/release-35/lib/MT/Asset/Image.pm

    r1829 r1927  
    1010use base qw( MT::Asset ); 
    1111 
    12 __PACKAGE__->install_properties( { class_type => 'image', } ); 
    13 __PACKAGE__->install_meta( { columns => [ 'image_width', 'image_height', ], } ); 
     12__PACKAGE__->install_properties( { 
     13    class_type => 'image', 
     14    column_defs => { 
     15        'image_width' => 'integer meta', 
     16        'image_height' => 'integer meta', 
     17    }, 
     18} ); 
    1419 
    1520# List of supported file extensions (to aid the stock 'can_handle' method.) 
  • branches/release-35/lib/MT/Author.pm

    r1823 r1927  
    3737        'userpic_asset_id' => 'integer', 
    3838        'basename' => 'string(255)', 
     39 
     40        # meta properties 
     41        'widgets' => 'hash meta', 
     42        'favorite_blogs' => 'array meta', 
    3943    }, 
    4044    defaults => { 
     
    5963    audit => 1, 
    6064}); 
    61 __PACKAGE__->install_meta({ 
    62     columns => [ 
    63         'favorite_blogs', 
    64         'widgets', 
    65     ], 
    66 }); 
    6765 
    6866sub class_label { 
     
    263261    die unless $perms->isa('MT::Permission'); 
    264262    $perms->can_edit_all_posts || 
    265     ($perms->can_create_post && $entry->author_id == $author->id); 
     263        ($perms->can_create_post && $entry->author_id == $author->id); 
    266264} 
    267265 
  • branches/release-35/lib/MT/Blog.pm

    r1868 r1927  
    7777        'archive_tmpl_category' => 'string(255)', 
    7878        'archive_tmpl_individual' => 'string(255)', 
     79 
     80        # meta properties 
     81        'image_default_wrap_text' => 'integer meta', 
     82        'image_default_align' => 'string meta', 
     83        'image_default_thumb' => 'integer meta', 
     84        'image_default_width' => 'integer meta', 
     85        'image_default_wunits' => 'integer meta', 
     86        'image_default_constrain' => 'integer meta', 
     87        'image_default_popup' => 'integer meta', 
     88        'commenter_authenticators' => 'string meta', 
     89        'require_typekey_emails' => 'integer meta', 
     90        'nofollow_urls' => 'integer meta', 
     91        'follow_auth_links' => 'integer meta', 
     92        'update_pings' => 'integer meta', 
     93        'captcha_provider' => 'string meta', 
     94        'publish_queue' => 'integer meta', 
     95        'nwc_smart_replace' => 'integer meta', 
     96        'nwc_replace_field' => 'string meta', 
     97        'template_set' => 'string meta', 
     98        'page_layout' => 'string meta', 
     99        'include_system' => 'integer meta', 
     100        'include_cache' => 'integer meta', 
    79101    }, 
    80102    meta => 1, 
     
    93115    datasource => 'blog', 
    94116    primary_key => 'id', 
    95 }); 
    96 __PACKAGE__->install_meta({ 
    97     columns => [ 
    98         'image_default_wrap_text', 
    99         'image_default_align', 
    100         'image_default_thumb', 
    101         'image_default_width', 
    102         'image_default_wunits', 
    103         'image_default_constrain', 
    104         'image_default_popup', 
    105         'commenter_authenticators', 
    106         'require_typekey_emails', 
    107         'nofollow_urls', 
    108         'follow_auth_links', 
    109         'update_pings', 
    110         'captcha_provider', 
    111         'publish_queue', 
    112         'nwc_smart_replace', 
    113         'nwc_replace_field', 
    114         'template_set', 
    115         'page_layout', 
    116         'include_system', 
    117         'include_cache', 
    118     ], 
    119117}); 
    120118 
  • branches/release-35/lib/MT/Component.pm

    r1572 r1927  
    508508 
    509509                # check for a yaml file reference... 
    510                 if ( !ref($v) && ( $v =~ m/^[-\w]+\.yaml$/ ) ) { 
    511                     my $f = File::Spec->catfile( $c->path, $v ); 
    512                     if ( -f $f ) { 
    513                         require YAML::Tiny; 
    514                         my $y = eval { YAML::Tiny->read($f) } 
    515                             or die "Error reading $f: " . $YAML::Tiny::errstr; 
    516  
    517                         # skip over non-hash elements 
    518                         shift @$y while @$y && ( ref( $y->[0] ) ne 'HASH' ); 
    519                         if (@$y) { 
    520                             $r->{$p} = $y->[0]; 
     510                if ( !ref($v) ) { 
     511                    if ( $v =~ m/^[-\w]+\.yaml$/ ) { 
     512                        my $f = File::Spec->catfile( $c->path, $v ); 
     513                        if ( -f $f ) { 
     514                            require YAML::Tiny; 
     515                            my $y = eval { YAML::Tiny->read($f) } 
     516                                or die "Error reading $f: " 
     517                                    . $YAML::Tiny::errstr; 
     518                            # skip over non-hash elements 
     519                            shift @$y 
     520                                while @$y && ( ref( $y->[0] ) ne 'HASH' ); 
     521                            $r->{$p} = $y->[0] if @$y; 
     522                        } 
     523                    } elsif ($v =~ m/^\$\w+::/) { 
     524                        my $code = MT->handler_to_coderef($v); 
     525                        if (ref $code eq 'CODE') { 
     526                            $r->{$p} = $code->($c); 
    521527                        } 
    522528                    } 
  • branches/release-35/lib/MT/Object.pm

    r1873 r1927  
    5353    } 
    5454 
     55    my %meta; 
     56 
    5557    my $super_props = $class->SUPER::properties(); 
     58    $props->{meta} = 1 if $super_props && $super_props->{meta}; 
     59 
     60    if ($props->{meta}) { 
     61        # yank out any meta columns before we start working on column_defs 
     62        $meta{$_} = delete $props->{column_defs}{$_} 
     63            for grep { $props->{column_defs}{$_} =~ m/\bmeta\b/ } 
     64            keys %{ $props->{column_defs} }; 
     65    } 
     66 
    5667    if ($super_props) { 
    5768        # subclass; merge hash 
    58         for (qw(primary_key meta_column class_column datasource driver audit meta)) { 
     69        for (qw(primary_key class_column datasource driver audit)) { 
    5970            $props->{$_} = $super_props->{$_} 
    6071                if exists $super_props->{$_} && !(exists $props->{$_}); 
    6172        } 
    62         for my $p (qw(column_defs defaults indexes meta_columns)) { 
     73        for my $p (qw(column_defs defaults indexes)) { 
    6374            if (exists $super_props->{$p}) { 
    6475                foreach my $k (keys %{ $super_props->{$p} }) { 
     
    8192    # Legacy MT::Object types only define 'columns'; we still support that 
    8293    # but they aren't handled properly with the upgrade system as a result. 
    83     if (exists $props->{column_defs}) { 
    84         $props->{columns} = [ keys %{ $props->{column_defs} } ]; 
    85     } else { 
     94    if (! exists $props->{column_defs}) { 
    8695        map { $props->{column_defs}{$_} = () } @{ $props->{columns} }; 
    8796    } 
     97    $props->{columns} = [ keys %{ $props->{column_defs} } ]; 
    8898 
    8999    # Support audit flags 
     
    98108    } 
    99109 
    100     # Metadata column 
    101     $props->{meta_column} ||= 'meta' if exists $props->{meta}; 
    102     if (my $col = $props->{meta_column}) { 
    103         if (!$props->{column_defs}{$col}) { 
    104             $props->{column_defs}{$col} = 'blob'; 
    105             push @{ $props->{columns} }, $col; 
    106         } 
    107         no strict 'refs'; ## no critic 
    108         *{$class . '::' . $col} = \&__meta_column; 
    109         $class->add_trigger( pre_save => \&pre_save_serialize_metadata ); 
    110     } 
    111  
    112110    # Classed object types 
    113111    $props->{class_column} ||= 'class' if exists $props->{class_type}; 
     
    151149        foreach my $isa_class (@classes) { 
    152150            next if UNIVERSAL::isa($class, $isa_class); 
    153             eval "require $isa_class;" or die; 
     151            eval "# line " . __LINE__ . " " . __FILE__ . "\nrequire $isa_class;" or die; 
    154152            no strict 'refs'; ## no critic 
    155153            push @{$class . '::ISA'}, $isa_class; 
     
    160158            for my $name (keys %$cols) { 
    161159                next if exists $props->{column_defs}{$name}; 
     160                if ($cols->{$name} =~ m/\bmeta\b/) { 
     161                    $meta{$name} = $cols->{$name}; 
     162                    next; 
     163                } 
     164 
    162165                $class->install_column($name, $cols->{$name}); 
    163166                $props->{indexes}{$name} = 1 
     
    226229        no strict 'refs'; ## no critic 
    227230        *{$class . '::driver'} = sub { $_[0]->dbi_driver(@_) }; 
     231    } 
     232 
     233    # inherit parent's metadata setup 
     234    if ($props->{meta}) { # if ($super_props && $super_props->{meta_installed}) { 
     235        $class->install_meta({ ( %meta ? ( column_defs => \%meta ) : ( columns => [] ) ) }); 
     236        $class->add_trigger( post_remove => \&remove_meta ); 
    228237    } 
    229238 
     
    347356            return $package; 
    348357        } else { 
    349             eval "use $package;"; 
     358            eval "# line " . __LINE__ . " " . __FILE__ . "\nuse $package;"; 
    350359            return $package unless $@; 
    351             eval "use $pkg; $package->new;"; 
     360            eval "# line " . __LINE__ . " " . __FILE__ . "\nuse $pkg; $package->new;"; 
    352361            return $package unless $@; 
    353362        } 
     
    373382# 'meta' metadata column support 
    374383 
     384sub new { 
     385    my $class = shift; 
     386    my $obj = $class->SUPER::new(@_); 
     387    if ($obj->properties->{meta_installed}) { 
     388        $obj->init_meta(); 
     389    } 
     390    return $obj; 
     391} 
     392 
     393sub init_meta { 
     394    my $obj = shift; 
     395    require MT::Meta::Proxy; 
     396    $obj->{__meta} = MT::Meta::Proxy->new($obj); 
     397} 
     398 
    375399sub install_meta { 
    376400    my $class = shift; 
    377     my ($props) = @_; 
     401    my ($params) = @_; 
    378402    if ( ( $class ne 'MT::Config' ) && (!$MT::plugins_installed) ) { 
    379         push @PRE_INIT_META, [$class, $props]; 
     403        push @PRE_INIT_META, [$class, $params]; 
    380404        return; 
    381405    } 
    382     my $cprops = $class->properties; 
    383     my $fields = $cprops->{meta_columns} ||= {}; 
    384     my $meta_col = $cprops->{meta_column}; 
    385     foreach my $name (@{ $props->{columns} }) { 
    386         $fields->{$name} = (); 
    387         # Skip adding this method if the class overloads it. 
    388         # this lets the SUPER::columnname magic do it's thing 
    389         unless ($class->can($name)) { 
    390             no strict 'refs'; ## no critic 
    391             *{"${class}::$name"} = sub { shift->$meta_col($name, @_) }; 
    392         } 
    393     } 
     406 
     407    require MT::Meta; 
     408    my $pkg = ref $class || $class; 
     409    if (!$pkg->SUPER::properties->{meta_installed}) { 
     410        $pkg->add_trigger( post_save => \&post_save_save_metadata ); 
     411        $pkg->add_trigger( post_load => \&post_load_initialize_metadata ); 
     412    } 
     413 
     414    my $props = $class->properties; 
     415 
     416    if (!$params->{columns} && !$params->{fields} && !$params->{column_defs}) { 
     417        return $class->error('No meta fields specified to install_meta'); 
     418    } 
     419 
     420    $params->{fields} ||= []; 
     421    if (my $cols = delete $params->{columns}) { 
     422        foreach my $col (@$cols) { 
     423            push @{ $params->{fields} }, { 
     424                name => $col, 
     425                type => 'vblob', 
     426            }; 
     427            # $props->{fields}{$col} = 'vblob'; 
     428        } 
     429    } 
     430    if (my $cols = delete $params->{column_defs}) { 
     431        foreach my $col ( keys %$cols ) { 
     432            my $type = $cols->{$col}; 
     433            $type =~ s/\s.*//; # take first keyword, ignoring anything after 
     434            $type .= '_indexed' 
     435                if $cols->{$col} =~ m/\bindexed\b/; 
     436            $type = MT::Meta->normalize_type($type); 
     437 
     438            push @{ $params->{fields} }, { 
     439                name => $col, 
     440                type => $type, 
     441            }; 
     442            # $props->{fields}{$col} = $type; 
     443        } 
     444    } 
     445 
     446    $params->{datasource} ||= $class->datasource . '_meta'; 
     447 
     448    if ($props->{meta_installed} && !@{ $params->{fields} }) { 
     449        return 1; 
     450    } 
     451 
     452    if (my $fields = MT::Meta->install($pkg, $params)) { 
     453        # we may have inherited meta fields so lets update with 
     454        # the fields returned by MT::Meta 
     455        $props->{fields} = $fields; 
     456    } 
     457 
     458    return $props->{meta_installed} = 1; 
     459
     460 
     461sub meta_args { 
     462    my $class = shift; 
     463    my $id_field = $class->datasource . '_id'; 
     464    return { 
     465        key         => $class->datasource, 
     466        column_defs => { 
     467            $id_field         => 'integer not null', 
     468            type              => 'string(255) not null', 
     469            vchar             => 'string(255)', 
     470            vchar_indexed     => 'string(255)', 
     471            vdatetime         => 'datetime', 
     472            vdatetime_indexed => 'datetime', 
     473            vinteger          => 'integer', 
     474            vinteger_indexed  => 'integer', 
     475            vfloat            => 'float', 
     476            vfloat_indexed    => 'float', 
     477            vblob             => 'blob', 
     478            vclob             => 'text', 
     479        }, 
     480        columns => [ $id_field, qw( 
     481            type 
     482            vchar 
     483            vchar_indexed 
     484            vdatetime 
     485            vdatetime_indexed 
     486            vinteger 
     487            vinteger_indexed 
     488            vfloat 
     489            vfloat_indexed 
     490            vblob 
     491            vclob 
     492        ) ], 
     493        indexes => { 
     494            $id_field => 1, 
     495            id_type   => { columns => [ $id_field, 'type' ] }, 
     496            id_type_vchar => { columns => [ $id_field, 'type', 'vchar_indexed' ] }, 
     497            id_type_vdatetime => { columns => [ $id_field, 'type', 
     498                'vdatetime_indexed' ] }, 
     499            id_type_vinteger => { columns => [ $id_field, 'type', 
     500                'vinteger_indexed' ] }, 
     501            id_type_vfloat => { columns => [ $id_field, 'type', 
     502                'vfloat_indexed' ] }, 
     503        }, 
     504        primary_key => [ $class->datasource . '_id', 'type' ], 
     505    }; 
    394506} 
    395507 
    396508sub has_meta { 
    397     my $props = $_[0]->properties; 
    398     return $props->{meta} && (@_ > 1 ? exists $props->{meta_columns}{$_[1]} : 1); 
    399 
    400  
    401 sub pre_save_serialize_metadata { 
    402     my ($obj) = shift; 
    403     my $meta_col = $obj->properties->{meta_column}; 
    404     if ($obj->{changed_cols}{$meta_col}) { 
    405         require MT::Serialize; 
    406         my $meta = $obj->$meta_col; 
    407         $obj->$meta_col(MT::Serialize->serialize(\$meta)); 
    408     } 
    409 
    410  
    411 sub __thaw_meta { 
    412     my ($meta) = @_; 
    413     $$meta = '' unless defined $$meta; 
    414     require MT::Serialize; 
    415     my $out = MT::Serialize->unserialize($$meta); 
    416     if (ref $out eq 'REF') { 
    417         return $$out; 
    418     } else { 
    419         return {}; 
    420     } 
    421 
    422  
    423 # $obj->meta returns a hashref of metadata information 
    424 # $obj->meta($scalar) allows assignment of a serialized value 
    425 # $obj->meta('name', 'value') assigns an individual metadata element 
    426 # $obj->meta('name') returns an individual metadata value 
    427 # $obj->save will automatically serialize the metadata back to the database 
    428 sub __meta_column { 
    429     my $obj = shift; 
    430     my $meta_col = $obj->properties->{meta_column} or return; 
    431  
    432     if (@_) { 
    433         my $var = shift; 
    434         if ((defined $var) && ($var =~ m/^SERG\0\0\0\0/)) { 
    435             return $obj->column($meta_col, $var); 
    436         } 
    437         my $meta = $obj->column($meta_col); 
    438         if (!defined($meta)) { 
    439             $obj->{column_values}{$meta_col} = $meta = {}; 
    440         } elsif (!ref $meta) { 
    441             $obj->{column_values}{$meta_col} = $meta = __thaw_meta(\$meta); 
    442         } 
     509    my $obj = shift; 
     510    return $obj->is_meta_column(@_) if @_; 
     511    return $obj->properties->{meta_installed} ? 1 : 0; 
     512
     513 
     514sub post_load_initialize_metadata { 
     515    my $obj = shift; 
     516    if (defined $obj && $obj->properties->{meta_installed}) { 
     517        $obj->init_meta(); 
     518        $obj->{__meta}->set_primary_keys($obj); 
     519    } 
     520
     521 
     522sub is_meta_column { 
     523    my $obj = shift; 
     524    my ($field) = @_; 
     525 
     526    my $props = $obj->properties; 
     527    return unless $props->{meta_installed}; 
     528 
     529    my $meta = $obj->meta_pkg; 
     530    return 1 if $props->{fields}{$field}; 
     531 
     532    return; 
     533
     534 
     535sub meta_pkg { 
     536    my $class = shift; 
     537    my $props = $class->properties; 
     538    return unless $props->{meta}; # this only works for meta-enabled classes 
     539 
     540    return $props->{meta_pkg} if $props->{meta_pkg}; 
     541 
     542    my $meta = ref $class || $class; 
     543    $meta .= '::Meta'; 
     544    return $props->{meta_pkg} = $meta; 
     545
     546 
     547sub has_column { 
     548    my $obj = shift; 
     549    return 1 if $obj->SUPER::has_column(@_); 
     550    return 1 if $obj->is_meta_column(@_); 
     551    return; 
     552
     553 
     554sub post_save_save_metadata { 
     555    my $obj = shift; 
     556    if (defined $obj && exists $obj->{__meta}) { 
     557        $obj->{__meta}->set_primary_keys($obj); 
     558        $obj->{__meta}->save; 
     559    } 
     560
     561 
     562sub meta { 
     563    my $obj = shift; 
     564    my ($name, $value) = @_; 
     565 
     566    return !$obj->{__meta} ? undef 
     567         : 2 == scalar @_  ? $obj->{__meta}->set($name, $value) 
     568         : 1 == scalar @_  ? $obj->{__meta}->get($name) 
     569         :                   $obj->{__meta}->get_hash 
     570         ; 
     571
     572 
     573sub meta_obj { 
     574    my $obj = shift; 
     575    return $obj->{__meta}; 
     576
     577 
     578sub column_func { 
     579    my $obj = shift; 
     580    my ($col) = @_; 
     581    return if !$col; 
     582 
     583    return $obj->SUPER::column_func(@_) 
     584        if !$obj->is_meta_column($col); 
     585 
     586    return sub { 
     587        my $obj = shift; 
    443588        if (@_) { 
    444             $meta->{$var} = shift if @_; 
    445             $obj->{changed_cols}{$meta_col}++; 
    446         } 
    447         return $meta->{$var}; 
    448     } else { 
    449         my $meta = $obj->column($meta_col); 
    450         if (!ref $meta) { 
    451             $meta = __thaw_meta(\$meta); 
    452             $obj->{column_values}{$meta_col} = $meta; 
    453         } 
    454         # we should assume changes are going to be made, since 
    455         # we can't really monitor the hash once it has left us 
    456         $obj->{changed_cols}{$meta_col}++; 
    457         return $meta; 
    458     } 
     589            $obj->{__meta}->set($col, @_); 
     590        } 
     591        else { 
     592            $obj->{__meta}->get($col); 
     593        } 
     594    }; 
    459595} 
    460596 
     
    466602    my $ret = sprintf '%04d-%02d-%02d %02d:%02d:%02d', unpack 'A4A2A2A2A2A2', $_[0];   
    467603    return $ret;   
    468 }   
     604} 
    469605   
    470606sub db2ts {   
     
    754890} 
    755891 
     892sub clone_all { 
     893    my $obj = shift; 
     894    my $clone = $obj->SUPER::clone_all(); 
     895    $clone->{__meta} = $obj->{__meta};  # TODO: clone this too 
     896    return $clone; 
     897} 
     898 
    756899sub clone { 
    757900    my $obj = shift; 
    758901    my($param) = @_; 
    759     my $clone = $obj->SUPER::clone_all
     902    my $clone = $obj->clone_all()
    760903 
    761904    ## If the caller has listed a set of columns not to copy to the clone, 
     
    821964} 
    822965 
     966sub remove_meta { 
     967    my $obj = shift; 
     968    return 1 unless ref $obj; 
     969    my $mpkg = $obj->meta_pkg or return; 
     970    my $id_field = $obj->datasource . '_id'; 
     971    return $mpkg->remove({ $id_field => $obj->id }); 
     972} 
     973 
    823974sub remove_children { 
    824975    my $obj = shift; 
     
    834985    my $obj_id = $obj->id; 
    835986    for my $class (@classes) { 
    836         eval "use $class;"; 
     987        eval "# line " . __LINE__ . " " . __FILE__ . "\nuse $class;"; 
    837988        $class->remove({ $key => $obj_id }); 
    838989    } 
     
    9431094    $def{key} = 1 if ($props->{primary_key}) && ($props->{primary_key} eq $col); 
    9441095    $def{auto} = 1 if $def =~ m/\bauto[_ ]increment\b/i; 
    945     $def{default} = $props->{defaults}{$col} if exists $props->{defaults}{$col}; 
     1096    $def{default} = $props->{defaults}{$col} 
     1097        if exists $props->{defaults}{$col}; 
    9461098    \%def; 
    9471099} 
     
    10081160    $hash; 
    10091161} 
     1162 
     1163package MT::Object::Meta; 
     1164 
     1165use base qw( Data::ObjectDriver::BaseObject ); 
     1166 
     1167sub driver { $MT::Object::DRIVER ||= MT::ObjectDriverFactory->new } 
     1168 
     1169sub install_properties { 
     1170    my $class = shift; 
     1171    my ($props) = @_; 
     1172    $props->{column_defs}->{$_} ||= 'string' 
     1173        for @{ $props->{columns} }; 
     1174    $class->SUPER::install_properties(@_); 
     1175} 
     1176 
     1177sub meta_pkg { undef } 
     1178 
     1179*table_name = \&MT::Object::table_name; 
     1180*column_defs = \&MT::Object::column_defs; 
     1181*column_def = \&MT::Object::column_def; 
     1182*index_defs = \&MT::Object::index_defs; 
     1183*__parse_defs = \&MT::Object::__parse_defs; 
     1184*__parse_def = \&MT::Object::__parse_def; 
     1185*count = \&MT::Object::count; 
     1186*columns_of_type = \&MT::Object::columns_of_type; 
     1187 
     1188# TODO: copy this too 
     1189sub blob_requires_zip {} 
    10101190 
    101111911; 
  • branches/release-35/lib/MT/ObjectDriver/DDL/mysql.pm

    r1174 r1927  
    2222    my $field_prefix = $class->datasource; 
    2323    my $table_name = $class->table_name; 
     24    local $dbh->{RaiseError} = 0; 
    2425    my $sth = $dbh->prepare('SHOW INDEX FROM ' . $table_name) 
    2526        or return undef; 
  • branches/release-35/lib/MT/Template.pm

    r1877 r1927  
    3535        'build_type' => 'smallint', 
    3636        'build_interval' => 'integer', 
     37 
     38        # meta properties 
     39        'last_rebuild_time' => 'integer meta', 
     40        'page_layout' => 'string meta', 
     41        'include_with_ssi' => 'integer meta', 
     42        'use_cache' => 'integer meta', 
     43        'cache_expire_type' => 'integer meta', 
     44        'cache_expire_interval' => 'integer meta', 
     45        'cache_expire_event' => 'string meta', 
    3746    }, 
    3847    indexes => { 
     
    5463    datasource => 'template', 
    5564    primary_key => 'id', 
    56 }); 
    57 __PACKAGE__->install_meta({ 
    58     columns => [ 
    59         'last_rebuild_time', 
    60         'page_layout', 
    61         'include_with_ssi', 
    62         'use_cache', 
    63         'cache_expire_type', 
    64         'cache_expire_interval', 
    65         'cache_expire_event', 
    66     ], 
    6765}); 
    6866__PACKAGE__->add_trigger('pre_remove' => \&pre_remove_children); 
  • branches/release-35/lib/MT/Upgrade.pm

    r1897 r1927  
    13521352        } 
    13531353    } 
     1354 
     1355    # handle schema updates for meta table 
     1356    if ($class->meta_pkg) { 
     1357        $self->check_type($type . ':meta'); 
     1358    } 
     1359 
    13541360    1; 
    13551361} 
  • branches/release-35/t/09-image.t

    r1100 r1927  
    2525    ); 
    2626    @drivers = qw( ImageMagick NetPBM ); 
    27     plan tests => scalar @Img + scalar @Img * scalar @drivers * 17; 
     27    plan tests => scalar @Img                           # file exists 
     28                + (scalar @Img * scalar @drivers * 18)  # 18 tests each for every image and driver 
     29                ; 
    2830} 
    2931 
     
    3840 
    3941for my $rec (@Img) { 
    40     my $img_file = File::Spec->catfile($BASE, 't', 'images', $rec->[0]); 
     42    my ($img_filename, $img_width, $img_height) = @$rec; 
     43    my $img_file = File::Spec->catfile($BASE, 't', 'images', $img_filename); 
    4144    ok(-B $img_file, "$img_file looks like a binary file"); 
    4245 
     
    4649SKIP : { 
    4750        skip("no $driver image", 17) unless $img; 
    48         isa_ok($img, 'MT::Image::' . $driver); 
     51        isa_ok($img, 'MT::Image::' . $driver, "driver $driver with image $img_file is an MT::Image::$driver"); 
    4952#        diag( MT::Image->errstr ) if MT::Image->errstr; 
    5053 
    51         is($img->{width}, $rec->[1], "width is $rec->[1]"); 
    52         is($img->{height}, $rec->[2], "height is $rec->[2]"); 
    53         my($w, $h) = $img->get_dimensions
    54         is($w, $rec->[1], "width is $rec->[1]"); 
    55         is($h, $rec->[2], "height is $rec->[2]"); 
     54        is($img->{width}, $img_width,  "$driver says $img_filename is $img_width px wide"); 
     55        is($img->{height}, $img_height, "$driver says $img_filename is $img_height px high"); 
     56        my($w, $h) = $img->get_dimensions()
     57        is($w, $img_width,  "${driver}'s get_dimensions says $img_filename is $img_width px wide"); 
     58        is($h, $img_height, "${driver}'s get_dimensions says $img_filename is $img_height px high"); 
    5659 
    5760        ($w, $h) = $img->get_dimensions(Scale => 50); 
    58         my($x, $y) = (int($img->{width} / 2), int($img->{height} / 2)); 
    59         is($w, $x, "width is $x"); 
    60         is($h, $y, "height is $y"); 
     61        my($x, $y) = (int($img_width / 2), int($img_height / 2)); 
     62        is($w, $x, "$driver says $img_filename at 50\% scale is $x px wide"); 
     63        is($h, $y, "$driver says $img_filename at 50\% scale is $y px high"); 
     64 
     65        ($w, $h) = $img->get_dimensions(); 
     66        is($w, $img_width,  "${driver}'s get_dimensions says $img_filename is still $img_width px wide after theoretical scaling"); 
     67        is($h, $img_height, "${driver}'s get_dimensions says $img_filename is still $img_height px high after theoretical scaling"); 
    6168 
    6269        ($w, $h) = $img->get_dimensions(Width => 50); 
    63         is($w, 50, 'width is 50'); 
     70        is($w, 50, "$driver says $img_filename scaled to 50 px wide is 50 px wide"); 
    6471 
    6572        ($w, $h) = $img->get_dimensions(Width => 50, Height => 100); 
    66         is($w, 50, 'width is 50'); 
    67         is($h, 100, 'height is 100'); 
     73        is($w, 50, "$driver says $img_filename scaled to 50x100 is 50 px wide"); 
     74        is($h, 100, "$driver says $img_filename scaled to 50x100 is 100 px high"); 
    6875 
    6976        (my($blob), $w, $h) = $img->scale(Scale => 50); 
    70         ($x, $y) = (int($img->{width} / 2), int($img->{height} / 2)); 
    71         is($w, $x, "width is $x"); 
    72         is($h, $y, "height is $y"); 
     77        ($x, $y) = (int($img_width / 2), int($img_height / 2)); 
     78        is($w, $x, "result of scaling $img_filename to 50\% with $driver is $x px wide"); 
     79        is($h, $y, "result of scaling $img_filename to 50\% with $driver is $y px high"); 
    7380 
    7481        open FH, $img_file or die $!; 
     
    8087        isa_ok($img, 'MT::Image::' . $driver); 
    8188#            diag( MT::Image->errstr ) if MT::Image->errstr; 
    82         is($img->{width}, $rec->[1], "width is $rec->[1]"); 
    83         is($img->{height}, $rec->[2], "height is $rec->[2]"); 
     89        is($img->{width}, $img_width,  "$driver says $img_filename from blob is $img_width px wide"); 
     90        is($img->{height}, $img_height, "$driver says $img_filename from blob is $img_height px high"); 
    8491        ($w, $h) = $img->get_dimensions; 
    85         is($w, $rec->[1], "width is $rec->[1]"); 
    86         is($h, $rec->[2], "height is $rec->[2]"); 
     92        is($w, $img_width,  "${driver}'s get_dimensions says $img_filename from blob is $img_width px wide"); 
     93        is($h, $img_height, "${driver}'s get_dimensions says $img_filename from blob is $img_height px high"); 
    8794} # END SKIP 
    8895    } 
  • branches/release-35/t/20-setup.t

    r1458 r1927  
    3939ObjectDriver DBI::sqlite 
    4040PluginPath ../plugins 
     41PluginPath plugins 
    4142CFG 
    4243    close $fh; 
  • branches/release-35/t/22-author.t

    r1100 r1927  
    88use lib 'extlib'; 
    99 
    10 use Test::More tests => 54; 
     10use Test::More tests => 64; 
    1111 
    1212use MT; 
     
    3434my $perm = $author->blog_perm(1); 
    3535ok($perm, "$author->blog_perm(1)") || die; 
    36 ok($author->can_edit_entry(1), 'can_edit_entry(1)'); 
    37 ok($author->can_edit_entry(2), 'can_edit_entry(2)'); 
     36ok($author->can_edit_entry(1), 'Chuck D can edit entry #1'); 
     37ok($author->can_edit_entry(2), 'Chuck D can edit entry #2'); 
    3838ok($perm->can_comment, 'can_comment'); 
    3939ok($perm->can_post, 'can_post'); 
     
    5858 
    5959{ 
     60diag('meta field tests'); 
     61 
     62my $author = MT::Author->load({ name => 'Chuck D' }); 
     63ok(eval { $author->widgets(); 1 }, 'Author obj has widgets accessor'); 
     64ok(!defined $author->widgets, "Author's widgets are undefined by default"); 
     65ok(!defined $author->favorite_blogs, "Author's favorite blogs are undefined by default"); 
     66 
     67    # same as in MT::CMS::Dashboard, but that's not necessary 
     68    my $default_widgets = { 
     69        'blog_stats' => 
     70          { param => { tab => 'entry' }, order => 1, set => 'main' }, 
     71        'this_is_you-1' => { order => 1, set => 'sidebar' }, 
     72        'mt_shortcuts'  => { order => 2, set => 'sidebar' }, 
     73        'mt_news'       => { order => 3, set => 'sidebar' }, 
     74    }; 
     75 
     76my $fav_blogs = [1, 7];  # not actually a blog #7, but meh 
     77 
     78ok($author->widgets($default_widgets), "Author's widgets can be set"); 
     79ok($author->favorite_blogs($fav_blogs), "Author's favorite blogs can be set"); 
     80ok($author->save(), "Author with modified widgets can be saved"); 
     81 
     82require MT::ObjectDriver::Driver::Cache::RAM; 
     83MT::ObjectDriver::Driver::Cache::RAM->clear_cache(); 
     84 
     85$author = MT::Author->load({ name => 'Chuck D' }); 
     86 
     87ok($author->widgets, "Modified author has widgets"); 
     88is_deeply($author->widgets, $default_widgets, "Author's widgets survived being saved accurately"); 
     89 
     90ok($author->favorite_blogs, "Modified author has favorite blogs"); 
     91is_deeply($author->favorite_blogs, $fav_blogs, "Author's favorite blogs survived being saved accurately"); 
     92