Revision ac552280
Von Moritz Bunkus vor etwa 14 Jahren hinzugefügt
SL/DB/Helper/ALL.pm | ||
---|---|---|
package SL::DB::Helper::ALL;
|
||
|
||
use strict;
|
||
|
||
use SL::DB::AccTrans;
|
||
use SL::DB::AccTransaction;
|
||
use SL::DB::Assembly;
|
||
use SL::DB::AuditTrail;
|
||
use SL::DB::BankAccount;
|
||
use SL::DB::Bin;
|
||
use SL::DB::Buchungsgruppe;
|
||
use SL::DB::Business;
|
||
use SL::DB::Chart;
|
||
use SL::DB::Contact;
|
||
use SL::DB::CustomVariable;
|
||
use SL::DB::CustomVariableConfig;
|
||
use SL::DB::CustomVariableValidity;
|
||
use SL::DB::Customer;
|
||
use SL::DB::CustomerTax;
|
||
use SL::DB::Datev;
|
||
use SL::DB::Default;
|
||
use SL::DB::DeliveryOrder;
|
||
use SL::DB::DeliveryOrderItem;
|
||
use SL::DB::DeliveryOrderItemsStock;
|
||
use SL::DB::Department;
|
||
use SL::DB::DptTrans;
|
||
use SL::DB::Draft;
|
||
use SL::DB::Dunning;
|
||
use SL::DB::DunningConfig;
|
||
use SL::DB::Employee;
|
||
use SL::DB::Exchangerate;
|
||
use SL::DB::Finanzamt;
|
||
use SL::DB::FollowUp;
|
||
use SL::DB::FollowUpAccess;
|
||
use SL::DB::FollowUpLink;
|
||
use SL::DB::GLTransaction;
|
||
use SL::DB::GenericTranslation;
|
||
use SL::DB::Gifi;
|
||
use SL::DB::History;
|
||
use SL::DB::Inventory;
|
||
use SL::DB::Invoice;
|
||
use SL::DB::InvoiceItem;
|
||
use SL::DB::Language;
|
||
use SL::DB::License;
|
||
use SL::DB::LicenseInvoice;
|
||
use SL::DB::MakeModel;
|
||
use SL::DB::Note;
|
||
use SL::DB::Order;
|
||
use SL::DB::OrderItem;
|
||
use SL::DB::Part;
|
||
use SL::DB::PartsGroup;
|
||
use SL::DB::PartsTax;
|
||
use SL::DB::PaymentTerm;
|
||
use SL::DB::PriceFactor;
|
||
use SL::DB::Pricegroup;
|
||
use SL::DB::Prices;
|
||
use SL::DB::Printer;
|
||
use SL::DB::Project;
|
||
use SL::DB::PurchaseInvoice;
|
||
use SL::DB::RMA;
|
||
use SL::DB::RMAItem;
|
||
use SL::DB::RecordLink;
|
||
use SL::DB::SchemaInfo;
|
||
use SL::DB::SepaExport;
|
||
use SL::DB::SepaExportItem;
|
||
use SL::DB::Shipto;
|
||
use SL::DB::Status;
|
||
use SL::DB::Tax;
|
||
use SL::DB::TaxKey;
|
||
use SL::DB::TaxZone;
|
||
use SL::DB::TodoUserConfig;
|
||
use SL::DB::TransferType;
|
||
use SL::DB::Translation;
|
||
use SL::DB::TranslationPaymentTerm;
|
||
use SL::DB::Unit;
|
||
use SL::DB::UnitsLanguage;
|
||
use SL::DB::Vendor;
|
||
use SL::DB::VendorTax;
|
||
use SL::DB::Warehouse;
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=pod
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::Helper::ALL: Dependency-only package for all SL::DB::* modules
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
use SL::DB::Helper::ALL;
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
This module depends on all modules in SL/DB/*.pm for the convenience
|
||
of being able to write a simple \C<use SL::DB::Helper::ALL> and
|
||
having everything loaded. This is supposed to be used only in the
|
||
Lx-Office console. Normal modules should C<use> only the modules they
|
||
actually need.
|
||
|
||
=head1 AUTHOR
|
||
|
||
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
|
||
|
||
=cut
|
SL/DB/Helper/Attr.pm | ||
---|---|---|
package SL::DB::Helper::Attr;
|
||
|
||
use strict;
|
||
|
||
sub auto_make {
|
||
my ($package, %params) = @_;
|
||
|
||
for my $col ($package->meta->columns) {
|
||
next if $col->primary_key_position; # don't make attr helper for primary keys
|
||
_make_by_type($package, $col->name, $col->type);
|
||
}
|
||
|
||
return $package;
|
||
}
|
||
|
||
sub make {
|
||
my ($package, %params) = @_;
|
||
|
||
for my $name (keys %params) {
|
||
my @types = ref $params{$name} eq 'ARRAY' ? @{ $params{$name} } : ($params{$name});
|
||
for my $type (@types) {
|
||
_make_by_type($package, $name, $type);
|
||
}
|
||
}
|
||
return $package;
|
||
}
|
||
|
||
|
||
|
||
sub _make_by_type {
|
||
my ($package, $name, $type) = @_;
|
||
_as_number ($package, $name, places => -2) if $type =~ /numeric | real | float/xi;
|
||
_as_percent($package, $name, places => 0) if $type =~ /numeric | real | float/xi;
|
||
_as_number ($package, $name, places => 0) if $type =~ /int/xi;
|
||
_as_date ($package, $name) if $type =~ /date | timestamp/xi;
|
||
}
|
||
|
||
sub _as_number {
|
||
my $package = shift;
|
||
my $attribute = shift;
|
||
my %params = @_;
|
||
|
||
$params{places} = 2 if !defined($params{places});
|
||
|
||
no strict 'refs';
|
||
*{ $package . '::' . $attribute . '_as_number' } = sub {
|
||
my ($self, $string) = @_;
|
||
|
||
$self->$attribute($::form->parse_amount(\%::myconfig, $string)) if @_ > 1;
|
||
|
||
return $::form->format_amount(\%::myconfig, $self->$attribute, $params{places});
|
||
};
|
||
}
|
||
|
||
sub _as_percent {
|
||
my $package = shift;
|
||
my $attribute = shift;
|
||
my %params = @_;
|
||
|
||
$params{places} = 2 if !defined($params{places});
|
||
|
||
no strict 'refs';
|
||
*{ $package . '::' . $attribute . '_as_percent' } = sub {
|
||
my ($self, $string) = @_;
|
||
|
||
$self->$attribute($::form->parse_amount(\%::myconfig, $string) / 100) if @_ > 1;
|
||
|
||
return $::form->format_amount(\%::myconfig, 100 * $self->$attribute, $params{places});
|
||
};
|
||
|
||
return 1;
|
||
}
|
||
|
||
sub _as_date {
|
||
my $package = shift;
|
||
my $attribute = shift;
|
||
my %params = @_;
|
||
|
||
no strict 'refs';
|
||
*{ $package . '::' . $attribute . '_as_date' } = sub {
|
||
my ($self, $string) = @_;
|
||
|
||
if (@_ > 1) {
|
||
if ($string) {
|
||
my ($yy, $mm, $dd) = $::locale->parse_date(\%::myconfig, $string);
|
||
$self->$attribute(DateTime->new(year => $yy, month => $mm, day => $dd));
|
||
} else {
|
||
$self->$attribute(undef);
|
||
}
|
||
}
|
||
|
||
return $self->$attribute
|
||
? $::locale->reformat_date(
|
||
{ dateformat => 'yy-mm-dd' },
|
||
( $self->$attribute eq 'now'
|
||
? DateTime->now
|
||
: $self->$attribute
|
||
)->ymd,
|
||
$::myconfig{dateformat}
|
||
)
|
||
: undef;
|
||
};
|
||
|
||
return 1;
|
||
}
|
||
|
||
1;
|
||
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::Helper::Attr - attribute helpers
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
use SL::DB::Helper::Attr;
|
||
SL::DB::Helper::Attr::make($class,
|
||
method_name => 'numeric(15,5)',
|
||
datemethod => 'date'
|
||
);
|
||
SL::DB::Helper::Attr::auto_make($class);
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
=head1 FUNCTIONS
|
||
|
||
=head1 BUGS
|
||
|
||
=head1 AUTHOR
|
||
|
||
=cut
|
SL/DB/Helper/ConventionManager.pm | ||
---|---|---|
package SL::DB::Helper::ConventionManager;
|
||
|
||
use strict;
|
||
|
||
use Rose::DB::Object::ConventionManager;
|
||
|
||
use base qw(Rose::DB::Object::ConventionManager);
|
||
|
||
sub auto_manager_class_name {
|
||
my $self = shift;
|
||
my $object_class = shift || $self->meta->class;
|
||
|
||
my @parts = split m/::/, $object_class;
|
||
my $last = pop @parts;
|
||
|
||
return join('::', @parts, 'Manager', $last);
|
||
}
|
||
|
||
# Base name used for 'make_manager_class', e.g. 'get_all',
|
||
# 'update_all'
|
||
sub auto_manager_base_name {
|
||
return 'all';
|
||
}
|
||
|
||
sub auto_manager_base_class {
|
||
return 'SL::DB::Helper::Manager';
|
||
}
|
||
|
||
1;
|
SL/DB/Helper/Manager.pm | ||
---|---|---|
package SL::DB::Helper::Manager;
|
||
|
||
use strict;
|
||
|
||
use Rose::DB::Object::Manager;
|
||
use base qw(Rose::DB::Object::Manager);
|
||
|
||
sub make_manager_methods {
|
||
my $class = shift;
|
||
my @params = scalar(@_) ? @_ : qw(all);
|
||
return $class->SUPER::make_manager_methods(@params);
|
||
}
|
||
|
||
sub find_by {
|
||
my $class = shift;
|
||
|
||
return if !@_;
|
||
return $class->get_all(query => [ @_ ], limit => 1)->[0];
|
||
}
|
||
|
||
sub get_first {
|
||
shift->get_all(
|
||
limit => 1,
|
||
)->[0];
|
||
}
|
||
|
||
1;
|
SL/DB/Helper/Mappings.pm | ||
---|---|---|
package SL::DB::Helpers::Mappings;
|
||
|
||
use utf8;
|
||
use strict;
|
||
|
||
# these will not be managed as Rose::DB models, because they are not normalized,
|
||
# significant changes are needed to get them done, or they were done by CRM.
|
||
my @lxoffice_blacklist_permanent = qw(
|
||
leads
|
||
);
|
||
|
||
# these are not managed _yet_, but will hopefully at some point.
|
||
# if you are confident that one of these works, remove it here.
|
||
my @lxoffice_blacklist_temp = qw(
|
||
);
|
||
|
||
my @lxoffice_blacklist = (@lxoffice_blacklist_permanent, @lxoffice_blacklist_temp);
|
||
|
||
# map table names to their models.
|
||
# unlike rails we have no singular<->plural magic.
|
||
# remeber: tables should be named as the plural of the model name.
|
||
my %lxoffice_package_names = (
|
||
acc_trans => 'acc_transaction',
|
||
audittrail => 'audit_trail',
|
||
ar => 'invoice',
|
||
ap => 'purchase_invoice',
|
||
bank_accounts => 'bank_account',
|
||
buchungsgruppen => 'buchungsgruppe',
|
||
contacts => 'contact',
|
||
custom_variable_configs => 'custom_variable_config',
|
||
custom_variables => 'custom_variable',
|
||
custom_variables_validity => 'custom_variable_validity',
|
||
customertax => 'customer_tax',
|
||
datev => 'datev',
|
||
defaults => 'default',
|
||
delivery_orders => 'delivery_order',
|
||
delivery_order_items => 'delivery_order_item',
|
||
department => 'department',
|
||
dpt_trans => 'dpt_trans',
|
||
drafts => 'draft',
|
||
dunning => 'dunning',
|
||
dunning_config => 'dunning_config',
|
||
employee => 'employee',
|
||
exchangerate => 'exchangerate',
|
||
finanzamt => 'finanzamt',
|
||
follow_up_access => 'follow_up_access',
|
||
follow_up_links => 'follow_up_link',
|
||
follow_ups => 'follow_up',
|
||
generic_translations => 'generic_translation',
|
||
gifi => 'gifi',
|
||
gl => 'GLTransaction',
|
||
history_erp => 'history',
|
||
inventory => 'inventory',
|
||
invoice => 'invoice_item',
|
||
language => 'language',
|
||
license => 'license',
|
||
licenseinvoice => 'license_invoice',
|
||
makemodel => 'make_model',
|
||
notes => 'note',
|
||
orderitems => 'order_item',
|
||
oe => 'order',
|
||
parts => 'part',
|
||
partsgroup => 'parts_group',
|
||
partstax => 'parts_tax',
|
||
payment_terms => 'payment_term',
|
||
prices => 'prices',
|
||
price_factors => 'price_factor',
|
||
pricegroup => 'pricegroup',
|
||
printers => 'Printer',
|
||
record_links => 'record_link',
|
||
rma => 'RMA',
|
||
rmaitems => 'RMA_item',
|
||
sepa_export => 'sepa_export',
|
||
sepa_export_items => 'sepa_export_item',
|
||
schema_info => 'schema_info',
|
||
status => 'status',
|
||
tax => 'tax',
|
||
taxkeys => 'tax_key',
|
||
tax_zones => 'tax_zone',
|
||
todo_user_config => 'todo_user_config',
|
||
translation => 'translation',
|
||
translation_payment_terms => 'translation_payment_term',
|
||
units => 'unit',
|
||
units_language => 'units_language',
|
||
vendortax => 'vendor_tax',
|
||
);
|
||
|
||
sub get_blacklist {
|
||
return LXOFFICE => \@lxoffice_blacklist;
|
||
}
|
||
|
||
sub get_package_names {
|
||
return LXOFFICE => \%lxoffice_package_names;
|
||
}
|
||
|
||
sub db {
|
||
my $string = $_[0];
|
||
my $lookup = $lxoffice_package_names{$_[0]} ||
|
||
plurify($lxoffice_package_names{singlify($_[0])});
|
||
|
||
for my $thing ($string, $lookup) {
|
||
|
||
# best guess? its already the name. like part. camelize it first
|
||
my $class = "SL::DB::" . camelify($thing);
|
||
return $class if defined *{ $class. '::' };
|
||
|
||
# next, someone wants a manager and pluralized.
|
||
my $manager = "SL::DB::Manager::" . singlify(camelify($thing));
|
||
return $manager if defined *{ $manager . '::' };
|
||
}
|
||
|
||
die "Can't resolve '$string' as a database model, sorry. Did you perhaps forgot to load it?";
|
||
}
|
||
|
||
sub camelify {
|
||
my ($str) = @_;
|
||
$str =~ s/_+(.)/uc($1)/ge;
|
||
ucfirst $str;
|
||
}
|
||
|
||
sub snakify {
|
||
my ($str) = @_;
|
||
$str =~ s/(?<!^)\u(.)/'_' . lc($1)/ge;
|
||
lcfirst $str;
|
||
}
|
||
|
||
sub plurify {
|
||
my ($str) = @_;
|
||
$str . 's';
|
||
}
|
||
|
||
sub singlify {
|
||
my ($str) = @_;
|
||
local $/ = 's';
|
||
chomp $str;
|
||
$str;
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::Helpers::Mappings - Rose Table <-> Model mapping information
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
use SL::DB::Helpers::Mappings qw(@blacklist %table2model);
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
This modul stores table <-> model mappings used by the
|
||
L<scripts/rose_auto_create_model.pl> script. If you add a new table that has
|
||
custom mappings, add it here.
|
||
|
||
=head2 db
|
||
|
||
A special function provided here is E<db>. Without it you'd have to write:
|
||
|
||
my $part = SL::DB::Part->new(id => 1234);
|
||
my @all_parts = SL::DB::Manager::Part->get_all;
|
||
|
||
with them it becomes:
|
||
|
||
my $part = db('part')->new(id => 123);
|
||
my @all_parts = db('parts')->get_all;
|
||
|
||
You don't have to care about add that SL::DB:: incantation anymore. Also, a
|
||
simple s at the end will get you the associated Manager class.
|
||
|
||
db is written to try to make sense of what you give it, but if all fails, it
|
||
will die with an error.
|
||
|
||
=head1 BUGS
|
||
|
||
nothing yet
|
||
|
||
=head1 SEE ALSO
|
||
|
||
L<scripts/rose_auto_create_model.pl>
|
||
|
||
=head1 AUTHOR
|
||
|
||
Sven Schöling <s.schoeling@linet-services.de>
|
||
|
||
=cut
|
SL/DB/Helper/Metadata.pm | ||
---|---|---|
package SL::DB::Helper::Metadata;
|
||
|
||
use strict;
|
||
|
||
use Rose::DB::Object::Metadata;
|
||
use SL::DB::Helper::ConventionManager;
|
||
|
||
use base qw(Rose::DB::Object::Metadata);
|
||
|
||
sub convention_manager_class {
|
||
return 'SL::DB::Helper::ConventionManager';
|
||
}
|
||
|
||
sub default_manager_base_class {
|
||
return 'SL::DB::Helper::Manager';
|
||
}
|
||
|
||
sub initialize {
|
||
my $self = shift;
|
||
$self->make_attr_auto_helpers unless $self->is_initialized;
|
||
$self->SUPER::initialize(@_);
|
||
}
|
||
|
||
sub make_attr_helpers {
|
||
my ($self, %params) = @_;
|
||
SL::DB::Helper::Attr::make($self->class, %params);
|
||
}
|
||
|
||
sub make_attr_auto_helpers {
|
||
my ($self) = @_;
|
||
SL::DB::Helper::Attr::auto_make($self->class);
|
||
}
|
||
|
||
1;
|
SL/DB/Helper/Sorted.pm | ||
---|---|---|
package SL::DB::Helper::Sorted;
|
||
|
||
use strict;
|
||
|
||
require Exporter;
|
||
our @ISA = qw(Exporter);
|
||
our @EXPORT = qw(get_all_sorted make_sort_string);
|
||
|
||
my %sort_spec;
|
||
|
||
sub make_sort_string {
|
||
my ($class, %params) = @_;
|
||
|
||
my $sort_spec = _get_sort_spec($class);
|
||
|
||
my $sort_dir = defined($params{sort_dir}) ? $params{sort_dir} * 1 : $sort_spec->{default}->[1];
|
||
my $sort_dir_str = $sort_dir ? 'ASC' : 'DESC';
|
||
|
||
my $sort_by = $params{sort_by};
|
||
$sort_by = $sort_spec->{default}->[0] unless $sort_spec->{columns}->{$sort_by};
|
||
|
||
my $nulls_str = '';
|
||
if ($sort_spec->{nulls}) {
|
||
$nulls_str = ref($sort_spec->{nulls}) ? ($sort_spec->{nulls}->{$sort_by} || $sort_spec->{nulls}->{default}) : $sort_spec->{nulls};
|
||
$nulls_str = " NULLS ${nulls_str}" if $nulls_str;
|
||
}
|
||
|
||
my $sort_by_str = $sort_spec->{columns}->{$sort_by};
|
||
$sort_by_str = [ $sort_by_str ] unless ref($sort_by_str) eq 'ARRAY';
|
||
$sort_by_str = join(', ', map { "${_} ${sort_dir_str}${nulls_str}" } @{ $sort_by_str });
|
||
|
||
return wantarray ? ($sort_by, $sort_dir, $sort_by_str) : $sort_by_str;
|
||
}
|
||
|
||
sub get_all_sorted {
|
||
my ($class, %params) = @_;
|
||
my $sort_str = $class->make_sort_string(sort_by => delete($params{sort_by}), sort_dir => delete($params{sort_dir}));
|
||
|
||
return $class->get_all(sort_by => $sort_str, %params);
|
||
}
|
||
|
||
sub _get_sort_spec {
|
||
my ($class) = @_;
|
||
return $sort_spec{$class} ||= _make_sort_spec($class);
|
||
}
|
||
|
||
sub _make_sort_spec {
|
||
my ($class) = @_;
|
||
|
||
my %sort_spec = $class->_sort_spec if defined &{ "${class}::_sort_spec" };
|
||
|
||
my $meta = $class->object_class->meta;
|
||
|
||
if (!$sort_spec{default}) {
|
||
my @primary_keys = $meta->primary_key;
|
||
$sort_spec{default} = [ "" . $primary_keys[0], 1 ];
|
||
}
|
||
|
||
$sort_spec{columns} ||= { SIMPLE => [ map { "$_" } $meta->columns ] };
|
||
|
||
if ($sort_spec{columns}->{SIMPLE}) {
|
||
my $table = $meta->table;
|
||
|
||
if (!ref($sort_spec{columns}->{SIMPLE}) && ($sort_spec{columns}->{SIMPLE} eq 'ALL')) {
|
||
map { $sort_spec{columns}->{"$_"} ||= "${table}.${_}"} @{ $meta->columns };
|
||
delete $sort_spec{columns}->{SIMPLE};
|
||
} else {
|
||
map { $sort_spec{columns}->{$_} = "${table}.${_}" } @{ delete($sort_spec{columns}->{SIMPLE}) };
|
||
}
|
||
}
|
||
|
||
return \%sort_spec;
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=encoding utf8
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::Helper::Sorted - Mixin for a manager class that handles
|
||
sorting of database records
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
package SL::DB::Manager::Message;
|
||
|
||
use SL::DB::Helper::Sorted;
|
||
|
||
sub _sort_spec {
|
||
return ( columns => { recipient_id => [ 'CASE
|
||
WHEN recipient_group_id IS NULL THEN lower(recipient.name)
|
||
ELSE lower(recipient_group.name)
|
||
END', ],
|
||
sender_id => [ 'lower(sender.name)', ],
|
||
created_at => [ 'created_at', ],
|
||
subject => [ 'lower(subject)', ],
|
||
status => [ 'NOT COALESCE(unread, FALSE)', 'created_at' ],
|
||
},
|
||
default => [ 'status', 1 ],
|
||
nulls => { default => 'LAST',
|
||
subject => 'FIRST',
|
||
}
|
||
);
|
||
}
|
||
|
||
package SL::Controller::Message;
|
||
|
||
sub action_list {
|
||
my $messages = SL::DB::Manager::Message->get_all_sorted(sort_by => $::form->{sort_by},
|
||
sort_dir => $::form->{sort_dir});
|
||
}
|
||
|
||
=head1 CLASS FUNCTIONS
|
||
|
||
=over 4
|
||
|
||
=item C<make_sort_string %params>
|
||
|
||
Evaluates C<$params{sort_by}> and C<$params{sort_dir}> and returns an
|
||
SQL string suitable for sorting. The package this package is mixed
|
||
into has to provide a method L</_sort_spec> that returns a hash whose
|
||
structure is explained below. That hash is authoritive in which
|
||
columns may be sorted, which column to sort by by default and how to
|
||
handle C<NULL> values.
|
||
|
||
Returns the SQL string in scalar context. In array context it returns
|
||
three values: the actual column it sorts by (suitable for another call
|
||
to L</make_sort_string>), the actual sort direction (either 0 or 1)
|
||
and the SQL string.
|
||
|
||
=item C<get_all_sorted %params>
|
||
|
||
Returns C<< $class->get_all >> with C<sort_by> set to the value
|
||
returned by c<< $class->make_sort_string(%params) >>.
|
||
|
||
=back
|
||
|
||
=head1 CLASS FUNCTIONS PROVIDED BY THE MIXING PACKAGE
|
||
|
||
=over 4
|
||
|
||
=item C<_sort_spec>
|
||
|
||
This method is actually not part of this package but can be provided
|
||
by the package this helper is mixed into. If it isn't then all columns
|
||
of the corresponding table (as returned by the model's meta data) will
|
||
be eligible for sorting.
|
||
|
||
Returns a hash with the following keys:
|
||
|
||
=over 2
|
||
|
||
=item C<default>
|
||
|
||
A two-element array containing the name and direction by which to sort
|
||
in default cases. Example:
|
||
|
||
default => [ 'name', 1 ],
|
||
|
||
Defaults to the table's primary key column (the first column if the
|
||
primary key is composited).
|
||
|
||
=item C<columns>
|
||
|
||
A hash reference. Its keys are column names, and its values are SQL
|
||
strings by which to sort. Example:
|
||
|
||
columns => { SIMPLE => [ 'transaction_description', 'orddate' ],
|
||
the_date => 'CASE WHEN oe.quotation THEN oe.quodate ELSE oe.orddate END',
|
||
customer_name => 'lower(customer.name)',
|
||
},
|
||
|
||
If sorting by a column is requested that is not a key in this hash
|
||
then the default column name will be used.
|
||
|
||
The value can be either a scalar or an array reference. If it's the
|
||
latter then both the sort direction as well as the null handling will
|
||
be appended to each of its members.
|
||
|
||
The special key C<SIMPLE> can be a scalar or an array reference. If it
|
||
is an array reference then it contains column names that are mapped
|
||
1:1 onto the table's columns. If it is the scalar 'ALL' then all
|
||
columns in that model's meta data are mapped 1:1 unless the C<columns>
|
||
hash already contains a key for that column.
|
||
|
||
If C<columns> is missing then all columns of the model will be
|
||
eligible for sorting. The list of columns is looked up in the model's
|
||
meta data.
|
||
|
||
=item C<nulls>
|
||
|
||
Either a scalar or a hash reference determining where C<NULL> values
|
||
will be sorted. If undefined then the decision is left to the
|
||
database.
|
||
|
||
If it is a scalar then all the same value will be used for all
|
||
classes. The value is either C<FIRST> or C<LAST>.
|
||
|
||
If it is a hash reference then its keys are column names (not SQL
|
||
names). The values are either C<FIRST> or C<LAST>. If a column name is
|
||
not found in this hash then the special keu C<default> will be looked
|
||
up and used if it is found.
|
||
|
||
Example:
|
||
|
||
nulls => { transaction_description => 'FIRST',
|
||
customer_name => 'FIRST',
|
||
default => 'LAST',
|
||
},
|
||
|
||
=back
|
||
|
||
=back
|
||
|
||
=head1 BUGS
|
||
|
||
Nothing here yet.
|
||
|
||
=head1 AUTHOR
|
||
|
||
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
|
||
|
||
=cut
|
SL/DB/Helpers/ALL.pm | ||
---|---|---|
package SL::DB::Helpers::ALL;
|
||
|
||
use strict;
|
||
|
||
use SL::DB::AccTrans;
|
||
use SL::DB::AccTransaction;
|
||
use SL::DB::Assembly;
|
||
use SL::DB::AuditTrail;
|
||
use SL::DB::BankAccount;
|
||
use SL::DB::Bin;
|
||
use SL::DB::Buchungsgruppe;
|
||
use SL::DB::Business;
|
||
use SL::DB::Chart;
|
||
use SL::DB::Contact;
|
||
use SL::DB::CustomVariable;
|
||
use SL::DB::CustomVariableConfig;
|
||
use SL::DB::CustomVariableValidity;
|
||
use SL::DB::Customer;
|
||
use SL::DB::CustomerTax;
|
||
use SL::DB::Datev;
|
||
use SL::DB::Default;
|
||
use SL::DB::DeliveryOrder;
|
||
use SL::DB::DeliveryOrderItem;
|
||
use SL::DB::DeliveryOrderItemsStock;
|
||
use SL::DB::Department;
|
||
use SL::DB::DptTrans;
|
||
use SL::DB::Draft;
|
||
use SL::DB::Dunning;
|
||
use SL::DB::DunningConfig;
|
||
use SL::DB::Employee;
|
||
use SL::DB::Exchangerate;
|
||
use SL::DB::Finanzamt;
|
||
use SL::DB::FollowUp;
|
||
use SL::DB::FollowUpAccess;
|
||
use SL::DB::FollowUpLink;
|
||
use SL::DB::GLTransaction;
|
||
use SL::DB::GenericTranslation;
|
||
use SL::DB::Gifi;
|
||
use SL::DB::History;
|
||
use SL::DB::Inventory;
|
||
use SL::DB::Invoice;
|
||
use SL::DB::InvoiceItem;
|
||
use SL::DB::Language;
|
||
use SL::DB::License;
|
||
use SL::DB::LicenseInvoice;
|
||
use SL::DB::MakeModel;
|
||
use SL::DB::Note;
|
||
use SL::DB::Order;
|
||
use SL::DB::OrderItem;
|
||
use SL::DB::Part;
|
||
use SL::DB::PartsGroup;
|
||
use SL::DB::PartsTax;
|
||
use SL::DB::PaymentTerm;
|
||
use SL::DB::PriceFactor;
|
||
use SL::DB::Pricegroup;
|
||
use SL::DB::Prices;
|
||
use SL::DB::Printer;
|
||
use SL::DB::Project;
|
||
use SL::DB::PurchaseInvoice;
|
||
use SL::DB::RMA;
|
||
use SL::DB::RMAItem;
|
||
use SL::DB::RecordLink;
|
||
use SL::DB::SchemaInfo;
|
||
use SL::DB::SepaExport;
|
||
use SL::DB::SepaExportItem;
|
||
use SL::DB::Shipto;
|
||
use SL::DB::Status;
|
||
use SL::DB::Tax;
|
||
use SL::DB::TaxKey;
|
||
use SL::DB::TaxZone;
|
||
use SL::DB::TodoUserConfig;
|
||
use SL::DB::TransferType;
|
||
use SL::DB::Translation;
|
||
use SL::DB::TranslationPaymentTerm;
|
||
use SL::DB::Unit;
|
||
use SL::DB::UnitsLanguage;
|
||
use SL::DB::Vendor;
|
||
use SL::DB::VendorTax;
|
||
use SL::DB::Warehouse;
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=pod
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::Helpers::ALL: Dependency-only package for all SL::DB::* modules
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
use SL::DB::Helpers::ALL;
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
This module depends on all modules in SL/DB/*.pm for the convenience
|
||
of being able to write a simple \C<use SL::DB::Helpers::ALL> and
|
||
having everything loaded. This is supposed to be used only in the
|
||
Lx-Office console. Normal modules should C<use> only the modules they
|
||
actually need.
|
||
|
||
=head1 AUTHOR
|
||
|
||
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
|
||
|
||
=cut
|
SL/DB/Helpers/Attr.pm | ||
---|---|---|
package SL::DB::Helper::Attr;
|
||
|
||
use strict;
|
||
|
||
sub auto_make {
|
||
my ($package, %params) = @_;
|
||
|
||
for my $col ($package->meta->columns) {
|
||
next if $col->primary_key_position; # don't make attr helper for primary keys
|
||
_make_by_type($package, $col->name, $col->type);
|
||
}
|
||
|
||
return $package;
|
||
}
|
||
|
||
sub make {
|
||
my ($package, %params) = @_;
|
||
|
||
for my $name (keys %params) {
|
||
my @types = ref $params{$name} eq 'ARRAY' ? @{ $params{$name} } : ($params{$name});
|
||
for my $type (@types) {
|
||
_make_by_type($package, $name, $type);
|
||
}
|
||
}
|
||
return $package;
|
||
}
|
||
|
||
|
||
|
||
sub _make_by_type {
|
||
my ($package, $name, $type) = @_;
|
||
_as_number ($package, $name, places => -2) if $type =~ /numeric | real | float/xi;
|
||
_as_percent($package, $name, places => 0) if $type =~ /numeric | real | float/xi;
|
||
_as_number ($package, $name, places => 0) if $type =~ /int/xi;
|
||
_as_date ($package, $name) if $type =~ /date | timestamp/xi;
|
||
}
|
||
|
||
sub _as_number {
|
||
my $package = shift;
|
||
my $attribute = shift;
|
||
my %params = @_;
|
||
|
||
$params{places} = 2 if !defined($params{places});
|
||
|
||
no strict 'refs';
|
||
*{ $package . '::' . $attribute . '_as_number' } = sub {
|
||
my ($self, $string) = @_;
|
||
|
||
$self->$attribute($::form->parse_amount(\%::myconfig, $string)) if @_ > 1;
|
||
|
||
return $::form->format_amount(\%::myconfig, $self->$attribute, $params{places});
|
||
};
|
||
}
|
||
|
||
sub _as_percent {
|
||
my $package = shift;
|
||
my $attribute = shift;
|
||
my %params = @_;
|
||
|
||
$params{places} = 2 if !defined($params{places});
|
||
|
||
no strict 'refs';
|
||
*{ $package . '::' . $attribute . '_as_percent' } = sub {
|
||
my ($self, $string) = @_;
|
||
|
||
$self->$attribute($::form->parse_amount(\%::myconfig, $string) / 100) if @_ > 1;
|
||
|
||
return $::form->format_amount(\%::myconfig, 100 * $self->$attribute, $params{places});
|
||
};
|
||
|
||
return 1;
|
||
}
|
||
|
||
sub _as_date {
|
||
my $package = shift;
|
||
my $attribute = shift;
|
||
my %params = @_;
|
||
|
||
no strict 'refs';
|
||
*{ $package . '::' . $attribute . '_as_date' } = sub {
|
||
my ($self, $string) = @_;
|
||
|
||
if (@_ > 1) {
|
||
if ($string) {
|
||
my ($yy, $mm, $dd) = $::locale->parse_date(\%::myconfig, $string);
|
||
$self->$attribute(DateTime->new(year => $yy, month => $mm, day => $dd));
|
||
} else {
|
||
$self->$attribute(undef);
|
||
}
|
||
}
|
||
|
||
return $self->$attribute
|
||
? $::locale->reformat_date(
|
||
{ dateformat => 'yy-mm-dd' },
|
||
( $self->$attribute eq 'now'
|
||
? DateTime->now
|
||
: $self->$attribute
|
||
)->ymd,
|
||
$::myconfig{dateformat}
|
||
)
|
||
: undef;
|
||
};
|
||
|
||
return 1;
|
||
}
|
||
|
||
1;
|
||
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::Helpers::Attr - attribute helpers
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
use SL::DB::Helpers::Attr;
|
||
SL::DB::Helpers::Attr::make($class,
|
||
method_name => 'numeric(15,5)',
|
||
datemethod => 'date'
|
||
);
|
||
SL::DB::Helpers::Attr::auto_make($class);
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
=head1 FUNCTIONS
|
||
|
||
=head1 BUGS
|
||
|
||
=head1 AUTHOR
|
||
|
||
=cut
|
SL/DB/Helpers/ConventionManager.pm | ||
---|---|---|
package SL::DB::Helpers::ConventionManager;
|
||
|
||
use strict;
|
||
|
||
use Rose::DB::Object::ConventionManager;
|
||
|
||
use base qw(Rose::DB::Object::ConventionManager);
|
||
|
||
sub auto_manager_class_name {
|
||
my $self = shift;
|
||
my $object_class = shift || $self->meta->class;
|
||
|
||
my @parts = split m/::/, $object_class;
|
||
my $last = pop @parts;
|
||
|
||
return join('::', @parts, 'Manager', $last);
|
||
}
|
||
|
||
# Base name used for 'make_manager_class', e.g. 'get_all',
|
||
# 'update_all'
|
||
sub auto_manager_base_name {
|
||
return 'all';
|
||
}
|
||
|
||
sub auto_manager_base_class {
|
||
return 'SL::DB::Helpers::Manager';
|
||
}
|
||
|
||
1;
|
SL/DB/Helpers/Manager.pm | ||
---|---|---|
package SL::DB::Helpers::Manager;
|
||
|
||
use strict;
|
||
|
||
use Rose::DB::Object::Manager;
|
||
use base qw(Rose::DB::Object::Manager);
|
||
|
||
sub make_manager_methods {
|
||
my $class = shift;
|
||
my @params = scalar(@_) ? @_ : qw(all);
|
||
return $class->SUPER::make_manager_methods(@params);
|
||
}
|
||
|
||
sub find_by {
|
||
my $class = shift;
|
||
|
||
return if !@_;
|
||
return $class->get_all(query => [ @_ ], limit => 1)->[0];
|
||
}
|
||
|
||
sub get_first {
|
||
shift->get_all(
|
||
limit => 1,
|
||
)->[0];
|
||
}
|
||
|
||
1;
|
SL/DB/Helpers/Mappings.pm | ||
---|---|---|
package SL::DB::Helpers::Mappings;
|
||
|
||
use utf8;
|
||
use strict;
|
||
|
||
# these will not be managed as Rose::DB models, because they are not normalized,
|
||
# significant changes are needed to get them done, or they were done by CRM.
|
||
my @lxoffice_blacklist_permanent = qw(
|
||
leads
|
||
);
|
||
|
||
# these are not managed _yet_, but will hopefully at some point.
|
||
# if you are confident that one of these works, remove it here.
|
||
my @lxoffice_blacklist_temp = qw(
|
||
);
|
||
|
||
my @lxoffice_blacklist = (@lxoffice_blacklist_permanent, @lxoffice_blacklist_temp);
|
||
|
||
# map table names to their models.
|
||
# unlike rails we have no singular<->plural magic.
|
||
# remeber: tables should be named as the plural of the model name.
|
||
my %lxoffice_package_names = (
|
||
acc_trans => 'acc_transaction',
|
||
audittrail => 'audit_trail',
|
||
ar => 'invoice',
|
||
ap => 'purchase_invoice',
|
||
bank_accounts => 'bank_account',
|
||
buchungsgruppen => 'buchungsgruppe',
|
||
contacts => 'contact',
|
||
custom_variable_configs => 'custom_variable_config',
|
||
custom_variables => 'custom_variable',
|
||
custom_variables_validity => 'custom_variable_validity',
|
||
customertax => 'customer_tax',
|
||
datev => 'datev',
|
||
defaults => 'default',
|
||
delivery_orders => 'delivery_order',
|
||
delivery_order_items => 'delivery_order_item',
|
||
department => 'department',
|
||
dpt_trans => 'dpt_trans',
|
||
drafts => 'draft',
|
||
dunning => 'dunning',
|
||
dunning_config => 'dunning_config',
|
||
employee => 'employee',
|
||
exchangerate => 'exchangerate',
|
||
finanzamt => 'finanzamt',
|
||
follow_up_access => 'follow_up_access',
|
||
follow_up_links => 'follow_up_link',
|
||
follow_ups => 'follow_up',
|
||
generic_translations => 'generic_translation',
|
||
gifi => 'gifi',
|
||
gl => 'GLTransaction',
|
||
history_erp => 'history',
|
||
inventory => 'inventory',
|
||
invoice => 'invoice_item',
|
||
language => 'language',
|
||
license => 'license',
|
||
licenseinvoice => 'license_invoice',
|
||
makemodel => 'make_model',
|
||
notes => 'note',
|
||
orderitems => 'order_item',
|
||
oe => 'order',
|
||
parts => 'part',
|
||
partsgroup => 'parts_group',
|
||
partstax => 'parts_tax',
|
||
payment_terms => 'payment_term',
|
||
prices => 'prices',
|
||
price_factors => 'price_factor',
|
||
pricegroup => 'pricegroup',
|
||
printers => 'Printer',
|
||
record_links => 'record_link',
|
||
rma => 'RMA',
|
||
rmaitems => 'RMA_item',
|
||
sepa_export => 'sepa_export',
|
||
sepa_export_items => 'sepa_export_item',
|
||
schema_info => 'schema_info',
|
||
status => 'status',
|
||
tax => 'tax',
|
||
taxkeys => 'tax_key',
|
||
tax_zones => 'tax_zone',
|
||
todo_user_config => 'todo_user_config',
|
||
translation => 'translation',
|
||
translation_payment_terms => 'translation_payment_term',
|
||
units => 'unit',
|
||
units_language => 'units_language',
|
||
vendortax => 'vendor_tax',
|
||
);
|
||
|
||
sub get_blacklist {
|
||
return LXOFFICE => \@lxoffice_blacklist;
|
||
}
|
||
|
||
sub get_package_names {
|
||
return LXOFFICE => \%lxoffice_package_names;
|
||
}
|
||
|
||
sub db {
|
||
my $string = $_[0];
|
||
my $lookup = $lxoffice_package_names{$_[0]} ||
|
||
plurify($lxoffice_package_names{singlify($_[0])});
|
||
|
||
for my $thing ($string, $lookup) {
|
||
|
||
# best guess? its already the name. like part. camelize it first
|
||
my $class = "SL::DB::" . camelify($thing);
|
||
return $class if defined *{ $class. '::' };
|
||
|
||
# next, someone wants a manager and pluralized.
|
||
my $manager = "SL::DB::Manager::" . singlify(camelify($thing));
|
||
return $manager if defined *{ $manager . '::' };
|
||
}
|
||
|
||
die "Can't resolve '$string' as a database model, sorry. Did you perhaps forgot to load it?";
|
||
}
|
||
|
||
sub camelify {
|
||
my ($str) = @_;
|
||
$str =~ s/_+(.)/uc($1)/ge;
|
||
ucfirst $str;
|
||
}
|
||
|
||
sub snakify {
|
||
my ($str) = @_;
|
||
$str =~ s/(?<!^)\u(.)/'_' . lc($1)/ge;
|
||
lcfirst $str;
|
||
}
|
||
|
||
sub plurify {
|
||
my ($str) = @_;
|
||
$str . 's';
|
||
}
|
||
|
||
sub singlify {
|
||
my ($str) = @_;
|
||
local $/ = 's';
|
||
chomp $str;
|
||
$str;
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::Helpers::Mappings - Rose Table <-> Model mapping information
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
use SL::DB::Helpers::Mappings qw(@blacklist %table2model);
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
This modul stores table <-> model mappings used by the
|
||
L<scripts/rose_auto_create_model.pl> script. If you add a new table that has
|
||
custom mappings, add it here.
|
||
|
||
=head2 db
|
||
|
||
A special function provided here is E<db>. Without it you'd have to write:
|
||
|
||
my $part = SL::DB::Part->new(id => 1234);
|
||
my @all_parts = SL::DB::Manager::Part->get_all;
|
||
|
||
with them it becomes:
|
||
|
||
my $part = db('part')->new(id => 123);
|
||
my @all_parts = db('parts')->get_all;
|
||
|
||
You don't have to care about add that SL::DB:: incantation anymore. Also, a
|
||
simple s at the end will get you the associated Manager class.
|
||
|
||
db is written to try to make sense of what you give it, but if all fails, it
|
||
will die with an error.
|
||
|
||
=head1 BUGS
|
||
|
||
nothing yet
|
||
|
||
=head1 SEE ALSO
|
||
|
||
L<scripts/rose_auto_create_model.pl>
|
||
|
||
=head1 AUTHOR
|
||
|
||
Sven Schöling <s.schoeling@linet-services.de>
|
||
|
||
=cut
|
SL/DB/Helpers/Metadata.pm | ||
---|---|---|
package SL::DB::Helpers::Metadata;
|
||
|
||
use strict;
|
||
|
||
use Rose::DB::Object::Metadata;
|
||
use SL::DB::Helpers::ConventionManager;
|
||
|
||
use base qw(Rose::DB::Object::Metadata);
|
||
|
||
sub convention_manager_class {
|
||
return 'SL::DB::Helpers::ConventionManager';
|
||
}
|
||
|
||
sub default_manager_base_class {
|
||
return 'SL::DB::Helpers::Manager';
|
||
}
|
||
|
||
sub initialize {
|
||
my $self = shift;
|
||
$self->make_attr_auto_helpers unless $self->is_initialized;
|
||
$self->SUPER::initialize(@_);
|
||
}
|
||
|
||
sub make_attr_helpers {
|
||
my ($self, %params) = @_;
|
||
SL::DB::Helper::Attr::make($self->class, %params);
|
||
}
|
||
|
||
sub make_attr_auto_helpers {
|
||
my ($self) = @_;
|
||
SL::DB::Helper::Attr::auto_make($self->class);
|
||
}
|
||
|
||
1;
|
SL/DB/Helpers/Sorted.pm | ||
---|---|---|
package SL::DB::Helpers::Sorted;
|
||
|
||
use strict;
|
||
|
||
require Exporter;
|
||
our @ISA = qw(Exporter);
|
||
our @EXPORT = qw(get_all_sorted make_sort_string);
|
||
|
||
my %sort_spec;
|
||
|
||
sub make_sort_string {
|
||
my ($class, %params) = @_;
|
||
|
||
my $sort_spec = _get_sort_spec($class);
|
||
|
||
my $sort_dir = defined($params{sort_dir}) ? $params{sort_dir} * 1 : $sort_spec->{default}->[1];
|
||
my $sort_dir_str = $sort_dir ? 'ASC' : 'DESC';
|
||
|
||
my $sort_by = $params{sort_by};
|
||
$sort_by = $sort_spec->{default}->[0] unless $sort_spec->{columns}->{$sort_by};
|
||
|
||
my $nulls_str = '';
|
||
if ($sort_spec->{nulls}) {
|
||
$nulls_str = ref($sort_spec->{nulls}) ? ($sort_spec->{nulls}->{$sort_by} || $sort_spec->{nulls}->{default}) : $sort_spec->{nulls};
|
||
$nulls_str = " NULLS ${nulls_str}" if $nulls_str;
|
||
}
|
||
|
||
my $sort_by_str = $sort_spec->{columns}->{$sort_by};
|
||
$sort_by_str = [ $sort_by_str ] unless ref($sort_by_str) eq 'ARRAY';
|
||
$sort_by_str = join(', ', map { "${_} ${sort_dir_str}${nulls_str}" } @{ $sort_by_str });
|
||
|
||
return wantarray ? ($sort_by, $sort_dir, $sort_by_str) : $sort_by_str;
|
||
}
|
||
|
||
sub get_all_sorted {
|
||
my ($class, %params) = @_;
|
||
my $sort_str = $class->make_sort_string(sort_by => delete($params{sort_by}), sort_dir => delete($params{sort_dir}));
|
||
|
||
return $class->get_all(sort_by => $sort_str, %params);
|
||
}
|
||
|
||
sub _get_sort_spec {
|
||
my ($class) = @_;
|
||
return $sort_spec{$class} ||= _make_sort_spec($class);
|
||
}
|
||
|
||
sub _make_sort_spec {
|
||
my ($class) = @_;
|
||
|
||
my %sort_spec = $class->_sort_spec if defined &{ "${class}::_sort_spec" };
|
||
|
||
my $meta = $class->object_class->meta;
|
||
|
||
if (!$sort_spec{default}) {
|
||
my @primary_keys = $meta->primary_key;
|
||
$sort_spec{default} = [ "" . $primary_keys[0], 1 ];
|
||
}
|
||
|
||
$sort_spec{columns} ||= { SIMPLE => [ map { "$_" } $meta->columns ] };
|
||
|
||
if ($sort_spec{columns}->{SIMPLE}) {
|
||
my $table = $meta->table;
|
||
|
||
if (!ref($sort_spec{columns}->{SIMPLE}) && ($sort_spec{columns}->{SIMPLE} eq 'ALL')) {
|
||
map { $sort_spec{columns}->{"$_"} ||= "${table}.${_}"} @{ $meta->columns };
|
||
delete $sort_spec{columns}->{SIMPLE};
|
||
} else {
|
||
map { $sort_spec{columns}->{$_} = "${table}.${_}" } @{ delete($sort_spec{columns}->{SIMPLE}) };
|
||
}
|
||
}
|
||
|
||
return \%sort_spec;
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=encoding utf8
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::Helpers::Sorted - Mixin for a manager class that handles
|
||
sorting of database records
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
package SL::DB::Manager::Message;
|
||
|
||
use SL::DB::Helpers::Sorted;
|
||
|
||
sub _sort_spec {
|
||
return ( columns => { recipient_id => [ 'CASE
|
||
WHEN recipient_group_id IS NULL THEN lower(recipient.name)
|
||
ELSE lower(recipient_group.name)
|
||
END', ],
|
||
sender_id => [ 'lower(sender.name)', ],
|
||
created_at => [ 'created_at', ],
|
||
subject => [ 'lower(subject)', ],
|
||
status => [ 'NOT COALESCE(unread, FALSE)', 'created_at' ],
|
||
},
|
||
default => [ 'status', 1 ],
|
||
nulls => { default => 'LAST',
|
||
subject => 'FIRST',
|
||
}
|
||
);
|
||
}
|
||
|
||
package SL::Controller::Message;
|
||
|
||
sub action_list {
|
||
my $messages = SL::DB::Manager::Message->get_all_sorted(sort_by => $::form->{sort_by},
|
||
sort_dir => $::form->{sort_dir});
|
||
}
|
||
|
||
=head1 CLASS FUNCTIONS
|
||
|
||
=over 4
|
||
|
||
=item C<make_sort_string %params>
|
||
|
||
Evaluates C<$params{sort_by}> and C<$params{sort_dir}> and returns an
|
||
SQL string suitable for sorting. The package this package is mixed
|
||
into has to provide a method L</_sort_spec> that returns a hash whose
|
||
structure is explained below. That hash is authoritive in which
|
||
columns may be sorted, which column to sort by by default and how to
|
||
handle C<NULL> values.
|
||
|
||
Returns the SQL string in scalar context. In array context it returns
|
||
three values: the actual column it sorts by (suitable for another call
|
||
to L</make_sort_string>), the actual sort direction (either 0 or 1)
|
||
and the SQL string.
|
||
|
||
=item C<get_all_sorted %params>
|
||
|
||
Returns C<< $class->get_all >> with C<sort_by> set to the value
|
||
returned by c<< $class->make_sort_string(%params) >>.
|
||
|
||
=back
|
||
|
||
=head1 CLASS FUNCTIONS PROVIDED BY THE MIXING PACKAGE
|
||
|
||
=over 4
|
||
|
||
=item C<_sort_spec>
|
||
|
||
This method is actually not part of this package but can be provided
|
Auch abrufbar als: Unified diff
Verzeichnis SL/DB/Helpers in SL/DB/Helper umbenannt (Konsistenz)