root/branches/feature-server/plagger/lib/Plagger/Plugin/Store/DBIC.pm

Revision 1017 (checked in by woremacx, 2 years ago)
  • Store::DBIC: not to use type stuff
  • Subscription::DBI: eval around Tag stuff
Line 
1 package Plagger::Plugin::Store::DBIC;
2 use strict;
3 use warnings;
4 use base qw/Plagger::Plugin Class::Accessor::Fast/;
5
6 use Algorithm::Diff;
7 use UNIVERSAL::require;
8
9 our $VERSION = '0.02';
10
11 __PACKAGE__->mk_accessors(qw/schema/);
12
13 =head1 NAME
14
15 Plagger::Plugin::Store::DBIC - Store feeds in DBI
16
17 =head1 SYNOPSIS
18
19     $ sqlite3 /path/to/plagger.db < sql/plagger.sqlite.sql
20
21     - module: Store::DBIC
22       config:
23         schema_class: Plagger::Schema::SQLite
24         connect_info: [ 'dbi:SQLite:/path/to/plagger.db', ]
25
26 =head1 DESCRIPTION
27
28 Store DBI
29
30 =head1 METHODS
31
32 =head2 register
33
34 =cut
35
36 sub register {
37     my ( $self, $c ) = @_;
38
39     unless ( $self->conf->{schema_class} and $self->conf->{connect_info} ) {
40         $c->error('schema_class and connect_info are required');
41     }
42
43     $self->conf->{schema_class}->require
44         or $c->error(
45         qq/Can't load schema class "@{[ $self->conf->{schema_class} ]}", $@/);
46
47     $self->schema( $self->conf->{schema_class}
48             ->connect( @{ $self->conf->{connect_info} } ) );
49
50     $c->register_hook( $self, 'publish.feed' => \&store, );
51 }
52
53 =head2 store
54
55 =cut
56
57 sub store {
58     my ( $self, $c, $args ) = @_;
59
60     # feed
61     my $feed = $self->schema->resultset('Feed')->find_or_new(
62         {   link => $args->{feed}->link,
63 #            type => $args->{feed}->type,
64         }
65     );
66
67     my $data;
68     for my $attr (qw/url title description language author updated/) {
69         $data->{$attr} = $args->{feed}->$attr if defined $args->{feed}->$attr;
70     }
71
72     # xxx
73     $data->{image} = $args->{feed}->image->{url} if $args->{feed}->image;
74     $data->{updated} ||= eval { $args->{feed}->entries->[0]->date } || Plagger::Date->now;
75
76     for my $attr (keys %$data) {
77         $feed->$attr( $data->{$attr} ) if !$feed->$attr or $feed->$attr ne $data->{$attr};
78     }
79     $feed->insert_or_update if !$feed->in_storage or $feed->is_changed;
80
81     # feed meta
82     $feed->metas->delete_all; # need more hack
83     for my $k ( keys %{ $args->{feed}->meta } ) {
84         $feed->add_to_metas( { keyid => $k, value=> $args->{feed}->meta->{$k} } );
85     }
86
87     # feed tag
88     my @feed_tags = map { $_->name } $feed->tags;
89     my $feed_diff = $self->diff( \@feed_tags, $args->{feed}->tags );
90
91     $feed->tags( { name => $feed_diff->{deleted} } )->delete_all
92         if @{ $feed_diff->{deleted} };
93
94     for ( @{ $feed_diff->{added} } ) {
95         $feed->add_to_tags( { name => $_ } );
96     }
97
98
99     # entry
100     for my $feed_entry ( @{ $args->{feed}->entries } ) {
101         my $entry = $self->schema->resultset('Entry')->find_or_new({
102             feed => $feed->id,
103             link => $feed_entry->link,
104         });
105
106         for my $attr (qw/title author summary date body rate/) {    # todo: icon
107             $entry->$attr( $feed_entry->$attr )
108                 if defined $feed_entry->$attr && (!$entry->$attr or $entry->$attr ne $feed_entry->$attr);
109         }
110         $entry->insert_or_update if $entry->is_changed;
111
112         # meta
113         $entry->metas->delete_all;
114         for my $k ( keys %{ $feed_entry->meta } ) {
115             $entry->add_to_metas(
116                 { keyid => $k, value => $feed_entry->meta->{$k}, } );
117         }
118
119         # tag
120         my @entry_tags = map { $_->name } $entry->tags;
121         my $entry_diff = $self->diff( \@entry_tags, $feed_entry->tags );
122
123         $entry->tags( { name => $entry_diff->{deleted} } )->delete_all
124             if @{ $entry_diff->{deleted} };
125
126         for ( @{ $entry_diff->{added} } ) {
127             $entry->add_to_tags( { name => $_ } ) if $entry->id; # xxx
128         }
129     }
130 }
131
132 =head2 diff
133
134 =cut
135
136 sub diff {
137     my ( $self, $old, $new ) = @_;
138
139     my $result = {
140         added   => [],
141         deleted => [],
142     };
143
144     my $diff = Algorithm::Diff->new( $old, $new );
145     while ( $diff->Next ) {
146         next if $diff->Same;
147
148         if ( !$diff->Items(2) ) {
149             push @{ $result->{deleted} }, $diff->Items(1);
150         }
151         else {
152             push @{ $result->{added} }, $diff->Items(2);
153         }
154     }
155
156     $result;
157 }
158
159 =head1 AUTHOR
160
161 Daisuke Murase <typester@cpan.org>
162
163 =head1 COPYRIGHT
164
165 This program is free software; you can redistribute
166 it and/or modify it under the same terms as Perl itself.
167
168 The full text of the license can be found in the
169 LICENSE file included with this module.
170
171 =cut
172
173 1;
174
Note: See TracBrowser for help on using the browser.