1 package SL::DBUpgrade2::Base;
 
   5 use parent qw(Rose::Object);
 
   9 use English qw(-no_match_vars);
 
  10 use File::Basename ();
 
  13 use List::MoreUtils qw(uniq);
 
  15 use Rose::Object::MakeMethods::Generic (
 
  16   scalar => [ qw(dbh myconfig) ],
 
  24   my $file_name = delete $params{file_name};
 
  26   if (!eval { require $file_name }) {
 
  27     delete $INC{$file_name};
 
  31   my $package =  delete $params{tag};
 
  32   $package    =~ s/[^a-zA-Z0-9_]+/_/g;
 
  33   $package    =  "SL::DBUpgrade2::${package}";
 
  35   $package->new(%params)->run;
 
  39   my ($self, $msg) = @_;
 
  41   die $::locale->text("Database update error:") . "<br>$msg<br>" . $self->db_errstr('DBI');
 
  45   my ($self, $query, %params) = @_;
 
  47   my $dbh = $params{dbh} || $self->dbh;
 
  49   return if $dbh->do($query, undef, @{ $params{bind} || [] });
 
  51   $self->db_error($query) unless $params{may_fail};
 
  58   my ($self, $handle) = @_;
 
  60   my $error = $handle ? $handle->errstr : $self->dbh->errstr;
 
  62   return Encode::decode('utf-8', $error);
 
  66   my ($self, $wanted_coa) = @_;
 
  68   my ($have_coa)          = selectrow_query($::form, $self->dbh, q{ SELECT count(*) FROM defaults WHERE coa = ? }, $wanted_coa);
 
  76   my $query = q{ SELECT count(*)
 
  77                  FROM ar, ap, gl, invoice, acc_trans, customer, vendor, parts
 
  79   my ($empty) = selectrow_query($::form, $self->dbh, $query);
 
  84 sub add_print_templates {
 
  85   my ($self, $src_dir, @files) = @_;
 
  87   $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: src_dir $src_dir files " . join('  ', @files));
 
  90     croak "File '${src_dir}/$_' does not exist" unless -f "${src_dir}/$_";
 
  93   my $template_dir = $::instance_conf->reload->get_templates;
 
  94   $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: template_dir $template_dir");
 
  96   return 1 if !$template_dir;
 
  98   foreach my $src_file (@files) {
 
  99     my $dest_file = $template_dir . '/' . $src_file;
 
 102       $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: dest_file exists, skipping: ${dest_file}");
 
 106     my $dest_dir = File::Basename::dirname($dest_file);
 
 108     if ($dest_dir && !-d $dest_dir) {
 
 109       File::Path::make_path($dest_dir) or die "Cannot create directory '${dest_dir}': $!";
 
 112     File::Copy::copy($src_dir . '/' . $src_file, $dest_file) or die "Cannot copy '${src_dir}/${src_file}' to '${dest_file}': $!";
 
 114     $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: copied '${src_dir}/${src_file}' to '${dest_file}'");
 
 120 sub drop_constraints {
 
 121   my ($self, %params) = @_;
 
 123   croak "Missing parameter 'table'" unless $params{table};
 
 124   $params{type}   ||= 'FOREIGN KEY';
 
 125   $params{schema} ||= 'public';
 
 127   my $constraints = $self->dbh->selectall_arrayref(<<SQL, undef, $params{type}, $params{schema}, $params{table});
 
 128     SELECT constraint_name
 
 129     FROM information_schema.table_constraints
 
 130     WHERE (constraint_type = ?)
 
 131       AND (table_schema    = ?)
 
 135   $self->db_query(qq|ALTER TABLE $params{schema}."$params{table}" DROP CONSTRAINT "${_}"|) for map { $_->[0] } @{ $constraints };
 
 147 SL::DBUpgrade2::Base - Base class for Perl-based database upgrade files
 
 151 Database scripts written in Perl must be derived from this class and
 
 152 provide a method called C<run>.
 
 154 The functions in this base class offer functionality for the upgrade
 
 159 The following properties (which can be accessed with
 
 160 C<$self-E<gt>property_name>) are available to the database upgrade
 
 167 The database handle; an Instance of L<DBI>. It is connected, and a
 
 168 transaction has been started right before the script (the method
 
 169 L</run>)) was executed.
 
 173 The stripped-down version of the C<%::myconfig> hash: this hash
 
 174 reference only contains the database connection parameters applying to
 
 175 the current database.
 
 183 =item C<add_print_templates $source_dir, @files>
 
 185 Adds (copies) new print templates to existing users. All existing
 
 186 users in the authentication database are read. The listed C<@files>
 
 187 are copied to each user's configured templates directory preserving
 
 188 sub-directory structure (non-existing sub-directories will be
 
 189 created). If a template with the same name exists it will be skipped.
 
 191 The source file names must all be relative to the source directory
 
 192 C<$source_dir>. This way only the desired sub-directories are created
 
 193 in the users' template directories. Example:
 
 195   $self->add_print_templates(
 
 196     'templates/print/Standard',
 
 197     qw(receipt.tex common.sty images/background.png)
 
 200 Let's assume a user's template directory is
 
 201 C<templates/big-money-inc>. The call above would trigger five actions:
 
 205 =item 1. Create the directory C<templates/big-money-inc> if it doesn't
 
 208 =item 2. Copy C<templates/print/Standard/receipt.tex> to
 
 209 C<templates/big-money-inc/receipt.tex> if there's no such file in that
 
 212 =item 3. Copy C<templates/print/Standard/common.sty> to
 
 213 C<templates/big-money-inc/common.sty> if there's no such file in that
 
 216 =item 4. Create the directory C<templates/big-money-inc/images> if it
 
 219 =item 5. Copy C<templates/print/Standard/images/background.png> to
 
 220 C<templates/big-money-inc/images/background.png> if there's no such
 
 221 file in that directory.
 
 225 =item C<check_coa $coa_name>
 
 227 Returns trueish if the database uses the chart of accounts named
 
 230 =item C<db_error $message>
 
 232 Outputs an error message C<$message> to the user and aborts execution.
 
 234 =item C<db_query $query, %params>
 
 236 Executes an SQL query. The following parameters are supported:
 
 242 What the method does if the query fails depends on this parameter. If
 
 243 it is falsish (the default) then the method will simply die outputting
 
 244 the error message via L</db_error>. If C<may_fail> is trueish then the
 
 245 current transaction will be rolled back, a new one will be started.
 
 249 An optional array reference containing bind parameter for the query.
 
 253 The database handle to use. If undefined then C<$self-E<gt>dbh> will
 
 258 =item C<db_errstr [$handle]>
 
 260 Returns the last database from C<$handle> error message encoded in
 
 261 Perl's internal encoding. The PostgreSQL DBD leaves the UTF-8 flag off
 
 262 for error messages even if the C<pg_enable_utf8> attribute is set.
 
 264 C<$handle> is optional and can be one of three things:
 
 268 =item 1. A database or statement handle. In that case
 
 269 C<$handle-E<gt>errstr> is used.
 
 271 =item 2. The string 'DBI'. In that case C<$DBI::errstr> is used.
 
 273 =item 3. If it is undefined then C<$self-E<gt>dbh-E<gt>errstr> is
 
 278 =item C<drop_constraints %params>
 
 280 Drops all constraints of a type (e.g. foreign keys) on a table. One
 
 281 parameter is mandatory: C<table>. Optional parameters include:
 
 285 =item * C<schema> -- if missing defaults to C<public>
 
 287 =item * C<type> -- if missing defaults to C<FOREIGN KEY>. Must be one of
 
 288 the values contained in the C<information_schema.table_constraints>
 
 289 view in the C<constraint_type> column.
 
 293 =item C<execute_script>
 
 295 Executes a named database upgrade script. This function is not
 
 296 supposed to be called from an upgrade script. Instead, the upgrade
 
 297 manager L<SL::DBUpgrade2> uses it in order to execute the actual
 
 298 database upgrade scripts.
 
 300 =item C<is_coa_empty>
 
 302 Returns trueish if no transactions have been recorded in the table
 
 307 This method is the entry point for the actual upgrade. Each upgrade
 
 308 script must provide this method.
 
 318 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>