Commit | Line | Data |
1f9daa1e |
1 | =head1 NAME |
2 | |
3 | Reaction::Manual::Internals |
4 | |
5 | =head2 Hacking on Reaction |
6 | |
7 | =head3 What is a component? |
8 | |
9 | =head3 What component types are there? |
10 | |
11 | =head3 How do I create a new component? |
12 | |
13 | =head3 How does it work with a database? |
14 | |
15 | =head3 What about Moose? |
16 | |
17 | L<Moose> |
18 | |
19 | =head3 Type system |
20 | |
21 | =head3 What Perl modules should I be familiar with, in order to hack on Reaction's |
22 | internals? |
23 | |
24 | =over |
25 | |
26 | =item L<Moose> |
27 | |
28 | A complete modern object system for Perl 5. |
29 | |
30 | =item L<aliased> |
31 | |
32 | Use shorter package names, i.e., "X::Y::Z" as "Z". |
33 | |
34 | =item L<Catalyst> |
35 | |
36 | The MVC application framework Reaction uses. |
37 | |
38 | =over |
39 | |
40 | =item * L<Catalyst::Controller::BindLex> |
41 | |
42 | =item * L<Catalyst::Model::DBIC::Schema> |
43 | |
44 | =item * L<Catalyst::Plugin::ConfigLoader> |
45 | |
46 | =item * L<Catalyst::Plugin::I18N> |
47 | |
48 | =item * L<Catalyst::Plugin::Static::Simple> |
49 | |
50 | =item * L<Catalyst::View::TT> |
51 | |
52 | =back |
53 | |
54 | =item TT |
55 | |
56 | Template Toolkit |
57 | |
58 | =item L<Config::General> |
59 | |
60 | Generic config file module. |
61 | |
62 | =item L<DBIx::Class> |
63 | |
64 | Object/Relational mapper. |
65 | |
66 | =item L<DateTime> |
67 | |
68 | =item L<DateTime::Format::MySQL> |
69 | |
70 | =item L<Digest::MD5> |
71 | |
72 | =item L<Email::MIME> |
73 | |
74 | =item L<Email::MIME::Creator> |
75 | |
76 | =item L<Email::Send> |
77 | |
78 | =item L<Email::Valid> |
79 | |
80 | =item L<SQL::Translator> |
81 | |
82 | =item L<Test::Class> |
83 | |
84 | =item L<Test::Memory::Cycle> |
85 | |
86 | =item L<Time::ParseDate> |
87 | |
88 | =back |
89 | |
90 | =head3 Packages involved |
91 | |
92 | =over |
93 | |
94 | =item L<Reaction::Class> |
95 | |
96 | Utility class, sets up to export a few methods that return parameters for use |
97 | within Moose's C<has> (as new parameters) in other packages. It also C<use>s |
98 | Moose itself. |
99 | |
100 | The methods it injects are: |
101 | |
102 | =over |
103 | |
104 | =item set_or_lazy_build($field_name) |
105 | |
106 | The attribute is required, if not provided beforehand the build_${name} method |
107 | will be called on the object when the attribute's getter is first called. If |
108 | the method does not exist, or returns undef, an error will be thrown. |
109 | |
110 | =item set_or_lazy_fail() |
111 | |
112 | The attribute is required, if not provided beforehand the 'lazy' parameter of |
113 | Moose will make it fail. |
114 | |
115 | =item trigger_adopt() |
116 | |
117 | Calls adopt_${type} after the attribute value is set to $type. |
118 | |
119 | =item register_inc_entry() |
120 | |
121 | Will mark the calling package as already included, using %INC. |
122 | |
123 | =back |
124 | |
125 | =item Reaction::InterfaceModel::Action |
126 | |
127 | =item Reaction::InterfaceModel::Action::DBIC::ResultSet::Create; |
128 | |
129 | =item Reaction::InterfaceModel::Action::DBIC::ActionReflector; |
130 | |
131 | A method "adaptor" that creates the needed objects to support CRUD DBIC |
132 | actions. In the future the code could be moved to a class higher in the |
133 | hierarchy and only contain the operations to adapt. |
134 | |
135 | Sample run: |
136 | |
137 | Reaction::InterfaceModel::Action::DBIC::ActionReflector->reflect_actions_for( |
138 | Reaction::InterfaceModel::Action::DBIC::ActionReflector=HASH(0x93cb2f0) |
139 | RTest::TestDB::Foo |
140 | ComponentUI::Model::Action |
141 | ) |
142 | |
143 | Generates and evaluates: |
144 | |
145 | package ComponentUI::Model::Action::DeleteFoo; |
146 | use Reaction::Class; |
147 | extends 'Reaction::InterfaceModel::Action::DBIC::Result::Delete'; |
148 | package ComponentUI::Model::Action::UpdateFoo; |
149 | use Reaction::Class; |
150 | extends 'Reaction::InterfaceModel::Action::DBIC::Result::Update'; |
151 | has 'baz_list' => (isa => 'ArrayRef', is => 'rw', set_or_lazy_fail('baz_list'), default => sub { [] }, valid_values => sub { |
152 | $_[0]->target_model |
153 | ->result_source |
154 | ->related_source('links_to_baz_list') |
155 | ->related_source('baz') |
156 | ->resultset; |
157 | }); |
158 | has 'last_name' => (isa => 'NonEmptySimpleStr', is => 'rw', set_or_lazy_fail('last_name')); |
159 | has 'first_name' => (isa => 'NonEmptySimpleStr', is => 'rw', set_or_lazy_fail('first_name')); |
160 | package ComponentUI::Model::Action::CreateFoo; |
161 | use Reaction::Class; |
162 | extends 'Reaction::InterfaceModel::Action::DBIC::ResultSet::Create'; |
163 | has 'baz_list' => (isa => 'ArrayRef', is => 'rw', set_or_lazy_fail('baz_list'), default => sub { [] }, valid_values => sub { |
164 | $_[0]->target_model |
165 | ->result_source |
166 | ->related_source('links_to_baz_list') |
167 | ->related_source('baz') |
168 | ->resultset; |
169 | }); |
170 | has 'last_name' => (isa => 'NonEmptySimpleStr', is => 'rw', set_or_lazy_fail('last_name')); |
171 | has 'first_name' => (isa => 'NonEmptySimpleStr', is => 'rw', set_or_lazy_fail('first_name')); |
172 | |
173 | =item Reaction::InterfaceModel::Action::DBIC::Result::Delete |
174 | |
175 | =item Reaction::InterfaceModel::Action::DBIC::Result::Update |
176 | |
177 | =item Reaction::InterfaceModel::Action::DBIC::User::ResetPassword |
178 | |
179 | =item Reaction::InterfaceModel::Action::DBIC::User::Role::SetPassword |
180 | |
181 | =item Reaction::InterfaceModel::Action::DBIC::User::ChangePassword |
182 | |
183 | =item Reaction::InterfaceModel::Action::User::ResetPassword |
184 | |
185 | =item Reaction::InterfaceModel::Action::User::ChangePassword |
186 | |
187 | =item Reaction::InterfaceModel::Action::User::SetPassword |
188 | |
189 | =item Reaction::Meta::InterfaceModel::Action::ParameterAttribute |
190 | |
191 | =item Reaction::Meta::InterfaceModel::Action::Class |
192 | |
193 | =item Reaction::Types::Email |
194 | |
195 | =item Reaction::Types::Core |
196 | |
197 | =item Reaction::Types::DateTime |
198 | |
199 | =item Reaction::Types::File |
200 | |
201 | =item Reaction::Types::DBIC |
202 | |
203 | =item Reaction::UI::ViewPort::ListView |
204 | |
205 | =item Reaction::UI::ViewPort::Field::Text |
206 | |
207 | =item Reaction::UI::ViewPort::Field::ChooseMany |
208 | |
209 | =item Reaction::UI::ViewPort::Field::String |
210 | |
211 | =item Reaction::UI::ViewPort::Field::Number |
212 | |
213 | =item Reaction::UI::ViewPort::Field::HiddenArray |
214 | |
215 | =item Reaction::UI::ViewPort::Field::DateTime |
216 | |
217 | =item Reaction::UI::ViewPort::Field::File |
218 | |
219 | =item Reaction::UI::ViewPort::Field::ChooseOne |
220 | |
221 | =item Reaction::UI::ViewPort::Field::Password |
222 | |
223 | =item Reaction::UI::ViewPort::ActionForm |
224 | |
225 | =item Reaction::UI::ViewPort::Field |
226 | |
227 | =item Reaction::UI::FocusStack |
228 | |
229 | =item Reaction::UI::RootController |
230 | |
231 | =item Reaction::UI::Window |
232 | |
233 | =item Reaction::UI::Renderer::XHTML |
234 | |
235 | =item Reaction::UI::ViewPort |
236 | |
237 | =item Reaction::UI::CRUDController |
238 | |
239 | =item Reaction::UI::Controller |
240 | |
241 | =back |
242 | |
243 | =head3 Remarks about POD |
244 | |
245 | Don't use C<=over N>. POD assumes that the indent level is 4 if you leave |
246 | it out. Most POD renderers ignore your indent level anyway. |
247 | |
248 | =head2 UNSORTED |
249 | |
250 | Packages involved |
251 | |
252 | t/lib/Rtest/TestDB*: TestDB DBIC declarations. |
253 | t/lib/RTest/TestDB.pm: does DBIC populate for t/. |
254 | t/lib/RTest/UI/ XXX |
255 | |
256 | Reaction::Test::WithDB; |
257 | Reaction::Test; |
258 | Reaction::Test::Mock::Context; |
259 | Reaction::Test::Mock::Request; |
260 | Reaction::Test::Mock::Response; |
261 | |
262 | =head1 AUTHORS |
263 | |
264 | See L<Reaction::Class> for authors. |
265 | |
266 | =head1 LICENSE |
267 | |
268 | See L<Reaction::Class> for the license. |
269 | |
270 | =cut |