Перейти к содержимому
Русский язык для Invision Community 5

Помогите создать tasks

Здравствуйте. Я не знаком с программированием, только на уровне чтения ну и основ. Мне нужно реализовать следующее:

 

В таблице 1 содержатся данные игрового аккаунта, в котором есть полу active и оно принимает значения 0 или 1.

 

Эта активность берется с двух других таблиц, где сравниваются ИГРОКИ и ИГРЫ, там где ИГРЫ есть дата игры, по ней и будет проходить сравнение, если игрок играл за последний месяц, то должно передаваться значение 1.

 

Я уже написал основу, разобрался немного, мне осталось составить SQL запрос для сравнения игрока и игр.

 

Т.е запрос примерно такой: Если "игрок" (stats_gameplayers.gameid, stats_gameplayers.name, stats_gameplayers.spoofedrealm) есть в "играх" за последний месяц (stats_games.id) то условие выполняется, true.

 

/**
* memberActive Task
*/
class _memberActive extends \IPS\Task
{
/**
 * Execute
 *
 * If ran successfully, should return anything worth logging. Only log something
 * worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
 * If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
 * Tasks should execute within the time of a normal HTTP request.
 *
 * @return	mixed	Message to log or NULL
 * @throws	\IPS\Task\Exception
 */
public function execute()
{
	$db = \IPS\sharedstats\DB::get();
    $accounts = [];
    foreach($db::i('stats')->select('id, status, name, active, server, created', 'stats_forum_connections') as $acc) {
           $accounts[$acc['id']] = [
               'status' => $acc['status'],
               'name' => $acc['name'],
               'server' => $acc['server'],
               'active'   => $acc['active']
           ];
       }
       $this->updateAccounts($accounts);
}

/**
 * Cleanup
 *
 * If your task takes longer than 15 minutes to run, this method
 * will be called before execute(). Use it to clean up anything which
 * may not have been done
 *
 * @return	void
 */
public function cleanup()
{

}

   /**
    * @param $accounts
    */
   protected function updateAccounts($accounts)
   {
       foreach($accounts as $id => $acc) {
           $data = $this->fetchAccount($acc);
           $account = \IPS\sharedstats\Records\ForumConnection::load($id);
           if(!$data) {
               $account->active = '0';
           } else {
               $account->active = '1';
           }
           $account->save();
       }
}

   protected function fetchAccount($acc)
   {
       $result = true;

       if (FALSE === $result) {
           return false;
       } else {
           return json_decode($result, true);
       }
}

}

 

Это готовый таск, он рабочий, данные изменяются где надо. Нужно вместо $result = true; вставить SQL запрос правильный.

Рекомендованные сообщения

  • Автор

Обе, если обе записи там есть и с обоих аккаунтов играли за последние 30 дней.

$names = iterator_to_array(\IPS\Db::i()->select(
   "CONCAT(stats_gameplayers.name, stats_gameplayers.spoofedrealm)",
   'stats_gameplayers',
   array( 'UNIX_TIMESTAMP(stats_games.datetime)>?', \IPS\DateTime::create()->sub(new \DateInterval('P30D'))->getTimestamp()),
   null,
   null,
   array('stats_gameplayers.name', 'stats_gameplayers.spoofedrealm')
)->join(
   'stats_games',
   'stats_games.id=stats_gameplayers.gameid'
));

 

if (count($names))
{
   \IPS\Db::i()->update('stats_forum_connections', array('active' => 1), \IPS\Db::i()->in("CONCAT(name, server)", $names));    
}

  • Автор

Так же делал, только без CONCAT. Спасибо, сейчас попробую.

  • Автор

Почему так не работает 0.

 

	public function execute()
{
       $db = \IPS\sharedstats\DB::get();
	$names = iterator_to_array($db::i('stats')->select(
	    "CONCAT(stats_gameplayers.name, stats_gameplayers.spoofedrealm)",
	    'stats_gameplayers',
	    array( 'UNIX_TIMESTAMP(stats_games.datetime)>?', \IPS\DateTime::create()->sub(new \DateInterval('P30D'))->getTimestamp()),
	    null,
	    null,
	    array('stats_gameplayers.name', 'stats_gameplayers.spoofedrealm')
	)->join(
	    'stats_games',
	    'stats_games.id=stats_gameplayers.gameid'
	));
	if (count($names))
	{
	    $db::i('stats')->update('stats_forum_connections', array('active' => 1), $db::i('stats')->in("CONCAT(name, server)", $names));
	}
	else {
		$db::i('stats')->update('stats_forum_connections', array('active' => 0), $db::i('stats')->in("CONCAT(name, server)", $names));
	}
}

        else {
           $db::i('stats')->update('stats_forum_connections', array('active' => 0), $db::i('stats')->in("CONCAT(name, server)", $names));
       }

