File Coverage

blib/lib/Backed_Objects.pm
Criterion Covered Total %
statement 6 56 10.7
branch 0 12 0.0
condition n/a
subroutine 2 25 8.0
pod 22 23 95.6
total 30 116 25.8


line stmt bran cond sub pod time code
1             package Backed_Objects;
2              
3 1     1   28266 use warnings;
  1         3  
  1         29  
4 1     1   5 use strict;
  1         2  
  1         1226  
5              
6             =head1 NAME
7              
8             Backed_Objects - Create static files from a database.
9              
10             =head1 VERSION
11              
12             Version 1.16
13              
14             =cut
15              
16             our $VERSION = '1.16';
17              
18             =head1 SYNOPSIS
19              
20             Create static files from a database.
21             Update the files every time when you update the database.
22              
23             It can be used with any kind of database, for example SQL databases,
24             Berkeley databases, data stored in .ini files, etc.
25              
26             =head1 USAGE OF THE CLASS
27              
28             The class C is an abstract base class and you need to
29             derive your class from it. For further suppose you developed a class
30             C derived from C. We will call HTML (for example)
31             files which are updated by this module I.
32              
33             All methods can be called either as object methods or as class methods.
34              
35             Calling these as class methods may be convienient when you do not need to
36             specify additional parameters to be put into an object.
37              
38             Thus the following alternatives are possible:
39              
40             HTML_DB->output_all_and_order;
41              
42             or
43              
44             my $obj = HTML_DB->new;
45             $obj->output_all_and_order;
46              
47             Examples below assume that you are familiar with SQL and C module.
48              
49             =head1 Database update methods
50              
51             The class C offers you flexibility on the way how you
52             update your database.
53              
54             One variant is to override C, C, C, C methods,
55             so that they will update your database when C, C, C
56             methods are called.
57              
58             The other variant is to update the database yourself and I
59             to call C, C, C which will call the default
60             do-nothing C, C, C, C methods.
61              
62             =head1 The object and the ID
63              
64             A database stores objects, every object stored in a database has an ID.
65             An object may be without an ID when it is not yet stored into the DB, but
66             you must assign an ID to an object when you store it in the DB, either
67             by overriding C method which should set the object ID or yourself
68             in your own code (without overriding C). C must have
69             C method which receives an object and return its ID.
70              
71             The interface of this module does not specify what objects are. Objects may
72             be hashes or any other data structures.
73              
74             Every object inserted into the database has ID (which may be a natural number,
75             but is not required to be a number).
76              
77             Sometimes you may want the objects and IDs to be the same. For example, it is
78             often OK for an object and an ID to be a row ID in a SQL database. Or you may
79             want an object to be a hash representing a row in an SQL DB.
80              
81             Sometimes a middle solution is fit: Store an object as a hash with some
82             values from the database and read the rest values from the DB when needed,
83             using the ID stored in the object.
84              
85             An other possibililty for an object is to be a hash based on user input in
86             a HTML form.
87              
88             =head1 METHODS
89              
90             =head2 id
91              
92             This abstract (not defined in C method) must be defined to
93             return the ID of an object.
94              
95             Examples:
96              
97             sub id {
98             my ($self, $obj) = @_;
99             return $obj->{id};
100             }
101              
102             or
103              
104             # Objects are simple IDs
105             sub id {
106             my ($self, $obj) = @_;
107             return $obj;
108             }
109              
110             =head2 all_ids
111              
112             This abstract (not defined in C method) must return a list of
113             all IDs in the database.
114              
115             sub all_ids {
116             my ($self) = @_;
117             return @{ $dbh->selectcol_arrayref("SELECT id FROM table") };
118             }
119              
120             =cut
121              
122             =head2 do_select
123              
124             This abstract method should return an object from the DB having a given ID.
125              
126             sub do_select {
127             my ($self, $id) = @_;
128             return $dbh->selectrow_hashref("SELECT * FROM table WHERE id=?", undef, $id);
129             }
130              
131             or
132              
133             # Objects are simple IDs
134             sub do_select {
135             my ($self, $id) = @_;
136             return $id;
137             }
138              
139             =head2 select
140              
141             This method returns an object from the DB or C if the ID is absent
142             (undefined or zero).
143              
144             See its implementation:
145              
146             sub select {
147             my ($self, $id) = @_;
148             return undef unless $id;
149             return $self->do_select($id);
150             }
151              
152             =cut
153              
154             sub select {
155 0     0 1   my ($self, $id) = @_;
156 0 0         return undef unless $id;
157 0           return $self->do_select($id);
158             }
159              
160             =head2 do_insert, do_update, do_delete, post_process
161              
162             By default these methods do nothing. (In this case you need to update database
163             yourself, before calling C, C, or C methods.)
164              
165             You may override these methods to do database updates:
166              
167             sub do_insert {
168             my ($self, $obj) = @_;
169             my @keys = keys %$obj;
170             my @values = values %$obj;
171             my $set = join ', ', map { "$_=?" } @keys;
172             $dbh->do("INSERT table SET $set", undef, @values);
173             $obj->{id} = $dbh->last_insert_id(undef, undef, undef, undef);
174             }
175              
176             sub do_update {
177             my ($self, $obj) = @_;
178             my @keys = keys %$obj;
179             my @values = values %$obj;
180             my $set = join ', ', map { "$_=?" } @keys;
181             $dbh->do("UPDATE table SET $set WHERE id=?", undef, @values, $obj->{id});
182             }
183              
184             sub do_delete {
185             my ($self, $id) = @_;
186             $dbh->do("DELETE FROM table WHERE id=?", undef, $id);
187             }
188              
189             sub post_process {
190             my ($self, $obj) = @_;
191             ...
192             }
193              
194             C should set object ID after it is saved into the database.
195              
196             C is called by C after the object is inserted into
197             the database (and the object ID is set). It can be used for amending the
198             object with operations which require some object ID, for example for
199             uploading files into a folder with name being based on the ID.
200              
201             C is also called by C.
202              
203             =cut
204              
205       0 1   sub do_insert { }
206       0 1   sub do_update { }
207       0 1   sub do_delete { }
208       0 1   sub post_process { }
209              
210             =head2 outputter
211              
212             This method should return a value used to output a view of the DB
213             (for example it may be used to output HTML files and be a hash whose values
214             are HTML templates).
215              
216             Example:
217              
218             use File::Slurp;
219              
220             sub outputter {
221             my ($self) = @_;
222             my $template_dir = "$ENV{DOCUMENT_ROOT}/templates";
223             return { main_tmpl => read_file("$template_dir/main.html"),
224             announce_tmpl => read_file("$template_dir/announce.html") };
225             }
226              
227             The default implementation returns C.
228              
229             =cut
230              
231       0 1   sub outputter { }
232              
233             =head2 insert, update, delete
234              
235             HTML_DB->insert($obj);
236             HTML_DB->update($obj);
237             HTML_DB->delete($id);
238              
239             These functions update the view based on the value C<$obj> from the DB.
240             They are to be called when an object is inserted, updated, or deleted in
241             the DB.
242              
243             If you've overridden the C, C, or C methods,
244             then C, C, or C methods update the database before
245             updating the view.
246              
247             Note that C methods calls both C and C methods
248             (as well as some other methods, see the source).
249              
250             C and C also call C.
251              
252             C also calls C before calling C.
253             The C method can be used to update the data based on
254             old data in the DB, before the DB is updated by C.
255              
256             =cut
257              
258             # Calls both on_update() and on_insert()
259             sub insert {
260 0     0 1   my ($self, $obj) = @_;
261 0 0         die "Inserting an object into DB second time!" if $self->id($obj);
262 0           $self->do_insert($obj);
263 0           $self->post_process($obj);
264 0           $self->on_insert($obj);
265 0           $self->on_update($obj);
266 0           $self->on_order_change;
267 0           $self->on_any_change;
268             }
269              
270             sub update {
271 0     0 1   my ($self, $obj) = @_;
272 0 0         die "Updating an object not in DB!" unless $self->id($obj);
273 0           $self->before_update($obj);
274 0           $self->do_update($obj);
275 0           $self->post_process($obj);
276 0           $self->on_update($obj);
277 0           $self->on_any_change;
278             }
279              
280             sub delete {
281 0     0 1   my ($self, $id) = @_;
282 0           $self->do_delete($id);
283 0           $self->on_order_change;
284 0           $self->on_delete($id);
285 0           $self->on_any_change;
286             }
287              
288             =head2 on_update, on_update_one
289              
290             C method it called when an object in the database is updated or after
291             a new object is inserted.
292              
293             C is the method called by C. The C
294             method is meant to update view of one object. Contrary to this, C
295             may be overridden to update several objects by calling C several
296             times. For example, when updating title of a HTML file, we may want to update
297             two more HTML files with titles of prev/next links dependent on the title of
298             this object.
299              
300             By default C calls the C method to update the view of the
301             object.
302              
303             =cut
304              
305             sub on_update {
306 0     0 1   my ($self, $obj) = @_;
307 0           $self->on_update_one($obj);
308             }
309              
310             sub on_update_one {
311 0     0 1   my ($self, $obj) = @_;
312 0           $self->output(scalar($self->outputter), $obj, 1);
313             }
314              
315             =head2 on_insert, on_delete, on_order_change, before_update
316              
317             sub on_insert {
318             my ($self, $obj) = @_;
319             ...
320             }
321              
322             sub on_delete {
323             my ($self, $id) = @_;
324             ...
325             }
326              
327             sub on_order_change {
328             my ($self) = @_;
329             ...
330             }
331              
332             sub before_update {
333             my ($self, $obj) = @_;
334             ...
335             }
336              
337             These methods (doing nothing by default) are called correspondingly when:
338              
339             =over
340              
341             =item inserting a new object into the database;
342              
343             =item deleting an object from the database;
344              
345             =item changing order of objects in the database (including the case of inserting a new object).
346              
347             =item before calling C to update the database.
348              
349             =back
350              
351             By default these methods do nothing.
352              
353             You may update your view in your overrides of these methods.
354              
355             C is called by C (but not by C) before updating
356             the DB with C.
357              
358             =cut
359              
360       0 1   sub on_insert { }
361       0 1   sub on_delete { }
362       0 1   sub on_order_change { }
363       0 1   sub before_update { }
364              
365             =head2 on_any_change
366              
367             sub on_any_change {
368             my ($self) = @_;
369             ...
370             }
371              
372             This method is called after every change of the database, for example,
373             after insertion, deletion, update, etc.
374              
375             =cut
376              
377       0 1   sub on_any_change { }
378              
379             =head2 do_output
380              
381             sub do_output {
382             my ($self, $outputter, $obj, $update) = @_;
383             ...
384             }
385              
386             This is the main method to output your files (the view).
387              
388             It receives the object and the outputter returned by the C method.
389              
390             $update is TRUE only if it is called from C method. It can be used
391             not to update what needs not updating. (TODO: Document it better.)
392              
393             =cut
394              
395       0 1   sub do_output { }
396              
397             =head2 order_change
398              
399             HTML_DB->order_change;
400              
401             Call C after you changed the order of objects in the
402             database (but not after calling C or C method which call
403             C automatically).
404              
405             =cut
406              
407             sub order_change {
408 0     0 1   my ($self) = @_;
409 0           $self->on_order_change;
410 0           $self->on_any_change;
411             }
412              
413             =head2 output_by_id
414              
415             An internal function.
416              
417             =cut
418              
419             sub output_by_id {
420 0     0 1   my ($self, $id, $outputter) = @_;
421 0 0         $outputter = $self->outputter unless $outputter;
422 0           my $obj = $self->select($id);
423 0           $self->output($outputter, $obj);
424             }
425              
426             =head2 output_all
427              
428             HTML_DB->output_all;
429             HTML_DB->output_all_and_order;
430              
431             C updates the entire set of your files based on the
432             data in the DB.
433              
434             C additionally updates data dependent on the order
435             of objects in the DB.
436              
437             Use these methods to update your all files (for example, after your template
438             changed).
439              
440             =cut
441              
442             sub output_all {
443 0     0 1   my ($self) = @_;
444 0           my @ids = $self->all_ids;
445 0           my $outputter = $self->outputter;
446 0           for my $id (@ids) {
447 0           $self->output_by_id($id, $outputter);
448             }
449 0           $self->on_any_change;
450             }
451              
452             # Is it better to first call output_all and then on_order_change, or the reverse
453             sub output_all_and_order {
454 0     0 0   my ($self) = @_;
455 0           $self->output_all;
456 0           $self->on_order_change;
457             }
458              
459             =head2 save
460              
461             HTML_DB->save($obj);
462              
463             This saves an object into the DB: updates it if it is already in the DB
464             (has an ID) or inserts it into the DB if it has an undefined ID.
465              
466             The actual code:
467              
468             sub save {
469             my ($self, $obj) = @_;
470             if($self->id($obj)) {
471             $self->update($obj);
472             } else {
473             $self->insert($obj);
474             }
475             }
476              
477             =cut
478              
479             sub save {
480 0     0 1   my ($self, $obj) = @_;
481 0 0         if($self->id($obj)) {
482 0           $self->update($obj);
483             } else {
484 0           $self->insert($obj);
485             }
486             }
487              
488             =head2 output
489              
490             An internal function.
491              
492             =cut
493              
494             sub output {
495 0     0 1   my ($self, $outputter, $obj, $update) = @_;
496 0 0         die "Object has no ID!" unless $self->id($obj);
497 0           $self->do_output(scalar($outputter), $obj, $update);
498             }
499              
500             =head1 AUTHOR
501              
502             Victor Porton, C<< >>
503              
504             =head1 BUGS
505              
506             Please report any bugs or feature requests to C, or through
507             the web interface at L. I will be notified, and then you'll
508             automatically be notified of progress on your bug as I make changes.
509              
510             In the current version of C there are no provision for passing
511             file handles for example got from a HTML form with a C control.
512             A complexity is that usually to upload a file we need to already know the
513             ID of a row in a database what is possible only I inserting into the DB.
514             Your suggestions how to deal with this problem are welcome.
515              
516             =head1 SUPPORT
517              
518             You can find documentation for this module with the perldoc command.
519              
520             perldoc Backed_Objects
521              
522              
523             You can also look for information at:
524              
525             =over 4
526              
527             =item * RT: CPAN's request tracker
528              
529             L
530              
531             =item * AnnoCPAN: Annotated CPAN documentation
532              
533             L
534              
535             =item * CPAN Ratings
536              
537             L
538              
539             =item * Search CPAN
540              
541             L
542              
543             =back
544              
545             =head1 LICENSE AND COPYRIGHT
546              
547             Copyright 2011 Victor Porton.
548              
549             This program is free software; you can redistribute it and/or modify it
550             under the terms of either: the GNU General Public License as published
551             by the Free Software Foundation; or the Artistic License.
552              
553             See http://dev.perl.org/licenses/ for more information.
554              
555              
556             =cut
557              
558             1; # End of Backed_Objects