CREATE TABLE employees (
employee_id INTEGER PRIMARY KEY AUTOINCREMENT,
- parent_id INTEGER NOT NULL,
+ parent_id INTEGER NOT NULL DEFAULT 0,
name TEXT NOT NULL
);
Thats it, now you can modify and analyze the tree.
- #!/use/bin/perl
+ #!/usr/bin/perl
use My::Employee;
my $employee = My::Employee->create({ name=>'Matt S. Trout' });
__PACKAGE__->parent_column('parent_id');
Declares the name of the column that contains the self-referential
-ID which defines the parent row. Defaults to "parent_id".
+ID which defines the parent row. Defaults to "parent_id". This
+will create a has_many (children) and belongs_to (parent)
+relationship.
=cut
-__PACKAGE__->mk_classdata( 'parent_column' => 'parent_id' );
+__PACKAGE__->mk_classdata( '_parent_column' => 'parent_id' );
+
+sub parent_column {
+ my $class = shift;
+ if (@_) {
+ my $parent_col = shift;
+ my $primary_col = ($class->primary_columns())[0];
+ $class->belongs_to( '_parent' => $class => { "foreign.$primary_col" => "self.$parent_col" } );
+ $class->has_many( 'children' => $class => { "foreign.$parent_col" => "self.$primary_col" } );
+ $class->_parent_column( $parent_col );
+ return 1;
+ }
+ return $class->_parent_column();
+}
=head2 parent
$employee->parent( $parent_obj );
$employee->parent( $parent_id );
-Retrieves the object's parent ID, or sets the object's
-parent ID. If setting the parent ID then 0 will be returned
-if the object already has the specified parent, and 1 on
-success.
+Retrieves the object's parent object, or changes the object's
+parent to the specified parent or parent ID.
=cut
sub parent {
- my( $self, $new_parent ) = @_;
- my $parent_column = $self->parent_column();
- if ($new_parent) {
+ my $self = shift;
+ if (@_) {
+ my $new_parent = shift;
+ my $parent_col = $self->_parent_column();
if (ref($new_parent)) {
- $new_parent = $new_parent->id() || 0;
+ $new_parent = $new_parent->id() || croak('Parent object does not have an ID');;
}
- return 0 if ($new_parent == ($self->get_column($parent_column)||0));
- $self->set_column( $parent_column => $new_parent );
+ return 0 if ($new_parent == ($self->get_column($parent_col)||0));
+ $self->set_column( $parent_col => $new_parent );
$self->update();
return 1;
}
- else {
- return $self->find( $self->get_column( $parent_column ) );
- }
+ return $self->_parent();
}
=head2 children
my @children = $employee->children();
Returns a list or record set, depending on context, of all
-the objects one level below the current one.
-
-=cut
-
-sub children {
- my( $self ) = @_;
- my $rs = $self->result_source->resultset->search(
- { $self->parent_column()=>$self->id() }
- );
- return $rs->all() if (wantarray());
- return $rs;
-}
+the objects one level below the current one. This method
+is created when parent_column() is called, which sets up a
+has_many relationship called children.
=head2 attach_child
$parent->attach_child( $child );
-Sets (or moves) the child to the new parent.
+Sets the child to the new parent.
=cut
sub attach_child {
my( $self, $child ) = @_;
- $child->parent( $self );
+ return $child->parent( $self );
}
+=head2 siblings
+
+ my $rs = $node->siblings();
+ my @siblings = $node->siblings();
+
+Returns either a result set or an array of all other objects
+with the same parent as the calling object.
+
+=cut
+
+sub siblings {
+ my( $self ) = @_;
+ my $parent_col = $self->_parent_column;
+ my $primary_col = ($self->primary_columns())[0];
+ my $rs = $self->result_source->resultset->search(
+ {
+ $parent_col => $self->get_column($parent_col),
+ $primary_col => { '!=' => $self->get_column($primary_col) },
+ },
+ );
+ return $rs->all() if (wantarray());
+ return $rs;
+}
+
+=cut
+
=head2 attach_sibling
$this->attach_sibling( $that );
=cut
sub attach_sibling {
- my( $self, $child ) = @_;
- $child->parent( $self->parent() );
+ my( $self, $node ) = @_;
+ return $node->parent( $self->parent() );
}
1;