/** * Access to settings, we can get a set of keys * @param mixed $key * @param array $options * array decrypt_keys - if we need to decrypt keys * boolean class - if we need to return proper class name * boolean backend_exists - if we need to determine if backend exists * @return mixed */ public static function get($key = null, $options = []) { // if we need to determine if backend exists if (!empty($options['backend_exists'])) { $key = str_replace('.', '_', $key); $existing = array_key_get(self::$settings, ['backend_exists', $key]); if (isset($existing)) { return $existing; } else { $flag = file_exists('./../libraries/vendor/' . str_replace('_', '/', $key)); array_key_set(self::$settings, ['backend_exists', $key], $flag); return $flag; } } // get data from settings $result = array_key_get(self::$settings, $key); // decrypting certain columns /* todo: maybe this is not needed at all if (!empty($options['decrypt_keys'])) { array_walk_recursive($result, create_function('&$v, $k, $fn', 'if (in_array($k, $fn)) $v = crypt::static_decrypt($v);'), $options['decrypt_keys']); } */ // if we need to fix class name if (!empty($options['class'])) { $result = str_replace('.', '_', $result); } return $result; }
/** * Get merged cookie, get and post * * @param mixed $key * @param boolean $xss * @param boolean $cookie * @return mixed */ public static function input($key = '', $xss = true, $cookie = false) { // cookie first, get and post after if ($cookie) { $result = array_merge2($_COOKIE, $_GET, $_POST); } else { $result = array_merge2($_GET, $_POST); } // protection against XSS attacks is on by default if ($xss) { $result = self::strip_tags($result); } // we need to get rid of session id from the result if (!$cookie) { unset($result[session_name()]); } // if we are debugging if (debug::$debug) { debug::$data['input'][] = $result; } // returning result if ($key) { return array_key_get($result, $key); } else { return $result; } }
/** * Multi level options * * @param array $data * @param array $optmultis_map * @param array $options * @return array */ public static function optmultis($data, $optmultis_map, $options = []) { $keys = array_keys($optmultis_map); $max_level = count($keys) - 1; $result = []; // process models $models = []; foreach ($optmultis_map as $k => $v) { if (!empty($v['model'])) { $model = $v['model']; $object = new $model(); $models[$k] = $object->options(); } } // generating all items in one run foreach ($data as $k => $v) { $temp_result = $k2_hash2 = $k2_hash = []; $level = -1; // a must foreach ($keys as $k2 => $v2) { $k2_alias = $optmultis_map[$v2]['alias'] ?? $v2; $k2_hash[$k2_alias] = $v[$v2]; if (!empty($v[$v2])) { $level++; if ($k2 != 0) { $k2_hash2[] = 'options'; } $k2_hash2[] = $v[$v2]; } if ($k2 < $max_level) { if (!array_key_get($result, $k2_hash2)) { $k2_temp = []; $k2_temp['level'] = $level; $k2_temp['name'] = $models[$v2][$v[$v2]]['name'] ?? $v[$v2]; if (!empty($options['i18n'])) { $k2_temp['name'] = i18n(null, $k2_temp['name']); } $k2_temp['json_key'] = json_encode($k2_hash); $k2_temp['disabled'] = $optmultis_map[$v2]['disabled'] ?? false; array_key_set($result, $k2_hash2, $k2_temp); } } // last key - we have items if ($k2 == $max_level) { $temp_result['level'] = $level; $name = ''; if (isset($optmultis_map[$v2]['column'])) { $name = $v[$optmultis_map[$v2]['column']]; } else { $name = $v[$k2_alias]; } if (empty($options['i18n'])) { $temp_result['name'] = $name; } else { $temp_result['name'] = i18n(null, $name); } // icon $temp_result['icon_class'] = null; if (isset($optmultis_map[$v2]['icon_column']) && !empty($v[$optmultis_map[$v2]['icon_column']])) { $temp_result['icon_class'] = html::icon(['type' => $v[$optmultis_map[$v2]['icon_column']], 'class_only' => true]); } // only this value flag if (!empty($optmultis_map[$v2]['only_this_value'])) { $temp_result['json_key'] = $v[$v2]; } else { $temp_result['json_key'] = json_encode($k2_hash); } array_key_set($result, $k2_hash2, $temp_result); } } } // sorting & generating final array array_key_sort($result, ['name' => SORT_ASC]); $result2 = []; foreach ($result as $v) { // level 0 $result2[$v['json_key']] = ['name' => $v['name'], 'level' => $v['level'], 'icon_class' => $v['icon_class'] ?? null, 'disabled' => $v['disabled'] ?? false]; // level 1 if (!empty($v['options'])) { array_key_sort($v['options'], ['name' => SORT_ASC]); foreach ($v['options'] as $v2) { $result2[$v2['json_key']] = ['name' => $v2['name'], 'level' => $v2['level'], 'icon_class' => $v2['icon_class'] ?? null, 'disabled' => $v2['disabled'] ?? false]; // level 2 if (!empty($v2['options'])) { array_key_sort($v2['options'], ['name' => SORT_ASC]); foreach ($v2['options'] as $v3) { $result2[$v3['json_key']] = ['name' => $v3['name'], 'level' => $v3['level'], 'icon_class' => $v3['icon_class'] ?? null, 'disabled' => $v3['disabled'] ?? false]; // level 3 if (!empty($v3['options'])) { array_key_sort($v3['options'], ['name' => SORT_ASC]); foreach ($v3['options'] as $v4) { $result2[$v4['json_key']] = ['name' => $v4['name'], 'level' => $v4['level'], 'icon_class' => $v4['icon_class'] ?? null, 'disabled' => $v4['disabled'] ?? false]; } } } } } } } return $result2; }
/** * Merge data to database * * @param array $data * @param array $options * @param object $form * @return array */ public function merge($data, $options = [], &$form = null) { $result = ['success' => false, 'error' => [], 'warning' => [], 'deleted' => false, 'inserted' => false, 'new_serials' => [], 'options_model' => []]; do { // start transaction $this->primary_model->db_object->begin(); // load data from database $original = []; if (array_key_exists('original', $options)) { $original = $options['original']; } else { // load data from database // assemble primary key $pk = []; $full_pk = true; foreach ($this->data['pk'] as $v) { if (isset($data[$v])) { $pk[$v] = $data[$v]; } else { $full_pk = false; } } // load data if (!empty($pk) && $full_pk) { $original = $this->get(['where' => $pk, 'single_row' => true]); } } // validate optimistic lock if ($this->primary_model->optimistic_lock && !empty($original)) { if (($data[$this->primary_model->optimistic_lock_column] ?? '') !== $original[$this->primary_model->optimistic_lock_column]) { $result['error'][] = object_content_messages::optimistic_lock; break; } } // we need to validate options_model if (!empty($options['options_model'])) { // get existing values foreach ($options['options_model'] as $k => $v) { // current values $value = array_key_get($data, $v['key']); if ($value !== null && (is_string($value) && $value !== '')) { if (is_array($value)) { $value = array_keys($value); } else { $value = [$value]; } $options['options_model'][$k]['current_values'] = $value; } else { $options['options_model'][$k]['current_values'] = null; } // we skip if we have no values if (empty($options['options_model'][$k]['current_values'])) { unset($options['options_model'][$k]); continue; } // existing values $value = array_key_get($original, $v['key']); if ($value !== null) { if (is_array($value)) { $value = array_keys($value); } else { $value = [$value]; } $options['options_model'][$k]['existing_values'] = $value; } else { $options['options_model'][$k]['existing_values'] = null; } } // validate object_data $sql_options = []; foreach ($options['options_model'] as $k => $v) { // we skip inactive model validations if ($v['options_model'] == 'object_data_model_inactive') { continue; } // process models $temp = explode('::', $v['options_model']); $model = factory::model($temp[0], true); if (empty($temp[1])) { $temp[1] = 'options'; } if ($model->initiator_class == 'object_data' || $model->initiator_class == 'object_table' && !in_array($temp[1], ['options', 'options_active'])) { $temp_options = array_keys(object_data_common::process_options($v['options_model'], null, $v['options_params'], $v['existing_values'])); // difference between arrays $diff = array_diff($v['current_values'], $temp_options); if (!empty($diff)) { $result['options_model'][$k] = 1; } } else { if ($model->initiator_class == 'object_table' && in_array($temp[1], ['options', 'options_active'])) { // last element in the pk is a field $pk = $model->pk; $last = array_pop($pk); // handling inactive $options_active = []; if ($temp[1] == 'options_active') { $options_active = $model->options_active ? $model->options_active : [$model->column_prefix . 'inactive' => 0]; } $sql_options[$k] = ['model' => $temp[0], 'field' => $last, 'params' => $v['options_params'], 'values' => $v['current_values'], 'existing_values' => $v['existing_values'], 'options_active' => $options_active]; } } } // validating options if (!empty($sql_options)) { $sql_model = new object_table_validator(); $sql_result = $sql_model->validate_options_multiple($sql_options); if (!empty($sql_result['discrepancies'])) { foreach ($sql_result['discrepancies'] as $k => $v) { $result['options_model'][$k] = 1; } } } // we roll back if we have errors if (!empty($result['options_model'])) { break; } } // comapare main row $this->timestamp = format::now('timestamp'); $temp = $this->compare_one_row($data, $original, $this->data, ['flag_delete_row' => $options['flag_delete_row'] ?? false, 'flag_main_record' => true]); // if we goe an error if (!empty($temp['error'])) { $result['error'] = $temp['error']; break; } // we display warning if form has not been changed if (empty($temp['data']['total'])) { $result['warning'][] = object_content_messages::no_changes; break; } // insert history if (!empty($temp['data']['history'])) { foreach ($temp['data']['history'] as $k => $v) { $temp2 = $this->primary_model->db_object->insert($k, $v); if (!$temp2['success']) { $result['error'] = $temp2['error']; goto error; } } } // audit if (!empty($temp['data']['audit'])) { // we need to put relation into pk if (!empty($this->primary_model->relation['field'])) { $temp['data']['audit']['pk'][$this->primary_model->relation['field']] = $temp['new_serials'][$this->primary_model->relation['field']] ?? $data[$this->primary_model->relation['field']] ?? $original[$this->primary_model->relation['field']]; } // merge $temp2 = factory::model($this->primary_model->audit_model, true)->merge($temp['data']['audit'], ['changes' => $temp['data']['total']]); if (!$temp2['success']) { $result['error'] = $temp2['error']; break; } } // if we got here we can commit $result['success'] = true; $result['deleted'] = $temp['data']['deleted']; $result['inserted'] = $temp['data']['inserted']; $result['updated'] = $temp['data']['updated']; $result['new_serials'] = $temp['new_serials']; // commit transaction $this->primary_model->db_object->commit(); return $result; } while (0); // we roll back on error error: $this->primary_model->db_object->rollback(); return $result; }
/** * Process dependencies * * @param array $options * @return array */ public static function process_deps_all($options = []) { $result = ['success' => false, 'error' => [], 'data' => []]; do { // processing main dependency file $main_dep_filename = 'config/application.ini'; if (!file_exists($main_dep_filename)) { $result['error'][] = "Main dep. file not found!"; break; } // some array arrangements $data = system_config::ini($main_dep_filename, 'dependencies'); $data = $data['dep'] ?? []; $data['composer'] = $data['composer'] ?? []; $data['submodule'] = $data['submodule'] ?? []; $data['submodule_dirs'] = []; $data['apache'] = $data['apache'] ?? []; $data['php'] = $data['php'] ?? []; $data['model'] = $data['model'] ?? []; $data['__model_dependencies'] = []; $data['model_import'] = []; $data['override'] = $data['override'] ?? []; $data['acl'] = $data['acl'] ?? []; $data['media'] = $data['media'] ?? []; $data['model_processed'] = []; $data['unit_tests'] = []; $data['__submodule_dependencies'] = []; $dummy = []; // we have small chicken and egg problem with composer $composer_data = []; $composer_dirs = []; $composer_dirs[] = 'config/'; if (file_exists('../libraries/composer.json')) { $composer_data = json_decode(file_get_contents('../libraries/composer.json'), true); } // if we have composer or submodules from main dep file if (!empty($data['composer']) || !empty($data['submodules'])) { $composer_data['require'] = []; if (!empty($data['composer'])) { self::process_deps_array($data['composer'], $composer_data['require'], $composer_dirs, 'dummy', $dummy); } if (!empty($data['submodule'])) { self::process_deps_array($data['submodule'], $composer_data['require'], $composer_dirs, 'dummy', $dummy); } } // processing submodules $mutex = []; $__any = []; if (!empty($composer_dirs)) { for ($i = 0; $i < 3; $i++) { foreach ($composer_dirs as $k => $v) { if (isset($mutex[$k])) { continue; } else { $mutex[$k] = 1; } if (file_exists($v . 'module.ini')) { $data['submodule_dirs'][$v] = $v; $sub_data = system_config::ini($v . 'module.ini', 'dependencies'); $sub_data = isset($sub_data['dep']) ? $sub_data['dep'] : []; if (!empty($sub_data['composer'])) { self::process_deps_array($sub_data['composer'], $composer_data['require'], $composer_dirs, $k, $dummy); $data['composer'] = array_merge2($data['composer'], $sub_data['composer']); } if (!empty($sub_data['submodule'])) { self::process_deps_array($sub_data['submodule'], $composer_data['require'], $composer_dirs, $k, $data['__submodule_dependencies']); $data['submodule'] = array_merge2($data['submodule'], $sub_data['submodule']); } if (!empty($sub_data['apache'])) { $data['apache'] = array_merge2($data['apache'], $sub_data['apache']); } if (!empty($sub_data['php'])) { $data['php'] = array_merge2($data['php'], $sub_data['php']); } if (!empty($sub_data['model'])) { $data['model'] = array_merge2($data['model'], $sub_data['model']); $temp = []; array_keys_to_string($sub_data['model'], $temp); foreach ($temp as $k0 => $v0) { $data['__model_dependencies'][$k][$k0] = $k0; } } if (!empty($sub_data['override'])) { $data['override'] = array_merge2($data['override'], $sub_data['override']); } if (!empty($sub_data['acl'])) { $data['acl'] = array_merge2($data['acl'], $sub_data['acl']); } if (!empty($sub_data['media'])) { $data['media'] = array_merge2($data['media'], $sub_data['media']); } // processing unit tests if (file_exists($v . 'unit_tests')) { // we have to reload the module.ini file to get module name $sub_data_temp = system_config::ini($v . 'module.ini', 'module'); $data['unit_tests'][$sub_data_temp['module']['name']] = $v . 'unit_tests/'; } } else { $keys = explode('/', $k); $last = end($keys); if ($last == '__any') { $temp2 = []; foreach ($keys as $v2) { if ($v2 != '__any') { $temp2[] = $v2; } } $__any[$k] = $temp2; } else { if ($keys[0] == 'numbers') { $result['error'][] = " - Submodule not found in {$v}module.ini"; } } } } } } // processing any dependencies if (!empty($__any)) { foreach ($__any as $k => $v) { $temp = array_key_get($data['submodule'], $v); unset($temp['__any']); if (empty($temp)) { $result['error'][] = " - Any dependency required {$k}!"; } } } // processing composer if (!empty($composer_data['require'])) { foreach ($composer_data['require'] as $k => $v) { if (!file_exists('../libraries/vendor/' . $k)) { $result['error'][] = " - Composer library \"{$k}\" is not loaded!"; } } } // sometimes we need to make sure we have functions available $func_per_extension = ['pgsql' => 'pg_connect']; // proceccing php extensions if (!empty($data['php']['extension'])) { foreach ($data['php']['extension'] as $k => $v) { if (isset($func_per_extension[$k]) && function_exists($func_per_extension[$k]) == false || !extension_loaded($k)) { $result['error'][] = " - PHP extension \"{$k}\" is not loaded!"; } } } // processing php ini settings if (!empty($data['php']['ini'])) { foreach ($data['php']['ini'] as $k => $v) { foreach ($v as $k2 => $v2) { $temp = ini_get($k . '.' . $k2); if (ini_get($k . '.' . $k2) != $v2) { $result['error'][] = " - PHP ini setting {$k}.{$k2} is \"{$temp}\", should be {$v2}!"; } } } } // processing apache modules if (!empty($data['apache']['module'])) { if (function_exists('apache_get_modules')) { $ext_have = array_map('strtolower', apache_get_modules()); } else { $temp = `apachectl -t -D DUMP_MODULES`; $ext_have = array_map('strtolower', explode("\n", $temp)); $temp = array(); foreach ($ext_have as $k => $v) { $temp[] = trim(str_replace(array('(shared)', '(static)'), '', $v)); } $ext_have = $temp; } foreach ($data['apache']['module'] as $k => $v) { if (!in_array($k, $ext_have)) { $result['error'][] = " - Apache module \"{$k}\" is not loaded!"; } } } // processing models if (!empty($data['model'])) { array_keys_to_string($data['model'], $data['model_processed']); } // processing imports, we need to sort them in order of dependencies $imports = []; foreach ($data['model_processed'] as $k => $v) { if ($v != 'object_import') { continue; } // find submodule foreach ($data['__model_dependencies'] as $k2 => $v2) { if (!empty($v2[$k])) { $imports[$k2][$k] = $k; break; } } } // clean up unused dependencies foreach ($data['__submodule_dependencies'] as $k2 => $v2) { if (empty($imports[$k2])) { $data['__submodule_dependencies'][$k2] = []; } else { foreach ($v2 as $k3 => $v3) { if (empty($imports[$k3])) { unset($data['__submodule_dependencies'][$k2][$k3]); } } } } // we need to go though an array few times to fix dependency issues for ($i = 0; $i < 3; $i++) { foreach ($imports as $k => $v) { if (empty($data['__submodule_dependencies'][$k])) { $data['model_import'][$k] = $v; // we need to remove file from dependency foreach ($data['__submodule_dependencies'] as $k2 => $v2) { unset($data['__submodule_dependencies'][$k2][$k]); } } } } foreach ($data['model_import'] as $k => $v) { foreach ($v as $k2 => $v2) { unset($data['model_processed'][$k2]); $data['model_processed'][$k2] = 'object_import'; } } unset($data['__submodule_dependencies'], $data['__model_dependencies'], $data['model_import']); // handling overrides, cleanup directory first helper_file::rmdir('./overrides/class', ['only_contents' => true, 'skip_files' => ['.gitkeep']]); $data['override'] = array_merge_hard($data['override'], $data['acl']); if (!empty($data['override'])) { array_keys_to_string($data['override'], $data['override_processed']); $override_classes = []; $override_found = false; foreach ($data['override_processed'] as $k => $v) { if (!isset($override_classes[$v])) { $override_classes[$v] = ['object' => new object_override_blank(), 'found' => false]; } $override_class = str_replace('.', '_', $k); $override_object = new $override_class(); $vars = get_object_vars($override_object); if (!empty($vars)) { $override_classes[$v]['found'] = true; $override_found = true; object_merge_values($override_classes[$v]['object'], $vars); } } // we need to write overrides to disk if ($override_found) { foreach ($override_classes as $k => $v) { if ($v['found']) { $class_code = "<?php\n\n" . '$object_override_blank_object = ' . var_export($v['object'], true) . ';'; helper_file::write('./overrides/class/override_' . $k . '.php', $class_code); } } } } // unit tests helper_file::rmdir('./overrides/unit_tests', ['only_contents' => true, 'skip_files' => ['.gitkeep']]); // submodule tests first if (!empty($data['unit_tests'])) { $xml = ''; $xml .= '<phpunit bootstrap="../../../libraries/vendor/numbers/framework/system/managers/unit_tests.php">'; $xml .= '<testsuites>'; foreach ($data['unit_tests'] as $k => $v) { $xml .= '<testsuite name="' . $k . '">'; foreach (helper_file::iterate($v, ['recursive' => true, 'only_extensions' => ['php']]) as $v2) { $xml .= '<file>../../' . $v2 . '</file>'; } $xml .= '</testsuite>'; } $xml .= '</testsuites>'; $xml .= '</phpunit>'; helper_file::write('./overrides/unit_tests/submodules.xml', $xml); } // application test last $application_tests = helper_file::iterate('misc/unit_tests', ['recursive' => true, 'only_extensions' => ['php']]); if (!empty($application_tests)) { $xml = ''; $xml .= '<phpunit bootstrap="../../../libraries/vendor/numbers/framework/system/managers/unit_tests.php">'; $xml .= '<testsuites>'; $xml .= '<testsuite name="application/unit/tests">'; foreach ($application_tests as $v) { $xml .= '<file>../../' . $v . '</file>'; } $xml .= '</testsuite>'; $xml .= '</testsuites>'; $xml .= '</phpunit>'; helper_file::write('./overrides/unit_tests/application.xml', $xml); } // updating composer.json file if ($options['mode'] == 'commit') { helper_file::write('../libraries/composer.json', json_encode($composer_data, JSON_PRETTY_PRINT)); } // assinging variables to return to the caller $result['data'] = $data; if (empty($result['error'])) { $result['success'] = true; } } while (0); return $result; }
/** * Get class object * * @param mixed $key * @return object */ public static function get($key) { return array_key_get(self::$class_objects, $key); }
/** * Render elements value * * @param array $options * @param mixed $value * @param array $neighbouring_values * @return string * @throws Exception */ public function render_element_value(&$options, $value = null, &$neighbouring_values = []) { // field name and values_key $options['options']['field_name'] = $options['options']['details_field_name'] ?? $options['options']['name']; $options['options']['field_values_key'] = implode('[::]', $options['options']['field_values_key'] ?? [$options['options']['field_name']]); // custom renderer if (!empty($options['options']['custom_renderer'])) { $method = factory::method($options['options']['custom_renderer'], null, true); $options_custom_renderer = $options; call_user_func_array($method, [&$this, &$options, &$value, &$neighbouring_values]); } // handling override_field_value method if (!empty($this->wrapper_methods['override_field_value']['main'])) { call_user_func_array($this->wrapper_methods['override_field_value']['main'], [&$this, &$options, &$value, &$neighbouring_values]); } $result_options = $options['options']; $options['options']['value'] = $value; array_key_extract_by_prefix($result_options, 'label_'); $element_expand = !empty($result_options['expand']); $html_suffix = $result_options['html_suffix'] ?? ''; // unset certain keys unset($result_options['order'], $result_options['required'], $result_options['html_suffix']); // processing options $flag_select_or_autocomplete = !empty($result_options['options_model']) || !empty($result_options['options']); if (!empty($result_options['options_model'])) { if (empty($result_options['options_params'])) { $result_options['options_params'] = []; } if (empty($result_options['options_options'])) { $result_options['options_options'] = []; } $result_options['options_options']['i18n'] = $result_options['options_options']['i18n'] ?? true; $result_options['options_options']['acl'] = $result_options['options_options']['acl'] ?? $this->acl; if (empty($result_options['options_depends'])) { $result_options['options_depends'] = []; } // options depends & params $this->process_params_and_depends($result_options['options_depends'], $neighbouring_values, $options, true); $this->process_params_and_depends($result_options['options_params'], $neighbouring_values, $options, false); $result_options['options_params'] = array_merge_hard($result_options['options_params'], $result_options['options_depends']); // we do not need options for autocomplete if (strpos($result_options['method'], 'autocomplete') === false) { $skip_values = []; if (!empty($options['options']['details_key'])) { if (!empty($options['options']['details_parent_key'])) { $temp_key = $options['options']['details_parent_key'] . '::' . $options['options']['details_key']; if (!empty($this->misc_settings['details_unique_select'][$temp_key][$options['options']['details_field_name']][$options['options']['__parent_row_number']])) { $skip_values = array_keys($this->misc_settings['details_unique_select'][$temp_key][$options['options']['details_field_name']][$options['options']['__parent_row_number']]); } } else { if (!empty($this->misc_settings['details_unique_select'][$options['options']['details_key']][$options['options']['details_field_name']])) { $skip_values = array_keys($this->misc_settings['details_unique_select'][$options['options']['details_key']][$options['options']['details_field_name']]); } } } $result_options['options'] = object_data_common::process_options($result_options['options_model'], $this, $result_options['options_params'], $value, $skip_values, $result_options['options_options']); } else { // we need to inject form id into autocomplete $result_options['form_id'] = "form_{$this->form_link}_form"; } } // by default all selects are searchable if not specified otherwise if ($flag_select_or_autocomplete) { $result_options['searchable'] = $result_options['searchable'] ?? false; } // different handling for different type switch ($options['type']) { case 'container': $options_container = $options; //$options_container['previous_data'] = $v; // todo: pass $form_data_key from parent $options_container['previous_key'] = $options['previous_key']; // render container $temp_container_value = $this->render_container($data['fm_part_child_container_name'], $parents, $options_container); if (!empty($html_expand)) { // get part id $temp_id = $this->id('part_details', ['part_name' => $data['fm_part_name'], 'part_id' => $options_container['previous_id']]); $temp_id_div_inner = $temp_id . '_html_expand_div_inner'; $temp_expand_div_inner = ['id' => $temp_id_div_inner, 'style' => 'display: none;', 'value' => $temp_container_value]; $temp_expand_div_a = ['href' => 'javascript:void(0);', 'onclick' => "numbers.element.toggle('{$temp_id_div_inner}');", 'value' => '+ / -']; $temp_expand_div_outer = ['align' => 'left', 'value' => html::a($temp_expand_div_a) . '<br />' . html::div($temp_expand_div_inner)]; $value = html::div($temp_expand_div_outer); } else { $value = $temp_container_value; } $result_options['value'] = $value; break; case 'field': $element_method = $result_options['method'] ?? 'html::input'; if (strpos($element_method, '::') === false) { $element_method = 'html::' . $element_method; } // value in special order $flag_translated = false; if (in_array($element_method, ['html::a', 'html::submit', 'html::button', 'html::button2'])) { // translate value $result_options['value'] = i18n($result_options['i18n'] ?? null, $result_options['value'] ?? null); // process confirm_message $result_options['onclick'] = $result_options['onclick'] ?? ''; if (!empty($result_options['confirm_message'])) { $result_options['onclick'] .= 'return confirm(\'' . strip_tags(i18n(null, $result_options['confirm_message'])) . '\');'; } // processing onclick for buttons if (in_array($element_method, ['html::submit', 'html::button', 'html::button2'])) { if (!empty($result_options['onclick']) && strpos($result_options['onclick'], 'this.form.submit();') !== false) { $result_options['onclick'] = str_replace('this.form.submit();', "numbers.form.trigger_submit(this.form);", $result_options['onclick']) . ' return true;'; } else { if (empty($result_options['onclick'])) { $result_options['onclick'] .= 'numbers.form.trigger_submit_on_button(this); return true;'; } else { $result_options['onclick'] = 'numbers.form.trigger_submit_on_button(this); ' . $result_options['onclick']; } } } $flag_translated = true; // icon if (!empty($result_options['icon'])) { $result_options['value'] = html::icon(['type' => $result_options['icon']]) . ' ' . $result_options['value']; } // accesskey if (isset($result_options['accesskey'])) { $accesskey = explode('::', i18n(null, 'accesskey::' . $result_options['name'] . '::' . $result_options['accesskey'], ['skip_translation_symbol' => true])); $result_options['accesskey'] = $accesskey[2]; $result_options['title'] = ($result_options['title'] ?? '') . ' ' . i18n(null, 'Shortcut Key: ') . $accesskey[2]; } } else { if (in_array($element_method, ['html::div', 'html::span'])) { if (!empty($result_options['i18n'])) { $result_options['value'] = i18n($result_options['i18n'] ?? null, $result_options['value'] ?? null); $flag_translated = true; } } else { // editable fields $result_options['value'] = $value; // if we need to empty value, mostly for password fields if (!empty($result_options['empty_value'])) { $result_options['value'] = ''; } // we need to empty zero integers and sequences, before format if (($result_options['php_type'] ?? '') == 'integer' && ($result_options['type'] ?? '') != 'boolean' && ($result_options['domain'] ?? '') != 'counter' && 'counter' && empty($result_options['value'])) { $result_options['value'] = ''; } // format, not for selects/autocompletes/presets if (!$flag_select_or_autocomplete) { if (!empty($result_options['format'])) { if (!empty($this->errors['fields'][$result_options['error_name']]) && empty($this->errors['formats'][$result_options['error_name']])) { // nothing } else { $result_options['format_options'] = $result_options['format_options'] ?? []; if (!empty($result_options['format_depends'])) { $this->process_params_and_depends($result_options['format_depends'], $neighbouring_values, $options, true); $result_options['format_options'] = array_merge_hard($result_options['format_options'], $result_options['format_depends']); } $method = factory::method($result_options['format'], 'format'); $result_options['value'] = call_user_func_array([$method[0], $method[1]], [$result_options['value'], $result_options['format_options']]); } } } // align if (!empty($result_options['align'])) { $result_options['style'] = ($result_options['style'] ?? '') . 'text-align:' . $result_options['align'] . ';'; } // processing persistent if (!empty($result_options['persistent']) && $this->values_loaded) { if ($result_options['persistent'] === 'if_set') { $original_value = $detail = array_key_get($this->original_values, $result_options['values_key']); if (!empty($original_value)) { $result_options['readonly'] = true; } } else { if (count($result_options['values_key']) == 1) { // parent record $result_options['readonly'] = true; } else { if (empty($result_options['__new_row'])) { // details $temp = $result_options['values_key']; array_pop($temp); $detail = array_key_get($this->original_values, $temp); if (!empty($detail)) { $result_options['readonly'] = true; } } } } } // maxlength if (in_array($result_options['type'] ?? '', ['char', 'varchar']) && !empty($result_options['length'])) { $result_options['maxlength'] = $result_options['length']; } // global readonly if (!empty($this->misc_settings['global']['readonly']) && empty($result_options['navigation'])) { $result_options['readonly'] = true; } // title if (isset($options['options']['label_name'])) { $result_options['title'] = ($result_options['title'] ?? '') . ' ' . strip_tags(i18n(null, $options['options']['label_name'])); } } } // translate place holder if (array_key_exists('placeholder', $result_options)) { if (!empty($result_options['placeholder'])) { $result_options['placeholder'] = strip_tags(i18n(null, $result_options['placeholder'])); } } else { if (!empty($result_options['validator_method']) && empty($result_options['value'])) { $temp = object_validator_base::method($result_options['validator_method'], $result_options['value'], $result_options['validator_params'] ?? [], $options['options'], $neighbouring_values); if ($flag_select_or_autocomplete) { $placeholder = $temp['placeholder_select']; } else { $placeholder = $temp['placeholder']; } if (!empty($placeholder)) { $result_options['placeholder'] = strip_tags(i18n(null, $placeholder)); } } } // events foreach (numbers_frontend_html_class_html5::$events as $e) { if (!empty($result_options['readonly'])) { // important - readonly emenets cannot have events unset($result_options[$e]); } else { if (!empty($result_options[$e])) { $result_options[$e] = str_replace('this.form.submit();', 'numbers.form.trigger_submit(this);', $result_options[$e]); $result_options[$e] = str_replace('this.form.extended.', $this->misc_settings['extended_js_class'] . '.', $result_options[$e]); } } } break; case 'html': $element_method = null; break; default: throw new Exception('Render detail type: ' . $data['fm_part_type']); } // handling html_method if (isset($element_method)) { $method = factory::method($element_method, 'html'); $field_method_object = factory::model($method[0], true); // todo: unset non html attributes $value = $field_method_object->{$method[1]}($result_options); // building navigation if (!empty($result_options['navigation'])) { $name = 'navigation[' . $result_options['name'] . ']'; $temp = '<table width="100%" dir="ltr">'; // always left to right $temp .= '<tr>'; $temp .= '<td width="1%">' . html::button2(['name' => $name . '[first]', 'value' => html::icon(['type' => 'step-backward']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'First')]) . '</td>'; $temp .= '<td width="1%"> </td>'; $temp .= '<td width="1%">' . html::button2(['name' => $name . '[previous]', 'value' => html::icon(['type' => 'caret-left']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'Previous')]) . '</td>'; $temp .= '<td width="1%"> </td>'; $temp .= '<td width="90%">' . $value . '</td>'; $temp .= '<td width="1%"> </td>'; $temp .= '<td width="1%">' . html::button2(['name' => $name . '[refresh]', 'value' => html::icon(['type' => 'refresh']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'Refresh')]) . '</td>'; $temp .= '<td width="1%"> </td>'; $temp .= '<td width="1%">' . html::button2(['name' => $name . '[next]', 'value' => html::icon(['type' => 'caret-right']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'Next')]) . '</td>'; $temp .= '<td width="1%"> </td>'; $temp .= '<td width="1%">' . html::button2(['name' => $name . '[last]', 'value' => html::icon(['type' => 'step-forward']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'Last')]) . '</td>'; $temp .= '</tr>'; $temp .= '</table>'; $value = $temp; } } // html suffix and prefix if (!empty($html_suffix)) { $value .= $html_suffix; } // if we need to display settings if (application::get('flag.numbers.frontend.html.form.show_field_settings')) { $id_original = $result_options['id'] . '__settings_original'; $id_modified = $result_options['id'] . '__settings_modified'; $value .= html::a(['href' => 'javascript:void(0);', 'onclick' => "\$('#{$id_original}').toggle();", 'value' => html::label2(['type' => 'primary', 'value' => count($options['options'])])]); $value .= html::a(['href' => 'javascript:void(0);', 'onclick' => "\$('#{$id_modified}').toggle();", 'value' => html::label2(['type' => 'warning', 'value' => count($result_options)])]); $value .= '<div id="' . $id_original . '" style="display:none; position: absolute; text-align: left; width: 500px; z-index: 32000;">' . print_r2($options['options'], true) . '</div>'; $value .= '<div id="' . $id_modified . '" style="display:none; position: absolute; text-align: left; width: 500px; z-index: 32000;">' . print_r2($result_options, true) . '</div>'; } // we need to put original options back if (!empty($options['options']['custom_renderer'])) { $options = $options_custom_renderer; } return $value; }
/** * Process import object * * @return array */ public function process() { $result = ['success' => false, 'error' => [], 'hint' => []]; if (empty($this->import_data)) { throw new Exception('You must pecify import_data parameter.'); } // if we have fixes to the data if (method_exists($this, 'overrides')) { $this->overrides(); } // initialize alias & crypt objects $alias_object = new object_data_aliases(); $alias_data = $alias_object->get(); $crypt = new crypt(); gc_enable(); // processing one by one foreach (array_keys($this->import_data) as $k) { // we continue if we have no rows if (count($this->import_data[$k]['data']) == 0) { continue; } // class and object $class = $this->import_data[$k]['options']['model']; $object = new $class(); // a short cut to skip updating large datasets if (!empty($this->import_data[$k]['options']['quick_pk_comparison'])) { // data from an array $groupped = []; foreach ($this->import_data[$k]['data'] as $k12 => $v12) { $keys = []; foreach ($this->import_data[$k]['options']['quick_pk_comparison'] as $v13) { $keys[] = $v12[$v13]; } $keys = implode('::', $keys); $temp = array_key_get($groupped, $keys); if (empty($temp)) { $temp = 0; } $temp++; array_key_set($groupped, $keys, $temp); } // get data from database $sql = "SELECT concat_ws('::', " . implode(', ', $this->import_data[$k]['options']['quick_pk_comparison']) . ") groupped, count(*) count FROM {$object->name} GROUP BY groupped"; $db = $object->db_object(); $result_compare = $db->query($sql); $groupped2 = []; foreach ($result_compare['rows'] as $v12) { $groupped2[$v12['groupped']] = $v12['count']; } // compare $discrepancies = false; foreach ($groupped as $k12 => $v12) { if (!isset($groupped2[$k12]) || $groupped2[$k12] != $v12) { $discrepancies = true; } } // we continue loop if there's no discrepancies if (!$discrepancies) { $result['hint'][] = ' * Skipping ' . $object->name . ', db link: ' . $object->db_link; continue; } } // if we need mass import $total_rows = count($this->import_data[$k]['data']); if ($total_rows >= self::mass_import_rows) { $db = $object->db_object(); $db->create_temp_table('temp_' . $object->name, $object->columns, $this->import_data[$k]['options']['pk'], ['skip_serials' => true]); } $counter = 0; $buffer = []; do { // grab first element from the array $v2 = array_shift($this->import_data[$k]['data']); // we need to process overrides foreach ($v2 as $k3 => $v3) { if (!is_string($v3)) { continue; } // if we need id if (strpos($v3, '~id~') === 0) { $value = substr($v3, 4); $alias = null; foreach ($alias_data as $k4 => $v4) { // todo: maybe need column prefix with alias if (strpos($k3, $k4) !== false) { $alias = $k4; } } $v2[$k3] = $alias_object->get_id_by_code($alias, substr($v3, 4)); continue; } // password if (strpos($v3, '~password~') === 0) { $v2[$k3] = $crypt->password_hash(substr($v3, 10)); } } // if we have multiple if (!empty($this->import_data[$k]['options']['multiple'])) { foreach ($v2[$this->import_data[$k]['options']['multiple'][0]] as $mv0) { $temp = $v2; $temp[$this->import_data[$k]['options']['multiple'][0]] = $mv0; if (!empty($this->import_data[$k]['options']['multiple'][1])) { foreach ($v2[$this->import_data[$k]['options']['multiple'][1]] as $mv1) { $temp[$this->import_data[$k]['options']['multiple'][1]] = $mv1; // todo: add third level } } $buffer[] = $temp; } } else { $buffer[] = $v2; } // if buffer has 100 rows or we have no data if (count($buffer) > 249 || count($buffer) > 0 && count($this->import_data[$k]['data']) == 0) { if ($total_rows >= self::mass_import_rows) { // insert all rows $result_insert = $db->insert('temp_' . $object->name, $buffer); if (!$result_insert['success']) { $result['error'] = $result_insert['error']; return $result; } $counter += count($buffer); // doing this might take some time echo "."; } else { // less than 1000 records foreach ($buffer as $v10) { switch ($this->import_data[$k]['options']['method'] ?? 'save') { case 'save_insert_new': $result_insert = $object->save($v10, ['pk' => $this->import_data[$k]['options']['pk'], 'flag_insert_only' => true, 'ignore_not_set_fields' => true]); break; case 'save': default: $result_insert = $object->save($v10, ['pk' => $this->import_data[$k]['options']['pk'], 'ignore_not_set_fields' => true]); } if (!$result_insert['success']) { $result['error'] = $result_insert['error']; return $result; } $counter++; } } $buffer = []; // free up memory gc_collect_cycles(); } } while (count($this->import_data[$k]['data']) > 0); // we need to run few queries for mass import if ($total_rows >= self::mass_import_rows) { $type = $this->import_data[$k]['options']['method'] ?? 'save'; $columns = []; $columns_mysql = []; $where = []; $where_mysql = []; $where_delete = []; $serials = false; foreach ($object->columns as $k12 => $v12) { if (in_array($k12, $this->import_data[$k]['options']['pk'])) { $where[] = "a.{$k12} = temp_{$object->name}.{$k12}"; $where_mysql[] = "{$object->name}.{$k12} = temp_{$object->name}.{$k12}"; $where_delete[] = "a.{$k12} = b.{$k12}"; } else { if (strpos($v12['type'], 'serial') !== false) { $serials = true; continue; } $columns[] = "{$k12} = temp_{$object->name}.{$k12}"; $columns_mysql[] = "{$object->name}.{$k12} = temp_{$object->name}.{$k12}"; } } if ($type == 'save') { // update existing rows if ($db->backend == 'pgsql') { $sql = "UPDATE {$object->name} AS a SET " . implode(', ', $columns) . " FROM temp_{$object->name} AS temp_{$object->name} WHERE " . implode(' AND ', $where); } else { $sql = "UPDATE {$object->name}, temp_{$object->name} SET " . implode(', ', $columns_mysql) . " WHERE " . implode(' AND ', $where_mysql); } $result_insert = $db->query($sql); if (!$result_insert['success']) { $result['error'] = $result_insert['error']; return $result; } } // delete existing rows if ($db->backend == 'pgsql') { $sql = "DELETE FROM temp_{$object->name} a WHERE EXISTS (SELECT 1 FROM {$object->name} b WHERE " . implode(' AND ', $where_delete) . ")"; } else { $sql = "DELETE FROM a USING temp_{$object->name} AS a INNER JOIN {$object->name} AS b WHERE " . implode(' AND ', $where_delete); } $result_insert = $db->query($sql); if (!$result_insert['success']) { $result['error'] = $result_insert['error']; return $result; } // we need to update serial columns if (!empty($serials)) { $columns = []; foreach ($object->columns as $k12 => $v12) { if (strpos($v12['type'], 'serial') !== false) { $columns[] = "{$k12} = nextval('{$object->name}_{$k12}_seq')"; } } $sql = "UPDATE temp_{$object->name} SET " . implode(', ', $columns); $result_insert = $db->query($sql); if (!$result_insert['success']) { $result['error'] = $result_insert['error']; return $result; } } // insert the rest of the rows $sql = "INSERT INTO {$object->name} SELECT * FROM temp_{$object->name}"; $result_insert = $db->query($sql); if (!$result_insert['success']) { $result['error'] = $result_insert['error']; return $result; } // drop temp table $sql = "DROP TABLE temp_{$object->name}"; $result_insert = $db->query($sql); if (!$result_insert['success']) { $result['error'] = $result_insert['error']; return $result; } } $result['hint'][] = ' * Imported ' . $counter . ' rows into ' . $object->name . ', db link: ' . $object->db_link; } $result['success'] = true; return $result; }
public function process($data, $options = []) { $temp = []; // we need to precess items that are controller and suboptions at the same time $subgroups = []; foreach ($data as $k => $v) { // determine acl if (!empty($v['sm_menuitm_acl_controller_id']) && !helper_acl::can_see_this_controller($v['sm_menuitm_acl_controller_id'], $v['sm_menuitm_acl_action_id'])) { unset($data[$k]); continue; } // go though each group for ($i = 1; $i <= 4; $i++) { if (!empty($v["g{$i}_code"])) { $subgroups[$v["g{$i}_code"]] = true; } } } $subgroup_items = []; foreach ($data as $k => $v) { if (isset($subgroups[$v['sm_menuitm_code']])) { $subgroup_items[$v['sm_menuitm_code']] = $v; unset($data[$k]); } } // loop though data foreach ($data as $k => $v) { // loop though groups and add them to menu $key = []; for ($i = 1; $i <= 4; $i++) { if (!empty($v['g' . $i . '_code'])) { $key[] = $v['g' . $i . '_code']; // we need to set all groups $temp2 = array_key_get($temp, $key); if (is_null($temp2)) { // if we have a controller that acts as submenu if (!empty($subgroup_items[$v['g' . $i . '_code']])) { $v9 = $subgroup_items[$v['g' . $i . '_code']]; array_key_set($temp, $key, ['code' => $v9['sm_menuitm_code'], 'name' => $v9['sm_menuitm_name'], 'name_extension' => null, 'icon' => $v9['sm_menuitm_icon'], 'url' => $v9['sm_menuitm_url'], 'order' => $v9['sm_menuitm_order'], 'options' => []]); } else { // if we do not have url we assume visitor wants to see extended menu if (empty($v['g' . $i . '_url'])) { $params = []; for ($j = 1; $j <= $i; $j++) { $params['group' . $j . '_code'] = $v['g' . $j . '_code']; } $v['g' . $i . '_url'] = '/numbers/backend/system/menu/controller/menu?' . http_build_query2($params); } array_key_set($temp, $key, ['code' => $v['g' . $i . '_code'], 'name' => $v['g' . $i . '_name'], 'icon' => $v['g' . $i . '_icon'], 'order' => $v['g' . $i . '_order'], 'url' => $v['g' . $i . '_url'], 'options' => []]); } } $key[] = 'options'; } } // some replaces $name_extension = null; if ($v['sm_menuitm_code'] == 'entites.authorization.__entity_name') { $name_extension = '<b>' . session::get(['numbers', 'entity', 'em_entity_name']) . '</b>'; } // finally we need to add menu item to the array $key[] = $v['sm_menuitm_code']; array_key_set($temp, $key, ['code' => $v['sm_menuitm_code'], 'name' => $v['sm_menuitm_name'], 'name_extension' => $name_extension, 'icon' => $v['sm_menuitm_icon'], 'url' => $v['sm_menuitm_url'], 'order' => $v['sm_menuitm_order'], 'options' => []]); // options generator if (!empty($v['sm_menuitm_options_generator'])) { $temp3 = explode('::', $v['sm_menuitm_options_generator']); $temp_data = factory::model($temp3[0])->{$temp3[1]}(); $temp_key = $key; $temp_key[] = 'options'; foreach ($temp_data as $k2 => $v2) { $temp_key2 = $temp_key; $temp_key2[] = $k2; array_key_set($temp, $temp_key2, $v2); } } } // sorting foreach ($temp as $k => $v) { if (!empty($v['options'])) { foreach ($v['options'] as $k2 => $v2) { if (!empty($v2['options'])) { foreach ($v2['options'] as $k3 => $v3) { if (!empty($v3['options'])) { foreach ($v3['options'] as $k4 => $v4) { if (!empty($v4['options'])) { array_key_sort($temp[$k]['options'][$k2]['options'][$k3]['options'][$k4]['options'], ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); } } array_key_sort($temp[$k]['options'][$k2]['options'][$k3]['options'], ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); } } array_key_sort($temp[$k]['options'][$k2]['options'], ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); } } array_key_sort($temp[$k]['options'], ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); } } // sort root array_key_sort($temp, ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); return $temp; }
/** * Get setting * * @param string $setting * @param string $property * @return mixed */ public static function get_setting($setting = null, $property = null) { $data = self::get_static(); $keys = []; if (isset($setting)) { $keys[] = $setting; if (isset($property)) { $keys[] = $property; } } return array_key_get($data, $keys); }
/** * Get session values * * @param type $key * @return type */ public function __get($key) { return array_key_get($_SESSION, $key); }