OSDN Git Service

Model: Implement Model::Loader to (semi-)autoload models
authorhylom <hylom@users.sourceforge.jp>
Sun, 25 Sep 2016 13:30:05 +0000 (22:30 +0900)
committerhylom <hylom@users.sourceforge.jp>
Sun, 25 Sep 2016 13:33:59 +0000 (22:33 +0900)
dev/newslash_web/lib/Newslash/Model.pm [new file with mode: 0644]
dev/newslash_web/lib/Newslash/Model/Base.pm
dev/newslash_web/lib/Newslash/Model/Loader.pm [new file with mode: 0644]
dev/newslash_web/lib/Newslash/Model/Submissions.pm [new file with mode: 0644]
dev/newslash_web/lib/Newslash/Web.pm
dev/newslash_web/lib/Newslash/Web/Controller/Index.pm
dev/newslash_web/lib/Newslash/Web/Controller/Journal.pm
dev/newslash_web/lib/Newslash/Web/Controller/Login.pm
dev/newslash_web/lib/Newslash/Web/Controller/Story.pm

diff --git a/dev/newslash_web/lib/Newslash/Model.pm b/dev/newslash_web/lib/Newslash/Model.pm
new file mode 100644 (file)
index 0000000..133ad26
--- /dev/null
@@ -0,0 +1,12 @@
+package Newslash::Model;
+use Newslash::Model::Loader;
+
+load(users => "Newslash::Model::Users");
+load(stories =>"Newslash::Model::Stories");
+load(comments => "Newslash::Model::Comments");
+load(discussions => "Newslash::Model::Discussions");
+load(journals => "Newslash::Model::Journals");
+load(submission => "Newslash::Model::Submissions");
+
+1;
+
diff --git a/dev/newslash_web/lib/Newslash/Model/Loader.pm b/dev/newslash_web/lib/Newslash/Model/Loader.pm
new file mode 100644 (file)
index 0000000..a1ab7cb
--- /dev/null
@@ -0,0 +1,51 @@
+package Newslash::Model::Loader;
+
+use strict;
+use warnings;
+use utf8;
+use feature ':5.10';
+
+use Module::Load qw(load);
+
+sub import {
+    my $class = shift;
+    my $caller = caller;
+
+    {
+        no strict 'refs';
+        *{"$caller\::load"} = \&load_model;
+        *{"$caller\::loader"} = \&loader;
+    }
+
+    $_->import for qw(strict warings utf8);
+    feature->import(':5.10');
+}
+
+state $models;
+
+sub loader {
+    my ($self, $opts) = @_;
+    my $r = $models;
+    return sub {
+        my $caller = shift;
+        my $a = shift || $caller;
+        my $c = $r->{$a};
+
+        if ($c) {
+            my $ret = $c->new($opts);
+            return $ret;
+        }
+    };
+}
+
+sub load_model {
+    my ($accessor, $class) = @_;
+    load $class;
+    if (!$models) {
+        $models = {};
+    }
+    $models->{$accessor} = $class;
+}
+
+1;
+
diff --git a/dev/newslash_web/lib/Newslash/Model/Submissions.pm b/dev/newslash_web/lib/Newslash/Model/Submissions.pm
new file mode 100644 (file)
index 0000000..5196e1d
--- /dev/null
@@ -0,0 +1,203 @@
+package Newslash::Model::Journals;
+use Newslash::Model::Base -base;
+
+use Data::Dumper;
+use Mojo::Log;
+
+#========================================================================
+
+=head2 latest(\%options)
+
+get latest stories.
+
+=over 4
+
+=item Parameters
+
+=over 4
+
+=item \%options
+
+options for query.
+
+$options->{show_future}: when 1, return feature stories. default is 0.
+$options->{limit}: number of stories. default is 10.
+
+=back
+
+=item Return value
+
+ARRAY of story contents
+
+=back
+
+=cut
+
+sub latest {
+  my ($self, $options) = @_;
+  $options ||= {};
+
+  my $show_future = $options->{show_future} || 0;
+  my $limit = $options->{limit} || 10;
+
+  my $dbh = $self->connect_db;
+
+  # get stories
+  my $where_clause = 'WHERE stories.time <= NOW()';;
+  if ($show_future) {
+    $where_clause = '';
+  }
+
+  my $sql = <<"EOSQL";
+SELECT latest.*, story_text.*, users.nickname as author
+  FROM (SELECT * from stories $where_clause ORDER BY time DESC LIMIT ?) AS latest
+    LEFT JOIN story_text ON latest.stoid = story_text.stoid
+    LEFT JOIN users ON latest.uid = users.uid
+EOSQL
+
+  my $sth = $dbh->prepare($sql);
+
+  $sth->execute($limit);
+  my $rs = $sth->fetchall_arrayref(+{});
+  $sth->finish;
+
+  if (@$rs == 0) {
+    $dbh->disconnect();
+    return [];
+  }
+
+  # get tags
+  $sql = <<"EOSQL";
+SELECT story_topics_rendered.*, story_topics_chosen.weight, topics.*
+  FROM (SELECT stoid FROM stories $where_clause ORDER BY time DESC LIMIT ?) AS latest
+    INNER JOIN story_topics_rendered ON latest.stoid = story_topics_rendered.stoid
+    LEFT JOIN story_topics_chosen ON story_topics_rendered.stoid = story_topics_chosen.stoid
+      AND story_topics_rendered.tid = story_topics_chosen.tid
+    LEFT JOIN topics ON story_topics_rendered.tid = topics.tid
+EOSQL
+
+  $sth = $dbh->prepare($sql);
+
+  $sth->execute($limit);
+  my $topics_table = $sth->fetchall_arrayref(+{});
+  $sth->finish;
+  $dbh->disconnect();
+
+  my $topics = {};
+  for my $topic (@$topics_table) {
+    if (!$topic->{stoid}) {
+      $topics->{$topic->{stoid}} = [];
+    }
+    push @{$topics->{$topic->{stoid}}}, $topic;
+  }
+
+  for my $story (@$rs) {
+    my $stoid = $story->{stoid};
+    $story->{topics} = $topics->{$stoid};
+    my $max_weight = 0;
+    for my $t (@{$story->{topics}}) {
+      if ($t->{weight} && $t->{weight} > $max_weight) {
+       $story->{primary_topic} = $t;
+       $max_weight = $t->{weight};
+      }
+    }
+  }
+
+  return $rs;
+}
+
+
+#========================================================================
+
+=head2 select($query_type, $value)
+
+get a story.
+
+=over 4
+
+=item Parameters
+
+=over 4
+
+=item $query_type
+
+query key, "sid" or "stoid"
+
+=item $value
+
+value for query
+
+=back
+
+=item Return value
+
+HASH of story contents
+
+=back
+
+=cut
+
+sub select {
+  my ($self, $query_type, $value) = @_;
+
+  if ($query_type !~ m/\A(sid|stoid)\z/) {
+    return undef;
+  }
+
+  my $dbh = $self->connect_db;
+  my $sql = <<"EOSQL";
+SELECT stories.*, story_text.*, users.nickname as author
+  FROM stories
+    LEFT JOIN story_text ON stories.stoid = story_text.stoid
+    LEFT JOIN users ON stories.uid = users.uid
+  WHERE stories.$query_type = ?
+EOSQL
+
+  my $sth = $dbh->prepare($sql);
+
+  $sth->execute($value);
+  my $story = $sth->fetchrow_hashref;
+  $sth->finish;
+
+  if (!$story) {
+    $dbh->disconnect();
+    return undef;
+  }
+
+  my $stoid = $story->{stoid};
+  if (!$stoid) {
+    $dbh->disconnect();
+    return undef;
+  }
+
+
+  # get tags
+  $sql = <<"EOSQL";
+SELECT story_topics_rendered.*, story_topics_chosen.weight, topics.*
+  FROM story_topics_rendered
+    LEFT JOIN story_topics_chosen ON story_topics_rendered.stoid = story_topics_chosen.stoid
+      AND story_topics_rendered.tid = story_topics_chosen.tid
+    LEFT JOIN topics ON story_topics_rendered.tid = topics.tid
+  WHERE story_topics_rendered.stoid = ?
+EOSQL
+
+  $sth = $dbh->prepare($sql);
+
+  $sth->execute($stoid);
+  my $topics = $sth->fetchall_arrayref(+{});
+  $sth->finish;
+  $dbh->disconnect();
+
+  $story->{topics} = $topics;
+  my $max_weight = 0;
+  for my $t (@$topics) {
+    if ($t->{weight} && $t->{weight} > $max_weight) {
+      $story->{primary_topic} = $t;
+      $max_weight = $t->{weight};
+    }
+  }
+
+  return $story;
+}
+
+1;
index b02e6a3..4efa13f 100644 (file)
@@ -7,6 +7,8 @@ use Newslash::Model::Comments;
 use Newslash::Model::Discussions;
 use Newslash::Model::Journals;
 
