English plugin dev 3 4 - Hiranyaloka/Documentation GitHub Wiki

MT Objects and Database

Developing an MT plugin, sooner or later you will have to manipulate MT objects.

So lets learn about MT’s object system and ORM

MT Object System

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)

How to use MT’s Objects (perl)

Notation – old and current

Some time ago MT changed how the object classes were loaded. Both ways exist in the system, so we will show them both.

Old notation

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.

Current Notation

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');

Creating a new Object

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.

Loading a specific object (loading by ID)

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);

Searching by conditions (loading by terms & args)

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
}

Reading objects one-by-one (load_iter)

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
}

Terms & args

About $terms

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 ] });

About $args

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, and JOIN_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

Setting object values

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');

Getting object values

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();

Save

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;

Delete

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;

Bulk remove

removes all the objects from the table, without loading them

$class->remove_all()
    or die $class->errstr;

Remove child objects

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;
}

Counting Objects

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 );

Checking for DB existence

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!";
}

Checking the type of an object

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

Specific object methods

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)

Using MT’s Objects (PHP)

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

Object loading

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 )

Navigation

Prev:Adding Scheduled Tasks << Index >> Next:Creating Your Own Objects

⚠️ **GitHub.com Fallback** ⚠️