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