« ぱどタウンの横浜タウンに中田市長が | メイン | Class::DBIでComunをData::SerializerでSerializeして保存。 »

Class::DBIでobejctやreferenceを保存

「Class::DBI で疑似的カラム」をちょっと機能強化で書いたモジュールをもとにClass::DBI でobejctやreferenceをシームレスに保存できるプラグインを書いてみた。

使い方

package My::Film;
use base 'Class::DBI';
use Class::DBI::Plugin::SerializeColumn;
__PACKAGE__->columns(All => qw/id title props/);
__PACKAGE__->serialize_column('props');

などとクラスを書いて、

My::Film->create({
    id=>1,
    title=>'四月物語',
    props =>{year=> 1998,director=>'岩井俊二'}
});

とできるし、

my $film = My::Film->retrieve(1);
$film->props->{director};#岩井俊二
$film->props->{cast}=[qw/松たか子 田辺誠一 加藤和彦 藤井かほり/];
$film->update;

こういうこともできると思う。

もうすこし方法ないのか探しているんだけど、↓追記にソース貼付け

package Class::DBI::Plugin::SerializeColumn;

use 5.006;
use strict;
use warnings;
use UNIVERSAL::require;
use vars qw($VERSION);
$VERSION='0.01';

sub import {
	my $class = shift;
	my $pkg   = caller(0);
	
	$pkg->mk_classdata('column_serializer'=>'Storable');
	$pkg->mk_classdata('__serialize_column'=>[]);

	my $before_create_update_callback=sub{
		my $self = shift;
		foreach my $column (@{$self->serialize_column}){
			my $ref=$self->_attrs($column) || next;
			my $freeze=$self->_serialize_column_freeze($ref);
			$self->_attribute_set($column,$freeze);
		}
	};
	my $select_callback=sub{
		my $self = shift;
		foreach my $column (@{$self->serialize_column}){
			my $freeze=$self->_attrs($column) || next;
			my $ref=$self->_serialize_column_thaw($freeze);
			$self->_attribute_store($column,$ref);
		}
	};
	
	$pkg->add_trigger('before_create',$before_create_update_callback);
	$pkg->add_trigger('before_update',$before_create_update_callback);
	$pkg->add_trigger('select',$select_callback);
	
	no strict 'refs';
	*{"$pkg\::serialize_column"} =  \&serialize_column;
	*{"$pkg\::_column_serializer"} = \&_column_serializer;
	*{"$pkg\::_serialize_column_freeze"} = \&_serialize_column_freeze;
	*{"$pkg\::_serialize_column_thaw"} =  \&_serialize_column_thaw;
}

sub serialize_column{
	my $class = shift;
	if(@_ >0){
		push(@{$class->__serialize_column},shift);
	}
	return $class->__serialize_column;
}

sub _column_serializer{
	my $self = shift;
	my $serializer = "Class::DBI::Plugin::SerializeColumn::" . $self->column_serializer;
	$serializer->require;
	return $self->_croak(qq(couldn't load serializer "$serializer" : ) . $@) if $@;
	return $serializer;
}

sub _serialize_column_freeze{
	my($self, $var) = @_;
	my $serializer = $self->_column_serializer;
	my $freeze;
	eval{
		$freeze=$serializer->freeze($var);
	};
	return $self->_croak(qq(couldn't freeze data : ) . $@) if $@;
	return $freeze;
}

sub _serialize_column_thaw{
	my($self, $freeze) = @_;
	my $serializer = $self->_column_serializer;
	my $thaw;
	eval{
		$thaw=$serializer->thaw($freeze);
	};
	return $self->_croak(qq(couldn't thaw data $freeze: ) . $@) if $@;
	return $thaw;
}

1;