File Coverage

blib/lib/Jifty/DBI/Schema.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1 3     3   207846 use warnings;
  3         5  
  3         136  
2 3     3   13 use strict;
  3         5  
  3         161  
3              
4             package Jifty::DBI::Schema;
5              
6             =head1 NAME
7              
8             Jifty::DBI::Schema - Use a simple syntax to describe a Jifty table.
9              
10             =head1 SYNOPSIS
11              
12             package MyApp::Model::Page;
13             use Jifty::DBI::Schema;
14             use Jifty::DBI::Record schema {
15             # ... your columns here ...
16             };
17              
18             =cut
19              
20             =head1 DESCRIPTION
21              
22             Each Jifty Application::Model::Class module describes a record class
23             for a Jifty application. Each C<column> statement sets out the name
24             and attributes used to describe the column in a backend database, in
25             user interfaces, and other contexts. For example:
26              
27             column content =>
28             type is 'text',
29             label is 'Content',
30             render as 'textarea';
31              
32             defines a column called C<content> that is of type C<text>. It will be
33             rendered with the label C<Content> (note the capital) and as a C<textarea> in
34             a HTML form.
35              
36             Jifty::DBI::Schema builds a L<Jifty::DBI::Column>. That class defines
37             other attributes for database structure that are not exposed directly
38             here. One example of this is the "refers_to" method used to create
39             associations between classes.
40              
41             =cut
42              
43 3     3   35 use Carp qw/croak carp/;
  3         6  
  3         200  
44 3     3   2821 use Scalar::Defer;
  0            
  0            
