Alzabo

 view release on metacpan or  search on metacpan

lib/Alzabo/MethodMaker.pm  view on Meta::CPAN


        my $name = $self->_make_method
            ( type => 'lookup_columns',
              class => $self->{row_class},
              returns => 'scalar value of column',
              code =>
              sub { my $self = shift;
                    my $row = $self->rows_by_foreign_key( foreign_key => $fk, @_ );
                    return unless $row;
                    return $row->select($col_name) },
              foreign_key => $fk,
              column => $_,
            ) or next;

        $self->{row_class}->add_method_docs
            ( Alzabo::MethodDocs->new
              ( name  => $name,
                group => 'Methods that follow a lookup table',
                description =>
                "returns the value of " . (join '.', $fk->table_to->name, $col_name) . " for the given row by following the foreign key relationship",
                spec  => 'same as Alzabo::Runtime::Table->rows_where',
              ) );
    }
}

sub make_hooks
{
    my $self = shift;
    my $table = shift;
    my $type = shift;

    my $class = $type eq 'insert' ? $self->{table_class} : $self->{row_class};

    my $pre = "pre_$type";
    my $post = "post_$type";

    return unless $class->can($pre) || $class->can($post);

    my $method = join '::', $class, $type;

    {
        no strict 'refs';
        return if *{$method}{CODE};
    }

    print STDERR "Making $type hooks method $class\->$type\n"
        if Alzabo::Debug::METHODMAKER;

    my $meth = "make_$type\_hooks";
    $self->$meth($table);
}

sub make_insert_hooks
{
    my $self = shift;

    my $code = '';
    $code .= "        return \$s->schema->run_in_transaction( sub {\n";
    $code .= "            my \$new;\n";
    $code .= "            \$s->pre_insert(\\\%p);\n" if $self->{table_class}->can('pre_insert');
    $code .= "            \$new = \$s->SUPER::insert(\%p);\n";
    $code .= "            \$s->post_insert({\%p, row => \$new});\n" if $self->{table_class}->can('post_insert');
    $code .= "            return \$new;\n";
    $code .= "        } );\n";

    eval <<"EOF";
{
    package $self->{table_class};
    sub insert
    {
        my \$s = shift;
        my \%p = \@_;

$code

    }
}
EOF

    Alzabo::Exception::Eval->throw( error => $@ ) if $@;

    my $hooks =
        $self->_hooks_doc_string( $self->{table_class}, 'pre_insert', 'post_insert' );

    $self->{table_class}->add_class_docs
        ( Alzabo::ClassDocs->new
          ( group => 'Hooks',
            description => "$hooks",
          ) );
}

sub _hooks_doc_string
{
    my $self = shift;
    my ($class, $hook1, $hook2) = @_;

    my @hooks;
    push @hooks, $hook1 if $class->can($hook1);

    push @hooks, $hook2 if $class->can($hook2);

    my $hooks = 'has';
    $hooks .= @hooks > 1 ? '' : ' a ';
    $hooks .= join ' and ', @hooks;
    $hooks .= @hooks > 1 ? ' hooks' : ' hook';

    return $hooks;
}

sub make_update_hooks
{
    my $self = shift;

    my $code = '';
    $code .= "        \$s->schema->run_in_transaction( sub {\n";
    $code .= "            \$s->pre_update(\\\%p);\n" if $self->{row_class}->can('pre_update');
    $code .= "            \$s->SUPER::update(\%p);\n";
    $code .= "            \$s->post_update(\\\%p);\n" if $self->{row_class}->can('post_update');
    $code .= "        } );\n";

    eval <<"EOF";
{
    package $self->{row_class};

    sub update
    {
        my \$s = shift;
        my \%p = \@_;

$code

    }
}
EOF

    Alzabo::Exception::Eval->throw( error => $@ ) if $@;

    my $hooks =
        $self->_hooks_doc_string( $self->{row_class}, 'pre_update', 'post_update' );

    $self->{row_class}->add_class_docs
        ( Alzabo::ClassDocs->new
          ( group => 'Hooks',
            description => "$hooks",
          ) );
}

sub make_select_hooks
{
    my $self = shift;

    my ($pre, $post) = ('', '');
    $pre  = "            \$s->pre_select(\\\@cols);\n"
        if $self->{row_class}->can('pre_update');

    $post = "            \$s->post_select(\\\%r);\n"
        if $self->{row_class}->can('post_update');

    eval <<"EOF";
{
    package $self->{row_class};

    sub select
    {
        my \$s = shift;
        my \@cols = \@_;

        return \$s->schema->run_in_transaction( sub {

$pre

            my \@r;
            my %r;

            if (wantarray)
            {
                \@r{ \@cols } = \$s->SUPER::select(\@cols);
            }
            else
            {
                \$r{ \$cols[0] } = (scalar \$s->SUPER::select(\$cols[0]));
            }
$post
            return wantarray ? \@r{\@cols} : \$r{ \$cols[0] };
        } );
    }

    sub select_hash
    {
        my \$s = shift;
        my \@cols = \@_;

        return \$s->schema->run_in_transaction( sub {

$pre

            my \%r = \$s->SUPER::select_hash(\@cols);

$post

            return \%r;
        } );
    }
}
EOF

    Alzabo::Exception::Eval->throw( error => $@ ) if $@;

    my $hooks =
        $self->_hooks_doc_string( $self->{row_class}, 'pre_select', 'post_select' );

    $self->{row_class}->add_class_docs
        ( Alzabo::ClassDocs->new
          ( group => 'Hooks',
            description => "$hooks",
          ) );
}

sub make_delete_hooks
{
    my $self = shift;

    my $code = '';
    $code .= "        \$s->schema->run_in_transaction( sub {\n";
    $code .= "            \$s->pre_delete(\\\%p);\n" if $self->{row_class}->can('pre_delete');
    $code .= "            \$s->SUPER::delete(\%p);\n";
    $code .= "            \$s->post_delete(\\\%p);\n" if $self->{row_class}->can('post_delete');
    $code .= "        } );\n";

    eval <<"EOF";
package $self->{row_class};

sub delete
{
    my \$s = shift;
    my \%p = \@_;

$code

}
EOF

    Alzabo::Exception::Eval->throw( error => $@ ) if $@;

    my $hooks =
        $self->_hooks_doc_string( $self->{row_class}, 'pre_delete', 'post_delete' );

    $self->{row_class}->add_class_docs
        ( Alzabo::ClassDocs->new
          ( group => 'Hooks',
            description => "$hooks",
          ) );
}

sub name
{
    my $self = shift;
    my %p = @_;

    return $p{table}->name if $p{type} eq 'table';

    return $p{column}->name if $p{type} eq 'table_column';

    return $p{column}->name if $p{type} eq 'row_column';

    if ( $p{type} eq 'foreign_key' )
    {
        return $p{foreign_key}->table_to->name;
    }

    if ( $p{type} eq 'linking_table' )
    {
        my $method = $p{foreign_key}->table_to->name;
        my $tname = $p{foreign_key}->table_from->name;
        $method =~ s/^$tname\_?//;
        $method =~ s/_?$tname$//;

        return $method;
    }

    return join '_', map { lc $_->name } $p{foreign_key}->table_to, $p{column}
        if $p{type} eq 'lookup_columns';

    return $p{column}->name if $p{type} eq 'lookup_columns';

    return $p{parent} ? 'parent' : 'children'



( run in 0.508 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )