English plugin dev 3 4 - Hiranyaloka/Documentation GitHub Wiki
Developing an MT plugin, sooner or later you will have to manipulate MT objects.
So lets learn about MT’s object system and ORM
The MT object system was build around the Data::Object::Driver module, (or more correctly, DOD was written for MT) and the base type of any object that MT uses is MT::Object.
Well, any Database-saved object that is. i.e. MT::Blog and MT::Entry.
Don’t worry, we won’t make you write SQL statements for loading, saving or updating objects. The ORM (which is the layer that hides the fact that we are dealing with a DB, and in our case it is the DOD) handles it. (actually, it is not easy to write and execute raw SQL in MT)
Some time ago MT changed how the object classes were loaded. Both ways exist in the system, so we will show them both.
In a classic Perl notation, simply write the Perl class directly
my $obj = MT::Foo->new();
Of course, it is quite possible that the MT::Foo module was not loaded, and the code will fail.
So you need to add “require MT::Foo” before it.
Also, this code is quite rigid. the “require” command does not plays well with dynamic package names, which will create problems if you want to reuse code between, say, entries and comments.
Obtain the Perl package name using $class = MT->model($model_name)
my $class = MT->model('foo'); my $obj = $class->new();
If a type has sub-types, (i.e. ‘asset’ have ‘asset.image’, ‘asset.video’, etc.)we can load a list of all the sub-types using the models
command:
my @types = MT->models('asset');
All hail the new
command!
my $class = MT->model($class_name); my $obj = $class->new();
Of course, if we don’t need $class afterwards, we can shorten it a bit
my $obj = MT->model($class_name)->new();
The new command creates an empty object in-memory. You can not give it parameters to fill it beforehand. It will not be saved to the DB unless you tell it to.
The easiest and fastest way to load an object is by its ID. Assuming that you know the ID, of course.
The function loads the object from the DB and returns it, or returns undef if not found
my $obj = $class->load($id);
Well, not always we know the ID of the object. Sometimes we want to load more then one object, using some search criteria.
This is the general form of object loading. Generally the terms are defining which objects we want to load, and the args do operations on them. (such as sorting, limiting and more)
We will talk later about what can go into the terms and args.
my $terms = { author_id => $author->id, blog_id => $blog->id }; my $args = { sort => 'created_on', direction => 'ascend', limit => 20 }; my @obj = $class->load( $terms, $args ); for my $obj (@obj) { # do something }
Similar to the terms & args load, load_iter( $terms, $args )
loads bunch of objects, but deliver them one-by-one.
So instead of getting a large list of objects, you get an iterator and fetch one object every time.
To retrieve an object use $obj = $iter->()
, which will return the next object or undef if no more objects exist
my $iter = $class->load_iter( $terms, $args ); while (my $obj = $iter->()) { # do something }
A hash-ref, of which the keys are the DB columns names and the keys are the desired value.
For example, to load all the foo objects whose ‘foo’ column equal to ‘bar’, write:
my @foo = MT->model('foo')->load({ foo => 'bar' });
it is also possible to specify a list of values for a column, the object loaded will be the ones with either values. In the following example, all the objects with foo equal ‘bar’, and the status is either 1 or 2 will be loaded:
my @foo = MT->model('foo')->load({ foo => 'bar', status => [ 1, 2 ] });
The $args parameter is a hash-ref too, and can contain the following items:
- sort => “column”
- Sorts the resulting objects by the column ‘column’
- direction => “ascend|descend”
- The sort mentioned previously can be either done ascending or descending
- limit => “N”
- If no limit is specified, loads all the objects that answer the criteria. Limit cause it to load only the first N objects
- offset => “M”
- To be used together with limit. instead of loading the first N, loads from object M to M+N-1
- start_val => “value”
- Used together with sort and possible limit. instead of loading the first N objects, skip all the objects whose the sorted column value is smaller the “value”
- range
- In the terms explanation we showed that you can supply an array, and any value in it will be searched. specifying range in the args will turn this array from a list of values to a range
- the range parameter is a hash-ref, with the keys are the columns to be turned to range, and the values are all ones
my $class = MT->model('entry'); my @entries = $class->load( { created_on => ['201103010000', '201104010000'] }, { range => { created_on => 1 } } );
- join
- Select objects based on other object types. For example, if you want to select the latest N entries that were commented upon, you can join the comment table as a search criteria for fetching the entries. It is much faster then reading the comments table, checking which entries the last comments are on, and then load the entries
- Note that this join is not equal to SQL’s join. The result here will be entries, and you can not select columns from the comments table, even if it was used in the query
- The syntax of the join is:
join => CLASS→join_on( JOIN_COLUMN, $terms, $args )
-
CLASS
is the class for the other object type, andJOIN_COLUMN
is the name of the column that should be equal between the tables. After that we have$terms
and$args
, filtering that table. - For example, we fetch the ten entries with the latest comments. Note the unique flag, otherwise we may get the same entry twice
my @entries = MT->model('entry')->load(undef, { 'join' => MT->model('comment')->join_on('entry_id', { blog_id => $blog_id }, { 'sort' => 'created_on', direction => 'descend', unique => 1, limit => 10 } ) });
- unique
- Ensures that the objects return are unique
- This is only useful for joins, as in simple loads the object loaded are always unique
We said that you can’t set initial values in the new command. so this is how you set the value foobar
to property bar
:
$obj->bar('foobar');
Similarly, to get a property value just call the same function, without parameters. the code below will return foobar
, if the code above was run first
my $value = $obj->bar();
When you create an object using new or set a property for an existing object, the changes are not saved to the database. Calling $obj->save()
will do it.
The save operation return true on success or false on error
$obj->save() or die $obj->errstr;
For removing a loaded object from the database. The object is left in the memory until you get rid of it
$obj->remove() or die $obj->errstr;
removes all the objects from the table, without loading them
$class->remove_all() or die $class->errstr;
Some classes have registered children-classes. For example, the entry class have comments as children.
This command removes the children of the current object from the DB.
Usually it is done but the parent class automatically, overriding the remove function, and you don’t need to care about it.
sub remove { my $obj = shift; $obj->remove_children({ key => 'class_id' }); $obj->SUPER::remove; }
Sometimes we don’t want to load the objects themselves, but just to know how many there are.
The syntax is similar to the load command, just that it does not loads anything, but return the number
$count = $class->count( $terms, $args );
Does this object already exists on the DB?
Of course, if a table does not have a primary key, the answer is always no.
if ($foo->exists()) { printf "Foo $foo already exists!"; }
First of all, we can ask the Perl way, is this object is of type:
if ( $obj->isa('MT::Foo') ) { # do something }
alternatively, we can ask $obj->datasource eq 'entry'
, to check the base object class of this object. If you want to check for subclasses, use $obj->class
Of course, each object type has a bunch of other methods that are useful only for them. see the documentation for details
Movable Type Perl Documentation(English)
Movable Type オブジェクト・リファレンス(Japanese)
We talked a lot about Perl’s object system, loading, deleting and manipulating. Now we can use this footnote to explain about PHP’s object system.
Well, it is a lot simpler then the Perl one. As the PHP is used mainly for viewing the pages and not manipulating it, that is the focus of our data access functions
Note that while in the Perl side, you needed to specify if you wanted only the published / public objects, in the PHP version only the public objects are loaded, always
$mt = $ctx->mt; $obj = $mt->db()->fetch_foo($foo_id);
$args['class'] = 'foo'; $args['blog_id'] = $blog_id; $args['offset'] = 20; $args['limit'] = 10; $mt = $ctx->mt; $obj = $mt->db()->fetch_foos($args);
Below are the main functions listed by the object that they load:
Class | Function |
MT::Website | fetch_website( $website_id ) |
MT::Website (multiple) | fetch_websites( $args ) |
MT::Blog | fetch_blog( $blog_id ) |
MT::Blog (multiple) | fetch_blogs( $args ) |
MT::Template (multiple) | fetch_templates( $args ) |
MT::Page | fetch_page( $page_id ) |
MT::Page (multiple) | fetch_pages( $args ) |
MT::Entry | fetch_entry( $entry_id ) |
MT::Entry (multiple) | fetch_entries( $args, &$total_count ) |
MT::Category | fetch_category( $cat_id ) |
MT::Category (multiple) | fetch_categories( $args ) |
MT::Folder | fetch_folder( $folder_id ) |
MT::Folder (multiple) | fetch_folders( $args ) |
MT::Author | fetch_author( $author_id ) |
MT::Author (multiple) | fetch_authors( $args ) |
MT::Comment | fetch_comment( $comment_id ) |
MT::Comment (multiple) | fetch_comments( $args ) |
Prev:Adding Scheduled Tasks << Index >> Next:Creating Your Own Objects