[Jifty-commit] r3696 - in jifty/trunk: . lib/Jifty lib/Jifty/Script t/TestApp-Plugin-AppPluginHasModels t/TestApp-Plugin-AppPluginHasModels/bin t/TestApp-Plugin-AppPluginHasModels/doc t/TestApp-Plugin-AppPluginHasModels/etc t/TestApp-Plugin-AppPluginHasModels/lib/TestApp t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Action t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Model t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin/Model t/TestApp-Plugin-AppPluginHasModels/log t/TestApp-Plugin-AppPluginHasModels/share t/TestApp-Plugin-AppPluginHasModels/share/po t/TestApp-Plugin-AppPluginHasModels/share/web t/TestApp-Plugin-AppPluginHasModels/share/web/static t/TestApp-Plugin-AppPluginHasModels/share/web/templates t/TestApp-Plugin-AppPluginHasModels/t t/TestApp-Plugin-AppPluginHasModels/var t/TestApp-Plugin-AppPluginHasModels/var/mason t/TestApp-Plugin-AppPluginHasModels/var/mason/cache t/TestApp-Plugin-AppPluginHasModels/var/mason/obj

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Mon Jul 16 22:28:58 EDT 2007


Author: sterling
Date: Mon Jul 16 22:28:58 2007
New Revision: 3696

Added:
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/Makefile.PL
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/bin/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/bin/jifty   (contents, props changed)
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/doc/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/etc/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/etc/config.yml
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Action/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Model/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin.pm
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin/Model/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin/Model/Color.pm
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/log/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/share/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/share/po/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/share/web/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/share/web/static/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/share/web/templates/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/t/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/t/plugin-model.t
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/var/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/var/mason/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/var/mason/cache/
   jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/var/mason/obj/
Modified:
   jifty/trunk/   (props changed)
   jifty/trunk/lib/Jifty/ClassLoader.pm
   jifty/trunk/lib/Jifty/Plugin.pm
   jifty/trunk/lib/Jifty/Record.pm
   jifty/trunk/lib/Jifty/Schema.pm
   jifty/trunk/lib/Jifty/Script/Schema.pm

Log:
 r8092 at dynpc145:  andrew | 2007-07-16 21:28:04 -0500
 Plugins may now have regular models. These are deployed after the schema is setup after adding the plugin to installation. Plugins can bootstrap and upgrade their schema with their own version numbers just like applications (though with slightly different details).


Modified: jifty/trunk/lib/Jifty/ClassLoader.pm
==============================================================================
--- jifty/trunk/lib/Jifty/ClassLoader.pm	(original)
+++ jifty/trunk/lib/Jifty/ClassLoader.pm	Mon Jul 16 22:28:58 2007
@@ -151,7 +151,7 @@
         my $modelclass = $base . "::Model::" . $1;
         Jifty::Util->require($modelclass);
 
-        return undef unless eval { $modelclass->table };
+        return undef unless eval { $modelclass->isa('Jifty::Record') };
 
         return $self->return_class(
                   "package $module;\n"
@@ -165,9 +165,7 @@
 
         Jifty::Util->_require( module => $modelclass, quiet => 1);
 
-        local $@;
-            eval { $modelclass->table } ;
-        if(!$@) {
+        return undef unless eval { $modelclass->isa('Jifty::Record') };
 
         return $self->return_class(
                   "package $module;\n"
@@ -175,7 +173,6 @@
                 . "sub record_class { '$modelclass' };\n"
                 . "sub autogenerated { 1 };\n"
             );
-        }
 
     }
 

Modified: jifty/trunk/lib/Jifty/Plugin.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Plugin.pm	(original)
+++ jifty/trunk/lib/Jifty/Plugin.pm	Mon Jul 16 22:28:58 2007
@@ -183,4 +183,56 @@
     return ();
 }
 
+=head2 version
+
+Returns the database version of the plugin. Needs to be bumped any time the database schema needs to be updated. Plugins that do not directly define any models don't need to worry about this.
+
+=cut
+
+sub version {
+    return '0.0.1';
+}
+
+=head2 bootstrapper
+
+Returns the name of the class that can be used to bootstrap the database models. This normally returns the plugin's class name with C<::Bootstrap> added to the end. Plugin bootstrappers can be built in exactly the same way as application bootstraps.
+
+See L<Jifty::Bootstrap>.
+
+=cut
+
+sub bootstrapper {
+    my $self = shift;
+    my $class = ref $self;
+    return $class . '::Bootstrap';
+}
+
+=head2 upgrade_class
+
+Returns the name of the class that can be used to upgrade the database models and schema (such as adding new data, fixing default values, and renaming columns). This normally returns the plugin's class name with C<::Upgrade> added to the end. Plugin upgraders can be built in exactly the same was as application upgrade classes.
+
+See L<Jifty::Upgrade>.
+
+=cut
+
+sub upgrade_class {
+    my $self = shift;
+    my $class = ref $self;
+    return $class . '::Upgrade';
+}
+
+=head2 table_prefix
+
+Returns a prefix that will be placed in the front of all table names for plugin models. Be default, the plugin name is converted to an identifier based upon the class name.
+
+=cut
+
+sub table_prefix {
+    my $self = shift;
+    my $class = ref $self;
+    $class =~ s/\W+/_/g;
+    $class .= '_';
+    return lc $class;
+}
+
 1;

