File Coverage

blib/lib/OpenERP/OOM/Object.pm
Criterion Covered Total %
statement 25 83 30.1
branch 0 30 0.0
condition n/a
subroutine 8 19 42.1
pod 4 4 100.0
total 37 136 27.2


line stmt bran cond sub pod time code
1             package OpenERP::OOM::Object;
2              
3             =head1 NAME
4              
5             OpenERP::OOM::Object
6              
7             =head1 SYNOPSIS
8              
9             package Package::OpenERP::Object::Account;
10              
11             use 5.010;
12             use OpenERP::OOM::Object;
13              
14             openerp_model 'account.account';
15              
16             has active => (is => 'rw', isa => 'Bool'); # Active
17             has code => (is => 'rw', isa => 'Str'); # (required) Code
18              
19             ...
20              
21             relationship 'consolidated_children' => (
22             key => 'child_consol_ids',
23             type => 'many2many',
24             class => 'Account',
25             ); # Consolidated Children
26              
27             ...
28              
29             1;
30              
31             =head1 DESCRIPTION
32              
33             Use this module to create the 'objects' for your models. It also implicitly loads
34             Moose too.
35              
36             The class is linked to a model in OpenERP.
37              
38             =head1 METHODS
39              
40             =head2 openerp_model
41              
42             Specify the model in OpenERP.
43              
44             =head2 init_meta
45              
46             An internal method that hooks up the Moose internals and implicitly makes your
47             new classes inherit from OpenERP::OOM::Object::Base. See the
48             OpenERP::OOM::Object::Base documentation for a list of the methods your objects
49             will have by default.
50              
51             =head2 relationship
52              
53             Used to specify relationships between this object and others in OpenERP.
54              
55             Possible options for the type are many2one, one2many and many2many. These
56             are specified in OpenERP in those terms.
57              
58             =head2 has_link
59              
60             Used to indicate links with other systems. Typically this is to another table
61             in DBIC at the moment.
62              
63             The key field is in OpenERP and is used for the ids of the objects to link to.
64              
65             The class is used to ask the link provider to provide a link by this name. It
66             is not necessarily treated as a class, but the default link provider does do that.
67              
68             Possible options for type are C<single> and C<multiple>.
69              
70             has_link 'details' => (
71             key => 'x_dbic_link_id',
72             type => 'single',
73             class => 'DBIC',
74             args => {class => 'AuctionHouseDetails'},
75             );
76              
77             =head1 COPYRIGHT & LICENSE
78              
79             Copyright (C) 2011 OpusVL
80              
81             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
82              
83             =cut
84              
85 2     2   4000 use 5.010;
  2         7  
86 2     2   10 use Carp;
  2         5  
  2         118  
87 2     2   11 use Moose;
  2         3  
  2         12  
88 2     2   11507 use Moose::Exporter;
  2         6  
  2         8  
89 2     2   66 use Moose::Util::MetaRole;
  2         4  
  2         75  
90 2     2   12 use Moose::Util::TypeConstraints;
  2         3  
  2         14  
91 2     2   4727 use Switch::Plain;
  2         1351  
  2         9  
