Commit | Line | Data |
52d980cb |
1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
2 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
3 | |
4 | <html xmlns="http://www.w3.org/1999/xhtml"> |
5 | |
6 | <head> |
7 | <title>DBIx::Class (aka DBIC)</title> |
8 | <!-- metadata --> |
9 | <meta name="contributor" content="youcan[64]netzgesta[46]de" /> |
10 | <meta name="publisher" content="s5.netzgesta.de" /> |
11 | <meta name="description" content="S5 1.3 is a very flexible and lightweight slide show system available for anyone to use (including transitions and scalable fonts and images)" /> |
12 | <meta name="keywords" content="S5, version 1.3, slide show, presentation-mode, projection-mode, powerpoint-like, scala-like, keynote-like, incremental display, scalable fonts, scalable images, transitions, notes, osf, xoxo, css, javascript, xhtml, public domain" /> |
13 | |
14 | <meta name="generator" content="S5" /> |
15 | <meta name="version" content="1" /> |
16 | <meta name="subject" content="DBIx::Class" /> |
17 | <meta name="author" content="See first slide" /> |
18 | <meta name="company" content="N/A" /> |
19 | <meta name="robots" content="index, follow" /> |
20 | <meta name="revisit-after" content="7 days" /> |
21 | <!-- meta additionally --> |
22 | <meta http-equiv="content-type" content="text/html; charset=utf-8" /> |
23 | <meta http-equiv="Content-Script-Type" content="text/javascript" /> |
24 | <meta http-equiv="Content-Style-Type" content="text/css" /><!-- configuration parameters --> |
25 | <meta name="defaultView" content="slideshow" /> |
26 | <meta name="controlVis" content="hidden" /> |
27 | <!-- configuration transition extension --> |
28 | <meta name="tranSitions" content="true" /> |
29 | <meta name="fadeDuration" content="500" /> |
30 | <meta name="incrDuration" content="250" /> |
31 | <!-- configuration autoplay extension --> |
32 | <meta name="autoMatic" content="false" /> |
33 | <meta name="playLoop" content="true" /> |
34 | <meta name="playDelay" content="10" /> |
35 | <!-- configuration audio extension --> |
36 | <meta name="audioSupport" content="false" /> |
37 | <meta name="audioVolume" content="0" /> |
38 | <meta name="audioError" content="false" /> |
39 | <!-- configuration audio debug --> |
40 | <meta name="audioDebug" content="false" /> |
41 | <!-- style sheet links --> |
42 | <link rel="stylesheet" href="ui/scala_utf/slides.css" type="text/css" media="projection" id="slideProj" /> |
43 | <link rel="stylesheet" href="ui/scala_utf/outline.css" type="text/css" media="screen" id="outlineStyle" /> |
44 | <link rel="stylesheet" href="ui/scala_utf/print.css" type="text/css" media="print" id="slidePrint" /> |
45 | <link rel="stylesheet" href="ui/scala_utf/opera.css" type="text/css" media="projection" id="operaFix" /> |
46 | <!-- embedded styles --> |
47 | <style type="text/css" media="all"> |
48 | .imgcon {width: 100%; margin: 0 auto; padding: 0; text-align: center;} |
49 | #anim {width: 33%; height: 320px; position: relative;} |
50 | #anim img {position: absolute; top: 0px; left: 0px;} |
51 | .red {color: red;} |
52 | .grey {color: gray;} |
53 | </style> |
54 | <!-- S5 JS --> |
55 | <script src="ui/scala_utf/slides.js" type="text/javascript"></script> |
56 | </head> |
57 | <body> |
58 | |
59 | <div class="layout"> |
60 | <div id="controls"><!-- DO NOT EDIT --></div> |
61 | <div id="currentSlide"><!-- DO NOT EDIT --></div> |
62 | <div id="header"></div> |
63 | <div id="footer"> |
64 | <h1>DBIx::Class Introduction</h1> |
65 | <h2>YAPC::NA 2010</h2> |
66 | </div> |
67 | </div> |
68 | |
69 | <div class="presentation"> |
70 | |
71 | <div class="slide"> |
72 | <h1>DBIX::Class (aka DBIC)</h1> |
73 | <h3>for (advanced) beginners</h3> |
0cffcad7 |
74 | </div> |
75 | |
76 | <div class="slide"> |
77 | <h1>Authors</h1> |
78 | <h4>Originally Leo Lapworth @ LPW 2009</h4> |
79 | <h4>Matthew S. Trout</h4> |
80 | <h4>Arthur Axel "fREW" Schmidt</h4> |
81 | <h4>Justin D. Hunter</h4> |
52d980cb |
82 | </div> |
83 | |
84 | <div class="slide"> |
85 | <h1>assumptions</h1> |
86 | <p>You know a little about Perl and using objects</p> |
87 | <p>You know a little bit about databases and using foreign keys</p> |
0cffcad7 |
88 | <div class="notes"> |
89 | <ul> |
90 | <li>How many people have designed a database with Foreign Keys?</li> |
91 | <li>How many people have used any ORM?<ul> |
92 | <li>In Perl?<ul> |
93 | <li>DBIC?</li> |
94 | <li> Class::DBI? </li> |
95 | <li> Rose::DB? </li> |
96 | <li> Fey? </li> |
97 | <li> Others? </li> |
98 | </ul></li> |
99 | <li>AR? </li> |
100 | <li> DataMapper? </li> |
101 | <li>(N)Hibernate?</li> |
102 | </ul></li> |
103 | </ul> |
104 | </div> |
52d980cb |
105 | </div> |
106 | |
107 | <div class="slide"> |
108 | <h1>DBIx::Class?</h1> |
109 | <ul> |
110 | <li>ORM (object relational mapper)</li> |
111 | <li>SQL <-> OO (using objects instead of SQL)</li> |
112 | <li>Simple, powerful, complex, fab and confusing</li> |
113 | <li>There are many ORMs, DBIx::Class just happens to be the best in Perl (personal opinion)</li> |
114 | </ul> |
115 | </div> |
116 | |
117 | <div class="slide"> |
118 | <h1>why this talk?</h1> |
119 | <ul> |
120 | <li>Help avoid mistakes I made!</li> |
121 | <li>Help learn DBIx::Class faster</li> |
122 | <li>Make your coding easier</li> |
123 | </ul> |
124 | </div> |
125 | |
126 | <div class="slide"> |
127 | <h1>point of note</h1> |
128 | <p><em>"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." - Brian W. Kernighan</em></p> |
129 | <p>This talk is about making it easy so we are less likely to get confused</p> |
130 | </div> |
131 | |
132 | <div class="slide"> |
133 | <h1>table setup</h1> |
134 | </div> |
135 | |
136 | <div class="slide"> |
137 | <h1>example...</h1> |
138 | <ul> |
139 | <li>Authors</li> |
140 | <li>Books</li> |
141 | </ul> |
142 | </div> |
143 | |
144 | <div class="slide"> |
145 | <h1>authors table</h1> |
146 | <pre>CREATE TABLE authors( |
147 | id int(8) primary key auto_increment, |
148 | name varchar(255) |
149 | ) engine = InnoDB DEFAULT CHARSET=utf8;</pre> |
150 | </div> |
151 | |
152 | <div class="slide"> |
153 | <h1>tips</h1> |
154 | <p>Name tables as simple plurals (<strong>add an S</strong>) - makes relationships easier to understand</p> |
155 | <p>(issue: Matt Trout "Tables should not be plural as gives you plurals for Result:: package names which represent a single row" - talk may be rewritten in future to reflect this as this is better once you understand the relationship setup - either way, consistency is important)</p> |
156 | <p>Use a character set (<strong>UTF8</strong>) from the start (for international characters)</p> |
157 | </div> |
158 | |
159 | <div class="slide"> |
160 | <h1>authors table</h1> |
161 | <pre>CREATE TABLE author<strong>s</strong>( |
162 | id int(8) primary key auto_increment, |
163 | name varchar(255) |
164 | ) engine = <strong>InnoDB</strong> DEFAULT CHARSET=<strong>utf8</strong>;</pre> |
165 | </div> |
166 | |
167 | <div class="slide"> |
168 | <h1>books table</h1> |
169 | <pre>CREATE TABLE books( |
170 | id int(8) primary key auto_increment, |
171 | title varchar(255), |
172 | author int(8),foreign key (author) |
173 | references authors(id) |
174 | ) engine = InnoDB DEFAULT CHARSET=utf8;</pre> |
175 | </div> |
176 | |
177 | |
178 | <div class="slide"> |
179 | <h1>tips</h1> |
180 | <p>Name link fields as singular</p> |
181 | <p>Check foreign key is the same field and type and size in both tables</p> |
182 | </div> |
183 | |
184 | <div class="slide"> |
185 | <h1>books table</h1> |
186 | <pre>CREATE TABLE books( |
187 | id int(8) primary key auto_increment, |
188 | title varchar(255), |
189 | author <strong>int(8)</strong>,<strong>foreign key (<em>author</em>)</strong> |
190 | <strong>references <em>authors(id)</em></strong> |
191 | ) engine = InnoDB DEFAULT CHARSET=utf8;</pre> |
192 | </div> |
193 | |
194 | <div class="slide"> |
195 | <h1>CRUD compared</h1> |
196 | <ul> |
197 | <li><strong>C</strong> - Create</li> |
198 | <li><strong>R</strong> - Read</li> |
199 | <li><strong>U</strong> - Update</li> |
200 | <li><strong>D</strong> - Delete</li> |
201 | </ul> |
202 | </div> |
203 | |
204 | <div class="slide"> |
205 | <h1>Manual (SQL)</h1> |
206 | </div> |
207 | |
208 | <div class="slide"> |
209 | <h1>manual: create</h1> |
210 | <pre>my $sth = $dbh->prepare(' |
211 | INSERT INTO books |
212 | (title, author) |
213 | values (?,?) |
214 | '); |
215 | |
216 | $sth->execute( |
217 | 'A book title', $author_id |
218 | );</pre> |
219 | </div> |
220 | |
221 | <div class="slide"> |
222 | <h1>manual: create</h1> |
223 | <pre>my $sth = $dbh->prepare(' |
224 | <strong>INSERT INTO books |
225 | (title, author) |
226 | values (?,?)</strong> |
227 | '); |
228 | |
229 | $sth->execute( |
230 | 'A book title', <strong><em>$author_id</em></strong> |
231 | );</pre> |
232 | </div> |
233 | |
234 | <div class="slide"> |
235 | <h1>manual: retrieve</h1> |
236 | <pre>my $sth = $dbh->prepare(' |
237 | SELECT title, |
238 | authors.name as author_name |
239 | FROM books, authors |
240 | WHERE books.author = authors.id |
241 | ');</pre> |
242 | </div> |
243 | |
244 | <div class="slide"> |
245 | <h1>manual: retrieve</h1> |
246 | <pre>while( my $book = $sth->fetchrow_hashref() ) { |
247 | print 'Author of ' |
248 | . $book->{title} |
249 | . ' is ' |
250 | . $book->{author_name} |
251 | . "\n"; |
252 | }</pre> |
253 | </div> |
254 | |
255 | <div class="slide"> |
256 | <h1>manual: update</h1> |
257 | <pre>my $update = $dbh->prepare(' |
258 | UPDATE books |
259 | SET title = ? |
260 | WHERE id = ? |
261 | '); |
262 | |
263 | $update->execute( |
264 | 'New title',<strong>$book_id</strong> |
265 | );</pre> |
266 | </div> |
267 | |
268 | <div class="slide"> |
269 | <h1>manual: delete</h1> |
270 | <pre>my $delete = $dbh->prepare(' |
271 | DELETE FROM books |
272 | WHERE id = ? |
273 | '); |
274 | |
275 | $delete->execute(<strong>$book_id</strong>);</pre> |
276 | </div> |
277 | |
278 | <div class="slide"> |
279 | <h1>DBIx::Class</h1> |
280 | </div> |
281 | |
282 | <div class="slide"> |
283 | <h1>DBIC: create</h1> |
284 | <pre>my $book = $book_model->create({ |
285 | title => 'A book title', |
286 | author => $author_id, |
287 | });</pre> |
288 | <p>Look ma, no SQL!</p> |
289 | <p><strong>Tip:</strong> do not pass in primary_key field, even if it's empty/undef as the object returned will have an empty id, even if your field is auto increment.</p> |
290 | </div> |
291 | |
292 | <div class="slide"> |
293 | <h1>DBIC: create</h1> |
294 | <pre>my $book = $book_model->create({ |
295 | title => 'A book title', |
296 | author => <strong>$author_id</strong>, |
297 | });</pre> |
298 | </div> |
299 | |
300 | <div class="slide"> |
301 | <h1>DBIC: create</h1> |
302 | <pre>my $pratchett = $author_model->create({ |
303 | name => 'Terry Pratchett', |
304 | });</pre> |
305 | </div> |
306 | |
307 | <div class="slide"> |
308 | <h1>DBIC: create</h1> |
309 | <pre>my $book = $pratchett->create_related( |
310 | books => { |
311 | title => 'Another Discworld book', |
312 | });</pre> |
313 | <strong>or</strong> |
314 | <pre>my $book = $pratchett->add_to_books({ |
315 | title => 'Another Discworld book', |
316 | });</pre> |
317 | </div> |
318 | |
319 | <div class="slide"> |
320 | <h1>DBIC: create</h1> |
321 | <pre>my $book = $pratchett->create_related( |
322 | <strong>books</strong> => { |
323 | title => 'Another Discworld book', |
324 | });</pre> |
325 | <strong>or</strong> |
326 | <pre>my $book = $pratchett->add_to_<strong>books</strong>({ |
327 | title => 'Another Discworld book', |
328 | });</pre> |
329 | </div> |
330 | |
331 | <div class="slide"> |
332 | <h1>DBIC: retrieve</h1> |
333 | <p>DBIx::Class - Lots of ways to do the same thing...</p> |
334 | <p><em>"There is more than one way to do it (TIMTOWTDI, usually pronounced "Tim Toady") is a Perl motto"</em></p> |
335 | </div> |
336 | |
337 | <div class="slide"> |
338 | <h1>DBIC: retrieve</h1> |
339 | <pre>my $book = $book_model->find($book_id); |
340 | |
341 | my $book = $book_model->search({ |
342 | title => 'A book title', |
343 | })->single; |
344 | |
345 | my @books = $book_model->search({ |
346 | author => $author_id, |
347 | })->all;</pre> |
348 | </div> |
349 | |
350 | <div class="slide"> |
351 | <h1>DBIC: retrieve</h1> |
352 | <pre>while( my $book = $books_rs->next() ) { |
353 | print 'Author of ' |
354 | . $book->title |
355 | . ' is ' |
356 | . $book->author->name |
357 | . "\n"; |
358 | }</pre> |
359 | </div> |
360 | |
361 | <div class="slide"> |
362 | <h1>DBIC: retrieve</h1> |
363 | <pre>my $books_rs = $book_model->search({ |
364 | author => $author_id, |
365 | });</pre> |
366 | <p>Search takes SQL::Abstract formatted queries</p> |
367 | <pre>> perldoc SQL::Abstract</p> |
368 | </div> |
369 | |
370 | <div class="slide"> |
371 | <h1>DBIC: update</h1> |
372 | <pre>$book->update({ |
373 | title => 'New title', |
374 | });</pre> |
375 | </div> |
376 | |
377 | <div class="slide"> |
378 | <h1>DBIC: delete</h1> |
379 | <pre>$book->delete;</pre> |
380 | </div> |
381 | |
382 | <div class="slide"> |
383 | <h1>Creating models</h1> |
384 | </div> |
385 | |
386 | <div class="slide"> |
387 | <pre>Example of a DBIC Result</pre> |
388 | </div> |
389 | |
390 | <div class="slide"> |
391 | <pre>Example of a DBIC Result</pre> |
392 | </div> |
393 | |
394 | <div class="slide"> |
395 | <p>too much typing! too much maintenance!</p> |
396 | <p>too much maintenance!</p> |
397 | </div> |
398 | |
399 | <div class="slide"> |
400 | <h1>Schema::Loader</h1> |
401 | <pre>code for S::L here</pre> |
402 | </div> |
403 | |
404 | <div class="slide"> |
405 | <h1>splitting logic cleanly</h1> |
41a0eb8e |
406 | <p>Foo::Schema::Result::Foo = an individual row</p> |
407 | <p>Foo::Schema::ResultSet::Foo = searches / results</p> |
52d980cb |
408 | </div> |
409 | |
410 | <div class="slide"> |
411 | <h1>using your Schema</h1> |
412 | <pre>example usage code goes here</pre> |
413 | </div> |
414 | |
415 | <div class="slide"> |
416 | <h1>DEBUGGING</h1> |
417 | <pre>DBIC_TRACE=1 ./your_script.pl</pre> |
418 | </div> |
419 | |
420 | <div class="slide"> |
421 | <h1>Schema::Loader</h1> |
41a0eb8e |
422 | <pre>Foo::Schema::Result::Authors->table("authors"); |
423 | Foo::Schema::Result::Authors->add_columns( |
52d980cb |
424 | id => { |
425 | data_type => "INT", |
426 | default_value => undef, |
427 | is_nullable => 0, |
428 | size => 8 |
429 | }, |
430 | title => { |
431 | data_type => "VARCHAR", |
432 | default_value => undef, |
433 | is_nullable => 1, |
434 | size => 255, |
435 | }, |
436 | ); |
41a0eb8e |
437 | Foo::Schema::Result::Authors->set_primary_key("id");</pre> |
52d980cb |
438 | </div> |
439 | |
440 | <div class="slide"> |
441 | <h1>Schema::Loader</h1> |
41a0eb8e |
442 | <pre>Foo::Schema::Result::Books->table("books"); |
443 | Foo::Schema::Result::Books->add_columns( |
52d980cb |
444 | id => { |
445 | data_type => "INT", |
446 | default_value => undef, |
447 | is_nullable => 0, |
448 | size => 8 |
449 | }, |
450 | name => { |
451 | data_type => "VARCHAR", |
452 | default_value => undef, |
453 | is_nullable => 1, |
454 | size => 255, |
455 | }, |
456 | author => { |
457 | data_type => "INT", |
458 | default_value => undef, |
459 | is_nullable => 1, |
460 | size => 8 |
461 | }, |
462 | ); |
41a0eb8e |
463 | Foo::Schema::Result::Books->set_primary_key("id");</pre> |
52d980cb |
464 | </div> |
465 | |
466 | <div class="slide"> |
467 | <h1>Schema::Loader</h1> |
41a0eb8e |
468 | <pre>Foo::Schema::Result::Authors->has_many(books => "Foo::Schema::Books", |
52d980cb |
469 | { "foreign.author" => "self.id" }); |
470 | |
41a0eb8e |
471 | Foo::Schema::Result::Books->belongs_to(author => "Foo::Schema::Authors", |
52d980cb |
472 | { id => "author" });</pre> |
473 | </div> |
474 | |
475 | <div class="slide"> |
476 | <h1>SQL - debugging</h1> |
477 | <pre>INSERT INTO authors (name) |
478 | VALUES (?): 'Douglas Adams' |
479 | |
480 | INSERT INTO books (author, title) |
481 | VALUES (?, ?): '5', '42'</pre> |
482 | </div> |
483 | |
484 | <div class="slide"> |
485 | <h1>overloading</h1> |
41a0eb8e |
486 | <pre>Foo::Schema::Result::Books |
487 | Foo::Schema::ResultSet::Books |
488 | Foo::Schema::Result::Authors |
489 | Foo::Schema::ResultSet::Books</pre> |
52d980cb |
490 | </div> |
491 | |
492 | <div class="slide"> |
493 | <h1>Result::</h1> |
41a0eb8e |
494 | <pre>package Foo::Schema::Result::Books; |
52d980cb |
495 | use base 'DBIx::Class'; |
496 | use strict; |
497 | use warnings; |
498 | |
499 | sub isbn { |
500 | my $self = shift; |
501 | |
502 | # search amazon or something |
503 | my $api = Amazon::API->book({ |
504 | title => $self->title |
505 | }); |
506 | |
507 | return $api->isbn; |
508 | } |
509 | |
510 | 1;</pre> |
511 | </div> |
512 | |
513 | <div class="slide"> |
514 | <h1>Result::</h1> |
515 | <pre>print $book->isbn;</pre> |
516 | </div> |
517 | |
518 | <div class="slide"> |
519 | <h1>Result:: (inflating)</h1> |
41a0eb8e |
520 | <pre>package Foo::Schema::Result::Books; |
52d980cb |
521 | use base 'DBIx::Class'; |
522 | use strict; |
523 | use warnings; |
524 | |
525 | use DateTime::Format::MySQL; |
526 | |
527 | __PACKAGE__-><strong>inflate_column</strong>( |
528 | <strong>date_published</strong> => { |
529 | inflate => sub { DateTime::Format::MySQL->parse_date(shift) }, |
530 | deflate => sub { shift->ymd}, |
531 | } |
532 | ); |
533 | # Automatic see: DBIx::Class::InflateColumn::DateTime</pre> |
534 | </div> |
535 | |
536 | <div class="slide"> |
537 | <h1>Result:: (inflating)</h1> |
41a0eb8e |
538 | <pre>package Foo::Schema::Result::Books; |
52d980cb |
539 | use base 'DBIx::Class'; |
540 | use strict; |
541 | use warnings; |
542 | |
543 | use DateTime::Format::MySQL; |
544 | |
545 | __PACKAGE__->inflate_column( |
546 | date_published => { |
547 | <strong>inflate => sub { DateTime::Format::MySQL->parse_date(shift) }, |
548 | deflate => sub { shift->ymd},</strong> |
549 | } |
550 | ); |
551 | # Automatic see: DBIx::Class::InflateColumn::DateTime |
552 | # Automatic see: DBIx::Class::InflateColumn::DateTime |
553 | # Automatic see: DBIx::Class::InflateColumn::DateTime</pre> |
554 | </div> |
555 | |
556 | <div class="slide"> |
557 | <h1>Result:: (deflating)</h1> |
558 | <pre>$book->date_published(DateTime->now); |
559 | $book->update;</pre> |
560 | </div> |
561 | |
562 | <div class="slide"> |
563 | <h1>Result:: (inflating)</h1> |
564 | <pre>my $date_published = $book->date_published; |
565 | print $date_published->month_abbr;</pre> |
566 | |
567 | <strong><em>Nov</em></strong> |
568 | </div> |
569 | |
570 | <div class="slide"> |
571 | <h1>ResultSets::</h1> |
41a0eb8e |
572 | <pre>package Foo::Schema::ResultSet::Books; |
52d980cb |
573 | use base 'DBIx::Class::ResultSet'; |
574 | sub the_ultimate_books { |
575 | my $self = shift; |
576 | return $self->search({ title => { -like => '%42%' } }); |
577 | } |
578 | sub by_author { |
579 | my ( $self, $author ) = @_; |
580 | return $self->search({ author => $author->id }) |
581 | } |
582 | |
583 | 1;</pre> |
584 | </div> |
585 | |
586 | <div class="slide"> |
587 | <h1>ResultSets::</h1> |
41a0eb8e |
588 | <pre>package Foo::Schema::<strong>ResultSet::Books</strong>; |
52d980cb |
589 | use base '<strong>DBIx::Class::ResultSet</strong>'; |
590 | sub the_ultimate_books { |
591 | my $self = shift; |
592 | <strong>return $self->search({ title => { -like => '%42%' } })</strong> |
593 | } |
594 | sub by_author { |
595 | my ( $self, $author ) = @_; |
596 | return $self->search({ author => $author->id }) |
597 | } |
598 | |
599 | 1;</pre> |
600 | </div> |
601 | |
602 | <div class="slide"> |
603 | <h1>ResultSets::</h1> |
41a0eb8e |
604 | <pre>package Foo::Schema::ResultSet::Books; |
52d980cb |
605 | use base 'DBIx::Class::ResultSet'; |
606 | sub the_ultimate_books { |
607 | my $self = shift; |
608 | return $self->search({ title => { -like => '%42%' } }); |
609 | } |
610 | sub by_author { |
611 | my ( $self, $author ) = @_; |
612 | <strong>return $self->search({ author => $author->id })</strong> |
613 | } |
614 | |
615 | 1;</pre> |
616 | </div> |
617 | |
618 | <div class="slide"> |
619 | <h1>ResultSets::</h1> |
41a0eb8e |
620 | <pre>use Foo::Schema; |
621 | my $book_model = Foo::Schema->resultset('Books'); |
52d980cb |
622 | my $book_rs = $book_model->the_ultimate_books; |
623 | my @books = $book_rs->all;</pre> |
624 | </div> |
625 | |
626 | <div class="slide"> |
627 | <h1>ResultSets::chaining</h1> |
41a0eb8e |
628 | <pre>use Foo::Schema; |
629 | my $book_model = Foo::Schema->resultset('Books'); |
630 | my $author_model = Foo::Schema->resultset('Authors'); |
52d980cb |
631 | my $author = $author_model->search({ name => 'Douglas Adams' })->single; |
632 | my $book_rs = $book_model->the_ultimate_books->by_author($author); |
633 | my @books = $book_rs->all;</pre> |
634 | </div> |
635 | |
636 | <div class="slide"> |
637 | <h1>ResultSets::chaining</h1> |
638 | <pre>my $book_rs = $book_model |
639 | ->the_ultimate_books |
640 | ->by_author($author);</pre> |
641 | or |
642 | |
643 | <pre>my $book_rs = $book_model |
644 | ->the_ultimate_books(); |
645 | $book_rs = $book_rs->by_author($author);</pre> |
646 | <pre># Debug (SQL): |
647 | |
648 | # SELECT me.id, me.title, me.date_published, me.author |
649 | # FROM books me |
650 | # WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%' |
651 | # WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'</pre> |
652 | </div> |
653 | |
654 | <div class="slide"> |
655 | <h1>ResultSets::chaining</h1> |
656 | <pre>my $rs = $book_model |
657 | ->category('childrens') |
658 | ->by_author($author) |
659 | ->published_after('1812') |
660 | ->first_page_contains('once upon') |
661 | ->rating_greater_than(4); |
662 | |
663 | my @books = $rs->all;</pre> |
664 | </div> |
665 | |
666 | <div class="slide"> |
667 | <h1>overloading before new record</h1> |
668 | </div> |
669 | |
670 | <div class="slide"> |
671 | <h1>overloading before new record</h1> |
41a0eb8e |
672 | <pre>package Foo::Schema::Result::Authors; |
52d980cb |
673 | use base 'DBIx::Class'; |
674 | |
675 | sub new { |
676 | my ( $class, $attrs ) = @_; |
677 | # Mess with $attrs |
678 | my $new = $class->next::method($attrs); |
679 | return $new |
680 | } |
681 | |
682 | 1;</pre> |
683 | |
684 | <div class="slide"> |
685 | <h1>relationships</h1> |
686 | </div> |
687 | |
688 | <div class="slide"> |
689 | <h1>multiple authors</h1> |
690 | </div> |
691 | |
692 | <div class="slide"> |
693 | <h1>a few relationships</h1> |
694 | (authors -- author_link_to_book -- books) |
695 | </div> |
696 | |
697 | <div class="slide"> |
698 | <h1>a few relationships</h1> |
699 | ! |
700 | </div> |
701 | |
702 | <div class="slide"> |
703 | <h1>new join table</h1> |
704 | <pre>CREATE TABLE author_and_books( |
705 | id int(8) primary key auto_increment, |
706 | book int(8), |
707 | author int(8), |
708 | foreign key (book) references books(id), |
709 | foreign key (author) references authors(id) |
710 | ) engine = InnoDB DEFAULT CHARSET=utf8; |
711 | |
712 | ALTER TABLE `books` DROP `author`</pre> |
713 | </div> |
714 | |
715 | <div class="slide"> |
716 | <h1>new join table</h1> |
717 | <pre>CREATE TABLE author_and_books( |
718 | id int(8) primary key auto_increment, |
719 | book int(8), |
720 | author int(8), |
721 | <strong>foreign key (book) references books(id), |
722 | foreign key (author) references authors(id)</strong> |
723 | ) engine = InnoDB DEFAULT CHARSET=utf8; |
724 | |
725 | ALTER TABLE `books` DROP `author`</pre> |
726 | </div> |
727 | |
728 | <div class="slide"> |
729 | <h1>has_many</h1> |
730 | </div> |
731 | |
732 | <div class="slide"> |
733 | <h1>has_many</h1> |
41a0eb8e |
734 | <pre>package Foo::Schema::<strong>Result::Books</strong>; |
52d980cb |
735 | |
41a0eb8e |
736 | __PACKAGE__->has_many( author_and_books => "Foo::Schema::Result::AuthorAndBooks", |
52d980cb |
737 | { "foreign.book" => "self.id" }, |
738 | ); |
739 | |
740 | <strong># This is auto generated by Schema::Loader</strong></pre> |
741 | </div> |
742 | |
743 | <div class="slide"> |
744 | <h1>has_many</h1> |
41a0eb8e |
745 | <pre>package Foo::Schema::<strong>Result::Books</strong>; |
52d980cb |
746 | |
747 | __PACKAGE__->has_many( |
748 | author_and_books => <strong># name of accessor</strong> |
41a0eb8e |
749 | "Foo::Schema::Result::AuthorAndBooks", <strong># related class</strong> |
52d980cb |
750 | { "foreign.book" => "self.id" } <strong># Relationship (magic often works if not |
751 | # specified, but avoid!)</strong> |
752 | ); |
753 | </pre> |
754 | </div> |
755 | |
756 | <div class="slide"> |
757 | <h1>belongs_to</h1> |
758 | </div> |
759 | |
760 | <div class="slide"> |
761 | <h1>belongs_to</h1> |
41a0eb8e |
762 | <pre>package Foo::Schema::<strong>Result::AuthorAndBooks</strong>; |
52d980cb |
763 | |
764 | __PACKAGE__->belongs_to( |
765 | book => <strong># Accessor name</strong> |
41a0eb8e |
766 | "Foo::Schema::Result::Books", <strong># Related class</strong> |
52d980cb |
767 | { id => "book" } <strong># relationship</strong> |
768 | ); |
769 | </pre> |
770 | </div> |
771 | |
772 | <div class="slide"> |
773 | <h1>same for Authors</h1> |
774 | </div> |
775 | |
776 | <div class="slide"> |
777 | <h1>with no coding...</h1> |
778 | </div> |
779 | |
780 | <div class="slide"> |
781 | <h1>many_to_many</h1> |
782 | </div> |
783 | |
784 | <div class="slide"> |
785 | <h1>many_to_many</h1> |
41a0eb8e |
786 | <pre>package Foo::Schema::<strong>Result::Books</strong>; |
52d980cb |
787 | use base 'DBIx::Class'; |
788 | |
789 | __PACKAGE__->many_to_many( |
790 | authors => "author_and_books", 'author' |
791 | ); |
792 | |
793 | 1; |
794 | |
795 | <strong> # This is <em>NOT</em> auto generated by Schema::Loader </strong></pre> |
796 | </div> |
797 | |
798 | <div class="slide"> |
799 | <h1>many_to_many</h1> |
41a0eb8e |
800 | <pre>package Foo::Schema::<strong>Result::Books</strong>; |
52d980cb |
801 | use base 'DBIx::Class'; |
802 | |
803 | __PACKAGE__->many_to_many( |
804 | authors <strong># Accessor name</strong> |
805 | => "author_and_books", <strong># has_many</strong> |
806 | 'author' <strong># foreign relationship name</strong> |
807 | ); |
808 | |
809 | 1;</pre> |
810 | </div> |
811 | |
812 | <div class="slide"> |
813 | <h1>many_to_many</h1> |
41a0eb8e |
814 | <pre>package Foo::Schema::Result::Authors; |
52d980cb |
815 | use base 'DBIx::Class'; |
816 | |
817 | __PACKAGE__->many_to_many( |
818 | "books" <strong># Accessor Name</strong> |
819 | => "author_and_books", <strong># has_many accessor_name</strong> |
820 | 'book' <strong># foreign relationship name</strong> |
821 | ); |
822 | |
823 | 1; |
824 | |
825 | <strong># This is <em>NOT</em> auto generated by Schema::Loader</strong></pre> |
826 | </div> |
827 | |
828 | <div class="slide"> |
829 | <h1>using many_to_many</h1> |
830 | <pre>#!/usr/bin/perl |
831 | |
41a0eb8e |
832 | use Foo::Schema; |
52d980cb |
833 | |
41a0eb8e |
834 | my $author_model = Foo::Schema->resultset('Authors'); |
52d980cb |
835 | my $author = $author_model->search({ |
836 | name => 'Douglas Adams', |
837 | })->single; |
838 | $author->add_to_books({ |
839 | title => 'A new book', |
840 | });</pre> |
841 | </div> |
842 | |
843 | <div class="slide"> |
844 | <h1>using many_to_many</h1> |
845 | <pre>my $author = $author_model->search({ |
846 | name => 'Douglas Adams', |
847 | })->single; |
848 | <strong>$author->add_to_books({ |
849 | title => 'A new book', |
850 | });</strong> |
851 | |
852 | # SELECT me.id, me.name FROM authors me |
853 | # WHERE ( name = ? ): 'Douglas Adams'; |
854 | # INSERT INTO books (title) VALUES (?): 'A new book'; |
855 | # INSERT INTO author_and_books (author, book) |
856 | # VALUES (?, ?): '5', '2';</pre> |
857 | </div> |
858 | |
859 | <div class="slide"> |
860 | <h1>using many_to_many</h1> |
861 | <pre>$author->add_to_books($book); |
862 | |
863 | $book->add_to_authors($author_1); |
864 | $book->add_to_authors($author_2);</pre> |
865 | </div> |
866 | |
867 | <div class="slide"> |
868 | <h1>in 16 lines of code</h1> |
869 | </div> |
870 | |
871 | <div class="slide"> |
872 | <h1>errors</h1> |
873 | <p>Read them closely!</p> |
874 | </div> |
875 | |
876 | <div class="slide"> |
877 | <h1>error messages</h1> |
41a0eb8e |
878 | <pre>DBIx::Class::Schema::Loader::connection(): Failed to load external class definition for 'Foo::Schema::Result::Authors': Can't locate object method "many_to_many" via package "Foo::Schema::Result::Author" at lib/Foo/Schema/Result/Authors.pm line 9.Compilation failed in require at /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.</pre> |
52d980cb |
879 | </div> |
880 | |
881 | <div class="slide"> |
882 | <h1>error messages</h1> |
41a0eb8e |
883 | <pre>DBIx::Class::Schema::Loader::connection(): Failed to load external class definition for 'Foo::Schema::Result::Authors': Can't locate object method "many_to_many" via package "Foo::Schema::<strong>Result::Author</strong>" at lib/Foo/Schema/<strong>Result/Authors.pm</strong> line 9.Compilation failed in require at /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.</pre> |
52d980cb |
884 | </div> |
885 | |
886 | <div class="slide"> |
887 | <h1>errors</h1> |
888 | <ul> |
889 | <li>Turn on debugging</li> |
890 | <li>Read error messages (sometimes useful!)</li> |
891 | <li>Check field names</li> |
892 | <li>Check package names</li> |
893 | <li>Check which database you are connected to (dev/test/live?) - repeat above</li> |
894 | </ul> |
895 | </div> |
896 | |
897 | <div class="slide"> |
898 | <h1>bonus slides!</h1> |
899 | </div> |
900 | |
901 | <div class="slide"> |
902 | <h1>Template Toolkit</h1> |
903 | <ul> |
904 | <li><pre>[% author.books.count %]</pre> not working?</li> |
905 | <li>TT all methods are called in list context</li> |
906 | <li><pre>[% author.books<strong>_rs</strong>.count %]</pre> scalar context</li> |
907 | <li><em>Available for all relationships</em></li> |
908 | </ul> |
909 | </div> |
910 | |
911 | <div class="slide"> |
912 | <h1>Catalyst</h1> |
0cffcad7 |
913 | <pre>package Your::App::Model::<strong>Foo</strong>; |
41a0eb8e |
914 | use base qw(<strong>Catalyst::Model::Schema::Schema</strong>); |
52d980cb |
915 | |
916 | use strict; |
917 | use warnings; |
918 | |
919 | __PACKAGE__->config( |
41a0eb8e |
920 | schema_class => '<strong>Foo::Schema</strong>', |
52d980cb |
921 | ); |
922 | |
923 | 1;</pre> |
924 | <p>Keep your Schema in a <em>separate</em> package to your Catalyst application</p> |
925 | </div> |
926 | |
927 | <div class="slide"> |
928 | <h1>Catalyst</h1> |
929 | <pre>sub action_name : Local { |
930 | my ($self, $c) = @_; |
931 | |
41a0eb8e |
932 | my $model = $c->model('Schema::Foo'); |
52d980cb |
933 | my $author_model = $model->resultset('Authors'); |
934 | |
935 | } |
936 | |
937 | 1;</pre> |
938 | </div> |
939 | |
940 | </div> |
941 | </body> |
942 | </html> |