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
andflush_belongs_to
. - _before_update
-
Calls
flush_self_cache
. - _after_update
-
Calls
store_self_cache
. - _before_delete
-
Calls
flush_self_cache
andflush_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, <http://jkondo.vox.com/>, Naoya Ito, <naoya@hatena.ne.jp>
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.