Modified: jifty/trunk/lib/Jifty/Record.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Record.pm	(original)
+++ jifty/trunk/lib/Jifty/Record.pm	Mon Jul 16 22:28:58 2007
@@ -152,6 +152,41 @@
     return ($id,$msg);
 }
 
+=head2 _guess_table_name
+
+Guesses a table name based on the class's last part. In addition to the work performed in L<Jifty::DBI::Record>, this method also prefixes the table name with the plugin table prefix, if the model belongs to a plugin.
+
+=cut
+
+sub _guess_table_name {
+    my $self = shift;
+    my $table = $self->SUPER::_guess_table_name;
+
+    # Add plugin table prefix if a plugin model
+    my $class = ref($self) ? ref($self) : $self;
+    my $app_plugin_root = Jifty->app_class('Plugin');
+    if ($class =~ /^(?:Jifty::Plugin::|$app_plugin_root)/) {
+
+        # Guess the plugin class name
+        my $plugin_class = $class;
+        $plugin_class =~ s/::Model::(.*)$//;
+
+        # Try to load that plugin's configuration
+        my ($plugin) = grep { ref $_ eq $plugin_class } Jifty->plugins;
+
+        # Add the prefix if found
+        if (defined $plugin) {
+            $table = $plugin->table_prefix . $table;
+        }
+
+        # Uh oh. Warn, but try to keep going.
+        else {
+            warn "Model $class looks like a plugin model, but $plugin_class could not be found.";
+        }
+    }
+
+    return $table;
+}
 
 =head2 current_user_can RIGHT [ATTRIBUTES]
 

Modified: jifty/trunk/lib/Jifty/Schema.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Schema.pm	(original)
+++ jifty/trunk/lib/Jifty/Schema.pm	Mon Jul 16 22:28:58 2007
@@ -48,16 +48,18 @@
 =cut
 
 sub _init_model_list {
-
     my $self = shift;
 
+    # Plugins can have models too
+    my @plugins = map { (ref $_).'::Model' } Jifty->plugins;
+
     # This creates a sub "models" which when called, finds packages under
     # the application's ::Model, requires them, and returns a list of their
     # names.
     Jifty::Module::Pluggable->import(
         require     => 1,
         except      => qr/\.#/,
-        search_path => [ "Jifty::Model", Jifty->app_class("Model") ],
+        search_path => [ "Jifty::Model", Jifty->app_class("Model"), @plugins ],
         sub_name    => 'models',
     );
 }

Modified: jifty/trunk/lib/Jifty/Script/Schema.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Script/Schema.pm	(original)
+++ jifty/trunk/lib/Jifty/Script/Schema.pm	Mon Jul 16 22:28:58 2007
@@ -50,6 +50,7 @@
     } elsif ( $self->{'setup_tables'} ) {
         $self->upgrade_jifty_tables();
         $self->upgrade_application_tables();
+        $self->upgrade_plugin_tables();
     } else {
         print "Done.\n";
     }
@@ -179,11 +180,23 @@
     Jifty::Model::Metadata->store( application_db_version => $appv );
     Jifty::Model::Metadata->store( jifty_db_version       => $jiftyv );
 
+    # For each plugin, update the plugin version
+    for my $plugin (Jifty->plugins) {
+        my $pluginv = version->new( $plugin->version );
+        Jifty::Model::Metadata->store( (ref $plugin).'_db_version' => $pluginv );
+    }
+
     # Load initial data
     eval {
         my $bootstrapper = Jifty->app_class("Bootstrap");
         Jifty::Util->require($bootstrapper);
         $bootstrapper->run() if $bootstrapper->can('run');
+
+        for my $plugin (Jifty->plugins) {
+            my $plugin_bootstrapper = $plugin->bootstrapper;
+            Jifty::Util->require($plugin_bootstrapper);
+            $plugin_bootstrapper->run() if $bootstrapper->can('run');
+        }
     };
     die $@ if $@;
 
