2 package Module::Install::RTx::Factory;
3 use Module::Install::Base; @ISA = qw(Module::Install::Base);
9 my ($self, $action) = @_;
11 unshift @INC, substr(delete($INC{'RT.pm'}), 0, -5) if $INC{'RT.pm'};
14 unshift @INC, "$RT::LocalPath/lib" if $RT::LocalPath;
16 $RT::SbinPath ||= $RT::LocalPath;
17 $RT::SbinPath =~ s/local$/sbin/;
19 foreach my $file ($RT::CORE_CONFIG_FILE, $RT::SITE_CONFIG_FILE) {
20 next if !-e $file or -r $file;
21 die "No permission to read $file\n-- please re-run $0 with suitable privileges.\n";
26 my $lib_path = File::Basename::dirname($INC{'RT.pm'});
28 push @args, "-I$RT::LocalPath/lib" if $RT::LocalPath;
31 "$RT::SbinPath/rt-setup-database",
32 "--action" => $action,
34 (($action eq 'insert') ? ("--datafile" => "etc/initialdata") : ()),
35 "--dba" => $RT::DatabaseUser,
36 "--prompt-for-dba-password" => ''
39 (system($^X, @args) == 0) or die "...returned with error: $?\n";
43 my ($self, $RTx, $name, $drop) = @_;
44 my $namespace = "$RTx\::$name";
48 my $dbh = $RT::Handle->dbh;
49 # get all tables out of database
50 my @tables = $dbh->tables;
51 my ( %tablemap, %typemap, %modulemap );
52 my $driver = $RT::DatabaseType;
54 my $CollectionBaseclass = 'RT::SearchBuilder';
55 my $RecordBaseclass = 'RT::Record';
56 my $LicenseBlock = << '.';
61 my $Attribution = << '.';
62 # Autogenerated by Module::Intall::RTx::Factory
63 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.
65 # !! DO NOT EDIT THIS FILE !!
72 @tables = map { do { {
76 $table =~ s/^\Q$name\E_//i or next;
77 $table ne 'sessions' or next;
79 $table = ucfirst(lc($table));
80 $table =~ s/$_/\u$_/ for qw(field group custom member value);
81 $table =~ s/(?<=Scrip)$_/\u$_/ for qw(action condition);
82 $table =~ s/$_/\U$_/ for qw(Acl);
83 $table = $name . '_' . $table;
85 $tablemap{$table} = $table;
86 $modulemap{$table} = $table;
87 if ( $table =~ /^(.*)s$/ ) {
88 $tablemap{$1} = $table;
94 $tablemap{'CreatedBy'} = 'User';
95 $tablemap{'UpdatedBy'} = 'User';
97 $typemap{'id'} = 'ro';
98 $typemap{'Creator'} = 'auto';
99 $typemap{'Created'} = 'auto';
100 $typemap{'Updated'} = 'auto';
101 $typemap{'UpdatedBy'} = 'auto';
102 $typemap{'LastUpdated'} = 'auto';
103 $typemap{'LastUpdatedBy'} = 'auto';
105 $typemap{lc($_)} = $typemap{$_} for keys %typemap;
107 foreach my $table (@tables) {
109 $dbh->do("DROP TABLE $table");
110 $dbh->do("DROP sequence ${table}_id_seq") if $driver eq 'Pg';
111 $dbh->do("DROP sequence ${table}_seq") if $driver eq 'Oracle';
115 my $tablesingle = $table;
116 $tablesingle =~ s/^\Q$name\E_//i;
117 $tablesingle =~ s/s$//;
118 my $tableplural = $tablesingle . "s";
120 if ( $tablesingle eq 'ACL' ) {
121 $tablesingle = "ACE";
122 $tableplural = "ACL";
127 my $CollectionClassName = $namespace . "::" . $tableplural;
128 my $RecordClassName = $namespace . "::" . $tablesingle;
130 my $path = $namespace;
133 my $RecordClassPath = $path . "/" . $tablesingle . ".pm";
134 my $CollectionClassPath = $path . "/" . $tableplural . ".pm";
136 #create a collection class
139 my $ClassAccessible = "";
144 my $sth = $dbh->prepare("DESCRIBE $table");
146 if ( $driver eq 'Pg' ) {
147 $sth = $dbh->prepare(<<".");
148 SELECT a.attname, format_type(a.atttypid, a.atttypmod),
149 a.attnotnull, a.atthasdef, a.attnum
150 FROM pg_class c, pg_attribute a
151 WHERE c.relname ILIKE '$table'
153 AND a.attrelid = c.oid
157 elsif ( $driver eq 'mysql' ) {
158 $sth = $dbh->prepare("DESCRIBE $table");
161 die "$driver is currently unsupported";
166 while ( my $row = $sth->fetchrow_hashref() ) {
167 my ( $field, $type, $default );
168 if ( $driver eq 'Pg' ) {
170 $field = $row->{'attname'};
171 $type = $row->{'format_type'};
172 $default = $row->{'atthasdef'};
174 if ( $default != 0 ) {
175 my $tth = $dbh->prepare(<<".");
176 SELECT substring(d.adsrc for 128)
177 FROM pg_attrdef d, pg_class c
178 WHERE c.relname = 'acct'
179 AND c.oid = d.adrelid
180 AND d.adnum = $row->{'attnum'}
183 my @default = $tth->fetchrow_array;
184 $default = $default[0];
188 elsif ( $driver eq 'mysql' ) {
189 $field = $row->{'Field'};
190 $type = $row->{'Type'};
191 $default = $row->{'Default'};
196 #generate the 'accessible' datastructure
198 if ( $typemap{$field} eq 'auto' ) {
199 $ClassAccessible .= " $field =>
200 {read => 1, auto => 1,";
202 elsif ( $typemap{$field} eq 'ro' ) {
203 $ClassAccessible .= " $field =>
207 $ClassAccessible .= " $field =>
208 {read => 1, write => 1,";
212 $ClassAccessible .= " type => '$type', default => '$default'},\n";
214 #generate pod for the accessible fields
215 $FieldsPod .= $self->_pod(<<".");
218 Returns the current value of $field.
219 (In the database, $field is stored as $type.)
223 unless ( $typemap{$field} eq 'auto' || $typemap{$field} eq 'ro' ) {
224 $FieldsPod .= $self->_pod(<<".");
226 ^head2 Set$field VALUE
230 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
231 (In the database, $field will be stored as a $type.)
236 $FieldsPod .= $self->_pod(<<".");
241 if ( $modulemap{$field} ) {
242 $FieldsPod .= $self->_pod(<<".");
245 Returns the $modulemap{$field} Object which has the id returned by $field
252 my \$$field = ${namespace}::$modulemap{$field}->new(\$self->CurrentUser);
253 \$$field->Load(\$self->__Value('$field'));
257 $requirements{ $tablemap{$field} } =
258 "use ${namespace}::$modulemap{$field};";
262 unless ( $typemap{$field} eq 'auto' || $field eq 'id' ) {
264 #generate create statement
265 $CreateInParams .= " $field => '$default',\n";
267 " $field => \$args{'$field'},\n";
269 #gerenate pod for the create statement
270 $CreatePod .= " $type '$field'";
271 $CreatePod .= " defaults to '$default'" if ($default);
284 \$self->SUPER::Create(
289 $CreatePod .= "\n=cut\n\n";
291 my $CollectionClass = $LicenseBlock . $Attribution . $self->_pod(<<".") . $self->_magic_import($CollectionClassName);
295 $CollectionClassName -- Class Description
299 use $CollectionClassName
308 package $CollectionClassName;
310 use $CollectionBaseclass;
311 use $RecordClassName;
313 use vars qw( \@ISA );
314 \@ISA= qw($CollectionBaseclass);
319 \$self->{'table'} = '$table';
320 \$self->{'primary_key'} = 'id';
324 if ( $fields{'SortOrder'} ) {
326 $CollectionClass .= $self->_pod(<<".");
328 # By default, order by name
329 \$self->OrderBy( ALIAS => 'main',
330 FIELD => 'SortOrder',
334 $CollectionClass .= $self->_pod(<<".");
335 return ( \$self->SUPER::_Init(\@_) );
341 Returns an empty new $RecordClassName item
347 return($RecordClassName->new(\$self->CurrentUser));
351 my $RecordClassHeader = $Attribution . "
366 package $RecordClassName;
367 use $RecordBaseclass;
370 foreach my $key ( keys %requirements ) {
371 $RecordClassHeader .= $requirements{$key} . "\n";
373 $RecordClassHeader .= <<".";
375 use vars qw( \@ISA );
376 \@ISA= qw( $RecordBaseclass );
381 \$self->Table('$table');
382 \$self->SUPER::_Init(\@_);
387 my $RecordClass = $LicenseBlock . $RecordClassHeader . $self->_pod(<<".") . $self->_magic_import($RecordClassName);
391 ^head2 Create PARAMHASH
393 Create takes a hash of values and creates a row in the database:
401 sub _CoreAccessible {
410 print "About to make $RecordClassPath, $CollectionClassPath\n";
413 open( RECORD, ">$RecordClassPath" );
414 print RECORD $RecordClass;
417 open( COL, ">$CollectionClassPath" );
418 print COL $CollectionClass;
426 my $class = ref($self) || $self;
428 #if (exists \$warnings::{unimport}) {
429 # no warnings qw(redefine);
435 my $content = $self->_pod(<<".");
436 eval \"require ${class}_Overlay\";
437 if (\$@ && \$@ !~ qr{^Can't locate ${path}_Overlay.pm}) {
441 eval \"require ${class}_Vendor\";
442 if (\$@ && \$@ !~ qr{^Can't locate ${path}_Vendor.pm}) {
446 eval \"require ${class}_Local\";
447 if (\$@ && \$@ !~ qr{^Can't locate ${path}_Local.pm}) {
456 This class allows \"overlay\" methods to be placed
457 into the following files _Overlay is for a System overlay by the original author,
458 _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customizations.
460 These overlay files can contain new subs or subs to replace existing subs in this module.
462 If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line
464 no warnings qw(redefine);
466 so that perl does not kick and scream when you redefine a subroutine or variable in your overlay.
468 ${class}_Overlay, ${class}_Vendor, ${class}_Local
480 my ($self, $text) = @_;