root/branches/release-38/lib/MT/TemplateMap.pm @ 2396

Revision 2396, 9.3 kB (checked in by bchoate, 19 months ago)

Performance fix for refreshing templates. BugId:79805

  • Property svn:keywords set to Author Date Id Revision
Line 
1# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
2# This program is distributed under the terms of the
3# GNU General Public License, version 2.
4#
5# $Id$
6
7package MT::TemplateMap;
8
9use strict;
10use base qw( MT::Object );
11
12__PACKAGE__->install_properties({
13    column_defs => {
14        'id' => 'integer not null auto_increment',
15        'blog_id' => 'integer not null',
16        'template_id' => 'integer not null',
17        'archive_type' => 'string(25) not null',
18        'file_template' => 'string(255)',
19        'is_preferred' => 'boolean',
20        'build_type' => 'smallint',
21        'build_interval' => 'integer',
22    },
23    indexes => {
24        blog_id => 1,
25        template_id => 1,
26        archive_type => 1,
27        is_preferred => 1,
28    },
29    defaults => {
30        'build_type' => 1,
31    },
32    child_classes => ['MT::FileInfo'],
33    datasource => 'templatemap',
34    primary_key => 'id',
35    cacheable => 0,
36});
37
38sub class_label {
39    return MT->translate("Archive Mapping");
40}
41
42sub class_label_plural {
43    return MT->translate("Archive Mappings");
44}
45
46sub save {
47    my $map = shift;
48    my $res = $map->SUPER::save();
49    return $res unless $res;
50
51    my $at   = $map->archive_type;
52    my $blog = MT->model('blog')->load($map->blog_id)
53        or return;
54    my $blog_at   = $blog->archive_type;
55    my @ats = map { $_ } 
56        grep { $map->archive_type ne $_ }
57            split /,/, $blog_at
58                if $blog_at ne 'None';
59    push @ats, $map->archive_type;
60    my $new_at = join ',', @ats;
61    if ($new_at ne $blog_at) {
62        $blog->archive_type($new_at);
63        $blog->save;
64    }
65    return 1;
66}
67
68sub remove {
69    my $map = shift;
70    $map->remove_children({ key => 'templatemap_id' });
71    my $result = $map->SUPER::remove(@_);
72
73    if (ref $map) {
74        my $remaining = MT::TemplateMap->load(
75          {
76            blog_id => $map->blog_id,
77            archive_type => $map->archive_type,
78            id => [ $map->id ],
79          },
80          {
81            limit => 1,
82            not => { id => 1 }
83          }
84        );
85        if ($remaining) {
86            $remaining->is_preferred(1);
87            $remaining->save;
88        }
89        else {
90            my $blog = MT->model('blog')->load($map->blog_id)
91                or return;
92            my $at   = $blog->archive_type;
93            if ( $at && $at ne 'None' ) {
94                my @newat = map { $_ } grep { $map->archive_type ne $_ } split /,/, $at;
95                $blog->archive_type(join ',', @newat);
96                $blog->save;
97            }
98        }
99    }
100    else {
101        my $blog_id;
102        if ( $_[0] && $_[0]->{template_id} ) {
103            my $tmpl = MT::Template->load( $_[0]->{template_id} );
104            $blog_id = $tmpl->blog_id if $tmpl;
105        }
106
107        my $maps_iter = MT::TemplateMap->count_group_by(
108            { ( defined $blog_id ? ( blog_id => $blog_id ) : () ) },
109            { group => [ 'blog_id', 'archive_type' ] }
110        );
111        my %ats;
112        while ( my ( $count, $blog_id, $at ) = $maps_iter->() ) {
113            my $ats = $ats{$blog_id};
114            push @$ats, $at if $count > 0;
115            $ats{$blog_id} = $ats;
116        }
117        my $iter;
118        if ( $blog_id ) {
119            my $blog = MT::Blog->load( $blog_id );
120            $iter = sub { my $ret = $blog; $blog = undef; $ret; }
121        } else {
122            $iter = MT::Blog->load_iter();
123        }
124        while ( my $blog = $iter->() ) {
125            $blog->archive_type( $ats{ $blog->id } ? join ',', @{ $ats{ $blog->id } } : '' );
126            $blog->save;
127            for my $at ( @{ $ats{ $blog->id } } ) {
128                unless ( __PACKAGE__->exist({
129                    blog_id => $blog->id, archive_type => $at, is_preferred => 1 
130                }) ) {
131                    my $remaining = __PACKAGE__->load(
132                      {
133                        blog_id => $blog->id,
134                        archive_type => $at,
135                      },
136                      {
137                        limit => 1,
138                      }
139                    );
140                    if ($remaining) {
141                        $remaining->is_preferred(1);
142                        $remaining->save;
143                    }
144                }
145            }
146        }
147    }
148    $result;
149}
150
151sub prefer {
152    my $map = shift;
153    my ($prefer) = @_;
154    $prefer = (defined($prefer) && $prefer) ? 1 : 0;
155
156    if ($prefer) {
157        return 1 if $map->is_preferred;
158        my $preferred = MT::TemplateMap->load({
159                blog_id => $map->blog_id,
160                archive_type => $map->archive_type,
161                is_preferred => 1,
162            }) or return;
163        $preferred->is_preferred(0);
164        $preferred->save or return $map->error($preferred->errstr);
165        $map->is_preferred(1);
166        $map->save or return $map->error($map->errstr);
167    } else {
168        return 1 unless $map->is_preferred;
169        if ($map->_prefer_next_map) {
170            $map->is_preferred(0);
171            $map->save or return $map->error($map->errstr);
172        }
173    }
174}
175
176sub _prefer_next_map {
177    my $map = shift;
178    my @all = MT::TemplateMap->load({ blog_id => $map->blog_id,
179                                      archive_type => $map->archive_type });
180    @all = grep { $_->id != $map->id } @all;
181    if (@all) {
182        $all[0]->is_preferred(1);
183        $all[0]->save;
184        return 1;
185    }
186    return 0;
187}
188
1891;
190__END__
191
192=head1 NAME
193
194MT::TemplateMap - Movable Type archive-template association record
195
196=head1 SYNOPSIS
197
198    use MT::TemplateMap;
199    my $map = MT::TemplateMap->new;
200    $map->blog_id($tmpl->blog_id);
201    $map->template_id($tmpl->id);
202    $map->archive_type('Monthly');
203    $map->file_template('<$MTArchiveDate format="%Y/%m/index.html"$>');
204    $map->is_preferred(1);
205    $map->save
206        or die $map->errstr;
207
208=head1 DESCRIPTION
209
210An I<MT::TemplateMap> object represents a single association between an
211Archive Template and an archive type for a particular blog. For example, if
212you set up a template called C<Date-Based> and assign to the C<Monthly>
213archive type in your blog, such an association will be represented by one
214I<MT::TemplateMap> object.
215
216=head1 USAGE
217
218As a subclass of I<MT::Object>, I<MT::TemplateMap> inherits all of the
219data-management and -storage methods from that class; thus you should look
220at the I<MT::Object> documentation for details about creating a new object,
221loading an existing object, saving an object, etc.
222
223=head1 DATA ACCESS METHODS
224
225The I<MT::TemplateMap> object holds the following pieces of data. These
226fields can be accessed and set using the standard data access methods
227described in the I<MT::Object> documentation.
228
229=over 4
230
231=item * id
232
233The numeric ID of the template map record.
234
235=item * blog_id
236
237The numeric ID of the blog with which this template map record is associated.
238
239=item * template_id
240
241The numeric ID of the template.
242
243=item * archive_type
244
245The archive type; should be one of the following values: C<Individual>,
246C<Daily>, C<Weekly>, C<Monthly>, or C<Category>.
247
248=item * file_template
249
250The Archive File Template for this particular mapping; this defines the output
251files for the pages generated from the template for this archive type,
252using standard MT template tags.
253
254=item * is_preferred
255
256A boolean flag specifying whether this particular template is preferred over
257any others defined for this archive type. This is used when generating links
258to archives of this archive type--the link will always link to the preferred
259archive type.
260
261=back
262
263=head1 METHODS
264
265=over 4
266
267=item * save()
268
269Saves the object.  It also rearranges blog's archive type.  If the saved
270template map is new and there is no other template maps with the same
271archive type has been, the archive type is also added to the blog.
272
273=item * remove()
274
275Removes template maps specified in terms and args (if called as class method)
276or the template map (if called as instance method).  It also rearrange blog's
277archive types which are used to determine what types of archive will be
278published during rebuild.  If template map is removed and there remains no
279template map with the archive type, the archive type is removed from blog's
280archive types to be rebuilt.
281
282=item * prefer(boolean)
283
284Set the template map preferred or not, depending on the argument.  If the map
285has been preferred and is being unpreferred, and if there are any other
286I<MT::TemplateMap> objects defined for this particular archive type and blog,
287the first of the other objects will be set as the preferred object.
288Its I<is_preferred> flag will be set to true.  If the map is the only
289I<MT::TemplateMap> object for the blog and the archive type, the method does
290nothing - the map continues to be preferred.
291
292=back
293
294=head1 DATA LOOKUP
295
296In addition to numeric ID lookup, you can look up or sort records by any
297combination of the following fields. See the I<load> documentation in
298I<MT::Object> for more information.
299
300=over 4
301
302=item * blog_id
303
304=item * template_id
305
306=item * archive_type
307
308=item * is_preferred
309
310=back
311
312=head1 NOTES
313
314=over 4
315
316=item * $obj->remove()
317
318When you remove a I<MT::TemplateMap> object using I<MT::TemplateMap::remove>,
319if the I<$map> object you are removing has the I<is_preferred> flag set to
320true, and if there are any other I<MT::TemplateMap> objects defined for this
321particular archive type and blog, the first of the other objects will be
322set as the preferred object. Its I<is_preferred> flag will be set to true.
323
324=back
325
326=head1 AUTHOR & COPYRIGHT
327
328Please see L<MT/AUTHOR & COPYRIGHT>.
329
330=cut
Note: See TracBrowser for help on using the browser.