BLOG

Go to top


ちょっとイレギュラーな join 指定でオブジェクトを load する

June 3, 2009 1:19 PM

Movable Type 公式のオブジェクトリファレンスの MT::Object の項目には、二つのテーブルを join してオブジェクトを load する方法が記載されています。その場合の join の指定方法は以下のようになっています。

join => [ CLASS, JOIN_COLUMN, I<\%terms>, I<\%arguments> ]

この場合、Movable Type のテーブル構造から考えて行くと、ブログ記事とユーザ、mt_entry テーブルと mt_author テーブルを join するには、entry_author_id と author_id で join する必要があります。なので、JOIN_COLUMN には author_id を指定してやらなければなりません。例えば「ブログ記事のキーワード欄に各ユーザのログイン名を入れておいて、そのユーザが有効な場合のみ load する」ようなことはできません(そんなことをしたい人がいるかどうかは知らん)。

このようなことを実現したい場合は、以下のような指定でオブジェクトを load する必要があります。

    my ( %terms, %args );
    $terms{ status } = MT::Entry::RELEASE();

    my ( %join_terms, %join_args );
    $join_terms{ name } = \'=entry_keywords';
    $join_terms{ status } = MT::Author::ACTIVE();
    $join_args{ unique } = 1;

    $args{ 'join' } = MT->model( 'author' )->join_on( undef, \%join_terms, \%join_args );
    my @entries = MT->model( 'entry' )->load( \%terms, \%args );

「$join_terms{ name } = \'=entry_keywords';」がキモです。こうすることで、Data::ObjectDriver が SQL を組み立てるときに直接 SQL 文に組み込まれるのだと思いますが、詳しいことはともかく上記のようなやり方で指定できます。

プラグインにするなら、以下のようなコードになるでしょう。

package MT::Plugin::SampleEntries;
use strict;

use MT;
use MT::Plugin;

use base qw( MT::Plugin );

our $VERSION = 0.1;

@MT::Plugin::SampleEntries::ISA = qw( MT::Plugin );

my $plugin = new MT::Plugin::SampleEntries( {
    name => 'SampleEntries',
    id => 'SampleEntries',
    key => 'sampleentries',
    version => $VERSION,
} );

MT->add_plugin( $plugin );

sub init_registry {
    my $plugin = shift;
    $plugin->registry( {
        tags => {
            block => {
                SampleEntries => \&_hdlr_sample_entries,
                SampleEntriesHeader => \&_hdlr_pass_tokens,
                SampleEntriesFooter => \&_hdlr_pass_tokens,
            },
            function => {
                SampleEntriesCount => \&_hdlr_sample_entries,
            },
        },
   } );
}

sub _hdlr_sample_entries {
    my ( $ctx, $args, $cond ) = @_;
    my $builder = $ctx->stash( 'builder' );
    my $tokens = $ctx->stash( 'tokens' );

    my ( %terms, %args );
    $terms{ status } = MT::Entry::RELEASE();

    my ( %join_terms, %join_args );
    $join_terms{ name } = \'=entry_keywords';
    $join_terms{ status } = MT::Author::ACTIVE();
    $join_args{ unique } = 1;

    $args{ 'join' } = MT->model( 'author' )->join_on( undef, \%join_terms, \%join_args );

    if ( lc $ctx->stash( 'tag' ) eq 'sampleentriescount' ) {
        return MT->model( 'entry' )->count( \%terms, \%args );
    }
    my @entries = MT->model( 'entry' )->load( \%terms, \%args );

    my $res = ''; my $i = 0;
    my $vars = $ctx->{ __stash }{ vars } ||= {};
    if ( @entries ) {
        for my $entry ( @entries ) {
            local $vars->{ __first__ } = ! $i;
            local $vars->{ __last__ } = ! defined $entries[ $i + 1 ];
            local $vars->{ __odd__ } = ( $i % 2 ) == 0; # 0-based $i
            local $vars->{ __even__ } = ( $i % 2 ) == 1;
            local $vars->{ __counter__ } = $i + 1;
            local $ctx->{ __stash }{ entry } = $entry;
            local $ctx->{ __stash }{ blog } = $entry->blog;
            local $ctx->{ __stash }{ blog_id } = $entry->blog_id;
            local $ctx->{ current_timestamp } = $entry->modified_on;
            local $ctx->{ modification_timestamp } = $entry->modified_on;
            my $out = $builder->build( $ctx, $tokens, { %$cond,
                                                        SampleEntriesHeader => ! $i,
                                                        SampleEntriesFooter => 
                                                            !defined $entries[ $i + 1 ],
                                     } );
            $res .= $out if $out;
            $i++;
        }
        return $res || '';
    } else {
        return $ctx->_hdlr_pass_tokens_else( @_ );
    }
}

sub _hdlr_pass_tokens {
    my( $ctx, $args, $cond ) = @_;
    my $b = $ctx->stash( 'builder' );
    defined( my $out = $b->build( $ctx, $ctx->stash( 'tokens' ), $cond ) )
        or return $ctx->error( $b->errstr );
    return $out;
}

1;

お願い

基本的にご利用は無償かつ自己責任ですが、継続的な開発、更新のため、よろしければドネーションをご検討ください。以下のボタンから、PayPal を通じて行うことができます。

また、フィードバックもぜひ kenmin.okayama@gmail.com までお送りください。コメントでもかまいません。

Comments


Contact me

Copyright © 2005 - 2017 okayama All rights reserved.