@@ -216,20 +229,52 @@
     my $appv = version->new( Jifty->config->framework('Database')->{'Version'} );
     my $jiftyv = version->new( $Jifty::VERSION  );
 
+    my %pluginvs;
+    for my $plugin (Jifty->plugins) {
+        my $plugin_class = ref $plugin;
+        $pluginvs{ $plugin_class } = version->new( $plugin->version );
+    }
 
     for my $model ( @models) {
-       # TODO XXX FIXME:
-       #   This *will* try to generate SQL for abstract base classes you might
-       #   stick in $AC::Model::.
-        if ( $model->can( 'since' ) and ($model =~ /^Jifty::Model::/ ? $jiftyv : $appv) < $model->since ) {
-            $log->info( "Skipping $model, as it should already be in the database");
-            next;
+        # TODO XXX FIXME:
+        #   This *will* try to generate SQL for abstract base classes you might
+        #   stick in $AC::Model::.
+        if ($model->can('since')) {
+            my $app_class   = Jifty->app_class;
+            my $plugin_root = Jifty->app_class('Plugin');
+
+            my $installed_version = 0;
+
+            # Is it a Jifty core model?
+            if ($model =~ /^Jifty::Model::/) {
+                $installed_version = $jiftyv;
+            }
+
+            # Is it a Jifty or application plugin model?
+            elsif ($model =~ /^(?:Jifty::Plugin::|$plugin_root)/) {
+                my $plugin_class = $model;
+                $plugin_class =~ s/::Model::(.*)$//;
+
+                $installed_version = $pluginvs{ $plugin_class };
+            }
+
+            # Otherwise, an application model
+            else {
+                $installed_version = $appv;
+            }
+
+            if ($installed_version < $model->since) {
+                # XXX Is this message correct? 
+                $log->info("Skipping $model, as it should already be in the database");
+                next;
+            }
         }
+
         $log->info("Using $model, as it appears to be new.");
 
-            $self->schema->_check_reserved($model)
+        $self->schema->_check_reserved($model)
         unless ( $self->{'ignore_reserved'}
-            or !Jifty->config->framework('Database')->{'CheckSchema'} );
+                or !Jifty->config->framework('Database')->{'CheckSchema'} );
 
         if ( $self->{'print'} ) {
             print $model->printable_table_schema;
@@ -286,6 +331,29 @@
     }
 }
 
+=head2 upgrade_plugin_tables
+
+Upgrade the tables for each plugin.
+
+=cut
+
+sub upgrade_plugin_tables {
+    my $self   = shift;
+
+    for my $plugin (Jifty->plugins) {
+        my $plugin_class = ref $plugin;
+        my $dbv  = version->new( Jifty::Model::Metadata->load($plugin_class . '_version') || '0.0.1' );
+        my $appv = version->new( $plugin->version );
+
+        return unless $self->upgrade_tables( $plugin_class, $dbv, $appv, $plugin->upgrade_class );
+        if ( $self->{print} ) {
+            warn "Need to upgrade ${plugin_class}_db_version to $appv here!";
+        } else {
+            Jifty::Model::Metadata->store( $plugin_class . '_db_version' => $appv );
+        }
+    }
+}
+
 =head2 upgrade_tables BASECLASS, FROM, TO, [UPGRADECLASS]
 
 Given a C<BASECLASS> to upgrade, and two L<version> objects, C<FROM>

Added: jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/Makefile.PL
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/Makefile.PL	Mon Jul 16 22:28:58 2007
@@ -0,0 +1,7 @@
+use inc::Module::Install;
+
+name        'TestApp::Plugin::AppPluginHasModels';
+version     '0.01';
+requires    'Jifty' => '0.70129';
+
+WriteAll;

Added: jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/bin/jifty
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/bin/jifty	Mon Jul 16 22:28:58 2007
@@ -0,0 +1,11 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+use File::Basename qw(dirname); 
+use UNIVERSAL::require;
+
+use Jifty;
+use Jifty::Script;
+
+local $SIG{INT} = sub { warn "Stopped\n"; exit; };
+Jifty::Script->dispatch();

