S::L code
[dbsrgits/dbix-class-introduction-presentation.git] / slideshow.html
CommitLineData
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>
0cffcad7 80 <h4>Justin D. Hunter</h4>
5cac74c7 81 <h4>Arthur Axel "fREW" Schmidt</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 &lt;-&gt; 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">
52d980cb 118 <h1>point of note</h1>
5cac74c7 119 <p><em>"Debugging is twice as hard as writing the code in the first
120 place. Therefore, if you write the code as cleverly as possible,
121 you are, by definition, not smart enough to debug it." - Brian
122 W. Kernighan</em></p>
52d980cb 123
5cac74c7 124 <p>This talk is about making it easy so we are less likely to get
125 confused</p>
52d980cb 126 </div>
127
128 <div class="slide">
5cac74c7 129 <h1>Examples Table Setup</h1>
52d980cb 130 <ul>
131 <li>Authors</li>
132 <li>Books</li>
133 </ul>
5cac74c7 134 <em>MySQL not recommended</em>
52d980cb 135 </div>
136
137 <div class="slide">
138 <h1>authors table</h1>
139<pre>CREATE TABLE authors(
140 id int(8) primary key auto_increment,
141 name varchar(255)
142) engine = InnoDB DEFAULT CHARSET=utf8;</pre>
143 </div>
144
145 <div class="slide">
146 <h1>tips</h1>
147 <p>Name tables as simple plurals (<strong>add an S</strong>) - makes relationships easier to understand</p>
52d980cb 148 <p>Use a character set (<strong>UTF8</strong>) from the start (for international characters)</p>
149 </div>
150
151 <div class="slide">
152 <h1>authors table</h1>
153<pre>CREATE TABLE author<strong>s</strong>(
154 id int(8) primary key auto_increment,
155 name varchar(255)
156) engine = <strong>InnoDB</strong> DEFAULT CHARSET=<strong>utf8</strong>;</pre>
157 </div>
158
159 <div class="slide">
160 <h1>books table</h1>
161<pre>CREATE TABLE books(
5cac74c7 162 id int(8) primary key auto_increment,
163 title varchar(255),
164 author_id int(8),foreign key (author)
52d980cb 165 references authors(id)
166) engine = InnoDB DEFAULT CHARSET=utf8;</pre>
167 </div>
168
169
170 <div class="slide">
171 <h1>tips</h1>
172 <p>Name link fields as singular</p>
5cac74c7 173 <p>Ensure foreign key is the same type and size in both tables</p>
52d980cb 174 </div>
175
176 <div class="slide">
177 <h1>books table</h1>
178<pre>CREATE TABLE books(
5cac74c7 179 id int(8) primary key auto_increment,
180 title varchar(255),
181 author_id <strong>int(8)</strong>,<strong>foreign key (<em>author</em>)</strong>
52d980cb 182 <strong>references <em>authors(id)</em></strong>
183) engine = InnoDB DEFAULT CHARSET=utf8;</pre>
184 </div>
185
186 <div class="slide">
187 <h1>CRUD compared</h1>
188 <ul>
189 <li><strong>C</strong> - Create</li>
190 <li><strong>R</strong> - Read</li>
191 <li><strong>U</strong> - Update</li>
192 <li><strong>D</strong> - Delete</li>
193 </ul>
194 </div>
195
196 <div class="slide">
197 <h1>Manual (SQL)</h1>
198 </div>
199
200 <div class="slide">
5cac74c7 201 <h1>SQL: Create</h1>
52d980cb 202<pre>my $sth = $dbh-&gt;prepare('
203 INSERT INTO books
204 (title, author)
205 values (?,?)
206');
207
208$sth-&gt;execute(
209 'A book title', $author_id
210);</pre>
211 </div>
212
213 <div class="slide">
5cac74c7 214 <h1>SQL: Read</h1>
52d980cb 215<pre>my $sth = $dbh-&gt;prepare('
216 SELECT title,
217 authors.name as author_name
218 FROM books, authors
219 WHERE books.author = authors.id
220');</pre>
221 </div>
222
223 <div class="slide">
5cac74c7 224 <h1>SQL: Read</h1>
52d980cb 225<pre>while( my $book = $sth-&gt;fetchrow_hashref() ) {
226 print 'Author of '
227 . $book-&gt;{title}
228 . ' is '
229 . $book-&gt;{author_name}
230 . "\n";
231}</pre>
232 </div>
233
234 <div class="slide">
5cac74c7 235 <h1>SQL: Update</h1>
52d980cb 236<pre>my $update = $dbh-&gt;prepare('
237 UPDATE books
238 SET title = ?
239 WHERE id = ?
240');
241
242$update-&gt;execute(
243 'New title',<strong>$book_id</strong>
244);</pre>
245 </div>
246
247 <div class="slide">
5cac74c7 248 <h1>SQL: Delete</h1>
52d980cb 249<pre>my $delete = $dbh-&gt;prepare('
250 DELETE FROM books
251 WHERE id = ?
252');
253
254$delete-&gt;execute(<strong>$book_id</strong>);</pre>
255 </div>
256
257 <div class="slide">
258 <h1>DBIx::Class</h1>
259 </div>
260
261 <div class="slide">
5cac74c7 262 <h1>DBIC: Create</h1>
52d980cb 263<pre>my $book = $book_model-&gt;create({
264 title =&gt; 'A book title',
265 author =&gt; $author_id,
266});</pre>
267 <p>Look ma, no SQL!</p>
52d980cb 268 </div>
269
270 <div class="slide">
5cac74c7 271 <h1>DBIC: Create</h1>
52d980cb 272<pre>my $pratchett = $author_model-&gt;create({
273 name =&gt; 'Terry Pratchett',
274});</pre>
275 </div>
276
277 <div class="slide">
5cac74c7 278 <h1>DBIC: Create</h1>
52d980cb 279<pre>my $book = $pratchett-&gt;create_related(
280 <strong>books</strong> =&gt; {
281 title =&gt; 'Another Discworld book',
282});</pre>
283<strong>or</strong>
284<pre>my $book = $pratchett-&gt;add_to_<strong>books</strong>({
285 title =&gt; 'Another Discworld book',
286});</pre>
287 </div>
288
289 <div class="slide">
5cac74c7 290 <h1>DBIC: Read</h1>
52d980cb 291 <p>DBIx::Class - Lots of ways to do the same thing...</p>
292 <p><em>"There is more than one way to do it (TIMTOWTDI, usually pronounced "Tim Toady") is a Perl motto"</em></p>
293 </div>
294
295 <div class="slide">
5cac74c7 296 <h1>DBIC: Read</h1>
52d980cb 297<pre>my $book = $book_model-&gt;find($book_id);
298
299my $book = $book_model-&gt;search({
300 title =&gt; 'A book title',
5cac74c7 301}, { rows =&gt; 1 })-&gt;single;
52d980cb 302
303my @books = $book_model-&gt;search({
304 author =&gt; $author_id,
305})-&gt;all;</pre>
306 </div>
307
308 <div class="slide">
5cac74c7 309 <h1>DBIC: Read</h1>
310<pre>while( my $book = $books_rs-&gt;next ) {
52d980cb 311 print 'Author of '
312 . $book-&gt;title
313 . ' is '
314 . $book-&gt;author-&gt;name
315 . "\n";
316}</pre>
317 </div>
318
319 <div class="slide">
5cac74c7 320 <h1>DBIC: Read</h1>
321<pre>my $books_rs = $book_rs-&gt;search({
52d980cb 322 author =&gt; $author_id,
323});</pre>
324 <p>Search takes SQL::Abstract formatted queries</p>
325 <pre>&gt; perldoc SQL::Abstract</p>
326 </div>
327
328 <div class="slide">
5cac74c7 329 <h1>DBIC: Update</h1>
52d980cb 330<pre>$book-&gt;update({
331 title =&gt; 'New title',
332});</pre>
333 </div>
334
335 <div class="slide">
5cac74c7 336 <h1>DBIC: Delete</h1>
52d980cb 337<pre>$book-&gt;delete;</pre>
338 </div>
339
340 <div class="slide">
341 <h1>Creating models</h1>
342 </div>
343
344 <div class="slide">
492be2ae 345<pre>package MyApp::Schema::Result::Author;
346use strict; use warnings;
347__PACKAGE__-&gt;table('authors');
348__PACKAGE__-&gt;add_columns(
349 id =&gt; {
350 data_type =&gt; 'int',
351 size =&gt; 8,
352 },
353 title =&gt; {
354 data_type =&gt; 'varchar',
355 is_nullable =&gt; 1,
356 size =&gt; 255,
357 },
358);
359__PACKAGE__-&gt;set_primary_key('id');
360__PACKAGE__-&gt;has_many( books =&gt;
361 'MyApp::Schema::Result::Book', 'author_id'
362);
3631;
364</pre>
365 </div>
366
367 <div class="slide">
368<pre>package MyApp::Schema::Result::Book;
369use strict; use warnings;
370__PACKAGE__-&gt;table('books');
371__PACKAGE__-&gt;add_columns(
372 id =&gt; {
373 data_type =&gt; 'int',
374 size =&gt; 8,
375 },
376 name =&gt; {
377 data_type =&gt; 'varchar',
378 is_nullable =&gt; 1,
379 size =&gt; 255,
380 },
381 author_id =&gt; {
382 data_type =&gt; 'int',
383 size =&gt; 8,
384 is_nullable =&gt; 1, # &lt;-- probably should be 0
385 },
386);
387__PACKAGE__-&gt;set_primary_key('id');
388__PACKAGE__-&gt;belongs_to( author =&gt;
389 'MyApp::Schema::Result::Author', 'author_id'
390);
3911;
392</pre>
52d980cb 393 </div>
394
395 <div class="slide">
52d980cb 396 <h1>Schema::Loader</h1>
c7321880 397 <p>DB -&gt; Perl vs Perl -&gt; DB</p>
398<pre>package MyApp::Schema;
399use strict; use warnings;
400use base 'DBIx::Class::Schema::Loader';
401__PACKAGE__-&gt;loader_options({
402 naming =&gt; 'v7',
403 debug =&gt; $ENV{DBIC_TRACE},
404});
4051;
406
407# elsewhere...
408
409my $schema = MyApp::Schema-&gt;connect($dsn, $user, $pass);
410</pre>
52d980cb 411 </div>
412
413 <div class="slide">
414 <h1>splitting logic cleanly</h1>
41a0eb8e 415 <p>Foo::Schema::Result::Foo = an individual row</p>
416 <p>Foo::Schema::ResultSet::Foo = searches / results</p>
52d980cb 417 </div>
418
419 <div class="slide">
420 <h1>using your Schema</h1>
421 <pre>example usage code goes here</pre>
422 </div>
423
424 <div class="slide">
425 <h1>DEBUGGING</h1>
426 <pre>DBIC_TRACE=1 ./your_script.pl</pre>
427 </div>
428
429 <div class="slide">
430 <h1>Schema::Loader</h1>
41a0eb8e 431<pre>Foo::Schema::Result::Authors-&gt;table("authors");
432Foo::Schema::Result::Authors-&gt;add_columns(
52d980cb 433 id =&gt; {
434 data_type =&gt; "INT",
435 default_value =&gt; undef,
436 is_nullable =&gt; 0,
437 size =&gt; 8
438 },
439 title =&gt; {
440 data_type =&gt; "VARCHAR",
441 default_value =&gt; undef,
442 is_nullable =&gt; 1,
443 size =&gt; 255,
444 },
445);
41a0eb8e 446Foo::Schema::Result::Authors-&gt;set_primary_key("id");</pre>
52d980cb 447 </div>
448
449 <div class="slide">
450 <h1>Schema::Loader</h1>
41a0eb8e 451<pre>Foo::Schema::Result::Books->table("books");
452Foo::Schema::Result::Books->add_columns(
52d980cb 453 id =&gt; {
454 data_type =&gt; "INT",
455 default_value =&gt; undef,
456 is_nullable =&gt; 0,
457 size =&gt; 8
458 },
459 name =&gt; {
460 data_type =&gt; "VARCHAR",
461 default_value =&gt; undef,
462 is_nullable =&gt; 1,
463 size =&gt; 255,
464 },
465 author =&gt; {
466 data_type =&gt; "INT",
467 default_value =&gt; undef,
468 is_nullable =&gt; 1,
469 size =&gt; 8
470 },
471);
41a0eb8e 472Foo::Schema::Result::Books-&gt;set_primary_key("id");</pre>
52d980cb 473 </div>
474
475 <div class="slide">
476 <h1>Schema::Loader</h1>
41a0eb8e 477<pre>Foo::Schema::Result::Authors-&gt;has_many(books =&gt; "Foo::Schema::Books",
52d980cb 478 { "foreign.author" =&gt; "self.id" });
479
41a0eb8e 480Foo::Schema::Result::Books-&gt;belongs_to(author =&gt; "Foo::Schema::Authors",
52d980cb 481 { id =&gt; "author" });</pre>
482 </div>
483
484 <div class="slide">
485 <h1>SQL - debugging</h1>
486<pre>INSERT INTO authors (name)
487 VALUES (?): 'Douglas Adams'
488
489INSERT INTO books (author, title)
490 VALUES (?, ?): '5', '42'</pre>
491 </div>
492
493 <div class="slide">
494 <h1>overloading</h1>
41a0eb8e 495<pre>Foo::Schema::Result::Books
496Foo::Schema::ResultSet::Books
497Foo::Schema::Result::Authors
498Foo::Schema::ResultSet::Books</pre>
52d980cb 499 </div>
500
501 <div class="slide">
502 <h1>Result::</h1>
41a0eb8e 503<pre>package Foo::Schema::Result::Books;
52d980cb 504use base 'DBIx::Class';
505use strict;
506use warnings;
507
508sub isbn {
509 my $self = shift;
510
511 # search amazon or something
512 my $api = Amazon::API-&gt;book({
513 title =&gt; $self-&gt;title
514 });
515
516 return $api-&gt;isbn;
517}
518
5191;</pre>
520 </div>
521
522 <div class="slide">
523 <h1>Result::</h1>
524<pre>print $book-&gt;isbn;</pre>
525 </div>
526
527 <div class="slide">
528 <h1>Result:: (inflating)</h1>
41a0eb8e 529<pre>package Foo::Schema::Result::Books;
52d980cb 530use base 'DBIx::Class';
531use strict;
532use warnings;
533
534use DateTime::Format::MySQL;
535
536__PACKAGE__-&gt;<strong>inflate_column</strong>(
537 <strong>date_published</strong> =&gt; {
538 inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
539 deflate =&gt; sub { shift-&gt;ymd},
540 }
541);
542# Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
543 </div>
544
545 <div class="slide">
546 <h1>Result:: (inflating)</h1>
41a0eb8e 547<pre>package Foo::Schema::Result::Books;
52d980cb 548use base 'DBIx::Class';
549use strict;
550use warnings;
551
552use DateTime::Format::MySQL;
553
554__PACKAGE__-&gt;inflate_column(
555 date_published =&gt; {
556 <strong>inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
557 deflate =&gt; sub { shift-&gt;ymd},</strong>
558 }
559);
560# Automatic see: DBIx::Class::InflateColumn::DateTime
561# Automatic see: DBIx::Class::InflateColumn::DateTime
562# Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
563 </div>
564
565 <div class="slide">
566 <h1>Result:: (deflating)</h1>
567<pre>$book-&gt;date_published(DateTime-&gt;now);
568$book-&gt;update;</pre>
569 </div>
570
571 <div class="slide">
572 <h1>Result:: (inflating)</h1>
573<pre>my $date_published = $book-&gt;date_published;
574print $date_published-&gt;month_abbr;</pre>
575
576<strong><em>Nov</em></strong>
577 </div>
578
579 <div class="slide">
580 <h1>ResultSets::</h1>
41a0eb8e 581<pre>package Foo::Schema::ResultSet::Books;
52d980cb 582use base 'DBIx::Class::ResultSet';
583sub the_ultimate_books {
584 my $self = shift;
585 return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
586}
587sub by_author {
588 my ( $self, $author ) = @_;
589 return $self-&gt;search({ author =&gt; $author-&gt;id })
590}
591
5921;</pre>
593 </div>
594
595 <div class="slide">
596 <h1>ResultSets::</h1>
41a0eb8e 597<pre>package Foo::Schema::<strong>ResultSet::Books</strong>;
52d980cb 598use base '<strong>DBIx::Class::ResultSet</strong>';
599sub the_ultimate_books {
600 my $self = shift;
601 <strong>return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } })</strong>
602}
603sub by_author {
604 my ( $self, $author ) = @_;
605 return $self-&gt;search({ author =&gt; $author-&gt;id })
606}
607
6081;</pre>
609 </div>
610
611 <div class="slide">
612 <h1>ResultSets::</h1>
41a0eb8e 613<pre>package Foo::Schema::ResultSet::Books;
52d980cb 614use base 'DBIx::Class::ResultSet';
615sub the_ultimate_books {
616 my $self = shift;
617 return $self-&gt;search({ title =&gt; { -like =&gt; '%42%' } });
618}
619sub by_author {
620 my ( $self, $author ) = @_;
621 <strong>return $self-&gt;search({ author =&gt; $author-&gt;id })</strong>
622}
623
6241;</pre>
625 </div>
626
627 <div class="slide">
628 <h1>ResultSets::</h1>
41a0eb8e 629<pre>use Foo::Schema;
630my $book_model = Foo::Schema-&gt;resultset('Books');
52d980cb 631my $book_rs = $book_model-&gt;the_ultimate_books;
632my @books = $book_rs-&gt;all;</pre>
633 </div>
634
635 <div class="slide">
636 <h1>ResultSets::chaining</h1>
41a0eb8e 637<pre>use Foo::Schema;
638my $book_model = Foo::Schema-&gt;resultset('Books');
639my $author_model = Foo::Schema-&gt;resultset('Authors');
52d980cb 640my $author = $author_model-&gt;search({ name =&gt; 'Douglas Adams' })-&gt;single;
641my $book_rs = $book_model-&gt;the_ultimate_books-&gt;by_author($author);
642my @books = $book_rs-&gt;all;</pre>
643 </div>
644
645 <div class="slide">
646 <h1>ResultSets::chaining</h1>
647<pre>my $book_rs = $book_model
648 -&gt;the_ultimate_books
649 -&gt;by_author($author);</pre>
650or
651
652<pre>my $book_rs = $book_model
653 -&gt;the_ultimate_books();
654$book_rs = $book_rs-&gt;by_author($author);</pre>
655<pre># Debug (SQL):
656
657# SELECT me.id, me.title, me.date_published, me.author
658# FROM books me
659# WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'
660# WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'</pre>
661 </div>
662
663 <div class="slide">
664 <h1>ResultSets::chaining</h1>
665<pre>my $rs = $book_model
666 -&gt;category('childrens')
667 -&gt;by_author($author)
668 -&gt;published_after('1812')
669 -&gt;first_page_contains('once upon')
670 -&gt;rating_greater_than(4);
671
672my @books = $rs-&gt;all;</pre>
673 </div>
674
675 <div class="slide">
676 <h1>overloading before new record</h1>
677 </div>
678
679 <div class="slide">
680 <h1>overloading before new record</h1>
41a0eb8e 681 <pre>package Foo::Schema::Result::Authors;
52d980cb 682use base 'DBIx::Class';
683
684sub new {
685 my ( $class, $attrs ) = @_;
686 # Mess with $attrs
687 my $new = $class-&gt;next::method($attrs);
688 return $new
689}
690
6911;</pre>
692
693 <div class="slide">
694 <h1>relationships</h1>
695 </div>
696
697 <div class="slide">
698 <h1>multiple authors</h1>
699 </div>
700
701 <div class="slide">
702 <h1>a few relationships</h1>
703 (authors -- author_link_to_book -- books)
704 </div>
705
706 <div class="slide">
707 <h1>a few relationships</h1>
708 !
709 </div>
710
711 <div class="slide">
712 <h1>new join table</h1>
713<pre>CREATE TABLE author_and_books(
714 id int(8) primary key auto_increment,
715 book int(8),
716 author int(8),
717 foreign key (book) references books(id),
718 foreign key (author) references authors(id)
719) engine = InnoDB DEFAULT CHARSET=utf8;
720
721ALTER TABLE `books` DROP `author`</pre>
722 </div>
723
724 <div class="slide">
725 <h1>new join table</h1>
726<pre>CREATE TABLE author_and_books(
727 id int(8) primary key auto_increment,
728 book int(8),
729 author int(8),
730 <strong>foreign key (book) references books(id),
731 foreign key (author) references authors(id)</strong>
732) engine = InnoDB DEFAULT CHARSET=utf8;
733
734ALTER TABLE `books` DROP `author`</pre>
735 </div>
736
737 <div class="slide">
738 <h1>has_many</h1>
739 </div>
740
741 <div class="slide">
742 <h1>has_many</h1>
41a0eb8e 743<pre>package Foo::Schema::<strong>Result::Books</strong>;
52d980cb 744
41a0eb8e 745__PACKAGE__-&gt;has_many( author_and_books =&gt; "Foo::Schema::Result::AuthorAndBooks",
52d980cb 746 { "foreign.book" =&gt; "self.id" },
747);
748
749<strong># This is auto generated by Schema::Loader</strong></pre>
750 </div>
751
752 <div class="slide">
753 <h1>has_many</h1>
41a0eb8e 754<pre>package Foo::Schema::<strong>Result::Books</strong>;
52d980cb 755
756__PACKAGE__-&gt;has_many(
757author_and_books =&gt; <strong># name of accessor</strong>
41a0eb8e 758"Foo::Schema::Result::AuthorAndBooks", <strong># related class</strong>
52d980cb 759 { "foreign.book" =&gt; "self.id" } <strong># Relationship (magic often works if not
760 # specified, but avoid!)</strong>
761);
762</pre>
763 </div>
764
765 <div class="slide">
766 <h1>belongs_to</h1>
767 </div>
768
769 <div class="slide">
770 <h1>belongs_to</h1>
41a0eb8e 771<pre>package Foo::Schema::<strong>Result::AuthorAndBooks</strong>;
52d980cb 772
773__PACKAGE__-&gt;belongs_to(
774 book =&gt; <strong># Accessor name</strong>
41a0eb8e 775 "Foo::Schema::Result::Books", <strong># Related class</strong>
52d980cb 776 { id =&gt; "book" } <strong># relationship</strong>
777);
778</pre>
779 </div>
780
781 <div class="slide">
782 <h1>same for Authors</h1>
783 </div>
784
785 <div class="slide">
786 <h1>with no coding...</h1>
787 </div>
788
789 <div class="slide">
790 <h1>many_to_many</h1>
791 </div>
792
793 <div class="slide">
794 <h1>many_to_many</h1>
41a0eb8e 795 <pre>package Foo::Schema::<strong>Result::Books</strong>;
52d980cb 796use base 'DBIx::Class';
797
798__PACKAGE__-&gt;many_to_many(
799 authors =&gt; "author_and_books", 'author'
800);
801
8021;
803
804<strong> # This is <em>NOT</em> auto generated by Schema::Loader </strong></pre>
805 </div>
806
807 <div class="slide">
808 <h1>many_to_many</h1>
41a0eb8e 809 <pre>package Foo::Schema::<strong>Result::Books</strong>;
52d980cb 810use base 'DBIx::Class';
811
812__PACKAGE__-&gt;many_to_many(
813 authors <strong># Accessor name</strong>
814 =&gt; "author_and_books", <strong># has_many</strong>
815 'author' <strong># foreign relationship name</strong>
816);
817
8181;</pre>
819 </div>
820
821 <div class="slide">
822 <h1>many_to_many</h1>
41a0eb8e 823 <pre>package Foo::Schema::Result::Authors;
52d980cb 824use base 'DBIx::Class';
825
826__PACKAGE__-&gt;many_to_many(
827 "books" <strong># Accessor Name</strong>
828 =&gt; "author_and_books", <strong># has_many accessor_name</strong>
829 'book' <strong># foreign relationship name</strong>
830);
831
8321;
833
834<strong># This is <em>NOT</em> auto generated by Schema::Loader</strong></pre>
835 </div>
836
837 <div class="slide">
838 <h1>using many_to_many</h1>
839 <pre>#!/usr/bin/perl
840
41a0eb8e 841use Foo::Schema;
52d980cb 842
41a0eb8e 843my $author_model = Foo::Schema-&gt;resultset('Authors');
52d980cb 844my $author = $author_model-&gt;search({
845 name =&gt; 'Douglas Adams',
846})-&gt;single;
847$author-&gt;add_to_books({
848 title =&gt; 'A new book',
849});</pre>
850 </div>
851
852 <div class="slide">
853 <h1>using many_to_many</h1>
854 <pre>my $author = $author_model-&gt;search({
855 name =&gt; 'Douglas Adams',
856})-&gt;single;
857<strong>$author-&gt;add_to_books({
858 title =&gt; 'A new book',
859});</strong>
860
861# SELECT me.id, me.name FROM authors me
862# WHERE ( name = ? ): 'Douglas Adams';
863# INSERT INTO books (title) VALUES (?): 'A new book';
864# INSERT INTO author_and_books (author, book)
865# VALUES (?, ?): '5', '2';</pre>
866 </div>
867
868 <div class="slide">
869 <h1>using many_to_many</h1>
870 <pre>$author-&gt;add_to_books($book);
871
872$book-&gt;add_to_authors($author_1);
873$book-&gt;add_to_authors($author_2);</pre>
874 </div>
875
876 <div class="slide">
877 <h1>in 16 lines of code</h1>
878 </div>
879
880 <div class="slide">
881 <h1>errors</h1>
882 <p>Read them closely!</p>
883 </div>
884
885 <div class="slide">
886 <h1>error messages</h1>
41a0eb8e 887 <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 888 </div>
889
890 <div class="slide">
891 <h1>error messages</h1>
41a0eb8e 892 <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 893 </div>
894
895 <div class="slide">
896 <h1>errors</h1>
897 <ul>
898 <li>Turn on debugging</li>
899 <li>Read error messages (sometimes useful!)</li>
900 <li>Check field names</li>
901 <li>Check package names</li>
902 <li>Check which database you are connected to (dev/test/live?) - repeat above</li>
903 </ul>
904 </div>
905
906 <div class="slide">
907 <h1>bonus slides!</h1>
908 </div>
909
910 <div class="slide">
911 <h1>Template Toolkit</h1>
912 <ul>
913 <li><pre>[% author.books.count %]</pre> not working?</li>
914 <li>TT all methods are called in list context</li>
915 <li><pre>[% author.books<strong>_rs</strong>.count %]</pre> scalar context</li>
916 <li><em>Available for all relationships</em></li>
917 </ul>
918 </div>
919
920 <div class="slide">
921 <h1>Catalyst</h1>
0cffcad7 922 <pre>package Your::App::Model::<strong>Foo</strong>;
41a0eb8e 923use base qw(<strong>Catalyst::Model::Schema::Schema</strong>);
52d980cb 924
925use strict;
926use warnings;
927
928__PACKAGE__-&gt;config(
41a0eb8e 929 schema_class =&gt; '<strong>Foo::Schema</strong>',
52d980cb 930);
931
9321;</pre>
933 <p>Keep your Schema in a <em>separate</em> package to your Catalyst application</p>
934 </div>
935
936 <div class="slide">
937 <h1>Catalyst</h1>
938<pre>sub action_name : Local {
939 my ($self, $c) = @_;
940
41a0eb8e 941 my $model = $c-&gt;model('Schema::Foo');
52d980cb 942 my $author_model = $model-&gt;resultset('Authors');
943
944}
945
9461;</pre>
947 </div>
948
949</div>
950</body>
951</html>