intro wiki download guestbook contact

Rekursive Pages

Was sind rekursive Pages. Nun, zum Beispiel bei einem Weblog, wenn man Kommentare auf Kommentare schreiben kann, oder wie bei diesem Wiki, wo es Artikeln gibt und dazu dann UnterArtikel, und auf diese dann wieder UnterArtikel usw..

Wie machen wir das jetzt, wenn wir so ein Wiki wie hier bauen möchten?

Also zuerst mal die Datenbank. Hier muss jeder Eintrag wissen zu welchem Übergeordneten er gehört. Wir legen also jetzt mal folgende Tabelle an.


CREATE TABLE article (
   id int(10) NOT NULL auto_increment,
   parent_id int(10),
   title varchar(100) NOT NULL,
   text text,
   create_time datetime NOT NULL,
   modify_time datetime NOT NULL,
   PRIMARY_KEY (id),
   KEY title (title)
);

so, dann brauchen wir noch das Model:


./webtek Model Article

und jetzt müssen wir im Model, noch die Parent Beziehung einbaun. Dazu fügen wir einfach folgende Zeile ins Article.pm


__PACKAGE__->has_a('parent_id', __PACKAGE__);

das heisst nichts anderes, als daß parent_id wieder mit dem Model Article verknüpft wird. Etwas leserlicher wäre vielleicht:

MyApp::Model::Article->has_a('parent_id', MyApp::Model::Article);

So, nun geht es weiter zur Page. Diese erstellen wir jetzt mal


./webtek Page Article

und auch hier müssen wir wieder die Parent Beziehung einbaun.


package MyApp::Page::Article;

use strict;
use WebTek::Globals;
use MyApp::Model::Article
   'accessor' => 'article',
   'macros' => [ 'title', 'text', 'create_time', 'modify_time' ];
 
use WebTek::Parent qw( MyApp::Page::Article MyApp::Page::Root );

# ---------------------------------------------------------------------------
# constructors
# ---------------------------------------------------------------------------

sub new_for_title :Path([^/]+) {
   my $class = shift;
   my $title = shift;
   
   my $article = MyApp::Model::Article->find_one('title' => $title);
   return undef unless $article;
   return $class->new_for_article($article);
}
 
sub new_for_article {
   my $class = shift;
   my $article = shift; 	# MyApp::Model::Article
   
   my $self = $class->new;
   $self->path($article->title);
   $self->article($article);
   return $self;
}
 
sub new_from_child {
   my $class = shift;
   my $child = shift;	        # MyApp::Page::Article

   assert($child->isa('MyApp::Page::Article'), 'childpage has an invalid Prototype');
  
   return undef unless $child->article->parent;
   return $class->new_for_article($child->article->parent);
}
 
...
 
1;

Hier kennen wir schon ein paar sachen aus dem Tutorial, neu ist aber, dass bei use WebTek::Parent zwei Parent Pages stehen, und auch der new_from_child Konstruktor ist neu. Was heisst das?

Wenn bei WebTek::Parent zwei oder mehr Pages stehen, dann heißt das einfach, daß es für diese Page mehr als nur eine Möglichkeit gibt, welche Page von dieser die Parentpage ist. Und welche Parentpage dann erzeugt wird, hängt einzig und allein vom new_from_child Konstruktor ab. In unserem Fall fragen wir unser Kind, ob dem sein Article noch einen Parent hat, wenn ja, dann erzeugen wir die Article Parentpage. Wenn nicht, dann retournieren wir undef, und das heisst, daß einfach die nächste Page in der Liste erzeugt wird (in unserem Fall die Root Page). Und das sollte es auch schon wieder gewesen sein, noch ein paar Actions und Macros einbaun, und fertig :-)