File Coverage

blib/lib/Rubric/Entry.pm
Criterion Covered Total %
statement 62 62 100.0
branch 14 14 100.0
condition 4 6 66.6
subroutine 20 20 100.0
pod 8 9 88.8
total 108 111 97.3


line stmt bran cond sub pod time code
1 12     12   15682 use strict;
  12         22  
  12         341  
2 12     12   60 use warnings;
  12         85  
  12         720  
3             package Rubric::Entry;
4             # ABSTRACT: a single entry made by a user
5             $Rubric::Entry::VERSION = '0.156';
6 12     12   61 use parent qw(Rubric::DBI);
  12         19  
  12         75  
7              
8 12     12   10932 use Class::DBI::utf8;
  12         144082  
  12         54  
9              
10             #pod =head1 DESCRIPTION
11             #pod
12             #pod This class provides an interface to Rubric entries. It inherits from
13             #pod Rubric::DBI, which is a Class::DBI class.
14             #pod
15             #pod =cut
16              
17 12     12   1729 use Encode 2 qw(_utf8_on);
  12         201  
  12         472  
18 12     12   6905 use Rubric::Entry::Formatter;
  12         26  
  12         301  
19 12     12   7646 use String::TagString;
  12         311665  
  12         559  
20 12     12   9212 use Time::Piece;
  12         111106  
  12         81  
21              
22             __PACKAGE__->table('entries');
23              
24             #pod =head1 COLUMNS
25             #pod
26             #pod id - a unique identifier
27             #pod link - the link to which the entry refers
28             #pod username - the user who made the entry
29             #pod title - the title of the link's destination
30             #pod description - a short description of the entry
31             #pod body - a long body of text for the entry
32             #pod created - the time when the entry was first created
33             #pod modified - the time when the entry was last modified
34             #pod
35             #pod =cut
36              
37             __PACKAGE__->columns(
38             All => qw(id link username title description body created modified)
39             );
40              
41             __PACKAGE__->utf8_columns(qw( title description body ));
42              
43             #pod =head1 RELATIONSHIPS
44             #pod
45             #pod =head2 link
46             #pod
47             #pod The link attribute returns a Rubric::Link.
48             #pod
49             #pod =cut
50              
51             __PACKAGE__->has_a(link => 'Rubric::Link');
52              
53             #pod =head2 uri
54             #pod
55             #pod The uri attribute returns the URI of the entry's link.
56             #pod
57             #pod =cut
58              
59 4 100   4 1 3769 sub uri { my ($self) = @_; return unless $self->link; $self->link->uri; }
  4         28  
  2         275  
