~ubuntu-branches/debian/squeeze/movabletype-opensource/squeeze

« back to all changes in this revision

Viewing changes to lib/MT/Entry.pm

  • Committer: Bazaar Package Importer
  • Author(s): Dominic Hargreaves
  • Date: 2008-06-13 23:28:40 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080613232840-ya4jfxv1jgl45a3d
Tags: 4.2~rc2-1
* New upstream release candidate
* Update Standards-Version (no changes)
* Ensure that schema upgrade message is always seen

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
# This program is distributed under the terms of the
3
3
# GNU General Public License, version 2.
4
4
#
5
 
# $Id: Entry.pm 1174 2008-01-08 21:02:50Z bchoate $
 
5
# $Id: Entry.pm 2546 2008-06-11 00:07:21Z bchoate $
6
6
 
7
7
package MT::Entry;
8
8
 
19
19
use MT::Comment;
20
20
use MT::TBPing;
21
21
use MT::Util qw( archive_file_for discover_tb start_end_period extract_domain
22
 
                 extract_domains );
 
22
                 extract_domains weaken );
23
23
 
24
 
use constant CATEGORY_CACHE_TIME => 7 * 24 * 60 * 60;  ## 1 week
 
24
sub CATEGORY_CACHE_TIME () { 604800 } ## 7 * 24 * 60 * 60 == 1 week
25
25
 
26
26
__PACKAGE__->install_properties({
27
27
    column_defs => {
45
45
        'authored_on' => 'datetime',
46
46
        'week_number' => 'integer',
47
47
        'template_id' => 'integer',
 
48
        'comment_count' => 'integer',
 
49
        'ping_count' => 'integer',
48
50
## Have to keep this around for use in mt-upgrade.cgi.
49
51
        'category_id' => 'integer',
50
52
    },
51
53
    indexes => {
52
 
        blog_id => 1,
53
54
        status => 1,
54
55
        author_id => 1,
55
56
        created_on => 1,
56
57
        modified_on => 1,
57
58
        authored_on => 1,
58
 
        week_number => 1,
59
 
        basename => 1,
 
59
        # For lookups 
 
60
        blog_basename => {
 
61
            columns => [ 'blog_id', 'basename' ],
 
62
        },
 
63
        # Page listings are published in order by title
 
64
        title => 1,
 
65
        blog_author => {
 
66
            columns => [ 'blog_id', 'class', 'author_id', 'authored_on' ],
 
67
        },
 
68
        # For optimizing weekly archives, selected by blog, class,
 
69
        # status.
 
70
        blog_week => {
 
71
            columns => [ 'blog_id', 'class', 'status', 'week_number' ],
 
72
        },
 
73
        # For system-overview listings where we list all entries of
 
74
        # a particular class by authored on date
 
75
        class_authored => {
 
76
            columns => [ 'class', 'authored_on' ],
 
77
        },
 
78
        # For most blog-level listings, where we list all entries
 
79
        # in a blog with a particular class by authored on date.
60
80
        blog_authored => {
61
 
            columns => ['blog_id', 'authored_on'],
62
 
        },
 
81
            columns => ['blog_id', 'class', 'authored_on'],
 
82
        },
 
83
        # For most publishing listings, where we list entries in a blog
 
84
        # with a particular class, publish status (2) and authored on date
 
85
        blog_stat_date => {
 
86
            columns => ['blog_id', 'class', 'status', 'authored_on', 'id'],
 
87
        },
 
88
        # for tag count
 
89
        tag_count => {
 
90
            columns => ['status', 'class', 'blog_id', 'id'],
 
91
        },
 
92
    },
 
93
    defaults => {
 
94
        comment_count => 0,
 
95
        ping_count => 0,
63
96
    },
64
97
    child_of => 'MT::Blog',
65
98
    child_classes => ['MT::Comment','MT::Placement','MT::Trackback','MT::FileInfo'],
70
103
    class_type => 'entry',
71
104
});
72
105
 
73
 
use constant HOLD    => 1;
74
 
use constant RELEASE => 2;
75
 
use constant REVIEW  => 3;
76
 
use constant FUTURE  => 4;
 
106
sub HOLD ()    { 1 }
 
107
sub RELEASE () { 2 }
 
108
sub REVIEW ()  { 3 }
 
109
sub FUTURE ()  { 4 }
77
110
 
