generally I do have several corn scripts. so I want to get $user both in
MyApp and cron scripts.
what I tried to do is soemthing like that:
the first is a base module which contains schema cache and tt2 and others.
package Foorum::Adaptor::Base;
sub new {
my $self = shift;
my $params = {};
return bless $params => $self;
}
sub config {
my $self = shift;
return $self->{config} if ($self->{config});
my $config = LoadFile("$path/../../../foorum.yml");
my $extra_config = LoadFile("$path/../../../foorum_local.yml");
$config = { %$config, %$extra_config };
$self->{config} = $config;
return $self->{config};
}
sub schema {
my $self = shift;
return $self->{schema} if ($self->{schema});
my $config = $self->config();
$self->{schema}
= Foorum::Schema->connect( $config->{dsn}, $config->{dsn_user},
$config->{dsn_pwd}, { AutoCommit => 1, RaiseError => 1,
PrintError => 1 },
);
return $self->{schema};
}
.......
Check Attachment for more details.
then a User adaptor module:
package Foorum::Adaptor::User;
use strict;
use warnings;
use base 'Foorum::Adaptor::Base';
sub get {
my ( $c, $cond ) = @_;
my $cache_key = 'user|' . Object::Signature::signature($cond);
my $cache_val = $c->cache->get($cache_key);
if ($cache_val) {
return $cache_val;
}
$cache_val = get_user_from_db( $c, $cond );
return unless ($cache_val);
$c->cache->set( $cache_key, $cache_val, 7200 ); # two hours
return $cache_val;
}
and others. more see attachment.
at last:
package Foorum::Model::User;
use strict;
use warnings;
use base 'Catalyst::Model::Adaptor';
__PACKAGE__->config( class => 'Foorum::Adaptor::User' );
1;
so that we can do in MyApp:
my $user = $c->model('User')->get( { username => $username } );
or cron script:
use Foorum::Adaptor::User;
my $user_model = new Foorum::Adaptor::User();
my $user = $user_model->get( { user_id => 1 } );
is those code correct? or there is another way to do it?
Thanks.
--
Fayland Lam // http://www.fayland.org/
Foorum based on Catalyst // http://www.foorumbbs.com/
package Foorum::Adaptor::Base;
use strict;
use warnings;
use YAML qw/LoadFile/; # config
use Foorum::Schema; # schema
use TheSchwartz; # theschwartz
use Template; # template
use Template::Stash::XS;
use File::Spec;
use Cwd qw/abs_path/;
my ( undef, $path ) = File::Spec->splitpath(__FILE__);
sub new {
my $self = shift;
my $params = {};
return bless $params => $self;
}
sub base_path {
my $self = shift;
return $self->{path} if ( $self->{path} );
$self->{path} = abs_path("$path/../../../");
return $self->{path};
}
sub config {
my $self = shift;
return $self->{config} if ($self->{config});
my $config = LoadFile("$path/../../../foorum.yml");
my $extra_config = LoadFile("$path/../../../foorum_local.yml");
$config = { %$config, %$extra_config };
$self->{config} = $config;
return $self->{config};
}
sub schema {
my $self = shift;
return $self->{schema} if ($self->{schema});
my $config = $self->config();
$self->{schema}
= Foorum::Schema->connect( $config->{dsn}, $config->{dsn_user},
$config->{dsn_pwd}, { AutoCommit => 1, RaiseError => 1, PrintError => 1
},
);
return $self->{schema};
}
*default_cache_backend = \&cache;
sub cache {
my $self = shift;
return $self->{cache} if ($self->{cache});
my $config = $self->config();
my %params = %{ $config->{cache}{backends}{default} };
my $class = delete $params{class};
eval("use $class;"); ## no critic (ProhibitStringyEval)
unless ($@) {
$self->{cache} = $class->new( \%params );
}
return $self->{cache};
}
sub theschwartz {
my $self = shift;
return $self->{theschwartz} if ($self->{theschwartz});
my $config = $self->config();
$self->{theschwartz} = TheSchwartz->new(
databases => [
{ dsn => $config->{theschwartz_dsn},
user => $config->{theschwartz_user} || $config->{dsn_user},
pass => $config->{theschwartz_pwd} || $config->{dsn_pwd},
}
],
verbose => 0,
);
return $self->{theschwartz};
}
sub tt2 {
my $self = shift;
return $self->{tt2} if ($self->{tt2});
my $config = $self->config();
$self->{tt2} = Template->new(
{ INCLUDE_PATH => ["$path/../../../templates"],
PRE_CHOMP => 1,
POST_CHOMP => 1,
STASH => Template::Stash::XS->new,
}
);
return $self->{tt2};
}
sub error_log {
my ( $self, $level, $text ) = @_;
return unless ($text);
my $schema = $self->schema();
$schema->resultset('LogError')->create(
{ level => $level || 'debug',
text => $text,
time => \'NOW()', #'
}
);
}
1;
__END__
=pod
=head1 NAME
Foorum::Adaptor::Base - base module
=head2 AUTHOR
Fayland Lam <fayland at gmail.com>
=cut
package Foorum::Adaptor::User;
use strict;
use warnings;
use base 'Foorum::Adaptor::Base';
use Object::Signature ();
# Usage:
# get($c, { user_id => ? } );
# get($c, { username => ? } );
# get($c, { email => ? } );
sub get {
my ( $c, $cond ) = @_;
my $cache_key = 'user|' . Object::Signature::signature($cond);
my $cache_val = $c->cache->get($cache_key);
if ($cache_val) {
return $cache_val;
}
$cache_val = get_user_from_db( $c, $cond );
return unless ($cache_val);
$c->cache->set( $cache_key, $cache_val, 7200 ); # two hours
return $cache_val;
}
# Usage:
# get_multi($c, user_id => [1, 2, 3] );
# get_multi($c, username => ['fayland', 'testman'] );
sub get_multi {
my ( $c, $key, $val ) = @_;
my @mem_keys;
my %val_map_key;
foreach (@$val) {
my $cache_key = 'user|' . Object::Signature::signature( { $key => $_ }
);
push @mem_keys, $cache_key;
$val_map_key{$_} = $cache_key;
}
my $cache = $c->default_cache_backend;
my $users;
if ( $cache->can('get_multi') ) { # for Cache::Memcached
$users = $cache->get_multi(@mem_keys);
} else {
foreach (@mem_keys) {
$users->{$_} = $c->cache->get($_);
}
}
my %return_users;
foreach my $v (@$val) {
if ( $users->{ $val_map_key{$v} } ) {
$return_users{$v} = $users->{ $val_map_key{$v} };
} else {
$return_users{$v} = get_user_from_db( $c, { $key => $v } );
next unless ( $return_users{$v} );
$c->cache->set( $val_map_key{$v}, $return_users{$v}, 7200 ); #
two hours
}
}
return \%return_users;
}
sub get_user_from_db {
my ( $c, $cond ) = @_;
my $user = $c->schema->resultset('User')->find($cond);
return unless ($user);
# user_details
my $user_details = $c->schema->resultset('UserDetails')
->find( { user_id => $user->user_id } );
$user_details = $user_details->{_column_data} if ($user_details);
# user role
my @roles = $c->schema->resultset('UserRole')
->search( { user_id => $user->user_id, } )->all;
my $roles;
foreach (@roles) {
$roles->{ $_->field }->{ $_->role } = 1;
}
# user profile photo
my $profile_photo = $c->schema->resultset('UserProfilePhoto')
->find( { user_id => $user->user_id, } );
if ($profile_photo) {
$profile_photo = $profile_photo->{_column_data};
if ( $profile_photo->{type} eq 'upload' ) {
my $profile_photo_upload
= $c->model('Upload')->get( $c, $profile_photo->{value} );
$profile_photo->{upload} = $profile_photo_upload
if ($profile_photo_upload);
}
}
$user = $user->{_column_data};
$user->{details} = $user_details;
$user->{roles} = $roles;
$user->{profile_photo} = $profile_photo;
return $user;
}
sub delete_cache_by_user {
my ( $c, $user ) = @_;
return unless ($user);
my @ckeys;
push @ckeys,
'user|' . Object::Signature::signature( { user_id => $user->{user_id} }
);
push @ckeys,
'user|' . Object::Signature::signature( { username => $user->{username}
} );
push @ckeys, 'user|' . Object::Signature::signature( { email =>
$user->{email} } );
foreach my $ckey (@ckeys) {
$c->cache->remove($ckey);
}
return 1;
}
sub delete_cache_by_user_cond {
my ( $c, $cond ) = @_;
my $user = $c->get( $c, $cond );
$c->delete_cache_by_user( $c, $user );
}
# call this update will delete cache.
sub update {
my ( $c, $user, $update ) = @_;
$c->delete_cache_by_user( $c, $user );
$c->schema->resultset('User')->search( { user_id => $user->{user_id}, } )
->update($update);
}
# get user_settings
# we don't merge it into sub get_user_from_db is because it's not used so
frequently
sub get_user_settings {
my ( $c, $user ) = @_;
# this cachekey would be delete from Controller/Settings.pm
my $cachekey = 'user|user_settings|user_id=' . $user->{user_id};
my $cacheval = $c->cache->get($cachekey);
if ($cacheval) {
$cacheval = $cacheval->{val};
} else {
my $settings_rs = $c->schema->resultset('UserSettings')
->search( { user_id => $user->{user_id} } );
$cacheval = {};
while ( my $rs = $settings_rs->next ) {
$cacheval->{ $rs->type } = $rs->value;
}
$c->cache->set( $cachekey, { val => $cacheval, 1 => } ); # for empty
$cacheval
}
# if not stored in db, we use default value;
my $default = {
'send_starred_notification' => 'Y',
'show_email_public' => 'Y',
};
my $ret = { %$default, %$cacheval }; # merge
return $ret;
}
1;
__END__
=pod
=head1 NAME
Foorum::Model::User - User object
=head1 FUNC
=over 4
=item get
get($c, { user_id => ? } );
get($c, { username => ? } );
get($c, { email => ? } );
get() do not query database directly, it try to get from cache, if not exists,
get_user_from_db() and set cache. return is a hashref: (we may call it
$user_obj below)
{
user_id => 1,
username => 'fayland',
# etc. from user table columns
details => {
birthday => '1984-02-06',
gtalk => 'fayland'
# etc. from user_details table columns
},
roles => {
1 => { admin => 1 },
site => { admin => 1 },
# etc. from user_roles, $field => { $role => 1 }
}
profile_photo => {
type => 'upload',
value => 10,
# etc. from user_profile_photo table columns
upload => {
upload_id => 10,
filename => 'fayland.jpg',
# etc. from upload table columns
}
}
}
=item get_multi
get_multi($c, user_id => [1, 2, 3] );
get_multi($c, username => ['fayland', 'testman'] );
get_multi() is to ease a loop for many users. if cache backend is memcached, it
would use $memcached->get_multi(); to get cached user, and use
get_user_from_db() to missing users. return is a hashref:
# $user_obj is the user hash above
1 => $user_obj,
2 => $user_obj,
# or
fayland => $user_obj,
testman => $user_obj,
(TODO: we may use { user_id => { 'IN' => [EMAIL PROTECTED] } } for missing
users.)
=item get_user_from_db()
get_user_from_db($c, { user_id => ? } );
get_user_from_db($c, { username => ? } );
get_user_from_db($c, { email => ? } );
query db directly. return $user_obj
=item update()
update($c, $user_obj, { update_column => $value } );
the difference between $row->update of L<DBIx::Class> is that it delete cache.
=item delete_cache_by_user()
delete_cache_by_user($c, $user_obj);
=item delete_cache_by_user_cond
delete_cache_by_user_cond($c, { user_id => ? } );
delete_cache_by_user_cond($c, { username => ? } );
delete_cache_by_user_cond($c, { email => ? } );
=item get_user_settings
get_user_settings($c, $user_obj);
get records from user_settings table. return is hashref
{
send_starred_notification => 'N',
}
=back
=head2 AUTHOR
Fayland Lam <fayland at gmail.com>
=cut
_______________________________________________
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/