efc44ba3b49d7abb7f6629c47f85bb948a1983e4
[kivitendo-erp.git] / SL / DB / Helper / LinkedRecords.pm
1 package SL::DB::Helpers::LinkedRecords;
2
3 require Exporter;
4 our @ISA    = qw(Exporter);
5 our @EXPORT = qw(linked_records link_to_record);
6
7 use Carp;
8
9 use SL::DB::Helpers::Mappings;
10 use SL::DB::RecordLink;
11
12 sub linked_records {
13   my $self     = shift;
14   my %params   = @_;
15
16   my $wanted   = $params{direction} || croak("Missing parameter `direction'");
17   my $myself   = $wanted eq 'from' ? 'to' : $wanted eq 'to' ? 'from' : croak("Invalid parameter `direction'");
18
19   my $my_table = SL::DB::Helpers::Mappings::get_table_for_package(ref($self));
20
21   my @query    = ( "${myself}_table" => $my_table,
22                    "${myself}_id"    => $self->id );
23
24   if ($params{$wanted}) {
25     my $wanted_classes = ref($params{$wanted}) eq 'ARRAY' ? $params{$wanted} : [ $params{$wanted} ];
26     my $wanted_tables  = [ map { SL::DB::Helpers::Mappings::get_table_for_package($_) || croak("Invalid parameter `${wanted}'") } @{ $wanted_classes } ];
27     push @query, ("${wanted}_table" => $wanted_tables);
28   }
29
30   my $links            = SL::DB::Manager::RecordLink->get_all(query => [ and => \@query ]);
31
32   my $sub_wanted_table = "${wanted}_table";
33   my $sub_wanted_id    = "${wanted}_id";
34
35   my $records          = [];
36   @query               = ref($params{query}) eq 'ARRAY' ? @{ $params{query} } : ();
37
38   foreach my $link (@{ $links }) {
39     my $class = SL::DB::Helpers::Mappings::get_manager_package_for_table($link->$sub_wanted_table);
40     push @{ $records }, @{ $class->get_all(query => [ id => $link->$sub_wanted_id, @query ]) };
41   }
42
43   return $records;
44 }
45
46 sub link_to_record {
47   my $self   = shift;
48   my $other  = shift;
49
50   croak "self has no id"  unless $self->id;
51   croak "other has no id" unless $other->id;
52
53   my %params = ( from_table => SL::DB::Helpers::Mappings::get_table_for_package(ref($self)),
54                  from_id    => $self->id,
55                  to_table   => SL::DB::Helpers::Mappings::get_table_for_package(ref($other)),
56                  to_id      => $other->id,
57                );
58
59   my $link = SL::DB::Manager::RecordLink->find_by(and => [ %params ]);
60   return $link ? $link : SL::DB::RecordLink->new(%params)->save;
61 }
62
63 1;
64
65 __END__
66
67 =encoding utf8
68
69 =head1 NAME
70
71 SL::DB::Helpers::LinkedRecords - Mixin for retrieving linked records via the table C<record_links>
72
73 =head1 FUNCTIONS
74
75 =over 4
76
77 =item C<linked_records %params>
78
79 Retrieves records linked from or to C<$self> via the table
80 C<record_links>. The mandatory parameter C<direction> (either C<from>
81 or C<to>) determines whether the function retrieves records that link
82 to C<$self> (for C<direction> = C<to>) or that are linked from
83 C<$self> (for C<direction> = C<from>).
84
85 The optional parameter C<from> or C<to> (same as C<direction>)
86 contains the package names of Rose models for table limitation. It can
87 be a single model name as a single scalar or multiple model names in
88 an array reference in which case all links matching any of the model
89 names will be returned.
90
91 If you only need invoices created from an order C<$order> then the
92 call could look like this:
93
94   my $invoices = $order->linked_records(direction => 'to',
95                                         to        => 'SL::DB::Invoice');
96
97 The optional parameter C<query> can be used to limit the records
98 returned. The following call limits the earlier example to invoices
99 created today:
100
101   my $invoices = $order->linked_records(direction => 'to',
102                                         to        => 'SL::DB::Invoice',
103                                         query     => [ transdate => DateTime->today_local ]);
104
105 Returns an array reference.
106
107 =item C<link_to_record $record>
108
109 Will create an entry in the table C<record_links> with the C<from>
110 side being C<$self> and the C<to> side being C<$record>. Will only
111 insert a new entry if such a link does not already exist.
112
113 Returns either the existing link or the newly created one as an
114 instance of C<SL::DB::RecordLink>.
115
116 =back
117
118 =head1 BUGS
119
120 Nothing here yet.
121
122 =head1 AUTHOR
123
124 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
125
126 =cut