NAME
DBIx::MoCo - Light & Fast Model Component
SYNOPSIS
# First, set up your db.
package Blog::DataBase;
use base qw(DBIx::MoCo::DataBase);
__PACKAGE__->dsn('dbi:mysql:dbname=blog');
__PACKAGE__->username('test');
__PACKAGE__->password('test');
1;
# Second, create a base class for all models.
package Blog::MoCo;
use base qw 'DBIx::MoCo'; # Inherit DBIx::MoCo
use Blog::DataBase;
__PACKAGE__->db_object('Blog::DataBase');
1;
# Third, create your models.
package Blog::User;
use base qw 'Blog::MoCo';
__PACKAGE__->table('user');
__PACKAGE__->has_many(
entries => 'Blog::Entry',
{ key => 'user_id' }
);
__PACKAGE__->has_many(
bookmarks => 'Blog::Bookmark',
{ key => 'user_id' }
);
1;
package Blog::Entry;
use base qw 'Blog::MoCo';
__PACKAGE__->table('entry');
__PACKAGE__->has_a(
user => 'Blog::User',
{ key => 'user_id' }
);
__PACKAGE__->has_many(
bookmarks => 'Blog::Bookmark',
{ key => 'entry_id' }
);
1;
package Blog::Bookmark;
use base qw 'Blog::MoCo';
__PACKAGE__->table('bookmark');
__PACKAGE__->has_a(
user => 'Blog::User',
{ key => 'user_id' }
);
__PACKAGE__->has_a(
entry => 'Blog::Entry',
{ key => 'entry_id' }
);
1;
# Now, You can use some methods same as in Class::DBI.
# And, all objects are stored in cache automatically.
my $user = Blog::User->retrieve(user_id => 123);
print $user->name;
$user->name('jkontan'); # update db immediately
print $user->name; # jkontan
my $user2 = Blog::User->retrieve(user_id => 123);
# $user is same as $user2
# You can easily get has_many objects array.
my $entries = $user->entries;
my $entries2 = $user->entries;
# $entries is same reference as $entries2
my $entry = $entries->first; # isa Blog::Entry
print $entry->title; # you can use methods in Entry class.
Blog::Entry->create(
user_id => 123,
title => 'new entry!',
);
# $user->entries will be flushed automatically.
my $entries3 = $user->entries;
# $entries3 isnt $entries
print ($entries->last eq $entries2->last); # 1
print ($entries->last eq $entries3->last); # 1
# same instance
# You can delay update/create query to database using session.
DBIx::MoCo->start_session;
$user->name('jkondo'); # not saved now. changed in cache.
print $user->name; # 'jkondo'
$user->save; # update db
print Blog::User->retrieve(123)->name; # 'jkondo'
# Or, update queries will be thrown automatically after ending session.
$user->name('jkontan');
DBIx::MoCo->end_session;
print Blog::User->retrieve(123)->name; # 'jkontan'
DESCRIPTION
Light & Fast Model Component
CACHE ALGORITHM
MoCo caches objects effectively. There are 3 functions to control MoCo's
cache. Their functions are called appropriately when some operations are
called to a particular object.
Here are the 3 functions.
store_self_cache
Stores self instance for all own possible object ids.
flush_self_cache
Flushes all caches for all own possible object ids.
flush_belongs_to
Flushes all caches whose have has_many arrays including the object.
And, here are the triggers which call their functions.
_after_create
Calls "store_self_cache" and "flush_belongs_to".
_before_update
Calls "flush_self_cache".
_after_update
Calls "store_self_cache".
_before_delete
Calls "flush_self_cache" and "flush_belongs_to".
CLASS METHODS
Here are common class methods of DBIx::MoCo.
add_trigger
Adds triggers. Here are the types which called from DBIx::MoCo.
before_create
after_create
before_update
after_update
before_delete
You can add your trigger like this.
package Blog::User;
__PACKAGE__->add_trigger(before_create => sub
my ($class, $args) = @_;
$args->{name} .= '-san';
});
# in your scripts
my $u = Blog::User->create(name => 'ishizaki');
is ($u->name, 'ishizaki-san'); # ok.
"before_create" passes a hash reference of new object data as the
second argument, and all other triggers pass the instance $self.
has_a
Defines has_a relationship between 2 models.
has_many
Defines has_many relationship between 2 models. You can define
additional conditions as below.
Blog::User->has_many(
root_messages => 'Blog::Message', {
key => {name => 'to_name'},
condition => 'reference_id is null',
order => 'modified desc',
},
);
"condition" is additional sql statement will be used in where
condition. "order" is used for specifying order statement. In above
case, SQL statement will be ..
SELECT message_id FROM message
WHERE to_name = 'myname' AND reference_id is null
ORDER BY modified desc
And, all each results will be inflated as Blog::Message by
retrieving (with using cache) all records again.
retrieve_keys
Defines keys for retrieving by retrieve_all etc. If there aren't any
unique keys in your table, please specify these keys.
package Blog::Bookmark;
__PACKAGE__->retrieve_keys(['user_id', 'entry_id']);
# When user can add multiple bookmarks onto same entry.
start_session
end_session
is_in_session
cache_status
Returns cache status hash reference. cache_status provides
retrieve_count, retrieve_cache_count, retrieved_oids
retrieve_all_count, has_many_count, has_many_cache_count,
cache
Set or get cache.
schema
Returns DBIx::MoCo::Schema object reference related with your model
class.
primary_keys
unique_keys
columns
has_column(col_name)
Returns which the table has the column or not.
retrieve
retrieve_or_create
retrieve_all
retrieve_all_id_hash
create
delete_all
count
search
find
Similar to search, but returns only the first item as a reference
(not array).
retrieve_by_column(_and_column2)
retrieve_by_column(_and_column2)_or_create
retrieve_by_column_or_column2
column_as_something
Inflate column value by using DBIx::MoCo::Column::* plugins. If you
set up your plugin like this,
package DBIx::MoCo::Column::MyColumn;
sub MyColumn {
my $self = shift;
return "My Column $$self";
}
1;
Then, you can use column_as_MyColumn method
my $o = MyObject->retrieve(..);
print $o->name; # "jkondo"
print $o->name_as_MyColumn; # "My Column jkondo";
You can also inflate your column value with blessing with other
classes. Method name which will be imported must be same as the
package name.
has_a, has_many auto generated methods
If you define has_a, has_many relationships,
package Blog::Entry;
use base qw 'Blog::MoCo';
__PACKAGE__->table('entry');
__PACKAGE__->has_a(
user => 'Blog::User',
{ key => 'user_id' }
);
__PACKAGE__->has_many(
bookmarks => 'Blog::Bookmark',
{ key => 'entry_id' }
);
You can use those keys as methods.
my $e = Blog::Entry->retrieve(..);
print $e->user; # isa Blog::User
print $e->bookmarks; # isa ARRAY of Blog::Bookmark
CLASS OR INSTANCE METHODS
Here are common class or instance methods of DBIx::MoCo.
object_id
delete
quote
INSTANCE METHODS
Here are common instance methods of DBIx::MoCo.
flush_self_cache
Flush caches for self possible object ids.
store_self_cache
Store self into cache for possible object ids.
flush
Delete attribute from given attr. name.
param
Set or get attribute from given attr. name.
set Set attribute which is not related with DB schema or set temporary.
has_primary_keys
save
Saves changed columns in session.
object_ids
Returns all possible object-ids.
FORM VALIDATION
You can validate user parameters using moco's schema. For example you
can define your validation profile using param like this,
package Blog::User;
__PACKAGE__->schema->param([
name => ['NOT_BLANK', 'ASCII', ['DBIC_UNIQUE', 'Blog::User', 'name']],
mail => ['NOT_BLANK', 'EMAIL_LOOSE'],
]);
And then,
# In your scripts
sub validate {
my $self = shift;
my $q = $self->query;
my $prof = Blog::User->schema->param('validation');
my $result = FormValidator::Simple->check($q => $prof);
# handle errors ...
}
SEE ALSO
SQL::Abstract, Class::DBI, Cache,
AUTHOR
Junya Kondo, , Naoya Ito,
COPYRIGHT AND LICENSE
Copyright (C) Hatena Inc. All Rights Reserved.
This library is free software; you may redistribute it and/or modify it
under the same terms as Perl itself.