File Coverage

blib/lib/RapidApp/Module/DbicNavTree.pm
Criterion Covered Total %
statement 38 49 77.5
branch 8 16 50.0
condition 2 5 40.0
subroutine 7 8 87.5
pod 0 3 0.0
total 55 81 67.9


line stmt bran cond sub pod time code
1             package RapidApp::Module::DbicNavTree;
2              
3 4     4   2082 use strict;
  4         13  
  4         123  
4 4     4   18 use warnings;
  4         8  
  4         143  
5              
6             # ABSTRACT: general purpose navtree for auto grid access to DBIC sources
7              
8 4     4   23 use Moose;
  4         5  
  4         30  
9             extends 'RapidApp::Module::NavTree';
10              
11              
12 4     4   23456 use RapidApp::Util qw(:all);
  4         9  
  4         7165  
13             require Module::Runtime;
14              
15             has 'dbic_models', is => 'ro', isa => 'Maybe[ArrayRef[Str]]', default => undef;
16             has 'table_class', is => 'ro', isa => 'Str', required => 1;
17             has 'configs', is => 'ro', isa => 'HashRef', default => sub {{}};
18             has 'menu_require_role', is => 'ro', isa => 'Maybe[Str]', default => sub {undef};
19              
20             has 'dbic_model_tree', is => 'ro', isa => 'ArrayRef[HashRef]', lazy => 1, default => sub {
21             my $self = shift;
22             die "Must supply either 'dbic_models' or 'dbic_model_tree'" unless ($self->dbic_models);
23             my $list = parse_dbic_model_list($self->app,@{$self->dbic_models});
24            
25             # validate models:
26             for my $itm (@$list) {
27             my $Model = $self->app->model($itm->{model});
28             die "Error: model '$itm->{model}' is not a Catalyst::Model::DBIC::Schema"
29             unless ($Model->isa('Catalyst::Model::DBIC::Schema'));
30            
31             warn join("\n",'',
32             " WARNING: using DBIC model '$itm->{model}' without 'quote_names' enabled.",
33             " It is strongly reccomended that this setting be enabled...",
34             " (Set env var RAPIDAPP_ISSUE99_IGNORE to supress this message)",'',''
35             ) unless ($Model->connect_info->{quote_names} || $ENV{RAPIDAPP_ISSUE99_IGNORE});
36             }
37            
38             # strip excludes/limits:
39             for my $itm (@$list) {
40             my $mdl_cfg = $self->configs->{$itm->{model}} || {};
41             my $exclude_sources = $mdl_cfg->{exclude_sources} || [];
42             my %excl_sources = map { $_ => 1 } @$exclude_sources;
43             @{$itm->{sources}} = grep { ! $excl_sources{$_} } @{$itm->{sources}};
44             my $lim = $mdl_cfg->{limit_sources} ? {map{$_=>1} @{$mdl_cfg->{limit_sources}}} : undef;
45             if($lim) {
46             @{$itm->{sources}} = grep { $lim->{$_} } @{$itm->{sources}};
47             }
48             }
49            
50             return $list;
51             };
52              
53             # return a flat list of all loaded source models:
54             sub all_source_models {
55 0     0 0 0 my $self = shift;
56 0         0 my @list = ();
57 0         0 foreach my $hash (@{$self->dbic_model_tree}) {
  0         0  
58 0         0 push @list, map { $hash->{model} . '::' . $_ } @{$hash->{sources}};
  0         0  
  0         0  
59             }
60 0         0 return @list;
61             }
62              
63              
64             # General func instead of class method for use in other packages (temporary):
65             sub parse_dbic_model_list {
66 4     4 0 10 my $c = shift;
67 4         16 my @models = @_;
68            
69 4         12 my %schemas = ();
70 4         10 my %sources = ();
71 4         10 my @list = ();
72 4         12 for my $model (@models) {
73 5 50       15 die "Bad argument" if (ref $model);
74 5 50       46 my $Model = $c->model($model) or die "No such model '$model'";
75 5         461 my ($schema, $result) = ($model);
76            
77 5 50       102 if($Model->isa('DBIx::Class::ResultSet')){
78 0         0 my @parts = split(/\:\:/,$model);
79 0         0 $result = pop @parts;
80 0         0 $schema = join('::',@parts);
81             }
82            
83 5 50       19 my $M = $c->model($schema) or die "No such model '$schema'";
84 5 50       274 die "Model '$schema' does not appear to be a DBIC Schema Model."
85             unless ($M->can('schema'));
86            
87 5 50       21 unless ($schemas{$schema}) {
88 5         14 $schemas{$schema} = [];
89             push @list, {
90             model => $schema,
91 5         24 sources => $schemas{$schema}
92             };
93             }
94            
95             # Either add specific/supplied result, or all results. Skip duplicates:
96 5 50       169 my @results = $result ? ($result) : $M->schema->sources;
97 5   50     496 $sources{$schema . '::' . $_}++ or push @{$schemas{$schema}}, $_ for (@results);
  54         170  
98             }
99            
100 4         23 return \@list;
101             }
102              
103              
104             sub BUILD {
105 4     4 0 17 my $self = shift;
106            
107 4         112 Module::Runtime::require_module($self->table_class);
108            
109             # menu_require_role only applies to the top level/navtree nodes which
110             # simply hides the links, but preserves access to the real pages/data
111 4 50 33     145 $self->apply_extconfig( require_role => $self->menu_require_role ) if (
112             ! $self->require_role &&
113             $self->menu_require_role
114             );
115            
116             # init
117 4         109 $self->TreeConfig;
118             }
119              
120              
121             has 'TreeConfig', is => 'ro', isa => 'ArrayRef[HashRef]', lazy => 1, default => sub {
122             my $self = shift;
123            
124             my @items = ();
125             for my $s (@{$self->dbic_model_tree}) {
126             my $model = $s->{model};
127             my $schema = $self->app->model($model)->schema;
128            
129             my $require_role = $self->require_role || try{$self->configs->{$model}{require_role}};
130             my $menu_req_role = $self->configs->{$model}{menu_require_role} || $require_role || $self->menu_require_role;
131            
132             my @children = ();
133             for my $source (sort @{$s->{sources}}) {
134             my $Source = $schema->source($source) or die "Source $source not found!";
135            
136             my $cust_def_config = try{$self->configs->{$model}{grid_params}{'*defaults'}} || {};
137             my $cust_config = try{$self->configs->{$model}{grid_params}{$source}} || {};
138             # since we're using these params over and over we need to protect refs in deep params
139             # since currently DataStore/TableSpec modules modify params like include_colspec in
140             # place (note this probably needs to be fixed in there for exactly this reason)
141             my $cust_merged = clone( Catalyst::Utils::merge_hashes($cust_def_config,$cust_config) );
142            
143             my $local_require_role = $cust_merged->{require_role} || $require_role;
144            
145             my $grid_class = $cust_merged->{grid_class} ? delete $cust_merged->{grid_class} :
146             try{$self->configs->{$model}{grid_class}} || $self->table_class;
147            
148             #my $table = $Source->schema->class($Source->source_name)->table;
149             #$table = (split(/\./,$table,2))[1] || $table; #<-- get 'table' for both 'db.table' and 'table' format
150             my $module_name = lc(join('_',$model,$source));
151             $module_name =~ s/\:\:/_/g;
152             $self->apply_init_modules( $module_name => {
153             class => $grid_class,
154             params => {
155             require_role => $local_require_role,
156             %$cust_merged,
157             ResultSource => $Source,
158             source_model => $model . '::' . $source,
159             }
160             });
161            
162             my $class = $schema->class($source);
163             my $text = $class->TableSpec_get_conf('title_multi') || $source;
164             my $iconCls = $class->TableSpec_get_conf('multiIconCls') || 'ra-icon-application-view-detail';
165             push @children, {
166             id => $module_name,
167             text => $text,
168             iconCls => $iconCls ,
169             module => $module_name,
170             params => {},
171             expand => 1,
172             children => [],
173             require_role => $local_require_role
174             }
175             }
176            
177            
178             my $exclude_sources = try{$self->configs->{$model}{exclude_sources}} || [];
179             my $expand = (try{$self->configs->{$model}{expand}}) ? 1 : 0;
180             my $text = (try{$self->configs->{$model}{text}}) || $model;
181             my $template = try{$self->configs->{$model}{template}};
182            
183            
184             my $dbd_driver = $schema->storage->dbh->{Driver}->{Name} || '';
185             my $iconcls = (try{$self->configs->{$model}{iconCls}}) || (
186             $dbd_driver eq 'SQLite'
187             ? 'ra-icon-page-white-database'
188             : 'ra-icon-server-database'
189             );
190            
191             my $module_name = lc($model);
192             $module_name =~ s/\:\:/_/g;
193             $self->apply_init_modules( $module_name => {
194             class => 'RapidApp::Module::DbicSchemaGrid',
195             params => {
196             Schema => $self->app->model($model)->schema,
197             tabTitle => $text,
198             tabIconCls => $iconcls,
199             exclude_sources => $exclude_sources,
200             header_template => $template,
201             require_role => $require_role,
202             menu_require_role => $menu_req_role
203             }
204             });
205            
206             my $itm_id = lc($model) . '_tables';
207             $itm_id =~ s/\:\:/_/g;
208             push @items, {
209             id => $itm_id,
210             text => $text,
211             iconCls => $iconcls,
212             module => $module_name,
213             params => {},
214             expand => $expand,
215             children => \@children,
216             require_role => $menu_req_role
217             };
218             }
219            
220             return \@items;
221             };
222              
223              
224              
225             #### --------------------- ####
226              
227              
228 4     4   31 no Moose;
  4         14  
  4         22  
229             __PACKAGE__->meta->make_immutable;
230             1;