+use Newslash::Model;
+
 # This method will run once at server start
 sub startup {
     my $app = shift;
@@ -24,11 +26,7 @@ sub startup {
 
     # add Model
     my $db_opts = $app->config->{Database};
-    $app->helper(users => sub { state $users = Newslash::Model::Users->new($db_opts) });
-    $app->helper(stories => sub { state $stories = Newslash::Model::Stories->new($db_opts) });
-    $app->helper(discussions => sub { state $discussions = Newslash::Model::Discussions->new($db_opts) });
-    $app->helper(comments => sub { state $comments = Newslash::Model::Comments->new($db_opts) });
-    $app->helper(journals => sub { state $journals = Newslash::Model::Journals->new($db_opts) });
+    $app->helper(model => Newslash::Model->loader($db_opts));
 
     # use Template::Toolkit 2 render
     $app->plugin('Newslash::Plugin::TT2Renderer');
index 45f5892..b3ceeaa 100644 (file)
@@ -3,13 +3,13 @@ use Mojo::Base 'Mojolicious::Controller';
 
 sub root {
     my $c = shift;
-    my $stories = $c->stories->latest;
+    my $stories = $c->model('stories')->latest;
     $c->render(stories => $stories);
 }
 
 sub journals {
     my $c = shift;
-    my $journals = $c->app->journals->latest;
+    my $journals = $c->model('journals')->latest;
     $c->render(journals => $journals);
 }
 
index 4a181fa..33818e7 100644 (file)
@@ -5,16 +5,16 @@ use Data::Dumper;
 sub journal {
     my $c = shift;
     my $journal_id = $c->stash('id');
-    my $journal = $c->journals->select(id => $journal_id);
+    my $journal = $c->model('journals')->select(id => $journal_id);
     my $d_id = $journal->{discussion};
     my $comments = [];
     my $discuss;
 
     if ($d_id) {
-        $discuss = $c->discussions->select(id => $d_id);
-        $comments = $c->comments->select(discussion_id => $d_id);
+        $discuss = $c->model('discussions')->select(id => $d_id);
+        $comments = $c->model('comments')->select(discussion_id => $d_id);
     }
-    my $roots = $c->comments->build_comment_tree($comments, $c->app->log);
+    my $roots = $c->model('comments')->build_comment_tree($comments, $c->app->log);
     $c->render(journal => $journal, comments => $comments, root_comments => $roots);
 }
 
index 0e29902..03a4ca2 100644 (file)
@@ -17,7 +17,7 @@ sub login {
   }
 
   # TODO: if user already logged-in, force logout?
-  my $token = $c->users->authentification($nickname, $passwd);
+  my $token = $c->model('users')->authentification($nickname, $passwd);
   if ($token) {
     my $session = {
                   token => $token,
index bb7c37b..cad842d 100644 (file)
@@ -7,12 +7,12 @@ sub story {
     my $session = $c->session('session');
     my $sid = $c->stash('sid');
 
-    my $story = $c->stories->select(sid => $sid);
-    my $discuss = $c->discussions->select(sid => $sid);
+    my $story = $c->model('stories')->select(sid => $sid);
+    my $discuss = $c->model('discussions')->select(sid => $sid);
     my $d_id = $discuss->{id};
     my $comments = [];
     if ($d_id) {
-        $comments = $c->comments->select(discussion_id => $d_id);
+        $comments = $c->model('comments')->select(discussion_id => $d_id);
     }
     my $roots = $c->_build_comment_tree($comments);
     $c->render(story => $story, comments => $comments, root_comments => $roots);