]> git.decadent.org.uk Git - maypole.git/blob - lib/Maypole/Model/Base.pm
use strict
[maypole.git] / lib / Maypole / Model / Base.pm
1 package Maypole::Model::Base;
2
3 use strict;
4 use Maypole::Constants;
5 use attributes ();
6
7 our %remember;
8
9 sub MODIFY_CODE_ATTRIBUTES { $remember{ $_[1] } = $_[2]; () }
10
11 sub FETCH_CODE_ATTRIBUTES { $remember{ $_[1] } || () }
12
13 sub process {
14     my ( $class, $r ) = @_;
15     my $method = $r->action;
16     return if $r->{template};    # Authentication has set this, we're done.
17
18     $r->{template} = $method;
19     my $obj = $class->fetch_objects($r);
20     $r->objects([$obj]) if $obj;
21     $class->$method( $r, $obj, @{ $r->{args} } );
22 }
23
24 sub list_columns {
25     shift->display_columns;
26 }
27
28 sub display_columns {
29     sort shift->columns;
30 }
31
32 =head1 NAME
33
34 Maypole::Model::Base - Base class for model classes
35
36 =head1 DESCRIPTION
37
38 This is the base class for Maypole data models. This is an abstract class
39 that defines the interface, and can't be used directly.
40
41 =head2 process
42
43 This is the engine of this module. Given the request object, it populates
44 all the relevant variables and calls the requested action.
45
46 Anyone subclassing this for a different database abstraction mechanism
47 needs to provide the following methods:
48
49 =head2 setup_database
50
51     $model->setup_database($config, $namespace, @data)
52
53 Uses the user-defined data in C<@data> to specify a database- for
54 example, by passing in a DSN. The model class should open the database,
55 and create a class for each table in the database. These classes will
56 then be C<adopt>ed. It should also populate C<< $config->tables >> and
57 C<< $config->classes >> with the names of the classes and tables
58 respectively. The classes should be placed under the specified
59 namespace. For instance, C<beer> should be mapped to the class
60 C<BeerDB::Beer>.
61
62 =head2 class_of
63
64     $model->class_of($r, $table)
65
66 This maps between a table name and its associated class.
67
68 =head2 fetch_objects
69
70 This class method is passed a request object and is expected to return an
71 object of the appropriate table class from information stored in the request
72 object.
73
74 =head2 adopt
75
76 This class method is passed the name of a model class that represensts a table
77 and allows the master model class to do any set-up required.
78
79 =head2 columns
80
81 This is a list of all the columns in a table. You may also override
82 see also C<display_columns>
83
84 =head2 table
85
86 This is the name of the table.
87
88 =cut 
89
90 sub class_of       { die "This is an abstract method" }
91 sub setup_database { die "This is an abstract method" }
92 sub fetch_objects { die "This is an abstract method" }
93
94 =head2 Actions
95
96 =over
97
98 =item do_edit
99
100 If there is an object in C<$r-E<gt>objects>, then it should be edited
101 with the parameters in C<$r-E<gt>params>; otherwise, a new object should
102 be created with those parameters, and put back into C<$r-E<gt>objects>.
103 The template should be changed to C<view>, or C<edit> if there were any
104 errors. A hash of errors will be passed to the template.
105
106 =cut
107
108 sub do_edit { die "This is an abstract method" }
109
110 =item list
111
112 The C<list> method should fill C<$r-E<gt>objects> with all of the
113 objects in the class. You may want to page this using C<Data::Page> or
114 similar.
115
116 =item edit
117
118 Empty Action.
119
120 =item view
121
122 Empty Action.
123
124
125 =back
126
127 =cut
128
129 sub list : Exported {
130     die "This is an abstract method";
131 }
132
133 sub view : Exported {
134 }
135
136 sub edit : Exported {
137 }
138
139 =pod
140
141 Also, see the exported commands in C<Maypole::Model::CDBI>.
142
143 =head1 Other overrides
144
145 Additionally, individual derived model classes may want to override the
146 following methods:
147
148 =head2 display_columns
149
150 Returns a list of columns to display in the model. By default returns
151 all columns in alphabetical order. Override this in base classes to
152 change ordering, or elect not to show columns.
153
154 =head2 list_columns
155
156 Same as display_columns, only for listings. Defaults to display_columns
157
158 =head2 column_names
159
160 Return a hash mapping column names with human-readable equivalents.
161
162 =cut
163
164 sub column_names {
165     my $class = shift;
166     map {
167         my $col = $_;
168         $col =~ s/_+(\w)?/ \U$1/g;
169         $_ => ucfirst $col
170     } $class->columns;
171 }
172
173 =head2 is_public
174
175 should return true if a certain action is supported, or false otherwise. 
176 Defaults to checking if the sub has the C<:Exported> attribute.
177
178 =cut
179
180 sub is_public {
181     my ( $self, $action ) = @_;
182     my $cv = $self->can($action);
183     return 0 unless $cv;
184     my $attrs = join " ", (attributes::get($cv) || ());
185     do {
186         warn "$action not exported" if Maypole->debug;
187         return 0;
188     } unless $attrs =~ /\bExported\b/i;
189     return 1;
190 }
191
192 =head2 related
193
194 This can go either in the master model class or in the individual
195 classes, and returns a list of has-many accessors. A brewery has many
196 beers, so C<BeerDB::Brewery> needs to return C<beers>.
197
198 =cut
199
200 sub related {
201 }
202
203 1;
204
205