45             use Object::Declare (
46             mapping => {
47             column => sub { Jifty::DBI::Column->new({@_}) } ,
48             },
49             aliases => {
50             default_value => 'default',
51             available => 'available_values',
52             valid => 'valid_values',
53             render => 'render_as',
54             order => 'sort_order',
55             filters => 'input_filters',
56             },
57             copula => {
58             is => '',
59             are => '',
60             as => '',
61             ajax => 'ajax_',
62             refers_to => sub { refers_to => @_ },
63             refers => sub { refers_to => @_ },
64             }
65             );
66             use Class::Data::Inheritable;
67              
68             our @EXPORT = qw( defer lazy column schema by );
69              
70             our $SCHEMA;
71             our $SORT_ORDERS = {};
72              
73             use Exporter::Lite ();
74             # TODO - This "sub import" is strictly here to catch the deprecated "length is 40".
75             # Once the deprecation cycle is over we should take this away and rever to
76             # "use Exporter::Lite" in the line above.
77             sub import {
78             my $old_sig_die = $SIG{__DIE__};
79              
80             $SIG{__DIE__} = sub {
81             # Calling it by hand means we restore the old sighandler.
82             $SIG{__DIE__} = (($old_sig_die == $SIG{__DIE__}) ? undef : $old_sig_die);
83             return unless @_;
84              
85             local $SIG{__DIE__} = sub { 1 };
86             if ($_[0] =~ /near "is (\d+)"/) {
87             carp @_, << ".";
88              
89             *********************************************************
90              
91             Due to an incompatible API change, the "length" field in
92             Jifty::DBI columns has been renamed to "max_length":
93            
94             column foo =>
95             length is $1; # NOT VALID
96              
97             Please write this instead:
98            
99             column foo =>
100             max_length is $1 # VALID
101              
102             Sorry for the inconvenience.
103              
104             **********************************************************
105              
106              
107             .
108             exit 1;
109             }
110             elsif ($_[0] =~ /Undefined subroutine &Jifty::DBI::Schema::column|Can't locate object method "type" via package "(?:is|are)"/) {
111             my $from = (caller)[0];
112             $from =~ s/::Schema$//;
113             my $base = $INC{'Jifty/Record.pm'} ? "Jifty::Record" : "Jifty::DBI::Record";
114              
115             no strict 'refs';
116             carp @_, << ".";
117             *********************************************************
118              
119             Calling 'column' within a schema class is an error:
120            
121             package $from\::Schema;
122             column foo => ...; # NOT VALID
123              
124             Please write this instead:
125              
126             package $from;
127             use Jifty::DBI::Schema;
128             use @{[(${"$from\::ISA"} || [$base])->[0] || $base]} schema {
129             column foo => ...; # VALID
130             };
131              
132             Sorry for the inconvenience.
133              
134             *********************************************************
135             .
136             }
137              
138             die @_;
139             };
140              
141             goto &Exporter::Lite::import;
142             }
143              
144             sub by { @_ }
145              
146             =head1 FUNCTIONS
147              
148             All these functions are exported. However, if you use the C<schema> helper function,
149             they will be unimported at the end of the block passed to C<schema>.
150              
151             =head2 schema
152              
153             Takes a block with schema declarations. Unimports all helper functions after
154             executing the code block. Usually used at C<BEGIN> time via this idiom:
155              
156             use Jifty::DBI::Record schema { ... };
157              
158             If your application subclasses C<::Record>, then write this instead:
159              
160             use MyApp::Record schema { ... };
161              
162             =cut
163              
164             sub schema (&) {
165             my $code = shift;
166             my $from = caller;
167              
168             my $new_code = sub {
169             no warnings 'redefine';
170             local *_ = sub { my $args = \@_; defer { _(@$args) } };
171             $from->_init_columns;
172              
173             my @columns = &declare($code);
174              
175             # Unimport all our symbols from the calling package.
176             foreach my $sym (@EXPORT) {
177             no strict 'refs';
178             undef *{"$from\::$sym"}
179             if \&{"$from\::$sym"} == \&$sym;
180             }
181              
182             foreach my $column (@columns) {
183             next if !ref($column);
184             _init_column($column);
185             }
186              
187             # Then initialize all columns
188             foreach my $column ( sort keys %{ $from->COLUMNS || {} } ) {
189             $from->_init_methods_for_column( $from->COLUMNS->{$column} );
190             }
191             };
192              
193             return ('-base' => $new_code);
194             }
195              
196             use Hash::Merge ();
197              
198             no warnings 'uninitialized';
199             use constant MERGE_PARAM_BEHAVIOUR => {
200             SCALAR => {
201             SCALAR => sub { CORE::length($_[1]) ? $_[1] : $_[0] },
202             ARRAY => sub { [ @{$_[1]} ] },
203             HASH => sub { $_[1] } },
204             ARRAY => {
205             SCALAR => sub { CORE::length($_[1]) ? $_[1] : $_[0] },
206             ARRAY => sub { [ @{$_[1]} ] },
207             HASH => sub { $_[1] } },
208             HASH => {
209             SCALAR => sub { CORE::length($_[1]) ? $_[1] : $_[0] },
210             ARRAY => sub { [ @{$_[1]} ] },
211             HASH => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) } }
212             };
213              
214             =head2 merge_params HASHREF HASHREF
215              
216             Takes two hashrefs. Merges them together and returns the merged hashref.
217              
218             - Empty fields in subclasses don't override nonempty fields in superclass anymore.
219             - Arrays don't merge; e.g. if parent class's valid_values is [1,2,3,4], and
220             subclass's valid_values() is [1,2], they don't somehow become [1,2,3,4,1,2].
221              
222             BUG: This should either be a private routine or factored out into Jifty::Util
223              
224              
225              
226             =cut
227              
228             sub merge_params {
229             my $prev_behaviour = Hash::Merge::get_behavior();
230             Hash::Merge::specify_behavior( MERGE_PARAM_BEHAVIOUR, "merge_params" );
231             my $rv = Hash::Merge::merge(@_);
232             Hash::Merge::set_behavior( $prev_behaviour );
233             return $rv;
234             }
235              
236              
237             sub _init_column {
238             my $column = shift;
239             my $name = $column->name;
240              
241             my $from = (caller(2))[0];
242             $from =~ s/::Schema//;
243              
244             croak "Base of schema class $from is not a Jifty::DBI::Record"
245             unless UNIVERSAL::isa($from, "Jifty::DBI::Record");
246              
247             croak "Illegal column definition for column $name in $from"
248             if grep {not UNIVERSAL::isa($_, "Jifty::DBI::Schema::Trait")} @_;
249              
250             $column->readable(!(delete $column->{unreadable}));
251             $column->writable(!(delete $column->{immutable}));
252              
253             # XXX: deprecated
254             $column->mandatory(1) if delete $column->{not_null};
255              
256             $column->sort_order($SORT_ORDERS->{$from}++);
257              
258             $column->input_filters($column->{input_filters} || []);
259             $column->output_filters($column->{output_filters} || []);
260              
261             if ( my $refclass = $column->refers_to ) {
262             if (ref($refclass) eq 'ARRAY') {
263             $column->by($refclass->[1]);
264             $column->refers_to($refclass = $refclass->[0]);
265             }
266              
267             $refclass->require();
268             $column->type('integer') unless ( $column->type );
269              
270             if ( UNIVERSAL::isa( $refclass, 'Jifty::DBI::Record' ) ) {
271             if ( $name =~ /(.*)_id$/ ) {
272             my $aliased_as = $1;
273             my $virtual_column = $from->add_column($aliased_as);
274              
275             # XXX FIXME I think the next line is wrong, but things
276             # explode without it -- mostly because we unique-key
277             # on name instead of some conbination of name and
278             # alias_for_column in a couple places
279             $virtual_column->name( $name );
280             $virtual_column->aliased_as($aliased_as);
281             # $_->apply($virtual_column) for @args;
282             $column->refers_to(undef);
283             $virtual_column->alias_for_column($name);
284             $from->_init_methods_for_column($virtual_column);
285             }
286             $column->by('id') unless $column->by;
287             $column->type('integer') unless $column->type;
288             } elsif ( UNIVERSAL::isa( $refclass, 'Jifty::DBI::Collection' ) ) {
289             $column->by('id') unless $column->by;
290             $column->virtual('1');
291             } else {
292             warn "Error: $refclass neither Record nor Collection";
293             }
294             } else {
295             $column->type('varchar(255)') unless $column->type;
296             }
297              
298              
299             $from->COLUMNS->{$name} = $column;
300              
301             # Heuristics: If we are called through Jifty::DBI::Schema,
302             # then we know that we are going to initialize methods later
303             # through the &schema wrapper, so we defer initialization here
304             # to not upset column names such as "label" and "type".
305             # (We may not *have* a caller(1) if the user is executing a .pm file.)
306             }
307              
308             1;
309              
310             __END__
311              
312             =head2 refers_to
313              
314             Indicates that the column references an object or a collection of objects in another
315             class. You may refer to either a class that inherits from Jifty::Record by a primary
316             key in that class or to a class that inherits from Jifty::Collection.
317              
318             Correct usage is C<refers_to Application::Model::OtherClass by 'column_name'>, where
319             Application::Model::OtherClass is a valid Jifty model and C<'column_name'> is
320             a column containing unique values in OtherClass. You can omit C<by 'column_name'> and
321             the column name 'id' will be used.
322              
323             If you are referring to a Jifty::Collection then you must specify C<by 'column_name'>.
324              
325             When accessing the value in the column the actual object referenced will be returned for
326             refernces to Jifty::Records and a reference to a Jifty::Collection will be returned for
327             columns referring to Jifty::Collections.
328              
329             For columns referring to Jifty::Records you can access the actual value of the column
330             instead of the object reference by appending '_id' to the column name. As a result,
331             you may not end any column name which uses 'refers_to' using '_id'.
332              
333             =cut
334              
335             =head2 type
336              
337             type passed to our database abstraction layer, which should resolve it
338             to a database-specific type. Correct usage is C<type is 'text'>.
339              
340             Currently type is passed directly to the database. There is no
341             intermediary mapping from abstract type names to database specific
342             types.
343              
344             The impact of this is that not all column types are portable between
345             databases. For example blobs have different names between
346             mysql and postgres.
347              
348             =head2 default
349              
350             Give a default value for the column. Correct usage is C<default is
351             'foo'>.
352              
353             =head2 literal
354              
355             Used for default values, to connote that they should not be quoted
356             before being supplied as the default value for the column. Correct
357             usage is C<default is literal 'now()'>.
358              
359             =head2 validator
360              
361             Defines a subroutine which returns a true value only for valid values
362             this column can have. Correct usage is C<validator is \&foo>.
363              
364             =head2 immutable
365              
366             States that this column is not writable. This is useful for
367             properties that are set at creation time but not modifiable
368             thereafter, like 'created by'. Correct usage is C<is immutable>.
369              
370             =head2 unreadable
371              
372             States that this column is not directly readable by the application
373             using C<< $record->column >>; this is useful for password columns and
374             the like. The data is still accessible via C<< $record->_value('') >>.
375             Correct usage is C<is unreadable>.
376              
377             =head2 max_length
378              
379             Sets a maximum max_length to store in the database; values longer than
380             this are truncated before being inserted into the database, using
381             L<Jifty::DBI::Filter::Truncate>. Note that this is in B<bytes>, not
382             B<characters>. Correct usage is C<max_length is 42>.
383              
384              
385             =head2 mandatory
386              
387             Mark as a required column. May be used for generating user
388             interfaces. Correct usage is C<is mandatory>.
389              
390             =head2 not_null
391              
392             Same as L</mandatory>. This is deprecated. Currect usage would be
393             C<is not_null>.
394              
395             =head2 autocompleted
396              
397             Mark as an autocompleted column. May be used for generating user
398             interfaces. Correct usage is C<is autocompleted>.
399              
400             =head2 distinct
401              
402             Declares that a column should only have distinct values. This
403             currently is implemented via database queries prior to updates
404             and creates instead of constraints on the database columns
405             themselves. This is because there is no support for distinct
406             columns implemented in L<DBIx::DBSchema> at this time.
407             Correct usage is C<is distinct>.
408              
409             =head2 virtual
410              
411             Declares that a column is not backed by an actual column in the
412             database, but is instead computed on-the-fly.
413              
414             =head2 sort_order
415              
416             Declares an integer sort value for this column. By default, Jifty will sort
417             columns in the order they are defined.
418              
419             =head2 order
420              
421             Alias for C<sort_order>.
422              
423             =head2 input_filters
424              
425             Sets a list of input filters on the data. Correct usage is
426             C<input_filters are 'Jifty::DBI::Filter::DateTime'>. See
427             L<Jifty::DBI::Filter>.
428              
429             =head2 output_filters
430              
431             Sets a list of output filters on the data. Correct usage is
432             C<output_filters are 'Jifty::DBI::Filter::DateTime'>. See
433             L<Jifty::DBI::Filter>. You usually don't need to set this, as the
434             output filters default to the input filters in reverse order.
435              
436             =head2 filters
437              
438             Sets a list of filters on the data. These are applied when reading
439             B<and> writing to the database. Correct usage is C<filters are
440             'Jifty::DBI::Filter::DateTime'>. See L<Jifty::DBI::Filter>. In
441             actuality, this is the exact same as L</input_filters>, since output
442             filters default to the input filters, reversed.
443              
444             =head2 since
445              
446             What application version this column was last changed. Correct usage
447             is C<since '0.1.5'>.
448              
449             =head2 valid_values
450              
451             A list of valid values for this column. Jifty will use this to
452             autoconstruct a validator for you. This list may also be used to
453             generate the user interface. Correct usage is C<valid_values are
454             qw/foo bar baz/>.
455              
456             If you want to display different values than are stored in the DB
457             you can pass a list of hashrefs, each containing two keys, display
458             and value.
459              
460             valid_values are
461             { display => 'Blue', value => 'blue' },
462             { display => 'Red', value => 'red' }
463              
464             =head2 valid
465              
466             Alias for C<valid_values>.
467              
468             =head2 label
469              
470             Designates a human-readable label for the column, for use in user
471             interfaces. Correct usage is C<label is 'Your foo value'>.
472              
473             =head2 hints
474              
475             A sentence or two to display in long-form user interfaces about what
476             might go in this column. Correct usage is C<hints is 'Used by the
477             frobnicator to do strange things'>.
478              
479             =head2 render_as
480              
481             Used in user interface generation to know how to render the column.
482              
483             The values for this attribute are the same as the names of the modules under
484             L<Jifty::Web::Form::Field>, i.e.
485              
486             =over
487              
488             =item * Button
489              
490             =item * Checkbox
491              
492             =item * Combobox
493              
494             =item * Date
495              
496             =item * Hidden
497              
498             =item * InlineButton
499              
500             =item * Password
501              
502             =item * Radio
503              
504             =item * Select
505              
506             =item * Textarea
507              
508             =item * Upload
509              
510             =item * Unrendered
511              
512             =back
513              
514             You may also use the same names with the initial character in lowercase.
515              
516             The "Unrendered" may seem counter-intuitive, but is there to allow for
517             internal fields that should not actually be displayed.
518              
519             If these don't meet your needs, you can write your own subclass of
520             L<Jifty::Web::Form::Field>. See the documentation for that module.
521              
522             =head2 render
523              
524             Alias for C<render_as>.
525              
526             =head2 indexed
527              
528             An index will be built on this column
529             Correct usage is C<is indexed>
530              
531              
532             =head1 EXAMPLE
533              
534             =head1 AUTHOR
535              
536             =head1 BUGS
537              
538             =head1 SUPPORT
539              
540             =head1 COPYRIGHT & LICENSE
541              
542             This program is free software; you can redistribute it and/or modify it
543             under the same terms as Perl itself.
544              
545             =cut
546              
547             1;