78
111
use Exporter;
79
112
*import = \&Exporter::import;
184
217
        $args->{join} = $join;
185
218
    }
186
219
 
187
 
    return $obj->{$label} = $obj->nextprev(
 
220
    my $o = $obj->nextprev(
188
221
        direction => $direction,
189
222
        terms     => { blog_id => $obj->blog_id, class => $obj->class, %$terms },
190
223
        args      => $args,
191
224
        by        => 'authored_on',
192
225
    );
 
226
    weaken($obj->{$label} = $o) if $o;
 
227
    return $o;
193
228
}
194
229
 
195
230
sub trackback {
211
246
        my $author = $author_cache->{$entry->author_id};
212
247
        unless ($author) {
213
248
            require MT::Author;
214
 
            $author = MT::Author->load($entry->author_id);
 
249
            $author = MT::Author->load($entry->author_id)
 
250
                or return undef;
215
251
            $author_cache->{$entry->author_id} = $author;
216
252
            $req->stash('author_cache', $author_cache);
217
253
        }
221
257
 
222
258
sub __load_category_data {
223
259
    my $entry = shift;
 
260
    my $t = MT->get_timer;
 
261
    $t->pause_partial if $t;
224
262
    my $cache = MT::Memcached->instance;
225
263
    my $memkey = $entry->cache_key('categories');
226
264
    my $rows;
230
268
        $rows = [ map { [ $_->category_id, $_->is_primary ] } @maps ];
231
269
        $cache->set($memkey, $rows, CATEGORY_CACHE_TIME);
232
270
    }
 
271
    $t->mark('MT::Entry::__load_category_data') if $t;
233
272
    return $rows;
234
273
}
235
274
 
308
347
    });
309
348
}
310
349
 
311
 
MT::Comment->add_trigger( post_save => sub {
312
 
    my($clone, $comment) = @_;
313
 
 
314
 
    ## Note: This flag is set in MT::Comment::visible().
315
 
    if (my $delta = $comment->{__changed}{visibility}) {
316
 
        my $memkey = MT::Entry->cache_key($comment->entry_id, 'commentcount');
317
 
        my $cache = MT::Memcached->instance;
318
 
        if ($delta > 0) {
319
 
            $cache->incr($memkey, $delta);
320
 
        } elsif ($delta < 0) {
321
 
            $cache->decr($memkey, abs $delta);
322
 
        }
323
 
    }
324
 
} );
325
 
 
326
 
MT::Comment->add_trigger( post_remove => sub {
327
 
    my($comment) = @_;
328
 
 
329
 
    ## If this comment was published, decrement the cached count of
330
 
    ## visible comments on the entry.
331
 
    if ($comment->visible && !$comment->is_changed('visible')) {
332
 
        my $memkey = MT::Entry->cache_key($comment->entry_id, 'commentcount');
333
 
        MT::Memcached->instance->decr($memkey, 1);
334
 
    }
335
 
} );
336
 
 
337
 
sub comment_count {
338
 
    my $entry = shift;
339
 
    $entry->cache_property('comment_count', sub {
340
 
        my $cache = MT::Memcached->instance;
341
 
        my $memkey = $entry->cache_key('commentcount');
342
 
        if (defined( my $count = $cache->get($memkey) )) {
343
 
            return $count;
344
 
        } else { 
345
 
            require MT::Comment;
346
 
            my $count = MT::Comment->count({
347
 
                entry_id => $entry->id,
348
 
                visible => 1
349
 
            });
350
 
            $cache->add($memkey, $count, 7 * 24 * 60 * 60);  ## 1 week.
351
 
            return $count;
352
 
        }
353
 
    });
354
 
}
 
350
MT::Comment->add_trigger(
 
351
    post_save => sub {
 
352
        my $comment = shift;
 
353
        my $entry   = MT::Entry->load( $comment->entry_id )
 
354
            or return;
 
355
        my $count   = MT::Comment->count(
 
356
            {
 
357
                entry_id => $comment->entry_id,
 
358
                visible  => 1,
 
359
            }
 
360
        );
 
361
        $entry->comment_count($count);
 
362
        $entry->save;
 
363
    }
 
364
);
 
365
 
 
366
MT::Comment->add_trigger(
 
367
    post_remove => sub {
 
368
        my $comment = shift;
 
369
        my $entry   = MT::Entry->load( $comment->entry_id )
 
370
            or return;
 
371
        if ( $comment->visible ) {
 
372
            my $count = $entry->comment_count > 0 ? $entry->comment_count - 1 : 0;
 
373
            $entry->comment_count($count);
 
374
            $entry->save;
 
375
        }
 
376
    }
 
377
);
355
378
 