Added: jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/etc/config.yml
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/etc/config.yml	Mon Jul 16 22:28:58 2007
@@ -0,0 +1,54 @@
+--- 
+framework: 
+  AdminMode: 1
+  ApplicationClass: TestApp::Plugin::AppPluginHasModels
+  ApplicationName: TestApp-Plugin-AppPluginHasModels
+  ApplicationUUID: 646FD662-32DD-11DC-AD79-2A0157C3B83B
+  ConfigFileVersion: 2
+  Database: 
+    CheckSchema: 1
+    Database: testapp_plugin_apppluginhasmodels
+    Driver: SQLite
+    Host: localhost
+    Password: ''
+    RecordBaseClass: Jifty::DBI::Record::Cachable
+    RecordUUIDs: active
+    User: ''
+    Version: 0.0.1
+  DevelMode: 1
+  L10N: 
+    PoDir: share/po
+  LogLevel: INFO
+  Mailer: Sendmail
+  MailerArgs: []
+
+  Plugins: 
+    - LetMe: {}
+    - SkeletonApp: {}
+    - REST: {}
+    - Halo: {}
+    - ErrorTemplates: {}
+    - OnlineDocs: {}
+    - CompressedCSSandJS: {}
+    - AdminUI: {}
+    - TestApp::Plugin::AppPluginHasModels::Plugin::MyAppPlugin: {}
+
+  PubSub: 
+    Backend: Memcached
+    Enable: ~
+  SkipAccessControl: 0
+  TemplateClass: TestApp::Plugin::AppPluginHasModels::View
+  Web: 
+    BaseURL: http://localhost
+    DataDir: var/mason
+    Globals: []
+
+    MasonConfig: 
+      autoflush: 0
+      default_escape_flags: h
+      error_format: text
+      error_mode: fatal
+    Port: 8888
+    ServeStaticFiles: 1
+    StaticRoot: share/web/static
+    TemplateRoot: share/web/templates

Added: jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin.pm	Mon Jul 16 22:28:58 2007
@@ -0,0 +1,7 @@
+use strict;
+use warnings;
+
+package TestApp::Plugin::AppPluginHasModels::Plugin::MyAppPlugin;
+use base qw/ Jifty::Plugin /;
+
+1;

Added: jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin/Model/Color.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/lib/TestApp/Plugin/AppPluginHasModels/Plugin/MyAppPlugin/Model/Color.pm	Mon Jul 16 22:28:58 2007
@@ -0,0 +1,15 @@
+use strict;
+use warnings;
+
+package TestApp::Plugin::AppPluginHasModels::Plugin::MyAppPlugin::Model::Color;
+use Jifty::DBI::Schema;
+
+use TestApp::Plugin::AppPluginHasModels::Plugin::MyAppPlugin::Record schema {
+    column name =>
+        type is 'text';
+
+    column contrasting_color =>
+        type is 'text';
+};
+
+1;

Added: jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/t/plugin-model.t
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp-Plugin-AppPluginHasModels/t/plugin-model.t	Mon Jul 16 22:28:58 2007
@@ -0,0 +1,54 @@
+#!/usr/bin/env perl
+use warnings;
+use strict;
+
+=head1 DESCRIPTION
+
+A basic test harness for the Color model.
+
+=cut
+
+use lib 't/lib';
+use Jifty::SubTest;
+use Jifty::Test tests => 12;
+
+# Make sure we can load the model
+use_ok('TestApp::Plugin::AppPluginHasModels::Plugin::MyAppPlugin::Model::Color');
+
+# Grab a system user
+my $system_user = TestApp::Plugin::AppPluginHasModels::CurrentUser->superuser;
+ok($system_user, "Found a system user");
+
+# Try testing a create
+my $o = TestApp::Plugin::AppPluginHasModels::Plugin::MyAppPlugin::Model::Color->new(current_user => $system_user);
+my ($id) = $o->create();
+ok($id, "Color create returned success");
+ok($o->id, "New Color has valid id set");
+is($o->id, $id, "Create returned the right id");
+
+# Does it use a prefixed table
+is($o->table, 'testapp_plugin_apppluginhasmodels_plugin_myappplugin_colors', 'plugin table prefix');
+
+# And another
+$o->create();
+ok($o->id, "Color create returned another value");
+isnt($o->id, $id, "And it is different from the previous one");
+
+# Searches in general
+my $collection = TestApp::Plugin::AppPluginHasModels::Plugin::MyAppPlugin::Model::ColorCollection->new(current_user => $system_user);
+$collection->unlimit;
+is($collection->count, 2, "Finds two records");
+
+# Searches in specific
+$collection->limit(column => 'id', value => $o->id);
+is($collection->count, 1, "Finds one record with specific id");
+
+# Delete one of them
+$o->delete;
+$collection->redo_search;
+is($collection->count, 0, "Deleted row is gone");
+
+# And the other one is still there
+$collection->unlimit;
+is($collection->count, 1, "Still one left");
+


More information about the Jifty-commit mailing list