Commit | Line | Data |
d816d7bf |
1 | package Catalyst::TraitFor::Model::DBIC::Schema::SchemaProxy; |
2 | |
3 | use namespace::autoclean; |
4 | use Moose::Role; |
5 | use Carp::Clan '^Catalyst::Model::DBIC::Schema'; |
ae3d05c2 |
6 | use Catalyst::Model::DBIC::Schema::Types 'Schema'; |
d816d7bf |
7 | |
8 | =head1 NAME |
9 | |
10 | Catalyst::TraitFor::Model::DBIC::Schema::SchemaProxy - Proxy Schema Methods and |
11 | Options from Model |
12 | |
13 | =head1 DESCRIPTION |
14 | |
ae3d05c2 |
15 | Allows you to call your L<DBIx::Class::Schema> methods directly on the Model |
21d8159f |
16 | instance, and passes config options to your L<DBIx::Class::Schema> and |
17 | L<DBIx::Class::ResultSet> attributes at C<BUILD> time. |
d816d7bf |
18 | |
21d8159f |
19 | Methods and attributes local to your C<Model> take precedence over |
20 | L<DBIx::Class::Schema> or L<DBIx::Class::ResultSet> methods and attributes. |
21 | |
22 | =head1 CREATING SCHEMA CONFIG ATTRIBUTES |
23 | |
24 | To create attributes in your C<Schema.pm>, use either Moose or |
25 | L<Class::Accessor::Grouped>, which is inherited from by all L<DBIx::Class> |
26 | classes automatically. E.g.: |
27 | |
28 | __PACKAGE__->mk_group_accessors(simple => qw/ |
29 | config_key1 |
30 | config_key2 |
31 | ... |
32 | /); |
33 | |
34 | Or with L<Moose>: |
35 | |
36 | use Moose; |
37 | has config_key1 => (is => 'rw', default => 'default_value'); |
38 | |
39 | This code can be added after the md5sum on L<DBIx::Class::Schema::Loader> |
40 | generated schemas. |
41 | |
42 | At app startup, any non-local options will be passed to these accessors, and can |
43 | be accessed as usual via C<< $schema->config_key1 >>. |
44 | |
45 | These config values go into your C<Model::DB> block, along with normal config |
46 | values. |
47 | |
48 | =head1 CREATING RESULTSET CONFIG ATTRIBUTES |
49 | |
50 | You can create classdata on L<DBIx::Class::ResultSet> classes to hold values |
51 | from L<Catalyst> config. |
52 | |
53 | The code for this looks something like this: |
54 | |
55 | package MySchema::ResultSet::Foo; |
56 | |
57 | use base 'DBIx::Class::ResultSet'; |
58 | |
59 | __PACKAGE__->mk_group_accessors(inherited => qw/ |
60 | rs_config_key1 |
61 | rs_config_key2 |
62 | ... |
63 | /); |
64 | __PACKAGE__->rs_config_key1('default_value'); |
65 | |
66 | Or, if you prefer L<Moose>: |
67 | |
68 | package MySchema::ResultSet::Foo; |
69 | |
70 | use Moose; |
71 | use MooseX::NonMoose; |
72 | use MooseX::ClassAttribute; |
73 | extends 'DBIx::Class::ResultSet'; |
74 | |
81c30dcf |
75 | sub BUILDARGS { $_[2] } # important |
76 | |
21d8159f |
77 | class_has rs_config_key1 => (is => 'rw', default => 'default_value'); |
78 | |
81c30dcf |
79 | ... |
80 | |
81 | __PACKAGE__->meta->make_immutable; |
82 | |
83 | 1; |
84 | |
21d8159f |
85 | In your catalyst config, use the generated Model name as the config key, e.g.: |
86 | |
87 | <Model::DB::Users> |
88 | strict_passwords 1 |
89 | </Model::DB::Users> |
d816d7bf |
90 | |
91 | =cut |
92 | |
93 | after setup => sub { |
94 | my ($self, $args) = @_; |
95 | |
ae3d05c2 |
96 | my $schema = $self->schema; |
97 | |
d816d7bf |
98 | my $was_mutable = $self->meta->is_mutable; |
99 | |
100 | $self->meta->make_mutable; |
101 | $self->meta->add_attribute('schema', |
102 | is => 'rw', |
ae3d05c2 |
103 | isa => Schema, |
d816d7bf |
104 | handles => $self->_delegates # this removes the attribute too |
105 | ); |
106 | $self->meta->make_immutable unless $was_mutable; |
ae3d05c2 |
107 | |
108 | $self->schema($schema) if $schema; |
d816d7bf |
109 | }; |
110 | |
111 | after BUILD => sub { |
112 | my ($self, $args) = @_; |
113 | |
114 | $self->_pass_options_to_schema($args); |
21d8159f |
115 | |
116 | for my $source ($self->schema->sources) { |
117 | my $config_key = 'Model::' . $self->model_name . '::' . $source; |
118 | my $config = $self->app_class->config->{$config_key}; |
119 | next unless $config; |
120 | $self->_pass_options_to_resultset($source, $config); |
121 | } |
d816d7bf |
122 | }; |
123 | |
124 | sub _delegates { |
125 | my $self = shift; |
126 | |
127 | my $schema_meta = Class::MOP::Class->initialize($self->schema_class); |
128 | my @schema_methods = $schema_meta->get_all_method_names; |
129 | |
130 | # combine with any already added by other schemas |
131 | my @handles = eval { |
132 | @{ $self->meta->find_attribute_by_name('schema')->handles } |
133 | }; |
134 | |
135 | # now kill the attribute, otherwise add_attribute in BUILD will not do the right |
136 | # thing (it clears the handles for some reason.) May be a Moose bug. |
137 | eval { $self->meta->remove_attribute('schema') }; |
138 | |
139 | my %schema_methods; |
140 | @schema_methods{ @schema_methods, @handles } = (); |
141 | @schema_methods = keys %schema_methods; |
142 | |
143 | my @my_methods = $self->meta->get_all_method_names; |
144 | my %my_methods; |
145 | @my_methods{@my_methods} = (); |
146 | |
147 | my @delegates; |
148 | for my $method (@schema_methods) { |
149 | push @delegates, $method unless exists $my_methods{$method}; |
150 | } |
151 | |
152 | return \@delegates; |
153 | } |
154 | |
155 | sub _pass_options_to_schema { |
156 | my ($self, $args) = @_; |
157 | |
158 | my @attributes = map { |
159 | $_->init_arg || () |
160 | } $self->meta->get_all_attributes; |
161 | |
162 | my %attributes; |
163 | @attributes{@attributes} = (); |
164 | |
165 | for my $opt (keys %$args) { |
166 | if (not exists $attributes{$opt}) { |
167 | next unless $self->schema->can($opt); |
21d8159f |
168 | $self->schema->$opt($args->{$opt}); |
169 | } |
170 | } |
171 | } |
172 | |
173 | sub _pass_options_to_resultset { |
174 | my ($self, $source, $args) = @_; |
175 | |
21d8159f |
176 | for my $opt (keys %$args) { |
f24a5fbb |
177 | my $rs_class = $self->schema->source($source)->resultset_class; |
178 | next unless $rs_class->can($opt); |
179 | $rs_class->$opt($args->{$opt}); |
d816d7bf |
180 | } |
181 | } |
182 | |
183 | =head1 SEE ALSO |
184 | |
185 | L<Catalyst::Model::DBIC::Schema>, L<DBIx::Class::Schema> |
186 | |
187 | =head1 AUTHOR |
188 | |
189 | See L<Catalyst::Model::DBIC::Schema/AUTHOR> and |
190 | L<Catalyst::Model::DBIC::Schema/CONTRIBUTORS>. |
191 | |
192 | =head1 COPYRIGHT |
193 | |
194 | See L<Catalyst::Model::DBIC::Schema/COPYRIGHT>. |
195 | |
196 | =head1 LICENSE |
197 | |
198 | This program is free software, you can redistribute it and/or modify it |
199 | under the same terms as Perl itself. |
200 | |
201 | =cut |
202 | |
203 | 1; |