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