А что Вы тут пытаетесь обновить, если массив $names пуст, и запрос выглядит так

UPDATE stats_forum_connections SET active=0 WHERE 1=0

  • Автор

Да, массив пусть как и должно быть, т.е за последние 30 дней игры не найдены, и нужно установить active=0.

Да, массив пусть как и должно быть, т.е за последние 30 дней игры не найдены, и нужно установить active=0.

 

Кому Вы собираетесь устанавливать active=0, если в результате запроса получено 0 записей?

 

Устанавливайте всем active=0, а после устанавливайте active=1 юзерам, игравшим за последние 30 дней.

  • Автор

Всё правильно, а если после установки active - 1 игрок не играл в течении 30 дней, нужно вернуть 0.

1. Ставьте всем 0

2. Ставьте 1 тем, кто играл.

 

В чем проблема?

  • Автор

Проблема в том, что, c 1 на 0 не переключает, если игрок не играл за последние 30 дней.

 

Еще раз, смотрите: изначально у всех стоит 0, затем модуль присваивает 1 тем, кто играл за последние 30 дней, с этим всё в порядке. Проходит еще 2 дня, а игрок не играл, т.е уже 32 дня, модуль не возвращает 0, остается 1.

Покажите весь код.

  • Автор

Код таска? Сейчас такой: http://ipbskins.ru/forum/topic15678.html/page__view__findpost__p__104914

 

Т.е здесь должно быть ИНАЧЕ обновить на 0. Т.е если игрок не играл в течении 30 дней, должен обновить на 0, а он не обновляет (

Изменено пользователем TemKa_SD

  • Автор

Вот так работает вроде, это правильная реализация?

 

	public function execute()
{
       $db = \IPS\sharedstats\DB::get();
	$names = iterator_to_array($db::i('stats')->select(
	    "CONCAT(stats_gameplayers.name, stats_gameplayers.spoofedrealm)",
	    'stats_gameplayers',
	    array( 'UNIX_TIMESTAMP(stats_games.datetime)>?', \IPS\DateTime::create()->sub(new \DateInterval('P200D'))->getTimestamp()),
	    null,
	    null,
	    array('stats_gameplayers.name', 'stats_gameplayers.spoofedrealm')
	)->join(
	    'stats_games',
	    'stats_games.id=stats_gameplayers.gameid'
	));
	if (count($names))
	{
	    $db::i('stats')->update('stats_forum_connections', array('active' => 1), $db::i('stats')->in("CONCAT(name, server)", $names));
	}
	else {
		$db::i('stats')->update('stats_forum_connections', array('active' => 0));
	}
}

Вот так работает вроде, это правильная реализация?

Нет.

 

Вы не учитываете старых юзеров.

 

Допустим, что у всех установлено active=0

User1 -> active=0

User2 -> active=0

User3 -> active=0

User4 -> active=0

User5 -> active=0

User6 -> active=0

...

User100 -> active=0

 

Задача выполняется и находит юзеров, игравших за последние 30 дней: User1, User2, User3

User1 -> active=1

User2 -> active=1

User3 -> active=1

User4 -> active=0

User5 -> active=0

User6 -> active=0

...

User100 -> active=0

 

Задача выполняется и находит юзеров, игравших за последние 30 дней: User1, User2, User3, User4

User1 -> active=1

User2 -> active=1

User3 -> active=1

User4 -> active=1

User5 -> active=0

User6 -> active=0

...

User100 -> active=0

 

Если каждый раз будут находиться игроки, то код $db::i('stats')->update('stats_forum_connections', array('active' => 0)); не будет выполняться, но через 31 день у юзеров User1, User2, User3 должен быть active=0.

  • Автор

Да, вы правильно поняли. Ну задача выполняется раз в час, если в первом часе обновилось до 1, то во втором часе обновит на 0. Ну как и должно быть в принципе, ну да, реализация не правильная, условие нужно менять. Сделайте пожалуйста, и с этим вопросом покончено )))

Создайте аккаунт или войдите в него для комментирования

Аккаунт

Навигация

Поиск

Поиск

Настроить push-уведомления браузера

Chrome (Android)
  1. Нажмите на иконку замка рядом с адресной строкой.
  2. Нажмите Права доступа -> Уведомления.
  3. Измените свои настройки.
Chrome (компьютер)
  1. Нажмите на иконку замка в адресной строке.
  2. Выберите Настройки сайта.
  3. Найдите Уведомления и измените свои настройки.