356
379
sub pings {
357
380
    my $entry = shift;
358
381
    my ($terms, $args) = @_;
 
382
    my $tb = $entry->trackback;
 
383
    return undef unless $tb;
359
384
    if ($terms || $args) {
360
385
        $terms ||= {};
361
 
        $terms->{entry_id} = $entry->id;
 
386
        $terms->{tb_id} = $tb->id;
362
387
        return [ MT::TBPing->load( $terms, $args ) ];
363
388
    } else {
364
389
        $entry->cache_property('pings', sub {
365
 
            [ MT::TBPing->load({ entry_id => $entry->id }) ];
 
390
            [ MT::TBPing->load({ tb_id => $tb->id }) ];
366
391
        });
367
392
    }
368
393
}
369
394
 
370
 
MT::TBPing->add_trigger( post_save => sub {
371
 
    my($clone, $ping) = @_;
372
 
 
373
 
    ## Note: This flag is set in MT::TBPing::visible().
374
 
    if (my $delta = $ping->{__changed}{visibility}) {
375
 
        my($class, $entry_id) = $ping->parent_id;
376
 
        return unless $entry_id;
377
 
        my $memkey = MT::Entry->cache_key($entry_id, 'pingcount');
378
 
        my $cache = MT::Memcached->instance;
379
 
        if ($delta > 0) {
380
 
            $cache->incr($memkey, $delta);
381
 
        } elsif ($delta < 0) {
382
 
            $cache->decr($memkey, abs $delta);
383
 
        }
384
 
    }
385
 
} );
386
 
 
387
 
MT::TBPing->add_trigger( post_remove => sub {
388
 
    my($ping) = @_;
389
 
 
390
 
    ## If this ping was published, decrement the cached count of
391
 
    ## visible pings on the entry.
392
 
    if ($ping->visible && !$ping->is_changed('visible')) {
393
 
        my($class, $entry_id) = $ping->parent_id;
394
 
        return unless $entry_id;
395
 
        my $memkey = MT::Entry->cache_key($entry_id, 'pingcount');
396
 
        MT::Memcached->instance->decr($memkey, 1);
397
 
    }
398
 
} );
399
 
 
400
 
sub ping_count {
401
 
    my $entry = shift;
402
 
    $entry->cache_property('ping_count', sub {
403
 
        my $cache = MT::Memcached->instance;
404
 
        my $memkey = 'entrypingcount-' . $entry->id;
405
 
        if (defined( my $count = $cache->get($memkey) )) {
406
 
            return $count;
407
 
        } else { 
408
 
            require MT::TBPing;
409
 
            my $tb = $entry->trackback;
410
 
            my $count =
411
 
                $tb ? MT::TBPing->count({ tb_id => $tb->id, visible => 1 }) : 0;
412
 
            $cache->add($memkey, $count, 7 * 24 * 60 * 60);  ## 1 week.
413
 
            return $count;
414
 
        }
415
 
    });
416
 
}
 
395
MT::TBPing->add_trigger(
 
396
    post_save => sub {
 
397
        my $ping = shift;
 
398
        require MT::Trackback;
 
399
        if ( my $tb = MT::Trackback->load( $ping->tb_id ) ) {
 
400
            if ( $tb->entry_id ) {
 
401
                my $entry = MT::Entry->load( $tb->entry_id )
 
402
                    or return;
 
403
                my $count = MT::TBPing->count(
 
404
                    {
 
405
                        tb_id   => $tb->id,
 
406
                        visible => 1,
 
407
                    }
 
408
                );
 
409
                $entry->ping_count($count);
 
410
                $entry->save;
 
411
            }
 
412
        }
 
413
    }
 
414
);
 
415
 
 
416
MT::TBPing->add_trigger(
 
417
    post_remove => sub {
 
418
        my $ping = shift;
 
419
        require MT::Trackback;
 
420
        if ( my $tb = MT::Trackback->load( $ping->tb_id ) ) {
 
421
            if ( $tb->entry_id && $ping->visible ) {
 
422
                my $entry = MT::Entry->load( $tb->entry_id )
 
423
                    or return;
 
424
                my $count = $entry->ping_count > 0 ? $entry->ping_count - 1 : 0;
 
425
                $entry->ping_count($count);
 
426
                $entry->save;
 
427
            }
 
428
        }
 
429
    }
 
430
);
417
431
 
