Перейти к публикации
View in the app

A better way to browse. Learn more.

Дизайн и модификация Invision Community

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Node сохранение формы во внешнюю таблицу

Опубликовано:

Здравствуйте. имею две таблицы:

 

wc3_mapcfgs - основная для Node, используется для добавления, редактирования форм: http://prntscr.com/ng4iwq

wc3_mapcfgs_configuration - настройки, которые выбирает хост бот на C++: http://prntscr.com/ng4jbg

 

Задача: связать формы и добавление/изменение из них настроек в таблицу wc3_mapcfgs_configuration.

 

Я всё реализовал кроме сохранения и изменения настроек:

 

public function form( &$form )
{
$form->add( new \IPS\Helpers\Form\Text( 'mapcfg_name', $this->mapcfg_name, TRUE, array(), NULL, NULL, NULL ) );
$form->add( new \IPS\Helpers\Form\Node( 'map_id', isset($this->map_id) ? $this->map_id : NULL, TRUE, array( 'class' => 'IPS\wc3\Map' ) ) );
}

public function formatFormValues( $values )
{
isset($values['map_id']) ? $values['map_id'] = $values['map_id']->_data['id'] : NULL;

$this->updateAsSettings($values);

return $values;
}

public function updateAsSettings( $values )
{
if ( isset( $values['map_id'] ) )
{
	$map = \IPS\wc3\Map::load( $values['map_id'] );

	$values['map_localpath'] = $map->_data['map_name'];
	$values['map_path'] = "Maps\\Download\\" . $map->_data['map_name'];

	unset($values['map_id']);
}

if ( isset( $values['mapcfg_name'] ) )
{
	isset($values['mapcfg_name']) ? $cfg_name = $values['mapcfg_name'] : NULL;

	unset($values['mapcfg_name']);
}
}

 

updateAsSettings() - функция, которая разбирает значения для сохранения, вставки в таблицу: wc3_mapcfgs_configuration

 

Два foreach, для обновления и вставки записей, оно работает всё в порядке:

 

foreach ($values as $key => $value) {
\IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $value ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $key ) );
}

foreach ($values as $key => $value) {
\IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $key, 'cfg_value' => $value ) );
}

 

Вопрос в следующем: Как правильно реализовать вставку, обновление полей?

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

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

Опубликовано:
  • Автор

Сделал через $this->id

 

if ( !$this->id )
{
foreach ($values as $key => $value) {
	\IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $key, 'cfg_value' => $value ) );
}
} else {
foreach ($values as $key => $value) {
	\IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $value ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $key ) );
}
}

 

но оно мне не подходит, дело в том, что, весь конфиг я не хочу записывать, большая его часть использует стандартные значения в C++. Т.е там порядка 15 параметров, а для работы обязательных всего 2, это путь к карте и название карты.

 

Т.е если я запишу два параметра изначально из формы, потом когда захочу отредактировать её - будут редактироваться только старые параметры, которые, вставлялись через insert при создании $this->id, т.е это два параметра из 15. Нужно как-то проверять на наличие параметров во нешней таблице, которая НЕ используется формой.

 

Т.е нужна проверка если параметра нет - insert, иначе update и тут не учитывается $this->id. Помогите кодом плиз, это из формы же нужно делать? выборку.

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

Опубликовано:
Вопрос в следующем: Как правильно реализовать вставку, обновление полей?

Запросить в бд строку по этому условию, если оно имеется - обновлять. Если отсутствует - вставлять.

Опубликовано:
  • Автор

Ну вот я сделал обновление:

 

foreach ( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) as $k )
{
if ($k == key($values)) {
	foreach ($values as $key => $value) {
		$value ? \IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $value ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $key ) ) : NULL;
	}
}
}

 

Как теперь вставить? Т.е как написать if foreach else insert.

Опубликовано:

$result = \IPS\Db::i()->select( 'mapcfg_name', 'wc3_mapcfgs', array( 'mapcfg_name=?', $cfg_name ) );
if( $result->count() )
{
foreach( $values as $k => $v )
{
	\IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $v ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $k ) );
}
}
else
{
//INSERT wc3_mapcfgs
//INSERT static::$cfgTable
}

 

Как-то так.

Опубликовано:
  • Автор

Нет, это не то.

 

Давайте заново.

 

Сначала мне нужно выбрать текущие значения, которые есть в БД с where cfg_name = текущее сохраняемое имя конфига.

 

Т.е как в моем запросе:

 

foreach ( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) as $k )

 

Здесь я выбираю массив с текущими значениями: http://prntscr.com/ngnz7x т.е select cfg_key from static::$cfgTable where cfg_name=map1

 

Дальше сравниваем найденные значения в БД с теми, которые сохраняем в данный момент:

 

