Data-ObjectDriver

 view release on metacpan or  search on metacpan

lib/Data/ObjectDriver/BaseObject.pm  view on Meta::CPAN

# $Id$

package Data::ObjectDriver::BaseObject;
use strict;
use warnings;

our $HasWeaken;
eval q{ use Scalar::Util qw(weaken) }; ## no critic
$HasWeaken = !$@;

use Carp ();

use Class::Trigger qw( pre_save post_save post_load pre_search
                       pre_insert post_insert pre_update post_update
                       pre_remove post_remove post_inflate );

use Data::ObjectDriver::ResultSet;

## Global Transaction variables
our @WorkingDrivers;
our $TransactionLevel = 0;

sub install_properties {
    my $class = shift;
    my($props) = @_;
    my $columns = delete $props->{columns};
    $props->{columns} = [];
    {
        no strict 'refs'; ## no critic
        *{"${class}::__properties"} = sub { $props };
    }

    foreach my $col (@$columns) {
        $class->install_column($col);
    }
    return $props;
}

sub install_column {
    my($class, $col, $type) = @_;
    my $props = $class->properties;

    push @{ $props->{columns} }, $col;
    $props->{column_names}{$col} = ();
    # predefine getter/setter methods here
    # Skip adding this method if the class overloads it.
    # this lets the SUPER::columnname magic do it's thing
    if (! $class->can($col)) {
        no strict 'refs'; ## no critic
        *{"${class}::$col"} = $class->column_func($col);
    }
    if ($type) {
        $props->{column_defs}{$col} = $type;
    }
}

sub properties {
    my $this = shift;
    my $class = ref($this) || $this;
    $class->__properties;
}

# see docs below

sub has_a {
    my $class = shift;
    my @args = @_;

    # Iterate over each remote object
    foreach my $config (@args) {
        my $parentclass = $config->{class};

        # Parameters
        my $column = $config->{column};
        my $method = $config->{method};
        my $cached = $config->{cached} || 0;
        my $parent_method = $config->{parent_method};

        # column is required
        if (!defined($column)) {
            die "Please specify a valid column for $parentclass"
        }

        # create a method name based on the column
        if (! defined $method) {
            if (!ref($column)) {
                $method = $column;
                $method =~ s/_id$//;
                $method .= "_obj";
            } elsif (ref($column) eq 'ARRAY') {
                foreach my $col (@{$column}) {
                    my $part = $col;
                    $part =~ s/_id$//;
                    $method .= $part . '_';
                }
                $method .= "obj";
            }
        }

        # die if we have clashing methods method
        if (! defined $method || defined(*{"${class}::$method"})) {
            die "Please define a valid method for $class->$column";
        }

        if ($cached) {
            # Store cached item inside this object's namespace
            my $cachekey = "__cache_$method";

            no strict 'refs'; ## no critic
            *{"${class}::$method"} = sub {
                my $obj = shift;

                return $obj->{$cachekey}
                    if defined $obj->{$cachekey};

                my $id = (ref($column) eq 'ARRAY')
                    ? [ map { $obj->{column_values}->{$_} } @{$column}]
                    : $obj->{column_values}->{$column}
                    ;
                ## Hold in a variable here too, so we don't lose it immediately
                ## by having only the weak reference.
                my $ret = $parentclass->lookup($id);
                if ($HasWeaken) {
                    $obj->{$cachekey} = $ret;
                    weaken($obj->{$cachekey});
                }
                return $ret;
            };
        } else {
            if (ref($column)) {
                no strict 'refs'; ## no critic
                *{"${class}::$method"} = sub {
                    my $obj = shift;
                    return $parentclass->lookup([ map{ $obj->{column_values}->{$_} } @{$column}]);
                };
            } else {
                no strict 'refs'; ## no critic
                *{"${class}::$method"} = sub {
                    return $parentclass->lookup(shift()->{column_values}->{$column});
                };
            }
        }

        # now add to the parent
        if (!defined $parent_method) {
            $parent_method = lc($class);
            $parent_method =~ s/^.*:://;

            $parent_method .= '_objs';
        }
        if (ref($column)) {
            no strict 'refs'; ## no critic
            *{"${parentclass}::$parent_method"} = sub {
                my $obj = shift;
                my $terms = shift || {};
                my $args = shift;

                my $primary_key = $obj->primary_key;

                # inject pk search into given terms.
                # composite key, ugh
                foreach my $key (@$column) {
                    $terms->{$key} = shift(@{$primary_key});
                }

                return $class->search($terms, $args);
            };
        } else {
            no strict 'refs'; ## no critic
            *{"${parentclass}::$parent_method"} = sub {
                my $obj = shift;
                my $terms = shift || {};
                my $args = shift;
                # TBD - use primary_key_to_terms
                $terms->{$column} = $obj->primary_key;
                return $class->search($terms, $args);
            };
        };
    } # end of loop over class names
    return;
}

sub driver {
    my $class = shift;
    $class->properties->{driver} ||= $class->properties->{get_driver}->();



( run in 0.576 second using v1.01-cache-2.11-cpan-39bf76dae61 )