60              
61             #pod =head2 username
62             #pod
63             #pod The user attribute returns a Rubric::User.
64             #pod
65             #pod =cut
66              
67             __PACKAGE__->has_a(username => 'Rubric::User');
68              
69             #pod =head2 tags
70             #pod
71             #pod Every entry has_many tags that describe it. The C method will return the
72             #pod tags, and the C method will return the Rubric::EntryTag objects that
73             #pod represent them.
74             #pod
75             #pod =cut
76              
77             __PACKAGE__->has_many(entrytags => 'Rubric::EntryTag');
78             __PACKAGE__->has_many(tags => [ 'Rubric::EntryTag' => 'tag' ]);
79              
80             #pod =head3 recent_tags_counted
81             #pod
82             #pod This method returns a reference to an array of arrayrefs, each a (tag, count)
83             #pod pair for tags used on the week's 50 most recent entries.
84             #pod
85             #pod =cut
86              
87             __PACKAGE__->set_sql(recent_tags_counted => <<'');
88             SELECT tag, COUNT(*) as count
89             FROM entrytags
90             WHERE entry IN (SELECT id FROM entries WHERE created > ? LIMIT 100)
91             AND tag NOT LIKE '@%%'
92             AND entry NOT IN (SELECT entry FROM entrytags WHERE tag = '@private')
93             GROUP BY tag
94             ORDER BY count DESC
95             LIMIT 50
96              
97             sub recent_tags_counted {
98 11     11 1 2331 my ($class) = @_;
99 11         89 my $sth = $class->sql_recent_tags_counted;
100 11         19707 $sth->execute(time - (86400 * 7));
101 11         2917 my $result = $sth->fetchall_arrayref;
102 11         65 return $result;
103             }
104              
105             #pod =head1 INFLATIONS
106             #pod
107             #pod =head2 created
108             #pod
109             #pod =head2 modified
110             #pod
111             #pod The created and modified columns are stored as seconds since epoch, but
112             #pod inflated to Time::Piece objects.
113             #pod
114             #pod =cut
115              
116             __PACKAGE__->has_a(
117             $_ => 'Time::Piece',
118             deflate => 'epoch',
119             inflate => Rubric::Config->display_localtime ? sub { localtime($_[0]) }
120             : sub { gmtime($_[0]) }
121             ) for qw(created modified);
122              
123             __PACKAGE__->add_trigger(before_create => \&_default_title);
124              
125             __PACKAGE__->add_trigger(before_create => \&_create_times);
126             __PACKAGE__->add_trigger(before_update => \&_update_times);
127              
128             sub _default_title {
129 12     12   31103 my $self = shift;
130             $self->title('(default)') unless $self->{title}
131 12 100       133 }
132              
133             sub _create_times {
134 12     12   4119 my $self = shift;
135 12 100       119 $self->created(scalar gmtime) unless defined $self->{created};
136 12 100       5643 $self->modified(scalar gmtime) unless defined $self->{modified};
137             }
138              
139             sub _update_times {
140 29     29   4214 my $self = shift;
141 29         153 $self->modified(scalar gmtime);
142             }
143              
144             #pod =head1 METHODS
145             #pod
146             #pod =head2 query(\%arg)
147             #pod
148             #pod The arguments to C provide a set of abstract constraints for the query.
149             #pod These are sent to Rubric::Entry::Query, which builds an SQL query and returns
150             #pod the result of running it. (Either a list or an Iterator is returned.)
151             #pod
152             #pod (The built-in Class::DBI search method can't handle this kind of search.)
153             #pod
154             #pod user - entries for this User
155             #pod tags - entries with these tags (arrayref)
156             #pod link - entries for this Link
157             #pod urimd5 - entries for the Link with this md5 sum
158             #pod has_body - whether entries must have bodies (T, F, or undef)
159             #pod has_link - whether entries must have a link (T, F, or undef)
160             #pod (time spec) - {created,modified}_{before,after,on}
161             #pod limits entries by time; given as a complete or partial
162             #pod time and date string in the form "YYYY-MM-DD HH:MM"
163             #pod
164             #pod =cut
165              
166             sub query {
167 47     47 1 40908 my $self = shift;
168 47         1677 require Rubric::Entry::Query;
169 47         374 Rubric::Entry::Query->query(@_);
170             }
171              
172             #pod =head2 set_new_tags(\%tags)
173             #pod
174             #pod This method replaces all entry's current tags with the new set of tags.
175             #pod
176             #pod =cut
177              
178             sub set_new_tags {
179 13     13 1 4463 my ($self, $tags) = @_;
180 13         111 $self->entrytags->delete_all;
181 13         23244 $self->update;
182              
183 13         397706 while (my ($tag, $value) = each %$tags) {
184 17         198302 $self->add_to_tags({ tag => $tag, tag_value => $value });
185             }
186             }
187              
188             #pod =head2 tags_from_string
189             #pod
190             #pod my $tags = Rubric::Entry->tags_from_string($string);
191             #pod
192             #pod This (class) method takes a string of tags, delimited by whitespace, and
193             #pod returns an array of the tags, throwing an exception if it finds invalid tags.
194             #pod
195             #pod Valid tags (shouldn't this be documented somewhere else instead?) may contain
196             #pod letters, numbers, underscores, colons, dots, and asterisks. Hyphens me be
197             #pod used, but not as the first character.
198             #pod
199             #pod =cut
200              
201             sub tags_from_string {
202 35     35 1 92936 my ($class, $tagstring) = @_;
203              
204 35 100 66     410 return {} unless $tagstring and $tagstring =~ /\S/;
205              
206 29         682 String::TagString->tags_from_string($tagstring);
207             }
208              
209             #pod =head2 C< markup >
210             #pod
211             #pod This method returns the value of the entry's @markup tag, or C<_default> if
212             #pod there is no such tag.
213             #pod
214             #pod =cut
215              
216             sub markup {
217 20     20 1 37 my ($self) = @_;
218              
219 20         77 my ($tag)
220             = Rubric::EntryTag->search({ entry => $self->id, tag => '@markup' });
221              
222 20 100 66     16400 return ($tag and $tag->tag_value) ? $tag->tag_value : '_default';
223             }
224              
225              
226             #pod =head2 C< body_as >
227             #pod
228             #pod my $formatted_body = $entry->body_as("html");
229             #pod
230             #pod This method returns the body of the entry, formatted into the given format. If
231             #pod the entry cannot be rendered into the given format, an exception is thrown.
232             #pod
233             #pod =cut
234              
235             sub body_as {
236 18     18 1 87450 my ($self, $format) = @_;
237              
238 18         58 my $markup = $self->markup;
239              
240 18         4008 Rubric::Entry::Formatter->format({
241             text => $self->body,
242             markup => $markup,
243             format => $format
244             });
245             }
246              
247             sub accessor_name_for {
248 96     96 1 20275 my ($class, $field) = @_;
249              
250 96 100       278 return 'user' if $field eq 'username';
251              
252 84         978 return $field;
253             }
254              
255             ## return retrieve_all'd objects in recent-to-older order
256              
257             __PACKAGE__->set_sql(RetrieveAll => <<'');
258             SELECT __ESSENTIAL__
259             FROM __TABLE__
260             ORDER BY created DESC
261              
262             sub tagstring {
263 1     1 0 29 my ($self) = @_;
264             String::TagString->string_from_tags({
265 1         8 map {; $_->tag => $_->tag_value } $self->entrytags
  1         968  
266             });
267             }
268              
269             1;
270              
271             __END__