Bladeren bron

2017-11-28

Visman 7 jaren geleden
bovenliggende
commit
d1dbeb272a

+ 125 - 42
app/Models/Forum.php

@@ -5,9 +5,45 @@ namespace ForkBB\Models;
 use ForkBB\Models\DataModel;
 use ForkBB\Core\Container;
 use RuntimeException;
+use InvalidArgumentException;
 
 class Forum extends DataModel
 {
+    /**
+     * Получение родительского раздела
+     *
+     * @throws RuntimeException
+     *
+     * @return Models\Forum
+     */
+    protected function getparent()
+    {
+        if (null === $this->parent_forum_id && $this->id !== 0) {
+            throw new RuntimeException('Parent is not defined');
+        }
+
+        return $this->c->forums->forum($this->parent_forum_id);
+    }
+
+    /**
+     * Статус возможности создания новой темы
+     * 
+     * @return bool
+     */
+    protected function getcanCreateTopic()
+    {
+        $user = $this->c->user;
+        return $this->post_topics == 1
+            || (null === $this->post_topics && $user->g_post_topics == 1)
+            || $user->isAdmin
+            || ($user->isAdmMod && isset($this->moderators[$user->id]));
+    }
+
+    /**
+     * Получение массива подразделов
+     *
+     * @return array
+     */
     protected function getsubforums()
     {
         $sub = [];
@@ -19,6 +55,11 @@ class Forum extends DataModel
         return $sub;
     }
 
+    /**
+     * Получение массива всех дочерних разделов
+     *
+     * @return array
+     */
     protected function getdescendants()
     {
         $all = [];
@@ -30,16 +71,45 @@ class Forum extends DataModel
         return $all;
     }
 
-    protected function getparent()
+    /**
+     * Ссылка на раздел
+     *
+     * @return string
+     */
+    protected function getlink()
     {
-        return $this->c->forums->forum($this->parent_forum_id);
+        return $this->c->Router->link('Forum', ['id' => $this->id, 'name' => $this->forum_name]);
     }
 
-    protected function getlink()
+    /**
+     * Ссылка на последнее сообщение в разделе
+     *
+     * @return null|string
+     */
+    protected function getlinkLast()
     {
-        return $this->c->Router->link('Forum', ['id' => $this->id, 'name' => $this->forum_name]);
+        if ($this->last_post_id < 1) {
+            return null;
+        } else {
+            return $this->c->Router->link('ViewPost', ['id' => $this->last_post_id]);
+        }
+    }
+
+    /**
+     * Ссылка на создание новой темы
+     * 
+     * @return string
+     */
+    protected function getlinkCreateTopic()
+    {
+        return $this->c->Router->link('NewTopic', ['id' => $this->id]);
     }
 
+    /**
+     * Получение массива модераторов
+     *
+     * @return array
+     */
     protected function getmoderators()
     {
         if (empty($this->a['moderators'])) {
@@ -64,9 +134,14 @@ class Forum extends DataModel
         return $moderators;
     }
 
+    /**
+     * Возвращает общую статистику по дереву разделов с корнем в текущем разделе
+     *
+     * @return Models\Forum
+     */
     protected function gettree()
     {
-        if (empty($this->a['tree'])) {
+        if (empty($this->a['tree'])) { //????
             $numT   = (int) $this->num_topics;
             $numP   = (int) $this->num_posts;
             $time   = (int) $this->last_post;
@@ -93,49 +168,58 @@ class Forum extends DataModel
                 'last_poster'    => $poster,
                 'last_topic'     => $topic,
                 'newMessages'    => $fnew,
-                'last_post_link' => empty($postId) ? '' : $this->c->Router->link('ViewPost', ['id' => $postId]),
             ]);
         }
         return $this->a['tree'];
     }
 
     /**
-     * @param int $page
-     * 
-     * @return bool
+     * Количество страниц в разделе
+     *
+     * @throws RuntimeException
+     *
+     * @return int
      */
-    public function hasPage($page)
+    protected function getnumPages()
     {
         if (null === $this->num_topics) {
             throw new RuntimeException('The model does not have the required data');
         }
 
-        if (empty($this->num_topics)) {
-            if ($page !== 1) {
-                return false;
-            }
-            $this->page   = 1;
-            $this->pages  = 1;
-            $this->offset = 0;
-        } else {
-            $pages = ceil($this->num_topics / $this->c->user->disp_topics);
-            if ($page < 1 || $page > $pages) {
-                return false;
-            }
-            $this->page   = $page;
-            $this->pages  = $pages;
-            $this->offset = ($page - 1) * $this->c->user->disp_topics;
-        }
-        return true;
+        return $this->num_topics === 0 ? 1 : (int) ceil($this->num_topics / $this->c->user->disp_topics);
+    }
+
+    /**
+     * Массив страниц раздела
+     *
+     * @return array
+     */
+    protected function getpagination()
+    {
+        return $this->c->Func->paginate($this->numPages, $this->page, 'Forum', ['id' => $this->id, 'name' => $this->forum_name]);
+    }
+
+    /**
+     * Статус наличия установленной страницы в разделе
+     *
+     * @return bool
+     */
+    public function hasPage()
+    {
+        return $this->page > 0 && $this->page <= $this->numPages;
     }
 
     /**
+     * Возвращает массив тем с установленной страницы
+     *
+     * @throws InvalidArgumentException
+     *
      * @return array
      */
     public function topics()
     {
-        if (null === $this->page) {
-            throw new RuntimeException('The model does not have the required data');
+        if (! $this->hasPage()) {
+            throw new InvalidArgumentException('Bad number of displayed page');
         }
 
         if (empty($this->num_topics)) {
@@ -149,7 +233,6 @@ class Forum extends DataModel
             case 2:
                 $sortBy = 'subject ASC';
                 break;
-            case 0:
             default:
                 $sortBy = 'last_post DESC';
                 break;
@@ -157,13 +240,13 @@ class Forum extends DataModel
 
         $vars = [
             ':fid'    => $this->id,
-            ':offset' => $this->offset,
+            ':offset' => ($this->page - 1) * $this->c->user->disp_topics,
             ':rows'   => $this->c->user->disp_topics,
         ];
-        $sql = "SELECT id 
-                FROM ::topics 
-                WHERE forum_id=?i:fid 
-                ORDER BY sticky DESC, {$sortBy}, id DESC 
+        $sql = "SELECT id
+                FROM ::topics
+                WHERE forum_id=?i:fid
+                ORDER BY sticky DESC, {$sortBy}, id DESC
                 LIMIT ?i:offset, ?i:rows";
 
         $ids = $this->c->DB->query($sql, $vars)->fetchAll(\PDO::FETCH_COLUMN);
@@ -186,15 +269,15 @@ class Forum extends DataModel
         }
 
         if ($this->c->user->isGuest) {
-            $sql = "SELECT t.* 
-                    FROM ::topics AS t 
-                    WHERE t.id IN(?ai:ids) 
+            $sql = "SELECT t.*
+                    FROM ::topics AS t
+                    WHERE t.id IN(?ai:ids)
                     ORDER BY t.sticky DESC, t.{$sortBy}, t.id DESC";
         } else {
-            $sql = "SELECT t.*, mot.mt_last_visit, mot.mt_last_read 
-                    FROM ::topics AS t 
-                    LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:uid AND t.id=mot.tid) 
-                    WHERE t.id IN (?ai:ids) 
+            $sql = "SELECT t.*, mot.mt_last_visit, mot.mt_last_read
+                    FROM ::topics AS t
+                    LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:uid AND t.id=mot.tid)
+                    WHERE t.id IN (?ai:ids)
                     ORDER BY t.sticky DESC, t.{$sortBy}, t.id DESC";
         }
         $topics = $this->c->DB->query($sql, $vars)->fetchAll();

+ 7 - 11
app/Models/Pages/Admin/Statistics.php

@@ -69,18 +69,14 @@ class Statistics extends Admin
         $this->tOther    = $stat;
 
         // Check for the existence of various PHP opcode caches/optimizers
-        if (function_exists('mmcache')) {
-            $this->accelerator = '<a href="http://' . __('Turck MMCache link') . '">' . __('Turck MMCache') . '</a>';
-        } elseif (isset($_PHPA)) {
-            $this->accelerator = '<a href="http://' . __('ionCube PHP Accelerator link') . '">' . __('ionCube PHP Accelerator') . '</a>';
-        } elseif (ini_get('apc.enabled')) {
-            $this->accelerator ='<a href="http://' . __('Alternative PHP Cache (APC) link') . '">' . __('Alternative PHP Cache (APC)') . '</a>';
-        } elseif (ini_get('zend_optimizer.optimization_level')) {
-            $this->accelerator = '<a href="http://' . __('Zend Optimizer link') . '">' . __('Zend Optimizer') . '</a>';
-        } elseif (ini_get('eaccelerator.enable')) {
-            $this->accelerator = '<a href="http://' . __('eAccelerator link') . '">' . __('eAccelerator') . '</a>';
+        if (ini_get('opcache.enable') && function_exists('opcache_invalidate')) {
+            $this->accelerator = '<a href="https://secure.php.net/opcache/">Zend OPcache</a>';
+        } elseif (ini_get('wincache.fcenabled')) {
+            $this->accelerator = '<a href="https://secure.php.net/wincache/">Windows Cache for PHP</a>';
+        } elseif (ini_get('apc.enabled') && function_exists('apc_delete_file')) {
+            $this->accelerator = '<a href="https://secure.php.net/apc/">Alternative PHP Cache (APC)</a>'; //???? частичная эмуляция APCu
         } elseif (ini_get('xcache.cacher')) {
-            $this->accelerator = '<a href="http://' . __('XCache link') . '">' . __('XCache') . '</a>';
+            $this->accelerator = '<a href="https://xcache.lighttpd.net/">XCache</a>';
         } else {
             $this->accelerator = __('NA');
         }

+ 2 - 13
app/Models/Pages/Forum.php

@@ -28,26 +28,17 @@ class Forum extends Page
             return $this->c->Redirect->url($forum->redirect_url);
         }
 
-        $page = isset($args['page']) ? (int) $args['page'] : 1;
-        if (! $forum->hasPage($page)) {
+        $forum->page = isset($args['page']) ? (int) $args['page'] : 1;
+        if (! $forum->hasPage()) {
             return $this->c->Message->message('Bad request');
         }
 
         $topics = $forum->topics();
         $user = $this->c->user;
 
-        if (! $user->isGuest) {
-            $lower = max((int) $user->u_mark_all_read, (int) $forum->mf_mark_all_read);
-            $upper = max($lower, (int) $user->last_visit);
-        }
-
         if (empty($topics)) {
             $this->a['fIswev']['i'][] = __('Empty forum');
         }
-        $newOn = $forum->post_topics == 1
-            || (null === $forum->post_topics && $user->g_post_topics == 1)
-            || $user->isAdmin
-            || ($user->isAdmMod && isset($forum->moderators[$user->id]));
 
         $this->fIndex     = 'index';
         $this->nameTpl    = 'forum';
@@ -57,8 +48,6 @@ class Forum extends Page
         $this->forums     = $forum->subforums;
         $this->topics     = $topics;
         $this->crumbs     = $this->crumbs($forum);
-        $this->newTopic   = $newOn ? $this->c->Router->link('NewTopic', ['id' => $args['id']]) : null;
-        $this->pages      = $this->c->Func->paginate($forum->pages, $forum->page, 'Forum', ['id' => $args['id'], 'name' => $forum->forum_name]);
 
         return $this;
     }

+ 25 - 35
app/Models/Pages/Topic.php

@@ -10,9 +10,9 @@ class Topic extends Page
 
     /**
      * Переход к первому новому сообщению темы (или в конец)
-     * 
+     *
      * @param array $args
-     * 
+     *
      * @return Page
      */
     public function viewNew(array $args)
@@ -22,9 +22,9 @@ class Topic extends Page
 
     /**
      * Переход к первому непрочитанному сообщению (или в конец)
-     * 
+     *
      * @param array $args
-     * 
+     *
      * @return Page
      */
     public function viewUnread(array $args)
@@ -34,9 +34,9 @@ class Topic extends Page
 
     /**
      * Переход к последнему сообщению темы
-     * 
+     *
      * @param array $args
-     * 
+     *
      * @return Page
      */
     public function viewLast(array $args)
@@ -47,9 +47,9 @@ class Topic extends Page
 
     /**
      * Просмотр темы по номеру сообщения
-     * 
+     *
      * @param array $args
-     * 
+     *
      * @return Page
      */
     public function viewPost(array $args)
@@ -59,9 +59,9 @@ class Topic extends Page
 
     /**
      * Просмотр темы по ее номеру
-     * 
+     *
      * @param array $args
-     * 
+     *
      * @return Page
      */
     public function viewTopic(array $args)
@@ -72,17 +72,17 @@ class Topic extends Page
     /**
      * @param string $type
      * @param Models\Topic $topic
-     * 
+     *
      * @param Page
      */
     protected function go($type, $topic)
     {
         switch ($type) {
             case 'new':
-                $pid = $topic->post_new;
+                $pid = $topic->firstNew;
                 break;
             case 'unread':
-                $pid = $topic->post_unread;
+                $pid = $topic->firstUnread;
                 break;
             case 'last':
                 $pid = $topic->last_post_id;
@@ -90,30 +90,26 @@ class Topic extends Page
             default:
                 return $this->c->Message->message('Bad request');
         }
-        
-        if ($pid) {
-            return $this->c->Redirect->page('ViewPost', ['id' => $pid]);
-        } else {
-            return $this->c->Redirect->page('ViewPost', ['id' => $topic->last_post_id]);
-        }
+
+        return $this->c->Redirect->page('ViewPost', ['id' => $pid ?: $topic->last_post_id]);
     }
 
     /**
      * Подготовка данных для шаблона
-     * 
+     *
      * @param string $type
      * @param array $args
-     * 
+     *
      * @return Page
      */
     protected function view($type, array $args)
     {
         $topic = $this->c->ModelTopic->load((int) $args['id'], $type === 'post');
-            
+
         if (! $topic->id || ! $topic->last_post_id) {
             return $this->c->Message->message('Bad request');
         }
-    
+
         if ($topic->moved_to) {
             return $this->c->Redirect->page('Topic', ['id' => $topic->moved_to]);
         }
@@ -140,8 +136,8 @@ class Topic extends Page
         $this->c->Lang->load('topic');
 
         $user = $this->c->user;
-        
-        
+
+
 /*
         list($fTree, $fDesc, $fAsc) = $this->c->forums;
 
@@ -323,7 +319,7 @@ class Topic extends Page
 */
         // данные для формы быстрого ответа
         $form = null;
-        if ($topic->post_replies && $this->c->config->o_quickpost == '1') {
+        if ($topic->canReply && $this->c->config->o_quickpost == '1') {
             $form = [
                 'action' => $this->c->Router->link('NewReply', ['id' => $topic->id]),
                 'hidden' => [
@@ -395,19 +391,13 @@ class Topic extends Page
         $this->topic        = $topic;
         $this->posts        = $posts;
         $this->crumbs       = $this->crumbs($topic);
-        $this->NewReply     = $topic->post_replies ? $this->c->Router->link('NewReply', ['id' => $topic->id]) : null;
-        $this->pages        = $topic->pages;
+        $this->pagination   = $topic->pagination;
         $this->online       = $this->c->Online->calc($this)->info();
         $this->stats        = null;
         $this->form         = $form;
 
-        if ($this->c->config->o_topic_views == '1') {
-            $vars = [
-                ':tid' => $topic->id,
-            ];
-            $sql = 'UPDATE ::topics SET num_views=num_views+1 WHERE id=?i:tid';
-
-            $this->c->DB->query($sql, $vars);
+        if ($topic->showViews) {
+            $topic->incViews();
         }
 /*
         if (! $user->isGuest) {

+ 41 - 6
app/Models/Post.php

@@ -8,11 +8,21 @@ use RuntimeException;
 
 class Post extends DataModel
 {
+    /**
+     * Ссылка на сообщение
+     *
+     * @return string
+     */
     protected function getlink()
     {
         return $this->c->Router->link('ViewPost', ['id' => $this->id]);
     }
 
+    /**
+     * Автор сообщения
+     *
+     * @return Models\User
+     */
     protected function getuser()
     {
         $attrs = $this->a; //????
@@ -20,26 +30,51 @@ class Post extends DataModel
         return $this->c->ModelUser->setAttrs($attrs);
     }
 
+    /**
+     * Статус видимости ссылки на профиль пользователя
+     *
+     * @return bool
+     */
     protected function getshowUserLink()
     {
         return $this->c->user->g_view_users == '1';
     }
 
+    /**
+     * Статус показа аватаров
+     *
+     * @return bool
+     */
     protected function getshowUserAvatar()
     {
         return $this->c->config->o_avatars == '1' && $this->c->user->show_avatars == '1';
     }
 
+    /**
+     * Статус показа информации пользователя
+     *
+     * @return bool
+     */
     protected function getshowUserInfo()
     {
         return $this->c->config->o_show_user_info == '1';
     }
 
+    /**
+     * Статус показа подписи
+     *
+     * @return bool
+     */
     protected function getshowSignature()
     {
         return $this->c->config->o_signatures == '1' && $this->c->user->show_sig == '1';
     }
 
+    /**
+     * Массив элементов управления
+     *
+     * @return array
+     */
     protected function getcontrols()
     {
         $user = $this->c->user;
@@ -49,21 +84,21 @@ class Post extends DataModel
             $controls['report'] = [$this->c->Router->link('ReportPost', $vars), 'Report'];
         }
         if ($user->isAdmin
-            || ($user->isAdmMod 
+            || ($user->isAdmMod
                 && ! $this->user->isAdmin
-                && isset($this->parent->parent->moderators[$user->id]) 
+                && isset($this->parent->parent->moderators[$user->id])
             )
         ) {
             $controls['delete'] = [$this->c->Router->link('DeletePost', $vars), 'Delete'];
             $controls['edit'] = [$this->c->Router->link('EditPost', $vars), 'Edit'];
         } elseif ($this->parent->closed != '1'
             && $this->user->id == $user->id
-            && ($user->g_deledit_interval == '0' 
-                || $this->edit_post == '1' 
+            && ($user->g_deledit_interval == '0'
+                || $this->edit_post == '1'
                 || time() - $this->posted < $user->g_deledit_interval
             )
         ) {
-            if (($this->id == $this->parent->first_post_id && $user->g_delete_topics == '1') 
+            if (($this->id == $this->parent->first_post_id && $user->g_delete_topics == '1')
                 || ($this->id != $this->parent->first_post_id && $user->g_delete_posts == '1')
             ) {
                 $controls['delete'] = [$this->c->Router->link('DeletePost', $vars), 'Delete'];
@@ -72,7 +107,7 @@ class Post extends DataModel
                 $controls['edit'] = [$this->c->Router->link('EditPost', $vars), 'Edit'];
             }
         }
-        if ($this->parent->post_replies) {
+        if ($this->parent->canReply) {
             $controls['quote'] = [$this->c->Router->link('NewReply', ['id' => $this->parent->id, 'quote' => $this->id]), 'Reply'];
         }
         return $controls;

+ 168 - 84
app/Models/Topic.php

@@ -8,7 +8,28 @@ use RuntimeException;
 
 class Topic extends DataModel
 {
-    protected function getpost_replies()
+    /**
+     * Получение родительского раздела
+     *
+     * @throws RuntimeException
+     *
+     * @return Models\Forum
+     */
+    protected function getparent()
+    {
+        if ($this->forum_id < 1) {
+            throw new RuntimeException('Parent is not defined');
+        }
+
+        return $this->c->forums->forum($this->forum_id);
+    }
+
+    /**
+     * Статус возможности ответа в теме
+     *
+     * @return bool
+     */
+    protected function getcanReply()
     {
         if ($this->c->user->isAdmin) {
             return true;
@@ -24,123 +45,151 @@ class Topic extends DataModel
         }
     }
 
-    protected function getnum_views()
+    /**
+     * Ссылка на тему
+     *
+     * @return string
+     */
+    protected function getlink()
     {
-        return $this->c->config->o_topic_views == '1' ? $this->a['num_views'] : null;
+        return $this->c->Router->link('Topic', ['id' => $this->moved_to ?: $this->id, 'name' => $this->cens()->subject]);
     }
 
-    protected function getparent()
+    /**
+     * Ссылка для ответа в теме
+     *
+     * @return string
+     */
+    protected function getlinkReply()
     {
-        return $this->c->forums->forum($this->forum_id);
+        return $this->c->Router->link('NewReply', ['id' => $this->id]);
     }
 
-    protected function getlink()
+    /**
+     * Ссылка для перехода на последнее сообщение темы
+     *
+     * @return null|string
+     */
+    protected function getlinkLast()
     {
         if ($this->moved_to) {
-            return $this->c->Router->link('Topic', ['id' => $this->moved_to, 'name' => $this->cens()->subject]);
+            return null;
         } else {
-            return $this->c->Router->link('Topic', ['id' => $this->id, 'name' => $this->cens()->subject]);
+            return $this->c->Router->link('ViewPost', ['id' => $this->last_post_id]);
         }
     }
 
-    protected function getlink_last()
+    /**
+     * Ссылка для перехода на первое новое сообщение в теме
+     *
+     * @return string
+     */
+    protected function getlinkNew()
     {
-        if ($this->moved_to) {
-            return null;
-        } else {
-            return $this->c->Router->link('ViewPost', ['id' => $this->last_post_id]);
-        }
+        return $this->c->Router->link('TopicViewNew', ['id' => $this->id]);
     }
 
-    protected function getlink_new()
+    /**
+     * Ссылка для перехода на первое не прочитанное сообщение в теме
+     */
+    protected function getlinkUnread()
     {
-        if ($this->c->user->isGuest || $this->moved_to) {
-            return null;
-        }
-        if ($this->last_post > max(
-            (int) $this->c->user->u_mark_all_read, 
-            (int) $this->parent->mf_mark_all_read,
-            (int) $this->c->user->last_visit, 
-            (int) $this->mt_last_visit)
-        ) {
-            return $this->c->Router->link('TopicViewNew', ['id' => $this->id]);
-        } else {
-            return null;
-        }
+        return $this->c->Router->link('TopicViewUnread', ['id' => $this->id]);
     }
 
-    protected function getpost_new()
+    /**
+     * Статус наличия новых сообщений в теме
+     *
+     * @return false|int
+     */
+    protected function gethasNew()
     {
         if ($this->c->user->isGuest || $this->moved_to) {
-            return null;
+            return false;
         }
-        $upper = max(
-            (int) $this->c->user->u_mark_all_read, 
+
+        $time = max(
+            (int) $this->c->user->u_mark_all_read,
             (int) $this->parent->mf_mark_all_read,
-            (int) $this->c->user->last_visit, 
+            (int) $this->c->user->last_visit,
             (int) $this->mt_last_visit
         );
-        if ($this->last_post > $upper) {
-            $vars = [
-                ':tid'   => $this->id,
-                ':visit' => $upper,
-            ];
-            $sql = 'SELECT MIN(id) FROM ::posts WHERE topic_id=?i:tid AND posted>?i:visit';
 
-            $pid = $this->c->DB->query($sql, $vars)->fetchColumn();
-
-            if (! empty($pid)) {
-                return $pid;
-            }
-        }
-
-        return null;
+        return $this->last_post > $time ? $time : false;
     }
 
-    protected function getlink_unread()
+    /**
+     * Статус наличия не прочитанных сообщений в теме
+     *
+     * @return false|int
+     */
+    protected function gethasUnread()
     {
         if ($this->c->user->isGuest || $this->moved_to) {
-            return null;
+            return false;
         }
-        if ($this->last_post > max(
-            (int) $this->c->user->u_mark_all_read, 
+
+        $time = max(
+            (int) $this->c->user->u_mark_all_read,
             (int) $this->parent->mf_mark_all_read,
-            (int) $this->mt_last_read)
-        ) {
-            return $this->c->Router->link('TopicViewUnread', ['id' => $this->id]);
-        } else {
-            return null;
-        }
+            (int) $this->mt_last_read
+        );
+
+        return $this->last_post > $time ? $time : false;
     }
 
-    protected function getpost_unread()
+    /**
+     * Номер первого нового сообщения в теме
+     *
+     * @return int
+     */
+    protected function getfirstNew()
     {
-        if ($this->c->user->isGuest || $this->moved_to) {
-            return null;
+        if (false === $this->hasNew) {
+            return 0;
         }
-        $lower = max(
-            (int) $this->c->user->u_mark_all_read, 
-            (int) $this->parent->mf_mark_all_read,
-            (int) $this->mt_last_read
-        );
-        if ($this->last_post > $lower) {
-            $vars = [
-                ':tid'   => $this->id,
-                ':visit' => $lower,
-            ];
-            $sql = 'SELECT MIN(id) FROM ::posts WHERE topic_id=?i:tid AND posted>?i:visit';
 
-            $pid = $this->c->DB->query($sql, $vars)->fetchColumn();
+        $vars = [
+            ':tid'   => $this->id,
+            ':visit' => $this->hasNew,
+        ];
+        $sql = 'SELECT MIN(id) FROM ::posts WHERE topic_id=?i:tid AND posted>?i:visit';
 
-            if (! empty($pid)) {
-                return $pid;
-            }
+        $pid = $this->c->DB->query($sql, $vars)->fetchColumn();
+
+        return $pid ?: 0;
+    }
+
+    /**
+     * Номер первого не прочитанного сообщения в теме
+     *
+     * @return int
+     */
+    protected function getfirstUnread()
+    {
+        if (false === $this->hasUnread) {
+            return 0;
         }
 
-        return null;
+        $vars = [
+            ':tid'   => $this->id,
+            ':visit' => $this->hasUnread,
+        ];
+        $sql = 'SELECT MIN(id) FROM ::posts WHERE topic_id=?i:tid AND posted>?i:visit';
+
+        $pid = $this->c->DB->query($sql, $vars)->fetchColumn();
+
+        return $pid ?: 0;
     }
 
-    protected function getnum_pages()
+    /**
+     * Количество страниц в теме
+     *
+     * @throws RuntimeException
+     *
+     * @return int
+     */
+    protected function getnumPages()
     {
         if (null === $this->num_replies) {
             throw new RuntimeException('The model does not have the required data');
@@ -150,27 +199,35 @@ class Topic extends DataModel
     }
 
     /**
-     * @returm array
+     * Массив страниц темы
+     *
+     * @return array
      */
-    protected function getpages()
+    protected function getpagination()
     {
         $page = (int) $this->page;
-        if ($page < 1 && $this->num_pages === 1) {
+
+        if ($page < 1 && $this->numPages === 1) {
+            // 1 страницу в списке тем раздела не отображаем
             return [];
-        } else {
-            return $this->c->Func->paginate($this->num_pages, $page, 'Topic', ['id' => $this->id, 'name' => $this->cens()->subject]);
+        } else { //????
+            return $this->c->Func->paginate($this->numPages, $page, 'Topic', ['id' => $this->id, 'name' => $this->cens()->subject]);
         }
     }
 
     /**
+     * Статус наличия установленной страницы в теме
+     *
      * @return bool
      */
     public function hasPage()
     {
-        return $this->page > 0 && $this->page <= $this->num_pages;
+        return $this->page > 0 && $this->page <= $this->numPages;
     }
 
     /**
+     * Вычисляет страницу темы на которой находится данное сообщение
+     *
      * @param int $pid
      */
     public function calcPage($pid)
@@ -190,12 +247,16 @@ class Topic extends DataModel
     }
 
     /**
+     * Возвращает массив сообщений с установленной рание страницы темы
+     *
+     * @throws InvalidArgumentException
+     *
      * @return array
      */
     public function posts()
     {
         if (! $this->hasPage()) {
-            throw new RuntimeException('The model does not have the required data');
+            throw new InvalidArgumentException('Bad number of displayed page');
         }
 
         $offset = ($this->page - 1) * $this->c->user->disp_posts;
@@ -271,4 +332,27 @@ class Topic extends DataModel
         unset($cur);
         return $posts;
     }
+
+    /**
+     * Статус показа/подсчета просмотров темы
+     *
+     * @return bool
+     */
+    protected function getshowViews()
+    {
+        return $this->c->config->o_topic_views == '1';
+    }
+
+    /**
+     * Увеличивает на 1 количество просмотров темы
+     */
+    public function incViews()
+    {
+        $vars = [
+            ':tid' => $this->id,
+        ];
+        $sql = 'UPDATE ::topics SET num_views=num_views+1 WHERE id=?i:tid';
+
+        $this->c->DB->query($sql, $vars);
+    }
 }

+ 63 - 3
app/Models/User.php

@@ -24,11 +24,21 @@ class User extends DataModel
         parent::__construct($container);
     }
 
+    /**
+     * Статус неподтвержденного
+     *
+     * @return bool
+     */
     protected function getisUnverified()
     {
         return $this->group_id == $this->c->GROUP_UNVERIFIED;
     }
 
+    /**
+     * Статус гостя
+     *
+     * @return bool
+     */
     protected function getisGuest()
     {
         return $this->group_id == $this->c->GROUP_GUEST
@@ -36,27 +46,52 @@ class User extends DataModel
             || $this->group_id == $this->c->GROUP_UNVERIFIED;
     }
 
+    /**
+     * Статус админа
+     *
+     * @return bool
+     */
     protected function getisAdmin()
     {
         return $this->group_id == $this->c->GROUP_ADMIN;
     }
 
+    /**
+     * Статус админа/модератора
+     *
+     * @return bool
+     */
     protected function getisAdmMod()
     {
         return $this->group_id == $this->c->GROUP_ADMIN
             || $this->g_moderator == '1';
     }
 
+    /**
+     * Время последнего действия пользователя
+     *
+     * @return int
+     */
     protected function getlogged()
     {
         return empty($this->a['logged']) ? $this->now : $this->a['logged'];
     }
 
+    /**
+     * Статус наличия данных пользователя в таблице online //????
+     *
+     * @return bool
+     */
     protected function getisLogged()
     {
         return ! empty($this->a['logged']);
     }
 
+    /**
+     * Текущий язык пользователя
+     *
+     * @return string
+     */
     protected function getlanguage()
     {
         $langs = $this->c->Func->getLangs();
@@ -72,6 +107,11 @@ class User extends DataModel
         }
     }
 
+    /**
+     * Текущий стиль отображения
+     *
+     * @return string
+     */
     protected function getstyle()
     {
         $styles = $this->c->Func->getStyles();
@@ -87,26 +127,41 @@ class User extends DataModel
         }
     }
 
+    /**
+     * Ссылка на профиль пользователя
+     *
+     * @return string
+     */
     protected function getlink()
     {
         return $this->c->Router->link('User', ['id' => $this->id, 'name' => $this->username]);
     }
 
+    /**
+     * Ссылка на аватару пользователя
+     *
+     * @return null|string
+     */
     protected function getavatar()
     {
         $filetypes = array('jpg', 'gif', 'png');
-            
+
         foreach ($filetypes as $type) {
             $path = $this->c->DIR_PUBLIC . "/{$this->c->config->o_avatars_dir}/{$this->id}.{$type}";
-        
+
             if (file_exists($path) && getimagesize($path)) {
                 return $this->c->PUBLIC_URL . "/{$this->c->config->o_avatars_dir}/{$this->id}.{$type}";
             }
         }
-    
+
         return null;
     }
 
+    /**
+     * Титул пользователя
+     *
+     * @return string
+     */
     public function title()
     {
         if (isset($this->c->bans->userList[mb_strtolower($this->username)])) { //????
@@ -122,6 +177,11 @@ class User extends DataModel
         }
     }
 
+    /**
+     * Статус online
+     *
+     * @return bool
+     */
     protected function getonline()
     {
         return isset($this->c->Online->online[$this->id]);

+ 0 - 36
app/lang/English/admin_index.po

@@ -96,42 +96,6 @@ msgstr "PHP: %s - %s"
 msgid "Environment data acc"
 msgstr "Accelerator: %s"
 
-msgid "Turck MMCache"
-msgstr "Turck MMCache"
-
-msgid "Turck MMCache link"
-msgstr "turck-mmcache.sourceforge.net/"
-
-msgid "ionCube PHP Accelerator"
-msgstr "ionCube PHP Accelerator"
-
-msgid "ionCube PHP Accelerator link"
-msgstr "www.php-accelerator.co.uk/"
-
-msgid "Alternative PHP Cache (APC)"
-msgstr "Alternative PHP Cache (APC)"
-
-msgid "Alternative PHP Cache (APC) link"
-msgstr "www.php.net/apc/"
-
-msgid "Zend Optimizer"
-msgstr "Zend Optimizer"
-
-msgid "Zend Optimizer link"
-msgstr "www.zend.com/products/guard/zend-optimizer/"
-
-msgid "eAccelerator"
-msgstr "eAccelerator"
-
-msgid "eAccelerator link"
-msgstr "www.eaccelerator.net/"
-
-msgid "XCache"
-msgstr "XCache"
-
-msgid "XCache link"
-msgstr "xcache.lighttpd.net/"
-
 msgid "Database label"
 msgstr "Database"
 

+ 2 - 38
app/lang/Russian/admin_index.po

@@ -19,7 +19,7 @@ msgid "Forum admin head"
 msgstr "Администрирование форума"
 
 msgid "NA"
-msgstr "N/A"
+msgstr "-"
 
 msgid "Welcome to admin"
 msgstr "Добро пожаловать в панель управления ForkBB! Здесь вы можете настроить ключевые параметры вашего форума. В зависимости от того, Администратор вы или Модератор, вы можете:"
@@ -94,43 +94,7 @@ msgid "Environment data version"
 msgstr "PHP: %s - %s"
 
 msgid "Environment data acc"
-msgstr "Accelerator: %s"
-
-msgid "Turck MMCache"
-msgstr "Turck MMCache"
-
-msgid "Turck MMCache link"
-msgstr "turck-mmcache.sourceforge.net"
-
-msgid "ionCube PHP Accelerator"
-msgstr "ionCube PHP Accelerator"
-
-msgid "ionCube PHP Accelerator link"
-msgstr "www.php-accelerator.co.uk/"
-
-msgid "Alternative PHP Cache (APC)"
-msgstr "Alternative PHP Cache (APC)"
-
-msgid "Alternative PHP Cache (APC) link"
-msgstr "www.php.net/apc/"
-
-msgid "Zend Optimizer"
-msgstr "Zend Optimizer"
-
-msgid "Zend Optimizer link"
-msgstr "www.zend.com/products/guard/zend-optimizer/"
-
-msgid "eAccelerator"
-msgstr "eAccelerator"
-
-msgid "eAccelerator link"
-msgstr "www.eaccelerator.net/"
-
-msgid "XCache"
-msgstr "XCache"
-
-msgid "XCache link"
-msgstr "xcache.lighttpd.net/"
+msgstr "Акселератор: %s"
 
 msgid "Database label"
 msgstr "База данных"

+ 19 - 19
app/templates/forum.tpl

@@ -9,16 +9,16 @@
 @endforeach
       </ul>
 @endsection
-@section('linkpost')
-@if($p->newTopic)
+@section('linknewtopic')
+@if($p->forum->canCreateTopic)
         <div class="f-link-post">
-          <a class="f-btn" href="{!! $p->newTopic !!}">{!! __('Post topic') !!}</a>
+          <a class="f-btn" href="{!! $p->forum->linkCreateTopic !!}">{!! __('Post topic') !!}</a>
         </div>
 @endif
 @endsection
-@section('pages')
+@section('pagination')
         <nav class="f-pages">
-@foreach($p->pages as $cur)
+@foreach($p->forum->pagination as $cur)
 @if($cur[2])
           <span class="f-page active">{{ $cur[1] }}</span>
 @elseif($cur[1] === 'space')
@@ -56,10 +56,10 @@
 @endif
     <div class="f-nav-links">
 @yield('crumbs')
-@if($p->newTopic || $p->pages)
+@if($p->forum->canCreateTopic || $p->forum->pagination)
       <div class="f-links-b clearfix">
-@yield('pages')
-@yield('linkpost')
+@yield('pagination')
+@yield('linknewtopic')
       </div>
 @endif
     </div>
@@ -85,9 +85,9 @@
           </li>
 @else
           <li id="topic-{!! $topic->id !!}" class="f-row<!-- inline -->
-@if($topic->link_new) f-fnew
+@if($topic->hasNew !== false) f-fnew
 @endif
-@if($topic->link_unread) f-funread
+@if($topic->hasUnread !== false) f-funread
 @endif
 @if($topic->sticky) f-fsticky
 @endif
@@ -115,9 +115,9 @@
                   <span class="f-polltxt">{!! __('Poll') !!}</span>
 @endif
                   <a class="f-ftname" href="{!! $topic->link !!}">{{ $topic->cens()->subject }}</a>
-@if($topic->pages)
+@if($topic->pagination)
                   <span class="f-tpages">
-@foreach($topic->pages as $cur)
+@foreach($topic->pagination as $cur)
 @if($cur[1] === 'space')
                     <span class="f-page f-pspacer">{!! __('Spacer') !!}</span>
 @else
@@ -126,8 +126,8 @@
 @endforeach
                   </span>
 @endif
-@if($topic->link_new)
-                  <span class="f-newtxt"><a href="{!! $topic->link_new !!}" title="{!! __('New posts info') !!}">{!! __('New posts') !!}</a></span>
+@if($topic->hasNew !== false)
+                  <span class="f-newtxt"><a href="{!! $topic->linkNew !!}" title="{!! __('New posts info') !!}">{!! __('New posts') !!}</a></span>
 @endif
                 </h3>
                 <p class="f-cmposter">{!! __('by') !!} {{ $topic->poster }}</p>
@@ -136,14 +136,14 @@
             <div class="f-cell f-cstats">
               <ul>
                 <li>{!! __('%s Reply', $topic->num_replies, $topic->num()->num_replies) !!}</li>
-@if($topic->num_views)
+@if($topic->showViews)
                 <li>{!! __('%s View', $topic->num_views, $topic->num()->num_views) !!}</li>
 @endif
               </ul>
             </div>
             <div class="f-cell f-clast">
               <ul>
-                <li class="f-cltopic"><a href="{!! $topic->link_last !!}" title="&quot;{{ $topic->cens()->subject }}&quot; - {!! __('Last post') !!}">{{ $topic->dt()->last_post }}</a></li>
+                <li class="f-cltopic"><a href="{!! $topic->linkLast !!}" title="&quot;{{ $topic->cens()->subject }}&quot; - {!! __('Last post') !!}">{{ $topic->dt()->last_post }}</a></li>
                 <li class="f-clposter">{!! __('by') !!} {{ $topic->last_poster }}</li>
               </ul>
             </div>
@@ -154,10 +154,10 @@
       </div>
     </section>
     <div class="f-nav-links">
-@if($p->newTopic || $p->pages)
+@if($p->forum->canCreateTopic || $p->forum->pagination)
       <div class="f-links-a clearfix">
-@yield('linkpost')
-@yield('pages')
+@yield('linknewtopic')
+@yield('pagination')
       </div>
 @endif
 @yield('crumbs')

+ 1 - 1
app/templates/layouts/subforums.tpl

@@ -60,7 +60,7 @@
               <div class="f-cell f-clast">
                 <ul>
 @if($cur->tree->last_post_id)
-                  <li class="f-cltopic"><a href="{!! $cur->tree->last_post_link !!}" title="&quot;{{ $cur->tree->cens()->last_topic }}&quot; - {!! __('Last post') !!}">{{ $cur->tree->cens()->last_topic }}</a></li>
+                  <li class="f-cltopic"><a href="{!! $cur->tree->linkLast !!}" title="&quot;{{ $cur->tree->cens()->last_topic }}&quot; - {!! __('Last post') !!}">{{ $cur->tree->cens()->last_topic }}</a></li>
                   <li class="f-clposter">{!! __('by') !!} {{ $cur->tree->last_poster }}</li>
                   <li class="f-cltime">{!! $cur->tree->dt()->last_post !!}</li>
 @else

+ 8 - 8
app/templates/topic.tpl

@@ -10,19 +10,19 @@
       </ul>
 @endsection
 @section('linkpost')
-@if($p->topic->post_replies || $p->topic->closed)
+@if($p->topic->canReply || $p->topic->closed)
         <div class="f-link-post">
 @if($p->topic->closed)
           __('Topic closed')
 @else
-          <a class="f-btn" href="{!! $p->NewReply !!}">{!! __('Post reply') !!}</a>
+          <a class="f-btn" href="{!! $p->topic->linkReply !!}">{!! __('Post reply') !!}</a>
 @endif
         </div>
 @endif
 @endsection
-@section('pages')
+@section('pagination')
         <nav class="f-pages">
-@foreach($p->pages as $cur)
+@foreach($p->pagination as $cur)
 @if($cur[2])
           <span class="f-page active">{{ $cur[1] }}</span>
 @elseif($cur[1] === 'space')
@@ -40,9 +40,9 @@
 @extends('layouts/main')
     <div class="f-nav-links">
 @yield('crumbs')
-@if($p->topic->post_replies || $p->topic->closed || $p->pages)
+@if($p->topic->canReply || $p->topic->closed || $p->pagination)
       <div class="f-links-b clearfix">
-@yield('pages')
+@yield('pagination')
 @yield('linkpost')
       </div>
 @endif
@@ -118,10 +118,10 @@
 @endforeach
     </section>
     <div class="f-nav-links">
-@if($p->topic->post_replies || $p->topic->closed || $p->pages)
+@if($p->topic->canReply || $p->topic->closed || $p->pagination)
       <div class="f-links-a clearfix">
 @yield('linkpost')
-@yield('pages')
+@yield('pagination')
       </div>
 @endif
 @yield('crumbs')