if ($k == key($values)) {

 

Т.е если КЛЮЧ в бд равен Ключу сохраняемого значения (map_localpath) то выполняем обновление, значит данные нужно обновить в этом поле а не вставить.

Иначе, нужно выполнить insert.

 

Т.е код рабочий, мне в него просто insert Нужно добавить ЗА foreach, так как если резульатов в нем не будет, внутри условия не будут выполнены.:

 

		foreach ( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) as $k )
		{
			if ($k == key($values)) {
				foreach ($values as $key => $value) {
					$value ? \IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $value ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $key ) ) : NULL;
				}
			}
		}

Опубликовано:
  • Автор

Тест: Создаем конфиг: http://prntscr.com/ngo96s (правильно), добавляем в него новое значение (редактируем): http://prntscr.com/ngo9ic здесь вот добавились уже существующие значения и новое (не правильно), должно быть только новое значение.

 

$result = \IPS\Db::i()->select( 'mapcfg_name', 'wc3_mapcfgs', array( 'mapcfg_name=?', $cfg_name ) );
// Если конфиг уже существует, вы полняем условия.
if( $result->count() )
{	// Выбираем текущие значения ключи из БД
foreach ( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) as $k )
{	// Если ключ БД равен срхраняемому, выполняем обновление
	if ($k == key($values)) {
		foreach ($values as $key => $value) {
			$value ? \IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $value ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $key ) ) : NULL;
		}
	}
	// Иначе insert
	else {
		foreach ($values as $key => $value) {
			$value ? \IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $key, 'cfg_value' => $value ) ) : NULL;
		}
	}
}
}
// Если конфига нет, только создаем, записываем все данные.
else
{
foreach ($values as $key => $value) {
	$value ? \IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $key, 'cfg_value' => $value ) ) : NULL;
}
}

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

Опубликовано:
  • Автор

	if ( $this->id )
	{
		foreach ( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) as $k )
		{   // Если ключ БД равен срхраняемому, выполняем обновление
		    if ($k == key($values)) {
				foreach ($values as $key => $value) {
					$value ? \IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $value ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $key ) ) : NULL;
				}
		    }
		    // Иначе insert
		    else {
		    	// здесь должен быть insert, и вставленны те данные, еоторые не равны выше, которые не обновляются и вставляются.
		    }
		}
	} else {
		foreach ($values as $key => $value) {
			$value ? \IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $key, 'cfg_value' => $value ) ) : NULL;
		}
	}

 

Вот так, только дописать insert.

Опубликовано:

Обновлять нужно если в бд отсутствует такой ключ, а не если он чему-то равен. Ничего сравнивать, тем более таким образом не нужно.

 

$result = iterator_to_array( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) );
if( $result )
{
$keys = array_map( function( $a ){ return $a['cfg_key']; }, $result );

foreach( $values as $k => $v )
{
	if( $v )
	{
		if( in_array( $k, $keys ) )
		{
			\IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $v ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $key ) );
		}
		else
		{
			\IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $k, 'cfg_value' => $v ) );
		}
	}
}
}
else
{
//INSERT mapеtable
//INSERT static::$cfgTable
}

Опубликовано:
  • Автор

Спасибо большое, работает!!!!!!!!!!

 

Добавил this->id

 

Исправил баг: return $a['cfg_key']; // здесь возвращалась строка, нужен массив.

 

Да, для меня это сложно еще, с array_map совсем не знаком.

 

Финальный код:

if ( $this->id )
{
$result = iterator_to_array( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) );
if( $result )
{
    $keys = array_map( function( $a ){
    	return $a;
    }, $result );

    foreach( $values as $k => $v )
    {
        if( $v )
        {
            if( \in_array( $k, $keys ) )
            {
                \IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $v ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $k ) );
            }
            else
            {
                \IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $k, 'cfg_value' => $v ) );
            }
        }
    }
}
} else {
foreach ($values as $key => $value) {
	$value ? \IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $key, 'cfg_value' => $value ) ) : NULL;
}
}

Опубликовано:

Исправил баг: return $a['cfg_key']; // здесь возвращалась строка, нужен массив.

Это не баг. Его суть в том, чтобы из многомерного результат создать одномерный массив со всеми ключами. Только если выбирать одно поле в запросе, результат будет одномерный массив. Так что в принципе он здесь не нужен. Можете удалить. А в условие использовать in_array( $k, $result )

Опубликовано:
  • Автор

	if ( $this->id )
	{
		$result = iterator_to_array( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) );
		if( $result )
		{
		    foreach( $values as $k => $v )
		    {
		        if( $v )
		        {
		            if( \in_array( $k, $result ) )
		            {
		                \IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $v ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $k ) );
		            }
		            else
		            {
		                \IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $k, 'cfg_value' => $v ) );
		            }
		        }
		    }
		}
	} else {
		foreach ($values as $key => $value) {
			$value ? \IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $key, 'cfg_value' => $value ) ) : NULL;
		}
	}

 

