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

1.4.12 Изменение пользователя без записи в журнал

Тема в разделе "Вопросы и ответы по XenForo Framework", создана пользователем Egorpom, 24.07.2016.

Загрузка
  1. Egorpom

    Egorpom Местный

    Регистрация:
    30.11.12
    Сообщения:
    11
    Симпатии:
    1
    Версия XF:
    1.4.12
    Имеется задача в планировщике, которая вызывает метод раз в 3 часа. Сам метод определенным образом изменяет дополнительное поле всех пользователей.
    PHP:
    $userModel XenForo_Model::create('XenForo_Model_User');
    XenForo_Db::beginTransaction();
    $user $userModel->getUserById($userId);
    $writer XenForo_DataWriter::create('XenForo_DataWriter_User'XenForo_DataWriter::ERROR_SILENT);
    $writer->setExistingData($userId); //ID юзера для изменения поля
    $writer->setOption(XenForo_DataWriter_User::OPTION_ADMIN_EDITtrue); //это признак, что админ редактирует, чтобы игнорить запрет на редактирование
    $writer->setCustomFields(array('playtime' => $playtime)); // собственно установка значения поля
    $writer->save();
    XenForo_Db::commit();
    Вопрос: Есть ли какой-либо параметр, который отключит логирование этих изменений?
    Имею ввиду то, что эти изменения отображаются в журнале изменений пользователя.
    Или же придется изменять DataWriter/вручную чистить логи?

    Второй вопрос:
    Для этого же дополнительного поля мне нужно установить дефолтное значение.
    Пока что есть идея сделать это с помощью расширения класса XenForo_ControllerPublic_Register, метода _completeRegistration
    Т.е. вставить туда код, который задает нужное мне значение дополнительного поля.
    Есть ли более правильный/простой способ сделать это?
    Под изменением стандартных классов и методов движка я подразумеваю вынос изменений в отдельный плагин.
    --- добавлено : Jul 23, 2016 9:12 PM ---
    Также, если Вы знаете плагин, который так или иначе работает с дополнительными полями пользователей, я был бы рад услышать его название и разобрать в качестве примера.
     
    Последнее редактирование модератором: 31.07.2016
  2. Egorpom

    Egorpom Местный

    Регистрация:
    30.11.12
    Сообщения:
    11
    Симпатии:
    1
    Версия XF:
    1.4.12
    1.
    PHP:
    $writer->setOption(XenForo_DataWriter_User::OPTION_LOG_CHANGESfalse);
     
  3. infis

    infis Местный

    Регистрация:
    27.06.11
    Сообщения:
    5 966
    Симпатии:
    3 548
    Версия XF:
    1.5.9
    Это делается одним запросом:
    Код:
    INSERT INTO xf_user_field_value (user_id, field_id, field_value)
     SELECT user_id, 'здесь_ид_поля', 'здесь_его_значение'
     FROM xf_user
    ON DUPLICATE KEY UPDATE
     field_value = VALUES(field_value);
    
    Если поле в виде флажка, то в качестве значения записывается сериализованный массив. Например:
    Код:
    INSERT INTO xf_user_field_value (user_id, field_id, field_value)
     SELECT user_id, 'здесь_ид_поля', 'a:1:{s:11:"ид_значения";s:11:"ид_значения";}'
     FROM xf_user
    ON DUPLICATE KEY UPDATE
     field_value = VALUES(field_value);
    Проще всего создать поле и посмотреть, что запишется в таблицу, вручную установив нужное значение. Ну а это значение уже подставить в запрос.

    Запрос отработает быстро даже для большого количества пользователей. И явно быстрее, чем создавать датарайтер и пихать через него. Поэтому в планировщике в этом случае можно не напрягаться с ограничением работы скрипта по времени и не создавать процедуру deffered.
    Я через actionRegister (из которого уже и вызывается _completeRegistration) дефолтное значение прописывал. Но нужно помнить, что нового пользователя можно создать и через админку. В этом случае actionRegister не вызовется. Но администратор должен контролировать все данные пользователя, которого он создает. Поэтому логично оставить ему возможность заполнять все поля самостоятельно.
    В любом случае приходиться отдельно записывать в базу значение этого поля. Так как эта операция нечастая, то никакой дополнительной нагрузки на сервер это не создаст. Но сам по себе метод установки дефолтного значения через дополнительный запрос - это, конечно, не хорошо. Разработчикам об этом уже говорили. Но они отмахнулись.
    Если поле доступно при регистрации и должно отображаться пользователю с дефолтным значением, то, насколько я помню, на офе был пример, как это сделать через скрипты. Тоже не изящное решение, но вроде работает.
     
    Egorpom нравится это.
  4. Egorpom

    Egorpom Местный

    Регистрация:
    30.11.12
    Сообщения:
    11
    Симпатии:
    1
    Версия XF:
    1.4.12
    Этот метод был выбран из-за проблем с отображением на форуме, после изменения поля. Придется выполнять rebuildCustomFields или я ошибаюсь?
    И если не ошибаюсь:
    1. В этом случае все равно оптимальнее будет прямой запрос в БД с вызовом rebuildCustomFields?
    2. Для rebuildCustomFields все равно придется создавать датарайтер, разве нет?
    Да видел вроде пример, но у меня это поле не должно отображаться при регистрации в принципе. Это поле содержит в себе данные о времени проведенном в игре, которые находятся в другой БД и соответственно, давать пользователю возможность редактировать это поле не хотелось бы.
    У меня установлен аддон External Accounts Extended
    Он переопределяет метод actionRegister.
    Также установлен Alter Ego Detector и он переопределяет _completeRegistration
    Допустим, что я хочу переопределить _completeRegistration или любой другой метод, который уже переопределен другим плагином.
    Как это сделать, чтобы не было конфликта плагинов? Или его не будет в принципе?
     
    Последнее редактирование: 25.07.2016
  5. infis

    infis Местный

    Регистрация:
    27.06.11
    Сообщения:
    5 966
    Симпатии:
    3 548
    Версия XF:
    1.5.9
    Не надо. То есть достаточно просто выполнить запрос.
    Если плагин написан корректно, то он вызывает родительский метод, а результат дополняет. То есть хоть десяток плагинов могут один и тот же метод класса расширять. Вызов родительского метода прост:
    PHP:
    $result parent::метод(параметры_если_они_есть);
    У меня примерно так реализуется:
    PHP:
    public function actionRegister()
    {
      
    /**
      * @var $response XenForo_ControllerResponse_View
      */
      
    $response parent::actionRegister();
      
    $params $response->params;
      if(isset(
    $params['user']['user_id']))
      {
         
    $userId $params['user']['user_id'];
         
    $userModel $this->_getUserModel();
         
    $userProfile $userModel->getFullUserById($userId);
         
    $customFields unserialize($userProfile['custom_fields']);
         
    $customFields['ид_поля'] = 'ид_значения';
         
    $dw $this->_getDataWriterUser();
         
    $dw->setExistingData($userProfile);
         
    $dw->setCustomFields($customFields);
         
    $dw->rebuildCustomFields();
         
    $dw->save();   
      }
      return 
    $response;
    }
    То есть я абсолютно не трогаю результат вызова родительского метода и возвращаю его в неизменном виде. А значение дополнительного поля устанавливаю отдельным вызовом DataWrite.
     
    Egorpom нравится это.

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