[Dbix-class] DateTime personalization
Bernhard Graf
dbic3 at augensalat.de
Fri Oct 31 22:35:32 GMT 2008
For my datetime and date fields I use DBIC:InflateColumn::DateTime and
DBIC:Timestamp.
Now I wanted to personalize those DateTime objects for the authenticated
user: Time zone and output format should be set on inflation, according
to what the authenticated user has configured in his/her personal
settings.
Here is how this is done currently:
In the user table there are columns for the time zone (Olson format),
datetime and date format (strftime format) and the current locale
(setlocale(3) format):
package MyApp::Schema::User;
__PACKAGE__->add_columns(
[...]
locale => {data_type => 'varchar'},
timezone => {data_type => 'varchar'},
format_datetime => {data_type => 'varchar'},
format_date => {data_type => 'varchar'},
[...]
);
In MyApp::Schema I have:
__PACKAGE__->mk_group_accessors(
'simple' => qw/
current_locale
current_time_zone
current_datetime_format
current_date_format
/
);
It is up to the application to fill those fields in as soon as it can
catch the user data. In my Catalyst application it is
MyApp::Controller::Admin::auto() that does this:
my $schema = $c->model('DB')->schema;
my $user = $c->user->get_object;
my $locale = $user->locale || 'en_US';
my $timezone = $user->timezone || 'local';
$schema->current_locale($locale);
$schema->current_time_zone($timezone);
my $dtf = $user->format_datetime || '%Y-%m-%e %T';
$schema->current_datetime_format(
DateTime::Format::Strptime->new(
pattern => $dtf, locale => $locale, time_zone => $timezone,
)
);
dtf = $user->format_date || '%Y-%m-%e';
$schema->current_date_format(
DateTime::Format::Strptime->new(
pattern => $dtf, locale => $locale, time_zone => $timezone,
)
);
The question was now how to do personalization on DateTime inflation.
Unfortunately I didn't find a better solution than using a patched
version of DBIC::InflateColumn::DateTime.
The inflate-part for inflate_column now looks like this:
inflate => sub {
my ($value, $obj) = @_;
my $z;
my $dt = $obj->_datetime_parser->$parse($value);
$dt->set_time_zone($timezone) if $timezone;
$z = $obj->get_user_time_zone
and $dt->set_time_zone($z);
$z = "get_user_${type}_format";
$z = $obj->$z()
and $dt->set_formatter($z);
return $dt;
},
And also in this package there are three stub methods:
sub get_user_time_zone { }
sub get_user_datetime_format { }
sub get_user_date_format { }
Since those stub methods don't do anything DBIC::InflateColumn::DateTime
works as before unless you load this component before it:
package DBIx::Class::DateTimeMethods;
use strict;
use warnings;
use base qw/DBIx::Class/;
sub get_user_time_zone {
return shift->result_source->schema->current_time_zone;
}
sub get_user_datetime_format {
return shift->result_source->schema->current_datetime_format;
}
sub get_user_date_format {
return shift->result_source->schema->current_date_format;
}
1;
LBNL all I have to change in my DBIC::Schema classes is loading
component DateTimeMethods before InflateColumn::DateTime or TimeStamp:
_PACKAGE__->load_components(qw/DateTimeMethods TimeStamp Core/);
Now all datetime objects stringify automagically according to the
authenticated user's settings.
My only concern is: Would this be possible without patching
DBIC::InflateColumn::DateTime ?
--
Bernhard Graf
More information about the DBIx-Class
mailing list