Верно?

Опубликовано:
  • Автор

Здравствуйте. Я хочу удалить строку, если её значение 0. Т.е http://prntscr.com/nhi2k6 тут 0, я хочу удалить эту строку, так как 0 и так берется в приложении на C++ изначально, и хранить это в конфиге нет смысла, чище бд будет.

 

Во первых, здесь дописываю если значение не равняется NULL, чтобы проходили нули в проверку: http://prntscr.com/nhi2uu.

 

Вставляем условие в если id уже есть и если его еще нет. В моем случае 0 передает как строку, наверно потому что у меня в форме RADIO:

 

$form->add( new \IPS\Helpers\Form\Radio( 'map_loadingame', isset($settings['map_loadingame']) ? $settings['map_loadingame'] : 0, FALSE, array(
'options' => array
(
	0 => 'Загрузка карты с заставкой',
	1 => 'В игре'
)
), NULL, NULL, NULL, 'map_loadingame' ) );

 

Где бы мне тут в форме указать что это int, не хочется делать новое условие для этого, лучше прям в форме?

 

public function updateAsSettings( $cfg_name, $settingValues )
{
if ( $this->id )
{
	$result = iterator_to_array( \IPS\Db::i()->select( 'cfg_key', static::$cfgTable, array( 'cfg_name=?', $cfg_name ) ) );
	if( $result )
	{
	    foreach( $settingValues as $k => $v )
	    {
			if ($v != '0')
			{
				if( \in_array( $k, $result ) )
				{
				    \IPS\Db::i()->update( static::$cfgTable, array( 'cfg_value' => $v ), array( 'cfg_name=? AND cfg_key=?', $cfg_name, $k ) );
				}
				else
				{
				    \IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $k, 'cfg_value' => $v ) );
				}
			}
			else
			{
				\IPS\Db::i()->delete( static::$cfgTable, array( 'cfg_name=? AND cfg_key=?', $cfg_name, $k ) );
			}
	    }
	}
} else {
	foreach ($settingValues as $k => $v) {
		if ($v != '0')
		{
			\IPS\Db::i()->insert( static::$cfgTable, array( 'cfg_name' => $cfg_name, 'cfg_key' => $k, 'cfg_value' => $v ) );
		}
	}
}
}

 

Вроде всё правильно?

 

P.S.: Для NULL тоже самое надо сделать, только я че-то не понял, почему оно так перестает вообще работать:

 

if ($v != '0' OR $v != NULL)

 

А так работает:

 

if ($v != '0' AND $v != NULL)

 

Условие должно выполнятся: Если V не равно 0 ИЛИ V не равно NULL. // Неужели я что-то не так думаю, сейчас оно должно искать оба параметра, т.е если V 0 и нулл тогда выполняется.

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

Опубликовано:
  • Автор

Добавил, чтобы нельзя было редактировать имя конфига:

 

$this->mapcfg_name ? $disabled = TRUE : $disabled = FALSE;

$form->add( new \IPS\Helpers\Form\Text( 'mapcfg_name', isset($this->mapcfg_name) ? $this->mapcfg_name : NULL, TRUE, array( 'disabled' => $disabled ), NULL, NULL, NULL, 'mapcfg_name' ) );

 

Вроде всё правильно.

  • 1 месяц спустя...
Опубликовано:
  • Автор

Здравствуйте. Переписываю сохранение настроек, хочу реализовать через ActiveRecord. Я сейчас напишу задачу и проблемы.

 

Начнем по порядку, допустим, я подключил форму и всё остальное, выглядит это так:

 

<?php

namespace IPS\wc3\Bot;

class _Settings extends \IPS\Patterns\ActiveRecord
{
protected static $multitons;
public static $databaseTable = 'wc3_bots_configuration';
public static $databaseColumnId = 'cfg_botid';

public function form( &$form )
{
	$form->addTab( 'wc3_bots_settingsBot', 'cogs' );
	$form->add( new \IPS\Helpers\Form\Text( 'autohost_gamename' ));
}
}

 

_Settings - через этот класс сохраняются настройки, проблема в том, что, значения полей - это данные в базе данных а не ячейки.

 

Выглядит это так: http://prntscr.com/nz4yhe

 

cfg_name = это id поля формы.

cfg_value = значение поля формы.

 

т.е нужно сделать что-то вроде такого:

 

if ( $values = $form->values() )
{
foreach ($values as $key => $value) {
	$values['cfg_botid'] = 1;
	$values['cfg_name'] = $key;
	$values['cfg_value'] = $value;
}
}

 

Какой самый правильный способ для реализации этой задачи?

 

Может как-то через $form->saveAsSettings(); переопределив таблицу сохранения?

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

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

Сейчас на странице 0

  • Нет пользователей, просматривающих эту страницу.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.