92              
93             #-------------------------------------------------------------------------------
94              
95             # Set up a subtype for many2one relationships. On object retrieval, OpenERP
96             # presents this relationship as an array reference holding the ID and the name
97             # of the related object, e.g.
98             #
99             # [ 1, 'Related object name' ]
100             #
101             # However, when updating the object OpenERP expects this to be presented back
102             # as a single integer containing the related object ID.
103              
104             subtype 'OpenERP::OOM::Type::Many2One'
105             => as 'Maybe[Int]';
106              
107             coerce 'OpenERP::OOM::Type::Many2One'
108             => from 'ArrayRef'
109             => via { $_->[0] };
110              
111              
112             #-------------------------------------------------------------------------------
113              
114             # Export the 'openerp_model' and 'relationship' methods
115              
116             Moose::Exporter->setup_import_methods(
117             with_meta => ['openerp_model', 'relationship', 'has_link'],
118             also => 'Moose',
119             );
120              
121              
122             #-------------------------------------------------------------------------------
123              
124             sub init_meta {
125 1     1 1 110 shift;
126 1         5 my %args = @_;
127              
128 1         7 Moose->init_meta( %args, base_class => 'OpenERP::OOM::Object::Base' );
129              
130             Moose::Util::MetaRole::apply_metaroles(
131             for => $args{for_class},
132 1         573 class_metaroles => {
133             class => [
134             'OpenERP::OOM::Meta::Class::Trait::HasRelationship',
135             'OpenERP::OOM::Meta::Class::Trait::HasLink',
136             ],
137             attribute => ['OpenERP::OOM::Roles::Attribute'],
138             },
139             );
140              
141             Moose::Util::MetaRole::apply_base_class_roles(
142             for_class => $args{for_class},
143 1         3512 roles => ['OpenERP::OOM::Roles::Class'],
144             );
145              
146             }
147              
148              
149             #-------------------------------------------------------------------------------
150              
151             sub openerp_model {
152 0     0 1   my ($meta, $name, %options) = @_;
153              
154             $meta->add_method(
155             'model',
156 0     0     sub {return $name},
157 0           );
158             }
159              
160              
161             #-------------------------------------------------------------------------------
162              
163             sub relationship {
164 0     0 1   my ($meta, $name, %options) = @_;
165              
166             #carp "Adding relationship $name";
167              
168             $meta->relationship({
169 0           %{$meta->relationship},
  0            
170             $name => \%options
171             });
172              
173             #say "Adding hooks";
174              
175             sswitch ($options{type}) {
176             case ('many2one'): {
177 0           goto &_add_rel2one;
178             }
179             case ('one2many'): {
180 0           goto &_add_rel2many;
181             }
182 0 0         case ('many2many'): {
    0          
    0          
183 0           goto &_add_rel2many;
184             }
185 0           }
186             }
187              
188              
189             #-------------------------------------------------------------------------------
190              
191             sub _add_rel2many {
192 0     0     my ($meta, $name, %options) = @_;
193              
194             $meta->add_attribute(
195             $options{key},
196 0           isa => 'ArrayRef',
197             is => 'rw',
198             );
199              
200             $meta->add_method(
201             $name,
202             sub {
203 0     0     my ($self, @args) = @_;
204 0           my $field_name = $options{key};
205 0 0         if(@args)
206             {
207 0           my @ids;
208 0 0         if(ref $args[0] eq 'ARRAY')
209             {
210             # they passed in an arrayref.
211             # i.e. $obj->rel([ $obj1, $obj2 ]);
212 0           my $objects = $args[0];
213 0           @ids = map { _id($_) } @$objects;
  0            
214             }
215             else
216             {
217             # assume they passed each object in as an arg
218             # i.e. $obj->rel($obj1, $obj2);
219 0           @ids = map { _id($_) } @args;
  0            
220             }
221 0           $self->$field_name(\@ids);
222 0 0         return unless defined wantarray; # avoid needless retrieval
223             }
224 0 0         return unless $self->{$field_name};
225 0           return $self->class->schema->class($options{class})->retrieve_list($self->{$field_name});
226             },
227 0           );
228             }
229              
230              
231             # this method means the user can simply pass in id's as well as
232             # objects.
233             sub _id
234             {
235 0     0     my $var = shift;
236 0 0         return ref $var ? $var->id : $var;
237             }
238              
239              
240             #-------------------------------------------------------------------------------
241              
242             sub _add_rel2one {
243 0     0     my ($meta, $name, %options) = @_;
244              
245 0           my $field_name = $options{key};
246 0           $meta->add_attribute(
247             $field_name,
248             isa => 'OpenERP::OOM::Type::Many2One',
249             is => 'rw',
250             coerce => 1,
251             );
252              
253 0           my $cache_field = '__cache_' . $field_name;
254 0           $meta->add_attribute(
255             $cache_field,
256             is => 'rw',
257             );
258              
259             $meta->add_method(
260             $name,
261             sub {
262 0     0     my $self = shift;
263 0 0         if(@_)
264             {
265 0           my $val = shift;
266 0 0         $self->$field_name($val ? _id($val) : undef);
267 0           $self->$cache_field(undef);
268 0 0         return unless defined wantarray; # avoid needless retrieval
269             }
270 0 0         return unless $self->{$options{key}};
271 0 0         return $self->$cache_field if defined $self->$cache_field;
272 0           my $val = $self->class->schema->class($options{class})->retrieve($self->{$options{key}});
273 0           $self->$cache_field($val);
274 0           return $val;
275             },
276 0           );
277             }
278              
279              
280             #-------------------------------------------------------------------------------
281              
282             sub has_link {
283 0     0 1   my ($meta, $name, %options) = @_;
284              
285             $meta->link({
286 0           %{$meta->link},
  0            
287             $name => \%options
288             });
289              
290             sswitch ($options{type}) {
291             case ('single'): {
292 0           goto &_add_link_single;
293             }
294 0 0         case ('multiple'): {
    0          
295 0           goto &_add_link_multiple;
296             }
297 0           }
298             }
299              
300              
301             #-------------------------------------------------------------------------------
302              
303             sub _add_link_single {
304 0     0     my ($meta, $name, %options) = @_;
305              
306             $meta->add_attribute(
307             $options{key},
308 0           isa => 'Int',
309             is => 'ro',
310             );
311              
312             }
313              
314              
315             #-------------------------------------------------------------------------------
316              
317             sub _add_link_multiple {
318 0     0     my ($meta, $name, %options) = @_;
319              
320             $meta->add_attribute(
321             $options{key},
322 0           isa => 'ArrayRef',
323             is => 'ro',
324             );
325              
326             }
327              
328              
329             #-------------------------------------------------------------------------------
330              
331             1;