package LIMS::Base; use parent 'LIMS'; use strict; use Data::Dumper; use LIMS::Local::Utils; use JavaScript::DataFormValidator; #------------------------------------------------------------------------------- # GLOBAL METHODS #------------------------------------------------------------------------------- # render_view(), get_yaml_file() & model() moved to LIMS::Role::Base #------------------------------------------------------------------------------- sub error { my ($self, $msg) = @_; # map { $self->debug("CALLER: $_") } ($package, $filename, $line); my ($package, $filename, $line) = caller; my $str = length $msg > 125 # width, array(ref) of args to wrap: ? LIMS::Local::Utils::text_wrap(120, [ "\n\t", "\t", $msg ]) : $msg; my $time = LIMS::Local::Utils::time_now(); $self->tt_params( package => $package, time => $time, line => $line, msg => $str, ); return $self->tt_process('site/error.tt'); } #------------------------------------------------------------------------------- # alternative to CAP::Flash - accepts args in same format as CAP::Flash, but # uses CAP::MessageStack instead: #=============================================================================== # => !!! MUST INSTALL YAML::Syck IF USING CGI::Session::Serialize::yaml <= !!!!! #=============================================================================== sub flash { # warn 'here'; warn Dumper caller(); my $self = shift; my ($type, $msg, $scope) = @_; # warn Dumper [ $type, $msg, $scope ]; # !!!! YAML serializer can't handle leading hyphens - need YAML::Syck !!!! $self->push_message( -message => $msg, -classification => $type, -scope => $scope, ); } #------------------------------------------------------------------------------- sub get_meta_data { my $self = shift; my $class = shift; # warn $class; unless ( $self->stash->{meta_data}->{$class} ) { # warn 'here'; # should only be once per class my $meta_data = $self->model('Base')->get_meta_data($class); $self->stash->{meta_data}->{$class} = $meta_data; } return $self->stash->{meta_data}->{$class}; } #------------------------------------------------------------------------------- # uses CGI::Pager; accepts $args hashref (query_args and total_count); # makes cgi_pager object available to template and adds limit & offset params # to query_args; returns nothing sub pager { my $self = shift; my $args = shift; # hashref of query_args and total count my $args_for_query = $args->{query}; my $total_count = $args->{total}; my $entries_per_page = # config settings; can be overriden from form: $self->query->param('entries_per_page') || $self->cfg('settings')->{entries_per_page} || 10; my $pager = CGI::Pager->new( page_len => $entries_per_page, # default = 20 total_count => $total_count, ); $self->tt_params( cgi_pager => $pager ); # $self->debug($pager); # add limit & offset params to args_for_query hashref: $args_for_query->{limit} = $entries_per_page; $args_for_query->{offset} = $self->query->param('offset') || 0; } #------------------------------------------------------------------------------- # returns requested Data::FormValidator profile from LIMS::Validate sub validate { my $self = shift; my $profile_name = shift || return; # warn $profile_name; my $profile = $self->_get_validation_profile($profile_name); # return $profile if not a hashref (eg arrayref for FV::Simple or coderef): return $profile unless ref $profile eq 'HASH'; # remove 'ajax_methods' keys from hashref: my @keys = grep $_ ne 'ajax_methods', keys %$profile; # warn Dumper \@keys; my %dfv_profile = map { $_ => $profile->{$_} } @keys; # warn Dumper \%dfv_profile; return \%dfv_profile; } #------------------------------------------------------------------------------- # called from template with profile name to generate rules for jquery validation: # if used, need to load jquery.validate.js and # $(document).ready(function() { $("#id").validate({ rules: { } }) sub jquery_validation_profile { my $self = shift; my $profile_name = shift || return; # name of DFV profile to retrieve from $self->validate my $profile = $self->_get_validation_profile($profile_name); my $ajax_methods = $profile->{ajax_methods}; my $required = $profile->{required}; my $app_url = $self->query->url; my @rules; push @rules, ( qq!$_: "required"! ) for @$required; push @rules, ( qq!$_: { remote: "$app_url/ajax/$ajax_methods->{$_}" }! ) for keys %$ajax_methods; # warn Dumper \@rules; return \@rules; } #------------------------------------------------------------------------------- sub validation_models { my $self = shift; # warn 'creating validation_models'; # should only be called once my $_self = $self; weaken $_self; # or get circular refs inside the callbacks # validation models all return 1 if param being validated should 'pass': my %validation_models = ( validate_request_number => sub { my $request_number = shift; return $_self->model('Request')->get_requests_count($request_number); }, validate_specimen => sub { my $specimen = shift; # warn $specimen; return $_self->model('Specimen')->validate_specimen($specimen); }, # can have non-unique test_names, but not with same lab_section_id: # validate_lab_test => sub { # my $data = shift; # return $_self->model('LabTest')->check_lab_test_unique($data); # }, # check form field param is unique, or belongs to current record under edit: validate_param_ownership => sub { my $args = shift; # warn Dumper $args; return $_self->model('Validation')->validate_param_ownership($args); }, # just need to check nhs_number not already in use: validate_nhs_number_unique => sub { my $nhs_no = shift; return $_self->model('Patient')->check_patient_nhs_number_count($nhs_no); }, # check storage vial ID is unique: has_unique_storage_vialId => sub { my $id = shift; # return false if entry already exists: return $_self->model('Validation')->has_storage_vialId($id) ? 0 : 1; }, # how many lab_tests: get_lab_tests_count => sub { return $_self->model('Base')->get_objects_count('LabTest'); }, # hmrn_treatment_types: hmrn_treatment_types => sub { return $_self->model('HMRN')->get_tx_type_map; }, # hmrn_param_constraints: hmrn_param_constraints => sub { return $_self->model('HMRN')->get_parameter_constraints; }, # get meta data: get_meta => sub { $_self->get_meta_data(@_) } ); return \%validation_models; } #------------------------------------------------------------------------------- # sets tmpl vars & returns FormValidator::Simple::check result against supplied profile: sub form_validator { my $self = shift; my $profile = shift; # arrayref my $result = FormValidator::Simple->check( $self->query => $profile ); $self->tt_params( form_validator => $result ); return $result; } #------------------------------------------------------------------------------- # put requested JavaScript::DataFormValidator profile into tt_params # profile_name required - provides name for tmpl accessor and name of validation # profile to load (if not supplied direct) sub js_validation_profile { my $self = shift; my $profile_name = shift; # name of DFV profile to retrieve from $self->validate my $dfv_profile = shift; # optional; only C::Report::outreach() supplies it direct # get dfv validation profile from validate() if not supplied: if (! $dfv_profile) { $dfv_profile = $self->validate($profile_name) or die "cannot find validation profile for '$profile_name'"; } # grep methods compatible with JS::DFV: my %js_compatible_profile = map { $_ => $dfv_profile->{$_}, } grep $dfv_profile->{$_}, ( # only include methods supported in FormValidator.js v0.06 (not contraint_methods, # or contrainsts: named closures, sub-routine references or compiled regex): 'required', 'optional', 'dependencies', 'dependency_groups', 'constraints', 'msgs', ); # create js_validation_profile for template: $self->tt_params( # Javascript snippet for