418
432
sub archive_file {
419
433
    my $entry = shift;
567
581
        if ($send_tb eq 'selected') {
568
582
            @tb_domains = $cfg->OutboundTrackbackDomains;
569
583
        } elsif ($send_tb eq 'local') {
570
 
            my $iter = MT::Blog->load_iter();
 
584
            my $iter = MT::Blog->load_iter(undef, { fetchonly => ['site_url'], no_triggers => 1 });
571
585
            while (my $b = $iter->()) {
572
586
                next if $b->id == $blog->id;
573
587
                push @tb_domains, extract_domain($b->site_url);
620
634
    my @assets = MT::ObjectAsset->load({
621
635
        object_id => $entry->id,
622
636
        blog_id => $entry->blog_id,
623
 
        object_ds => $entry->datasource
 
637
        object_ds => $entry->datasource,
 
638
        embedded => 1,
624
639
    });
625
640
    my %assets = map { $_->asset_id => $_->id } @assets;
626
641
    while ($text =~ m!<form[^>]*?\smt:asset-id=["'](\d+)["'][^>]*?>(.+?)</form>!gis) {
627
642
        my $id = $1;
628
643
        my $innards = $2;
629
644
 
630
 
        # is asset exists?
631
 
        my $asset = MT->model('asset')->load({ id => $id }) or next;
632
 
 
633
645
        # reference to an existing asset...
634
646
        if (exists $assets{$id}) {
635
647
            $assets{$id} = 0;
636
648
        } else {
 
649
            # is asset exists?
 
650
            my $asset = MT->model('asset')->load({ id => $id }) or next;
 
651
 
637
652
            my $map = new MT::ObjectAsset;
638
653
            $map->blog_id($entry->blog_id);
639
654
            $map->asset_id($id);
640
655
            $map->object_ds($entry->datasource);
641
656
            $map->object_id($entry->id);
 
657
            $map->embedded(1);
642
658
            $map->save;
643
659
            $assets{$id} = 0;
644
660
        }
645
661
    }
646
662
    if (my @old_maps = grep { $assets{$_->asset_id} } @assets) {
647
 
        my @old_ids = map { $_->id } @old_maps;
648
 
        MT::ObjectAsset->remove( { id => \@old_ids });
 
663
        my @old_ids = map { $_->id } grep { $_->embedded } @old_maps;
 
664
        MT::ObjectAsset->remove( { id => \@old_ids })
 
665
            if @old_ids;
649
666
    }
650
667
    return 1;
651
668
}
714
731
        }
715
732
    }
716
733
 
717
 
    delete $entry->{__next} if exists $entry->{__next};
718
 
    delete $entry->{__previous} if exists $entry->{__previous};
719
 
    delete $entry->{__cache}{category}
720
 
        if $is_new && exists $entry->{__cache}{category};
 
734
    $entry->clear_cache() if $is_new;
 
735
 
721
736
    1;
722
737
}
723
738
 
728
743
 
729
744
        # Remove MT::ObjectAsset records
730
745
        my $class = MT->model('objectasset');
731
 
        my $iter = $class->load_iter({ object_id => $entry->id, object_ds => $entry->class_type });
732
 
        while (my $o = $iter->()) {
733
 
            $o->remove;
734
 
        }
 
746
        $class->remove({ object_id => $entry->id, object_ds => $entry->class_type });
735
747
    }
736
748
 
737
 
 
738
749
    $entry->SUPER::remove(@_);
739
750
}
740
751
 
873
884
Caches the return value internally so that subsequent calls will not have to
874
885
re-query the database.
875
886
 
876
 
=head2 $entry->comment_count
877
 
 
878
 
Returns the number of comments made on this entry.
879
 
 
880
 
Caches the return value internally so that subsequent calls will not have to
881
 
re-query the database.
882
 
 
883
 
=head2 $entry->ping_count
884
 
 
885
 
Returns the number of TrackBack pings made on this entry.
886
 
 
887
 
Caches the return value internally so that subsequent calls will not have to
888
 
re-query the database.
889
 
 
890
887
=head2 $entry->archive_file([ $archive_type ])
891
888
 
892
889
Returns the name of/path to the archive file for the entry I<$entry>. If