TemKa_SD Posted April 24, 2019 Share Posted April 24, 2019 (edited) Здравствуйте. имею две таблицы: wc3_mapcfgs - основная для Node, используется для добавления, редактирования форм: http://prntscr.com/ng4iwqwc3_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 ) ); } Вопрос в следующем: Как правильно реализовать вставку, обновление полей? Edited April 24, 2019 by TemKa_SD Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 24, 2019 Author Share Posted April 24, 2019 (edited) Сделал через $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. Помогите кодом плиз, это из формы же нужно делать? выборку. Edited April 24, 2019 by TemKa_SD Link to comment Share on other sites More sharing options...
siv1987 Posted April 24, 2019 Share Posted April 24, 2019 Вопрос в следующем: Как правильно реализовать вставку, обновление полей? Запросить в бд строку по этому условию, если оно имеется - обновлять. Если отсутствует - вставлять. Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 25, 2019 Author Share Posted April 25, 2019 Ну вот я сделал обновление: 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. Link to comment Share on other sites More sharing options...
siv1987 Posted April 25, 2019 Share Posted April 25, 2019 $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 } Как-то так. Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 25, 2019 Author Share Posted April 25, 2019 Нет, это не то. Давайте заново. Сначала мне нужно выбрать текущие значения, которые есть в БД с 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; } } } Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 25, 2019 Author Share Posted April 25, 2019 (edited) Тест: Создаем конфиг: 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; } } Edited April 25, 2019 by TemKa_SD Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 25, 2019 Author Share Posted April 25, 2019 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. Link to comment Share on other sites More sharing options...
siv1987 Posted April 25, 2019 Share Posted April 25, 2019 Обновлять нужно если в бд отсутствует такой ключ, а не если он чему-то равен. Ничего сравнивать, тем более таким образом не нужно. $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 } 1 Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 25, 2019 Author Share Posted April 25, 2019 Спасибо большое, работает!!!!!!!!!! Добавил 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; } } Link to comment Share on other sites More sharing options...
siv1987 Posted April 25, 2019 Share Posted April 25, 2019 Исправил баг: return $a['cfg_key']; // здесь возвращалась строка, нужен массив.Это не баг. Его суть в том, чтобы из многомерного результат создать одномерный массив со всеми ключами. Только если выбирать одно поле в запросе, результат будет одномерный массив. Так что в принципе он здесь не нужен. Можете удалить. А в условие использовать in_array( $k, $result ) Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 25, 2019 Author Share Posted April 25, 2019 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; } } Верно? Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 27, 2019 Author Share Posted April 27, 2019 (edited) Здравствуйте. Я хочу удалить строку, если её значение 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 и нулл тогда выполняется. Edited April 27, 2019 by TemKa_SD Link to comment Share on other sites More sharing options...
TemKa_SD Posted April 27, 2019 Author Share Posted April 27, 2019 Добавил, чтобы нельзя было редактировать имя конфига: $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' ) ); Вроде всё правильно. Link to comment Share on other sites More sharing options...
TemKa_SD Posted June 8, 2019 Author Share Posted June 8, 2019 (edited) Здравствуйте. Переписываю сохранение настроек, хочу реализовать через 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(); переопределив таблицу сохранения? Edited June 8, 2019 by TemKa_SD Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now