package Bigtop::Backend::Model::GantryCDBI;
use strict; use warnings;
use Bigtop::Backend::Model;
use File::Spec;
use Inline;
use Bigtop;
#-----------------------------------------------------------------
# The Default Template
#-----------------------------------------------------------------
our $template_is_setup = 0;
our $default_template_text = <<'EO_TT_blocks';
[% BLOCK stub_table_module %]
package [% package_name %];
use strict; use warnings;
use base '[% base_class || base_class_default %]', 'Exporter';
use [% gen_package_name %];
our $[% package_alias %] = '[% package_name %]';
our @EXPORT_OK = ( '$[% package_alias %]' );
1;
=head1 NAME
[% package_name %] - model for [% table_name %] table (stub part)
=head1 DESCRIPTION
This model inherits from [% base_class || base_class_default %] and uses its generated
helper [% gen_package_name %].
It was generated by Bigtop, but is NOT subject to regeneration.
=cut
[% END %]
[% BLOCK gen_table_module %]
# NEVER EDIT this file. It was generated and will be overwritten without
# notice upon regeneration of this application. You have been warned.
package [% package_name %];
use strict; use warnings;
[% package_name %]->table ( '[% real_table_name %]' );
[% IF sequence_name %]
[% package_name %]->sequence( '[% sequence_name %]' );
[% END %]
[% IF primary_key %]
[% package_name %]->columns ( Primary => qw/
[% IF primary_key.0 %]
[% primary_key.join( ' ' ) +%]
[% ELSE %]
[% primary_key +%]
[% END -%]
/ );
[% END -%]
[% package_name %]->columns ( All => qw/
[% FOREACH column IN all_columns %]
[% column +%]
[% END %]
/ );
[% package_name %]->columns ( Essential => qw/
[% FOREACH essential_column IN essential_columns %]
[% essential_column +%]
[% END %]
/ );
[% FOREACH has_a IN has_a_list %]
[% package_name %]->has_a( [% has_a.column %] => '[% base_package_name %]::[% has_a.table %]' );
[% END +%]
sub get_foreign_display_fields {
return [ qw( [% foreign_display_columns %] ) ];
}
sub get_foreign_tables {
return qw(
[% FOREACH foreign_table IN foreign_tables %]
[% base_package_name %]::[% foreign_table +%]
[% END %]
);
}
sub foreign_display {
my $self = shift;
[% foreign_display_body %]
}
1;
=head1 NAME
[% gen_package_name %] - model for [% table_name %] table (generated part)
=head1 DESCRIPTION
This model mixes into [% package_name %],
because Class::DBI bindings don't really allow a choice.
It was generated by Bigtop, and IS subject to regeneration.
=head1 METHODS
You may use all normal Class::DBI::Sweet methods and the ones listed here:
=over 4
=item get_foreign_display_fields
=item get_foreign_tables
=item foreign_display
=back
=cut
[% END %]
EO_TT_blocks
#-----------------------------------------------------------------
# Methods in the Bigtop::Model::GantryCDBI package
#-----------------------------------------------------------------
sub what_do_you_make {
return [
[ 'lib/AppName/Model/*.pm' =>
'Class::DBI style model stubs [safe to change]' ],
[ 'lib/AppName/Model/GEN/*.pm' =>
'Class::DBI style model specifications [please, do not change]' ],
[ 'note' =>
'This backend is incompatible with other Model backends.' ],
];
}
sub backend_block_keywords {
return [
{ keyword => 'no_gen',
label => 'No Gen',
descr => 'Skip everything for this backend',
type => 'boolean' },
{ keyword => 'model_base_class',
label => 'Models Inherit From',
descr => 'Defaults to Gantry::Utils::CDBI',
type => 'text' },
{ keyword => 'template',
label => 'Alternate Template',
descr => 'A custom TT template.',
type => 'text' },
];
}
sub setup_template {
my $class = shift;
my $template_text = shift || $default_template_text;
return if ( $template_is_setup );
Inline->bind(
TT => $template_text,
POST_CHOMP => 1,
TRIM_LEADING_SPACE => 0,
TRIM_TRAILING_SPACE => 0,
);
$template_is_setup = 1;
}
sub gen_Model {
my $class = shift;
my $build_dir = shift;
my $bigtop_tree = shift;
# make sure the directories are ready for us
my $model_name = $bigtop_tree->get_appname() . '::Model';
my ( $module_dir, @sub_dirs )
= Bigtop::make_module_path( $build_dir, $model_name );
my $gen_dir = File::Spec->catdir( $module_dir, 'GEN' );
mkdir $gen_dir;
# see if there is an alternate default base module
my $config_block = $bigtop_tree->get_config()->{ Model };
# build the individual model packages
$bigtop_tree->walk_postorder(
'output_model',
{
module_dir => $module_dir,
model_name => $model_name,
lookup => $bigtop_tree->{application}{lookup},
model_base_class => $config_block->{model_base_class}
|| 'Gantry::Utils::CDBI',
},
);
}
#-----------------------------------------------------------------
# Packages named in the grammar
#-----------------------------------------------------------------
# table_block
package # table_block
table_block;
use strict; use warnings;
sub output_model {
my $self = shift;
my $child_output = shift;
my $data = shift;
# Skip sequences, etc.
return unless ( $self->{__TYPE__} eq 'tables' );
my $table_lookup = $data->{lookup}{tables}{ $self->{__NAME__} };
if ( $table_lookup->{not_for} ) {
foreach my $skipped_type ( @{ $table_lookup->{not_for}{__ARGS__} } ) {
return if ( $skipped_type eq 'Model' );
}
}
# get columns sets
my $lookup = $table_lookup->{fields};
my $all = $self->walk_postorder(
'output_all_fields_cdbi', $lookup
);
my $essentials = $self->walk_postorder(
'output_essential_fields_cdbi', $lookup
);
# deal with foreign keys
my $foreign_tables = $self->walk_postorder(
'output_foreign_tables_cdbi', $lookup
);
my @foreign_table_names;
my @has_a_list;
foreach my $entry ( @{ $foreign_tables } ) {
my $entry_hash = { @{ $entry } };
my $foreign_table = $entry_hash->{ table };
$foreign_table =~ s/\./_/;
push @foreign_table_names, $foreign_table;
push @has_a_list, {
table => $foreign_table,
column => $entry_hash->{ column },
};
}
# Gone Fishing.
my $table = $self->{__NAME__};
$table =~ s/\./_/;
my $module_name = $data->{model_name} . '::' . $table;
my $gen_pack_name = $data->{model_name} . '::GEN::' . $table;
my $alias = uc $table;
my $sequence = $table_lookup->{sequence};
my $foreign_display = $table_lookup->{foreign_display};
my $sequence_name;
if ( $sequence ) {
$sequence_name = $sequence->{__ARGS__}[0];
}
my $primary_key = $self->find_primary_key(
$self->{__NAME__},
$data->{ lookup },
);
my $foreign_display_columns;
my $foreign_display_body;
if ( $foreign_display ) {
my $foreign_display_cols = $foreign_display->{__ARGS__}[0];
my @field_names = ( $foreign_display_cols =~ /%([\w\d_]*)/g );
$foreign_display_columns = "@field_names";
$foreign_display_body = _build_foreign_display_body(
$foreign_display_cols, @field_names
);
}
my $base_class;
if ( defined $table_lookup->{model_base_class} ) {
$base_class = $table_lookup->{model_base_class}{__ARGS__}[0];
}
# generate output
my $stub_content = Bigtop::Backend::Model::GantryCDBI::stub_table_module(
{
base_class => $base_class,
base_class_default => $data->{model_base_class},
base_package_name => $data->{model_name},
gen_package_name => $gen_pack_name,
package_name => $module_name,
package_alias => $alias,
table_name => $table,
}
);
my $gen_content = Bigtop::Backend::Model::GantryCDBI::gen_table_module(
{
base_package_name => $data->{model_name},
package_name => $module_name,
gen_package_name => $gen_pack_name,
package_alias => $alias,
table_name => $table,
real_table_name => $self->{__NAME__},
sequence_name => $sequence_name,
primary_key => $primary_key,
foreign_display_columns => $foreign_display_columns,
foreign_display_body => $foreign_display_body,
all_columns => $all,
essential_columns => $essentials,
has_a_list => \@has_a_list,
foreign_tables => \@foreign_table_names,
}
);
# store it
my $module_file = File::Spec->catfile( $data->{module_dir}, "$table.pm" );
my $gen_dir = File::Spec->catdir ( $data->{module_dir}, 'GEN' );
my $gen_file = File::Spec->catfile( $gen_dir, "$table.pm" );
eval {
no warnings qw( Bigtop );
Bigtop::write_file( $module_file, $stub_content, 'no overwrite' );
};
warn $@ if $@;
eval {
Bigtop::write_file( $gen_file, $gen_content );
};
warn $@ if $@;
}
# table_element_block
package # table_element_block
table_element_block;
use strict; use warnings;
sub output_all_fields_cdbi {
my $self = shift;
shift;
my $data = shift;
return unless ( ref( $self->{__BODY__} ) );
my $field = $data->{ $self->{__NAME__} };
return if ( _not_for_model( $field ) );
return [ $self->{__NAME__} ];
}
sub output_essential_fields_cdbi {
my $self = shift;
shift;
my $data = shift;
return unless ( ref( $self->{__BODY__} ) );
my $field = $data->{ $self->{__NAME__} };
if ( $field->{non_essential} ) {
my $non_essential_value = $field->{non_essential}{args}[0];
return if ( $non_essential_value );
}
return if ( _not_for_model( $field ) );
return [ $self->{__NAME__} ];
}
sub output_foreign_tables_cdbi {
my $self = shift;
shift;
my $data = shift;
return unless ( ref( $self->{__BODY__} ) );
my $field = $data->{ $self->{__NAME__} };
if ( $field->{refers_to} ) {
my $foreign_table_name = $field->{refers_to}{args}[0];
if ( ref( $foreign_table_name ) eq 'HASH' ) {
( $foreign_table_name ) = %{ $foreign_table_name };
}
return [
[ column => $self->{__NAME__}, table => $foreign_table_name ]
];
}
return;
}
1;
__END__
=head1 NAME
Bigtop::Backend::Model::GantryCDBI - Bigtop backend generating Class::DBI::Sweet models
=head1 SYNOPSIS
If your bigtop file looks like this:
config {
base_dir `/home/user`;
...
Model GantryCDBI {}
}
app Name {...}
and there are tables in the app block, when you type:
bigtop your.bigtop Model
or
bigtop your.bigtop all
this module will make model modules which are subclasses of
Gantry::Utils::CDBI (which inherits from Class::DBI::Sweet in a
mod_perl safe way).
All modules will live in the lib subdirectory of the app's build directory.
See Bigtop::Init::Std for an explanation of how base_dir and the
build directory are related.
=head1 DESCRIPTION
This is a Bigtop backend which generates data model modules which are
subclasses of Gantry::Utils::CDBI.
=head1 KEYWORDS
This module does not register any keywords. See Bigtop::Model for
a list of keywords models understand.
The default for the model_base_class keyword is Gantry::Utils::CDBI.
=head1 METHODS
To keep podcoverage tests happy.
=over 4
=item backend_block_keywords
Tells tentmaker that I understand these config section backend block keywords:
no_gen
model_base_class
template
=item what_do_you_make
Tells tentmaker what this module makes. Summary: Class::DBI models.
=item gen_Model
Called by Bigtop::Parser to get me to do my thing.
=item setup_template
Called by Bigtop::Parser so the user can substitute an alternate template
for the hard coded one here.
=back
=head1 AUTHOR
Phil Crow <crow.phil@gmail.com>
=head1 COPYRIGHT and LICENSE
Copyright (C) 2005 by Phil Crow
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.6 or,
at your option, any later version of Perl 5 you may have available.
=cut