1. Приветствуем Вас на неофициальном форуме технической поддержки XenForo на русском языке. XenForo - коммерческий форумный движок от бывших создателей vBulletin, написанный на PHP.
Загрузка

Any Resource Update Permission 1.0.0

Добавляет дополнительное право доступа для обновления ресурсов любого пользователя.

  1. Exile

    Exile Местный

    Регистрация:
    27.06.11
    Сообщения:
    997
    Симпатии:
    545
    Версия XF:
    1.4.4
    Пользователь Exile разместил новый ресурс:

    Any Resource Update Permission - Добавляет дополнительное право доступа для обновления ресурсов любого пользователя.

    Узнать больше об этом ресурсе...
    --- добавлено : Apr 25, 2015 11:03 AM ---
    @FractalizeR @infis @Yoskaldyr если у вас будет время - пожалуйста, посмотрите код дополнения. Просто это мое первое по сути такого плана дополнение и хотелось бы сразу знать, что именно делаю не так, какие моменты и как именно можно улучшить и т.п. Не хочется писать код в плохом стиле, лучше сразу же понять, в каком направлении поработать. Заранее большое спасибо.
     
    Последнее редактирование модератором: 03.05.2015
    Kolya groza morey и Mirovinger нравится это.
  2. infis

    infis Местный

    Регистрация:
    27.06.11
    Сообщения:
    5 966
    Симпатии:
    3 548
    Версия XF:
    1.5.9
    Обычно user_id и username получают следующим образом:
    Код:
    $visitor = XenForo_Visitor::getInstance()->toArray();
    $userId = $visitor['user_id'];
    $username = $visitor['username'];
    И еще один момент. Я в своем плагине прав автора темы не переписывал права, а сначала вызывал оригинальный код, а затем добавлял дополнительную проверку. Таким образом в случае изменения оригинального кода мой плагин с минимальными шансами перестанет работать, а также не сделает даунгрэйд нового кода движка. Насколько я прав - не знаю. Но мой плагин с минимальными усилиями адаптируется под новые версии движка (обычно вообще не требует адаптации).
     
    Exile нравится это.
  3. Exile

    Exile Местный

    Регистрация:
    27.06.11
    Сообщения:
    997
    Симпатии:
    545
    Версия XF:
    1.4.4
    infis, за указание на способ получения имени пользователя с id спасибо, на офф. форуме просто искал - примеров масса, выбрал который у себя. Таким образом на самом деле попроще будет, не будет лишнего запроса в базу. Про момент с переопределением стандартной функции тоже понял, просто вчера как-то особо не дошло как сделать не перезаписав, хотя подобный метод сразу же по сути и применял. Еще отзывы послушаю, переделаю.
     
  4. Yoskaldyr

    Yoskaldyr Пользователь

    Регистрация:
    27.09.10
    Сообщения:
    1 921
    Симпатии:
    1 163
    Версия XF:
    1.0.4
    PHP:
    XenForo_Visitor::getInstance()->toArray();
    не обязательно
    достаточно
    PHP:
    XenForo_Visitor::getInstance();
    магия сама разрулит при доступе к полям массива
     
    Exile нравится это.
  5. FractalizeR

    FractalizeR XenForo Addicted

    Регистрация:
    27.09.10
    Сообщения:
    1 085
    Симпатии:
    832
    Версия XF:
    1.3.2
    Момент по поводу стиля программирования - избегайте длинных вложенных конструкций.
    PHP:
        protected function _updateThread(array $resource)
        {
            if (
    is_array($resource))
            {
                
    $userModel $this->_getUserModel();

                
    $updaterUserId XenForo_Visitor::getUserId();
                
    $updaterUserData $userModel->getUserById($updaterUserId);

                
    $resource['user_id'] = $updaterUserData['user_id'];
                
    $resource['username'] = $updaterUserData['username'];
            }

            return 
    parent::_updateThread($resource);
        }
    Объем кода невелик, поэтому пока все ок. Однако, если бы внутри if было побольше строк, чтение было бы затруднено. Кстати, надо сказать, что разработчики самого движка со мной бывают несогласны. Очень уж там любят if / else / elseif на целый экран. Однако, я полагаю, что вот так будет лучше:

    PHP:
        protected function _updateThread(array $resource)
        {
            if (!
    is_array($resource)) {
                return 
    parent::_updateThread($resource);
            }

            
    $userModel $this->_getUserModel();

            
    $updaterUserId XenForo_Visitor::getUserId();
            
    $updaterUserData $userModel->getUserById($updaterUserId);

            
    $resource['user_id'] = $updaterUserData['user_id'];
            
    $resource['username'] = $updaterUserData['username'];
            return 
    parent::_updateThread($resource);
        }
    В этом случае сразу видно при каком условии производится стандартная обработка, а при каком кастомная. Недостатки моего подхода в данном случае - две точки выхода из метода вместо одной и так называемая negated "if" construction (в некоторых руководствах по стилю кодирования таких конструкций рекомендуется избегать).
     
    Exile нравится это.
  6. infis

    infis Местный

    Регистрация:
    27.06.11
    Сообщения:
    5 966
    Симпатии:
    3 548
    Версия XF:
    1.5.9
    На самом деле тут больше вопрос религии и наличие/отсутствие IDE. Дело в том, что при работе в IDE длинные if легко и просто одним щелчком мыши сворачиваются. Поэтому для чтения это не сказывается отрицательно. Но в простом блокноте, конечно же, листать длинные простыни кода неудобно. Также в IDE обычно подсвечиваются уровни вложенности, что облегчает чтение.
    Вероятно, по этой причине разработчики движка и используют длинные if. А при отрицательном if, как вы справедливо заметили, логика при двух return хромает, что не есть хорошо.
     
  7. FractalizeR

    FractalizeR XenForo Addicted

    Регистрация:
    27.09.10
    Сообщения:
    1 085
    Симпатии:
    832
    Версия XF:
    1.3.2
    В общем-то на эту тему немало копий уже поломано. Я против больших вложенных конструкций независимо от того, можно ли их свернуть в IDE или нет. Хотя, конечно, все зависит от ситуации. Самое главное - понижение сложности кода.
     
  8. FractalizeR

    FractalizeR XenForo Addicted

    Регистрация:
    27.09.10
    Сообщения:
    1 085
    Симпатии:
    832
    Версия XF:
    1.3.2
    Раскрою свою мысль немного.

    Я читаю код обычно линейно, т.е. сверху вниз. Мне хочется понимать, что делает код сразу, сейчас и полностью. Для того, чтобы понять, что делает код, все свернутые управляющие структуры все равно придется развернуть, либо читать код в несколько заходов (тоже, в принципе, вариант).

    Линейное чтение кода максимально облегчается его минимальной вложенностью. Скажем, в коде движка есть такой метод XenForo_ControllerPublic_Post::actionDelete:

    PHP:
        /**
         * Deletes an existing post.
         *
         * @return XenForo_ControllerResponse_Abstract
         */
        
    public function actionDelete()
        {
            
    $postId $this->_input->filterSingle('post_id'XenForo_Input::UINT);

            
    $ftpHelper $this->getHelper('ForumThreadPost');
            list(
    $post$thread$forum) = $ftpHelper->assertPostValidAndViewable($postId);

            
    $hardDelete $this->_input->filterSingle('hard_delete'XenForo_Input::UINT);
            
    $deleteType = ($hardDelete 'hard' 'soft');

            
    $this->_assertCanDeletePost($post$thread$forum$deleteType);

            
    $postModel $this->_getPostModel();

            if (
    $this->isConfirmedPost()) // delete the post
            
    {
                
    $options = array(
                    
    'reason' => $this->_input->filterSingle('reason'XenForo_Input::STRING),
                    
    'authorAlert' => $this->_input->filterSingle('send_author_alert'XenForo_Input::BOOLEAN),
                    
    'authorAlertReason' => $this->_input->filterSingle('author_alert_reason'XenForo_Input::STRING)
                );
                if (
    $thread['discussion_state'] != 'visible' || $post['message_state'] != 'visible' || $post['user_id'] == XenForo_Visitor::getUserId())
                {
                    
    $options['authorAlert'] = false;
                }

                
    $dw $postModel->deletePost($postId$deleteType$options$forum);

                if (
    $post['post_id'] == $thread['first_post_id'])
                {
                    
    XenForo_Model_Log::logModeratorAction(
                        
    'thread'$thread'delete_' $deleteType, array('reason' => $options['reason'])
                    );
                }
                else
                {
                    
    XenForo_Model_Log::logModeratorAction(
                        
    'post'$post'delete_' $deleteType, array('reason' => $options['reason']), $thread
                    
    );
                }

                
    XenForo_Helper_Cookie::clearIdFromCookie($postId'inlinemod_posts');

                if (
    $dw->discussionDeleted() || !$post['position'])
                {
                    
    XenForo_Helper_Cookie::clearIdFromCookie($thread['thread_id'], 'inlinemod_threads');

                    return 
    $this->responseRedirect(
                        
    XenForo_ControllerResponse_Redirect::SUCCESS,
                        
    XenForo_Link::buildPublicLink('forums'$forum)
                    );
                }
                else
                {
                    return 
    $this->responseRedirect(
                        
    XenForo_ControllerResponse_Redirect::SUCCESS,
                        
    $this->getDynamicRedirect(XenForo_Link::buildPublicLink('threads'$thread))
                    );
                }
            }
            else 
    // show a deletion confirmation dialog
            
    {
                
    $viewParams = array(
                    
    'post' => $post,
                    
    'thread' => $thread,
                    
    'forum' => $forum,
                    
    'nodeBreadCrumbs' => $ftpHelper->getNodeBreadCrumbs($forum),

                    
    'canHardDelete' => $postModel->canDeletePost($post$thread$forum'hard'),

                    
    'redirect' => $this->getDynamicRedirect(XenForo_Link::buildPublicLink('threads'$thread))
                );

                return 
    $this->responseView(
                    
    'XenForo_ViewPublic_Post_Delete',
                    
    'post_delete',
                    
    $viewParams
                
    );
            }
        }
    Я бы разбил его на три и немного переделал бы, навскидку, как-то так:

    PHP:
    <?php

    /**
    * Deletes an existing post.
    *
    * @return XenForo_ControllerResponse_Abstract
    */
    public function actionDelete()
    {
        
    $postId $this->_input->filterSingle('post_id'XenForo_Input::UINT);

        
    $ftpHelper $this->getHelper('ForumThreadPost');
        list(
    $post$thread$forum) = $ftpHelper->assertPostValidAndViewable($postId);

        
    $hardDelete $this->_input->filterSingle('hard_delete'XenForo_Input::UINT);
        
    $deleteType = ($hardDelete 'hard' 'soft');

        
    $this->_assertCanDeletePost($post$thread$forum$deleteType);

        
    //Showing the deletion form
        
    if ($this->isConfirmedPost()) {
            return 
    $this->doDeletePost($thread$post$postId$deleteType$forum);
        }

        
    $viewParams = array(
            
    'post' => $post,
            
    'thread' => $thread,
            
    'forum' => $forum,
            
    'nodeBreadCrumbs' => $ftpHelper->getNodeBreadCrumbs($forum),
            
    'canHardDelete' => $this->_getPostModel()->canDeletePost($post$thread$forum'hard'),
            
    'redirect' => $this->getDynamicRedirect(XenForo_Link::buildPublicLink('threads'$thread))
        );

        return 
    $this->responseView(
            
    'XenForo_ViewPublic_Post_Delete',
            
    'post_delete',
            
    $viewParams
        
    );
    }

    /**
    * @param $thread
    * @param $post
    * @param $postId
    * @param $deleteType
    * @param $forum
    *
    * @return XenForo_ControllerResponse_Redirect
    * @throws XenForo_Exception
    */
    protected function doDeletePost($thread$post$postId$deleteType$forum)
    {
        
    //Deleting the post
        
    $options = array(
            
    'reason' => $this->_input->filterSingle('reason'XenForo_Input::STRING),
            
    'authorAlert' => $this->_input->filterSingle('send_author_alert'XenForo_Input::BOOLEAN),
            
    'authorAlertReason' => $this->_input->filterSingle('author_alert_reason'XenForo_Input::STRING)
        );

        if (
    $thread['discussion_state'] != 'visible' || $post['message_state'] != 'visible' || $post['user_id'] == XenForo_Visitor::getUserId(
            )
        ) {
            
    $options['authorAlert'] = false;
        }

        
    $dw $this->_getPostModel()->deletePost($postId$deleteType$options$forum);
        
    $this->createModeratorLogDeletionEntry($thread$post$deleteType$options['reason']);

        
    XenForo_Helper_Cookie::clearIdFromCookie($postId'inlinemod_posts');

        if (
    $dw->discussionDeleted() || !$post['position']) {
            
    XenForo_Helper_Cookie::clearIdFromCookie($thread['thread_id'], 'inlinemod_threads');

            return 
    $this->responseRedirect(
                
    XenForo_ControllerResponse_Redirect::SUCCESS,
                
    XenForo_Link::buildPublicLink('forums'$forum)
            );
        } else {
            return 
    $this->responseRedirect(
                
    XenForo_ControllerResponse_Redirect::SUCCESS,
                
    $this->getDynamicRedirect(XenForo_Link::buildPublicLink('threads'$thread))
            );
        }
    }

    /**
    * @param int    $thread
    * @param array  $post
    * @param string $deleteType
    * @param string $reason
    */
    protected function createModeratorLogDeletionEntry($thread$post$deleteType$reason)
    {
        
    $isFirstPost $post['post_id'] == $thread['first_post_id'];

        
    XenForo_Model_Log::logModeratorAction(
            
    $isFirstPost 'thread' 'post',
            
    $isFirstPost $thread $post,
            
    'delete_'.$deleteType,
            array(
    'reason' => $reason)
        );
    }
     
    Последнее редактирование: 26.04.2015
  9. infis

    infis Местный

    Регистрация:
    27.06.11
    Сообщения:
    5 966
    Симпатии:
    3 548
    Версия XF:
    1.5.9
    Да вполне нормальный метод ксеновский там. Просто иногда не хватает комментариев, чтобы можно было быстро понять суть того или иного ветвления. Да и не всегда очевидны те или иные переменные.

    Кстати, по поводу кода Listener.php. Лучше все же использовать switch. В противном случае каждый раз будут идти лишние проверки. Понятно, что это несущественно повлияет на производительность, но кучка таких лишних проверок, и появится в дальнейшем повод для оптимизации.
     
    Kolya groza morey и Exile нравится это.
  10. FractalizeR

    FractalizeR XenForo Addicted

    Регистрация:
    27.09.10
    Сообщения:
    1 085
    Симпатии:
    832
    Версия XF:
    1.3.2
    Согласен.

    Иногда, однако, еще бывает так, что метод контроллера содержит слишком много всего, а нужно переопределить поведение только части его кода.
     
    Последнее редактирование: 26.04.2015
  11. infis

    infis Местный

    Регистрация:
    27.06.11
    Сообщения:
    5 966
    Симпатии:
    3 548
    Версия XF:
    1.5.9
    Это да. Причем, таких методов не так уж и мало. Но тут уже вопрос больше к разработчикам, которые должны это предполагать и разделять такие сложные методы на несколько более простых.
     
  12. FractalizeR

    FractalizeR XenForo Addicted

    Регистрация:
    27.09.10
    Сообщения:
    1 085
    Симпатии:
    832
    Версия XF:
    1.3.2
  13. infis

    infis Местный

    Регистрация:
    27.06.11
    Сообщения:
    5 966
    Симпатии:
    3 548
    Версия XF:
    1.5.9
    Да там вроде ничего нового. Просто все делают так, как им нравится :)
     

Поделиться этой страницей