Beispiel #1
0
 /**
  * Initializing i18n
  *
  * @param array $options
  */
 public static function init($options = [])
 {
     $i18n = application::get('flag.global.i18n') ?? [];
     $i18n = array_merge_hard($i18n, $options ?? []);
     // determine final language
     $languages = factory::model('numbers_backend_i18n_languages_model_languages')->get();
     $final_language = application::get('flag.global.__language_code') ?? session::get('numbers.entity.format.language_code') ?? $i18n['language_code'] ?? 'sys';
     if (empty($languages[$final_language])) {
         $final_language = 'sys';
         $i18n['rtl'] = 0;
     }
     // put settings into system
     if (!empty($languages[$final_language])) {
         foreach ($languages[$final_language] as $k => $v) {
             $k = str_replace('lc_language_', '', $k);
             if (in_array($k, ['code', 'inactive'])) {
                 continue;
             }
             if (empty($v)) {
                 continue;
             }
             $i18n[$k] = $v;
         }
     }
     $i18n['language_code'] = $final_language;
     self::$options = $i18n;
     session::set('numbers.entity.format.language_code', $final_language);
     application::set('flag.global.i18n', $i18n);
     self::$initialized = true;
     // initialize the module
     return factory::submodule('flag.global.i18n.submodule')->init($i18n);
 }
 /**
  * Whether we can perform certain action
  *
  * @param mixed $action_code_or_id
  * @return boolean
  */
 public static function can($action_code_or_id)
 {
     if (self::$cache_actions === null) {
         self::$cache_actions = factory::model('numbers_backend_system_controller_model_actions')->get();
     }
     if (is_string($action_code_or_id)) {
         foreach (self::$cache_actions as $k => $v) {
             if ($v['sm_cntractn_code'] == $action_code_or_id) {
                 $action_code_or_id = $k;
                 break;
             }
         }
     }
     if (!isset(self::$cache_actions[$action_code_or_id])) {
         throw new Exception('Unknown action!');
     }
     $permissions = application::get(['controller', 'acl', 'permissions']);
     $start = $action_code_or_id;
     do {
         // see if we have permission
         if (empty($permissions[$start])) {
             break;
         }
         // we need to check permission on a parent
         if (!empty(self::$cache_actions[$start]['sm_cntractn_parent_id'])) {
             $start = self::$cache_actions[$start]['sm_cntractn_parent_id'];
         } else {
             // exit if there's no parent
             return true;
         }
     } while (1);
     return false;
 }
 /**
  * Process options
  *
  * @param string $model_and_method - model::method
  * @param object $existing_object
  * @param array $where
  * @param array $existing_values
  * @param array $skip_values
  * @param array $options
  * @return array
  */
 public static function process_options($model_and_method, $existing_object = null, $where = [], $existing_values = [], $skip_values = [], $options = [])
 {
     // put changes into options
     $options['where'] = array_merge_hard($options['where'] ?? [], $where);
     $options['existing_values'] = $existing_values;
     $options['skip_values'] = $skip_values;
     // see if we have cached version
     $hash = sha1($model_and_method . serialize($options));
     if (isset(self::$cached_options[$hash])) {
         return self::$cached_options[$hash];
     } else {
         $temp = explode('::', $model_and_method);
         if (count($temp) == 1) {
             $model = $temp[0];
             $method = 'options';
         } else {
             $model = $temp[0];
             $method = $temp[1];
         }
         if ($model == 'this' && !empty($existing_object)) {
             $object = $existing_object;
         } else {
             $object = factory::model($model, true);
         }
         self::$cached_options[$hash] = $object->{$method}($options);
         return self::$cached_options[$hash];
     }
 }
    public function query($options = [])
    {
        $model = factory::model($options['model']);
        $db = $model->db_object();
        $where = '';
        if (!empty($options['where'])) {
            $where = 'AND ' . $db->prepare_condition($options['where']);
        }
        $ts = $db->full_text_search_query($options['fields'], $options['search_text'] . '');
        $fields = $options['fields'];
        $sql_pk = '';
        // we automatically include main pk into a query
        if (!in_array($options['pk'], $options['fields'])) {
            // in_array($options['pk'], $model->pk) &&
            $fields[] = $options['pk'];
            // we need to include integer types to the query
            $temp = intval($options['search_text']);
            if ($model->columns[$options['pk']]['php_type'] == 'integer' && $temp != 0) {
                $sql_pk .= " OR {$options['pk']} = " . (int) $options['search_text'];
            }
        }
        $fields[] = $ts['rank'];
        $fields = implode(', ', $fields);
        $tmp = <<<TTT
\t\t\tSELECT
\t\t\t\t{$fields}
\t\t\tFROM [table[{$options['model']}]] a
\t\t\tWHERE 1=1
\t\t\t\t\t{$where}
\t\t\t\t\tAND (({$ts['where']}){$sql_pk})
\t\t\tORDER BY {$ts['orderby']} DESC, {$options['fields'][0]}
\t\t\tLIMIT 11
TTT;
        return $tmp;
    }
Beispiel #5
0
 /**
  * Call validator method
  *
  * @param string $method
  * @param array $params
  * @param array $options
  * @param array $neighbouring_values
  * @return array
  */
 public static function method($method, $value, $params = [], $options = [], $neighbouring_values = [])
 {
     $method = factory::method($method);
     $params = $params ?? [];
     $params['options'] = $options;
     $params['neighbouring_values'] = $neighbouring_values;
     return factory::model($method[0], true)->{$method[1]}($value, $params);
 }
 public function save(&$form)
 {
     $model = factory::model($form->options['other']['model']);
     $save = [$model->column_prefix . 'important' => !empty($form->values['important']) ? 1 : 0, $model->column_prefix . 'comment_value' => $form->values['comment'] . '', $model->column_prefix . 'who_entity_id' => session::get('numbers.entity.em_entity_id'), $model->column_prefix . 'inserted' => format::now('timestamp')];
     foreach ($form->options['other']['map'] as $k => $v) {
         $save[$v] = $form->options['other']['pk'][$k];
     }
     $save_result = $model->save($save, ['ignore_not_set_fields' => true]);
     if ($save_result['success']) {
         $form->error('success', 'Comment has been added successfully!');
     } else {
         $form->error('danger', 'Could not add comment!');
     }
 }
 public function query($options = [])
 {
     $model = factory::model($options['model']);
     $db = $model->db_object();
     $where = null;
     if (!empty($options['where'])) {
         $where = 'AND ' . $db->prepare_condition($options['where']);
     }
     $columns = [];
     foreach ($model->columns as $k => $v) {
         $columns[] = 'a.' . $k . ' ' . str_replace($model->column_prefix, '', $k);
     }
     return "SELECT " . implode(', ', $columns) . ", b.em_entity_name FROM [table[{$options['model']}]] a LEFT JOIN [table[numbers_data_entities_entities_model_entities]] b ON a.{$model->column_prefix}who_entity_id = b.em_entity_id WHERE 1=1 {$where} ORDER BY {$model->column_prefix}inserted DESC";
 }
Beispiel #8
0
    public function query($options = [])
    {
        $where = null;
        if (!empty($options['where'])) {
            $model = factory::model($options['model']);
            $db = $model->db_object();
            $where = 'AND ' . $db->prepare_condition($options['where']);
        }
        return <<<TTT
\t\t\tSELECT
\t\t\t\tCOUNT(*) count
\t\t\tFROM [table[{$options['model']}]] a
\t\t\tWHERE 1=1
\t\t\t\t{$where}
TTT;
    }
 public function query($options = [])
 {
     $model = factory::model($options['model'], true);
     $this->db_object = $model->db_object;
     $column = $options['where']['column_name'];
     // adjust type based on value
     $where = null;
     if (empty($options['where']['column_value'])) {
         if ($options['type'] == 'previous') {
             $options['type'] = 'first';
         }
         if ($options['type'] == 'next') {
             $options['type'] = 'last';
         }
     } else {
         if ($options['type'] == 'previous') {
             $where = ' AND ' . $this->db_object->prepare_condition(["{$column},<" => $options['where']['column_value']]);
         } else {
             if ($options['type'] == 'next') {
                 $where = ' AND ' . $this->db_object->prepare_condition(["{$column},>" => $options['where']['column_value']]);
             } else {
                 if ($options['type'] == 'refresh') {
                     $where = ' AND ' . $this->db_object->prepare_condition(["{$column}" => $options['where']['column_value']]);
                 }
             }
         }
     }
     $depends = null;
     if (!empty($options['where']['depends'])) {
         $depends = ' AND (' . $this->db_object->prepare_condition($options['where']['depends']) . ')';
     }
     $pk = implode(', ', $options['pk']);
     // generate query based on type
     switch ($options['type']) {
         case 'first':
             return "SELECT {$pk} FROM {$model->name} WHERE {$column} = (SELECT MIN({$column}) new_value FROM {$model->name} WHERE {$column} IS NOT NULL {$depends}) {$depends}";
         case 'previous':
             return "SELECT {$pk} FROM {$model->name} WHERE 1=1 {$where} {$depends} ORDER BY {$column} DESC LIMIT 1";
         case 'next':
             return "SELECT {$pk} FROM {$model->name} WHERE 1=1 {$where} {$depends} ORDER BY {$column} ASC LIMIT 1";
         case 'last':
             return "SELECT {$pk} FROM {$model->name} WHERE {$column} = (SELECT MAX({$column}) new_value FROM {$model->name} WHERE {$column} IS NOT NULL {$depends}) {$depends}";
         case 'refresh':
         default:
             return "SELECT {$pk} FROM {$model->name} WHERE 1=1 {$where} {$depends}";
     }
 }
Beispiel #10
0
    public function query($options = [])
    {
        $model = factory::model($options['model']);
        $db = $model->db_object();
        $where = '';
        if (!empty($options['where'])) {
            $where = 'AND ' . $db->prepare_condition($options['where']);
        }
        $fields = $options['fields'];
        if (!in_array($options['pk'], $options['fields'])) {
            $fields[] = $options['pk'];
        }
        $fields = implode(', ', $fields);
        return <<<TTT
\t\t\tSELECT
\t\t\t\t{$fields}
\t\t\tFROM [table[{$options['model']}]] a
\t\t\tWHERE 1=1
\t\t\t\t\t{$where}
TTT;
    }
Beispiel #11
0
    /**
     * Destroy
     */
    public static function destroy()
    {
        if (empty(self::$missing)) {
            return;
        }
        //if (!chance(10)) return;
        // we would create temp table
        $db = factory::model('numbers_backend_i18n_basic_model_missing')->db_object();
        $db->query("CREATE TEMPORARY TABLE temp_translations (sys text, counter integer, lang text)");
        // insert data
        $data = [];
        foreach (self::$missing as $k => $v) {
            $data[] = ['sys' => $k, 'counter' => $v, 'lang' => self::$language_code];
        }
        $db->insert('temp_translations', $data);
        // merge data
        $sql = <<<TTT
\t\t\tINSERT INTO lc_missing (
\t\t\t\tlc_missing_id,
\t\t\t\tlc_missing_language_code,
\t\t\t\tlc_missing_text_sys, 
\t\t\t\tlc_missing_counter
\t\t\t)
\t\t\tSELECT
\t\t\t\tnextval('lc_missing_lc_missing_id_seq'),
\t\t\t\tlang lc_missing_language_code,
\t\t\t\tsys lc_missing_text_sys,
\t\t\t\t0 lc_missing_counter
\t\t\tFROM temp_translations a
\t\t\tLEFT JOIN lc_translations b ON a.sys = b.lc_translation_text_sys AND a.lang = b.lc_translation_language_code
\t\t\tLEFT JOIN lc_missing c ON a.sys = c.lc_missing_text_sys AND a.lang = c.lc_missing_language_code
\t\t\tWHERE b.lc_translation_language_code IS NULL AND c.lc_missing_language_code IS NULL
TTT;
        $db->query($sql);
        // last step perform update
        $sql = "UPDATE lc_missing a SET lc_missing_counter = lc_missing_counter + coalesce((SELECT counter FROM temp_translations b WHERE b.sys = a.lc_missing_text_sys AND b.lang = a.lc_missing_language_code), 0)";
        $db->query($sql);
    }
Beispiel #12
0
 /**
  * Initialize
  * 
  * @param array $options
  */
 public static function init($options = [])
 {
     // default options
     self::$defaut_options = ['language_code' => 'sys', 'locale' => 'en_CA.UTF-8', 'timezone' => 'America/Toronto', 'server_timezone' => application::get('php.date.timezone'), 'date' => 'Y-m-d', 'time' => 'H:i:s', 'datetime' => 'Y-m-d H:i:s', 'timestamp' => 'Y-m-d H:i:s.u', 'amount_frm' => 20, 'amount_fs' => 40, 'settings' => ['currency_codes' => []], 'locale_locales' => [], 'locale_locale_js' => null, 'locale_set_name' => null, 'locale_options' => [], 'locale_override_class' => null];
     // settings from config files
     $config = application::get('flag.global.format');
     // settings from user account
     $entity = entity::groupped('format');
     // merge all of them together
     self::$options = array_merge_hard(self::$defaut_options, $config, i18n::$options, $entity, $options);
     // fix utf8
     self::$options['locale'] = str_replace(['utf8', 'utf-8'], 'UTF-8', self::$options['locale']);
     // generate a list of available locales
     $locale_settings = self::set_locale(self::$options['locale'], self::$defaut_options['locale']);
     self::$options = array_merge_hard(self::$options, $locale_settings);
     // fix values
     self::$options['amount_frm'] = (int) self::$options['amount_frm'];
     self::$options['amount_fs'] = (int) self::$options['amount_fs'];
     self::$options['locale_options']['mon_thousands_sep'] = self::$options['locale_options']['mon_thousands_sep'] ?? ',';
     self::$options['locale_options']['mon_decimal_point'] = self::$options['locale_options']['mon_decimal_point'] ?? '.';
     if (empty(self::$options['locale_options']['mon_grouping'])) {
         self::$options['locale_options']['mon_grouping'] = [3, 3];
     }
     // load data from models
     if (!empty(self::$options['model'])) {
         foreach (self::$options['model'] as $k => $v) {
             $method = factory::method($v, null);
             self::$options['settings'][$k] = factory::model($method[0], true)->{$method[1]}();
         }
         unset(self::$options['model']);
     }
     // push js format version to frontend
     if (!empty(self::$options['locale_override_class'])) {
         $locale_override_class = self::$options['locale_override_class'];
         $locale_override_class::js();
     }
 }
Beispiel #13
0
    public function query($options = [])
    {
        $where = null;
        if (!empty($options['where'])) {
            $model = factory::model($options['model']);
            $db = $model->db_object();
            $where = 'AND ' . $db->prepare_condition($options['where']);
        }
        if (!empty($options['orderby']['full_text_search']) && !empty($options['where']['full_text_search,fts'])) {
            $temp = [];
            foreach ($options['orderby'] as $k => $v) {
                if ($k != 'full_text_search') {
                    $temp[$k] = $v;
                } else {
                    $model = factory::model($options['model']);
                    $db = $model->db_object();
                    $temp2 = $db->full_text_search_query($options['where']['full_text_search,fts']['fields'], $options['where']['full_text_search,fts']['str']);
                    $temp[$temp2['orderby']] = $v;
                }
            }
            $options['orderby'] = $temp;
        } else {
            unset($options['orderby']['full_text_search']);
        }
        $options['orderby'] = !empty($options['orderby']) ? 'ORDER BY ' . array_key_sort_prepare_keys($options['orderby'], true) : '';
        return <<<TTT
\t\t\tSELECT
\t\t\t\t*
\t\t\tFROM [table[{$options['model']}]] a
\t\t\tWHERE 1=1
\t\t\t\t{$where}
\t\t\t{$options['orderby']}
\t\t\tLIMIT {$options['limit']}
\t\t\tOFFSET {$options['offset']}
TTT;
    }
Beispiel #14
0
 /**
  * Format filter string as human readable
  *
  * @param object $object
  * @return array
  */
 public static function human($object)
 {
     $input = $object->options['input'];
     $filter = $object->filter;
     $full_text_search = $filter['full_text_search'] ?? null;
     unset($filter['full_text_search']);
     // generate values
     $result = [];
     foreach ($filter as $k => $v) {
         if (!empty($v['range'])) {
             $start = object_table_columns::process_single_column($k, $v, $input['filter'] ?? [], ['process_domains' => true, 'ignore_defaults' => true, 'ignore_not_set_fields' => true]);
             $end = object_table_columns::process_single_column($k . '2', $v, $input['filter'] ?? [], ['process_domains' => true, 'ignore_defaults' => true, 'ignore_not_set_fields' => true]);
             $result[i18n(null, $v['name'])] = '(' . ($start[$k] ?? null) . ') - (' . ($end[$k . '2'] ?? null) . ')';
         } else {
             $start = object_table_columns::process_single_column($k, $v, $input['filter'] ?? [], ['process_domains' => true, 'ignore_defaults' => true, 'ignore_not_set_fields' => true]);
             // we need to process arrays
             if (isset($start[$k]) && is_array($start[$k])) {
                 if (!empty($v['options_model'])) {
                     $params = $v['options_params'] ?? [];
                     $start[$k] = array_options_to_string(factory::model($v['options_model'])->options(['where' => $params, 'i18n' => true]), $start[$k]);
                 } else {
                     $start[$k] = implode(', ', $start[$k]);
                 }
             }
             $result[i18n(null, $v['name'])] = $start[$k] ?? null;
         }
     }
     // full text search
     if (!empty($full_text_search)) {
         $names = [];
         foreach ($full_text_search as $v) {
             $names[] = i18n(null, $filter[$v]['name']);
         }
         $result[i18n(null, 'Text Search')] = ($input['filter']['full_text_search'] ?? null) . ' (' . implode(', ', $names) . ')';
     }
     return $result;
 }
Beispiel #15
0
 /**
  * Create temporary table
  *
  * @param string $table
  * @param array $columns
  * @param array $pk
  * @param array $options
  *		skip_serials
  * @return array
  */
 public function create_temp_table($table, $columns, $pk = null, $options = [])
 {
     $ddl_object = factory::model(str_replace('_base_123', '_ddl', get_called_class() . '_123'));
     $columns_sql = [];
     foreach ($columns as $k => $v) {
         $temp = $ddl_object->is_column_type_supported($v, $table);
         // default
         $default = $temp['column']['default'] ?? null;
         if (is_string($default) && $default != 'now()') {
             $default = "'" . $default . "'";
         }
         // we need to cancel serial types
         if (!empty($options['skip_serials']) && strpos($temp['column']['type_original'] ?? $temp['column']['type'], 'serial') !== false) {
             $default = 0;
         }
         $columns_sql[] = $k . ' ' . $temp['column']['type'] . ($default !== null ? ' DEFAULT ' . $default : '') . (!($temp['column']['null'] ?? false) ? ' NOT NULL' : '');
     }
     // pk
     if ($pk) {
         $columns_sql[] = "PRIMARY KEY (" . implode(', ', $pk) . ")";
     }
     $columns_sql = implode(', ', $columns_sql);
     $sql = "CREATE TEMPORARY TABLE {$table} ({$columns_sql})";
     return $this->query($sql);
 }
 /**
  * Compare single row
  *
  * @param array $data_row
  * @param array $original_row
  * @param array $collection
  * @param array $options
  * @param array $parent_pk
  * @param array $parent_row
  * @return array
  */
 public final function compare_one_row($data_row, $original_row, $collection, $options, $parent_pk = null, $parent_row = [])
 {
     $result = ['success' => false, 'error' => [], 'data' => ['history' => [], 'audit' => [], 'total' => 0, 'updated' => false, 'deleted' => false, 'inserted' => false], 'new_serials' => []];
     $model = $collection['model_object'];
     // important to reset cache
     $model->reset_cache();
     // step 1, clenup data
     $data_row_final = $data_row;
     // we need to manualy inject parents keys
     if (!empty($parent_pk)) {
         foreach ($collection['map'] as $k => $v) {
             // if we are dealing with relations
             if (strpos($k, 'relation_id') !== false) {
                 $data_row_final[$v] = $parent_row[$k];
             } else {
                 $data_row_final[$v] = $parent_pk[$k];
             }
         }
     }
     $model->process_columns($data_row_final, ['ignore_not_set_fields' => true, 'skip_type_validation' => true]);
     // step 2 process row
     $delete = $update = $audit = $audit_details = $pk = [];
     $action = null;
     if (!empty($options['flag_delete_row']) || empty($data_row)) {
         // if we delete
         // if we have data
         if (!empty($original_row)) {
             $pk = extract_keys($collection['pk'], $original_row);
             $delete = ['table' => $model->name, 'pk' => $pk];
             // audit
             $action = 'delete';
             $audit = $original_row;
         }
     } else {
         if (empty($original_row)) {
             // if we insert
             // process who columns
             $model->process_who_columns(['inserted', 'optimistic_lock'], $data_row_final, $this->timestamp);
             // handle serial types
             foreach ($model->columns as $k => $v) {
                 if (strpos($v['type'], 'serial') !== false && empty($v['null'])) {
                     $temp = $this->primary_model->db_object->sequence($model->name . '_' . $k . '_seq');
                     $result['new_serials'][$k] = $data_row_final[$k] = $temp['rows'][0]['counter'];
                 }
             }
             $temp = $this->primary_model->db_object->insert($model->name, [$data_row_final], null);
             if (!$temp['success']) {
                 $result['error'] = $temp['error'];
                 return $result;
             }
             $result['data']['total']++;
             // flag for main record
             if (!empty($options['flag_main_record'])) {
                 $result['data']['inserted'] = true;
             }
             // pk
             $pk = extract_keys($collection['pk'], $data_row_final);
             // audit
             $action = 'insert';
             $audit = $data_row_final;
         } else {
             // if we update
             foreach ($data_row_final as $k => $v) {
                 // hard comparison
                 if ($v !== $original_row[$k]) {
                     $update[$k] = $v;
                 }
                 if (in_array($k, $collection['pk'])) {
                     $pk[$k] = $v;
                 }
             }
             // audit
             $action = 'update';
         }
     }
     // step 3 process details
     if (!empty($collection['details'])) {
         foreach ($collection['details'] as $k => $v) {
             // create new object
             $v['model_object'] = factory::model($k, true);
             if ($v['type'] == '11') {
                 $details_result = $this->compare_one_row($data_row[$k] ?? [], $original_row[$k] ?? [], $v, ['flag_delete_row' => !empty($delete)], $pk, $data_row_final);
                 if (!empty($details_result['error'])) {
                     $result['error'] = $details_result['error'];
                     return $result;
                 } else {
                     $result['data']['total'] += $details_result['data']['total'];
                 }
                 // audit
                 if (!empty($details_result['data']['audit'])) {
                     $audit_details[$k] = $details_result['data']['audit'];
                 }
             } else {
                 if ($v['type'] == '1M') {
                     $keys = [];
                     if (isset($original_row[$k]) && is_array($original_row[$k])) {
                         $keys = array_keys($original_row[$k]);
                     }
                     if (isset($data_row[$k]) && is_array($data_row[$k])) {
                         $keys = array_merge($keys, array_keys($data_row[$k]));
                     }
                     $keys = array_unique($keys);
                     if (!empty($keys)) {
                         foreach ($keys as $v2) {
                             $details_result = $this->compare_one_row($data_row[$k][$v2] ?? [], $original_row[$k][$v2] ?? [], $v, ['flag_delete_row' => !empty($delete)], $pk, $data_row_final);
                             if (!empty($details_result['error'])) {
                                 $result['error'] = $details_result['error'];
                                 return $result;
                             } else {
                                 $result['data']['total'] += $details_result['data']['total'];
                             }
                             // audit
                             if (!empty($details_result['data']['audit'])) {
                                 $audit_details[$k][$v2] = $details_result['data']['audit'];
                             }
                         }
                     }
                 }
             }
         }
     }
     // step 4 update record
     if (!empty($update) || $action == 'update' && $result['data']['total'] > 0) {
         // process who columns
         $model->process_who_columns(['updated', 'optimistic_lock'], $update, $this->timestamp);
         if (!empty($update)) {
             // update record
             $temp = $this->primary_model->db_object->update($model->name, $update, [], ['where' => $pk]);
             if (!$temp['success']) {
                 $result['error'] = $temp['error'];
                 return $result;
             }
             $result['data']['total']++;
         }
         // flag for main record
         if (!empty($options['flag_main_record'])) {
             $result['data']['updated'] = true;
         }
         // audit
         $audit = $update;
     }
     // step 5 delete record after we deleted all childrens
     if (!empty($delete)) {
         $temp = $this->primary_model->db_object->delete($delete['table'], [], [], ['where' => $delete['pk']]);
         if (!$temp['success']) {
             $result['error'] = $temp['error'];
             return $result;
         }
         $result['data']['total']++;
         // flag for main record
         if (!empty($options['flag_main_record'])) {
             $result['data']['deleted'] = true;
         }
     }
     // step 6 history only if we updated or deleted
     if ($model->history && (!empty($delete) || !empty($update))) {
         $temp = $original_row;
         $model->process_who_columns(['updated'], $temp, $this->timestamp);
         $result['data']['history'][$model->history_name][] = $temp;
     }
     // step 7 audit
     if ($this->primary_model->audit && !empty($audit)) {
         $result['data']['audit'] = ['action' => $action, 'pk' => $pk, 'columns' => []];
         foreach ($audit as $k => $v) {
             $old = $original_row[$k] ?? null;
             if ($v !== $old) {
                 if (($model->columns[$k]['domain'] ?? '') == 'password') {
                     $v = '*** *** ***';
                 }
                 $result['data']['audit']['columns'][$k] = [$v, $old];
             }
         }
         // details
         if (!empty($audit_details)) {
             $result['data']['audit']['details'] = $audit_details;
         }
     }
     // success
     if (!empty($result['data']['total'])) {
         $result['success'] = true;
     }
     return $result;
 }
    /**
     * Validate multiple options/autocompletes at the same time
     *
     * @param array $options
     * @return array
     */
    public function validate_options_multiple($options = [])
    {
        $result = ['success' => false, 'error' => [], 'discrepancies' => []];
        $mass_sql = [];
        foreach ($options as $k => $v) {
            $model = factory::model($v['model'], true);
            $values = [$v['field'] => $v['values']];
            $where2 = [];
            // values and options_active
            $temp2 = [];
            $temp2[] = $model->db_object->prepare_condition($values, 'AND');
            if (!empty($v['options_active'])) {
                $temp2[] = $model->db_object->prepare_condition($v['options_active'], 'AND');
            }
            $where2[] = '(' . implode(' OR ', $temp2) . ')';
            // processing existing values
            if (!empty($v['existing_values'])) {
                $existing_values = [$v['field'] => $v['existing_values']];
                $where2[] = $model->db_object->prepare_condition($existing_values, 'AND');
            }
            //print_r2($where2);
            // params must be there
            $where3 = $model->db_object->prepare_condition($v['params'], 'AND');
            if (empty($where3)) {
                $where3 = '1=1';
            }
            $where = '((' . $where3 . ') AND (' . implode(' OR ', $where2) . '))';
            //$where = $this->db_object->prepare_condition(array_merge_hard($v['params'] ?? [], $temp), 'AND');
            $fields = "concat_ws('', " . implode(', ', array_keys($values)) . ")";
            $mass_sql[] = <<<TTT
\t\t\t\tSELECT
\t\t\t\t\t'{$k}' validate_name,
\t\t\t\t\t{$fields} validate_value
\t\t\t\tFROM {$model->name}
\t\t\t\tWHERE 1=1
\t\t\t\t\tAND {$where}
TTT;
        }
        $mass_sql = implode("\n\nUNION ALL\n\n", $mass_sql);
        $temp = $model->db_object->query($mass_sql);
        if ($temp['success']) {
            // generate array of unique values
            $unique = [];
            foreach ($temp['rows'] as $k => $v) {
                if (!isset($unique[$v['validate_name']])) {
                    $unique[$v['validate_name']] = [];
                }
                $unique[$v['validate_name']][] = $v['validate_value'];
            }
            // find differencies
            foreach ($options as $k => $v) {
                // see if we found values
                if (!isset($unique[$k])) {
                    $result['discrepancies'][$k] = count($v['values']);
                } else {
                    foreach ($v['values'] as $v2) {
                        if (!in_array($v2 . '', $unique[$k])) {
                            if (!isset($result['discrepancies'][$k])) {
                                $result['discrepancies'][$k] = 0;
                            }
                            $result['discrepancies'][$k]++;
                        }
                    }
                }
            }
            $result['success'] = true;
        }
        return $result;
    }
Beispiel #18
0
 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;
 }
 /**
  * Convert method string to an array for future execution
  *
  * @param string $method
  * @param string $base_class
  * @return array
  */
 public static function method($method, $base_class = null, $model = false)
 {
     $temp = explode('::', $method);
     if (count($temp) > 1) {
         $temp_model = $temp[0];
         $temp_method = $temp[1];
     } else {
         $temp_model = $base_class;
         $temp_method = $temp[0];
     }
     if ($model) {
         $temp_model = factory::model($temp_model, true);
     }
     return [&$temp_model, $temp_method];
 }
Beispiel #20
0
 /**
  * Constructor
  *
  * @param array $options
  *		input - form input
  *		form - form options
  *		segment - segment options
  *			type
  *			header
  *			footer
  */
 public function __construct($options = [])
 {
     // we need to handle overrrides
     parent::override_handle($this);
     // step 0: apply data fixes
     if (method_exists($this, 'overrides')) {
         $this->overrides($this);
     }
     // we need to merge override input
     if (!empty($this->values)) {
         $options['input'] = array_merge_hard($options['input'] ?? [], $this->values);
     }
     if (isset($options['form_link'])) {
         $this->form_link = $options['form_link'];
     }
     // step 1: create form object
     $this->form_object = new numbers_frontend_html_form_base($this->form_link, array_merge_hard($this->options, $options));
     // class
     $this->form_object->form_class = get_called_class();
     $this->form_object->form_parent =& $this;
     $this->form_object->acl = $this->acl;
     // add collection
     $this->form_object->collection = $this->collection;
     $this->form_object->preload_collection_object();
     // must initialize it before calls to container/row/element
     $this->form_object->column_prefix = $this->column_prefix ?? $this->form_object->collection_object->primary_model->column_prefix ?? null;
     // master object
     if (!empty($this->master_options['model'])) {
         $this->master_options['type'] = $this->master_options['type'] ?? '';
         $this->master_options['ledger'] = strtoupper($this->master_options['ledger']) ?? '';
         $this->form_object->master_options = $this->master_options;
         $this->form_object->master_object = factory::model($this->master_options['model'], true);
     }
     // title
     if (!empty($this->title)) {
         $this->form_object->title = $this->title;
     } else {
         // we generate a title based on class name
         $temp = explode('_model_form_', get_called_class());
         $temp = explode('_', $temp[1]);
         $this->title = $this->form_object->title = ucwords(implode(' ', $temp));
     }
     // step 2: create all containers
     foreach ($this->containers as $k => $v) {
         if ($v === null) {
             continue;
         }
         $this->form_object->container($k, $v);
     }
     // step 3: create all rows
     foreach ($this->rows as $k => $v) {
         foreach ($v as $k2 => $v2) {
             if ($v2 === null) {
                 continue;
             }
             $this->form_object->row($k, $k2, $v2);
         }
     }
     // step 3: create all elements
     foreach ($this->elements as $k => $v) {
         foreach ($v as $k2 => $v2) {
             foreach ($v2 as $k3 => $v3) {
                 if ($v3 === null) {
                     continue;
                 }
                 $this->form_object->element($k, $k2, $k3, $v3);
             }
         }
     }
     // step 3: methods
     foreach (['save', 'validate', 'refresh', 'success', 'pre_render', 'override_field_value', 'override_tabs', 'process_default_value'] as $v) {
         if (method_exists($this, $v)) {
             $this->form_object->wrapper_methods[$v]['main'] = [&$this, $v];
         }
     }
     // extensions can have their own verify methods
     if (!empty($this->wrapper_methods)) {
         foreach ($this->wrapper_methods as $k => $v) {
             $index = 1;
             foreach ($v as $k2 => $v2) {
                 $this->form_object->wrapper_methods[$k][$index] = [new $k2(), $v2];
                 $index++;
             }
         }
     }
     // last step: process form
     if (empty($options['skip_processing'])) {
         $this->form_object->process();
     }
 }
Beispiel #21
0
 /**
  * Render pagination
  *
  * @param object $object
  * @return string
  */
 public function render($object, $type)
 {
     // fetched
     $fetched = i18n(null, 'Fetched') . ': ' . i18n(null, $object->num_rows) . ($object->total > 0 ? ' ' . i18n(null, 'of') . ' ' . i18n(null, $object->total) : '');
     // sorting
     $sort = '';
     if (!empty($object->orderby)) {
         $sort .= i18n(null, 'Sort') . ': ';
         $temp = [];
         foreach ($object->orderby as $k => $v) {
             if ($k == 'full_text_search') {
                 $temp[] = i18n(null, 'Text Search') . ' ' . html::icon(['type' => 'sort-alpha-' . ($v == SORT_ASC ? 'asc' : 'desc')]);
             } else {
                 $temp[] = i18n(null, $object->columns[$k]['name']) . ' ' . html::icon(['type' => 'sort-alpha-' . ($v == SORT_ASC ? 'asc' : 'desc')]);
             }
         }
         $sort .= implode(', ', $temp);
     }
     // displaying
     $displaying = i18n(null, 'Displaying') . ' ';
     $displaying .= '<div style="width: 80px; display: inline-block;">' . html::select(['id' => 'page_sizes_' . $type, 'options' => factory::model('numbers_frontend_html_list_pagination_pagesizes', true)->options(['i18n' => 'skip_sorting']), 'value' => $object->limit, 'no_choose' => true, 'onchange' => "\$('#offset').val(0); \$('#limit').val(this.value); numbers.frontend_list.trigger_submit(this.form);"]) . '</div>';
     // navigation
     $navigation = [];
     $flag_next_row_exists = false;
     $flag_last_row_exists = false;
     $current_page = intval($object->offset / $object->limit);
     if ($current_page >= 1) {
         $navigation[] = html::button2(['value' => i18n(null, 'First'), 'onclick' => "\$('#offset').val(0); numbers.frontend_list.trigger_submit(this.form);"]);
     }
     if ($current_page >= 2) {
         $previous = ($current_page - 1) * $object->limit;
         $navigation[] = html::button2(['value' => i18n(null, 'Previous'), 'onclick' => "\$('#offset').val({$previous}); numbers.frontend_list.trigger_submit(this.form);"]);
     }
     // select with number of pages
     $pages = ceil($object->total / $object->limit);
     if ($object->num_rows) {
         $temp = [];
         for ($i = 0; $i < $pages; $i++) {
             $temp[$i * $object->limit] = ['name' => i18n(null, $i + 1)];
         }
         $navigation2 = i18n(null, 'Page') . ': ';
         $previous = ($current_page - 1) * $object->limit;
         $navigation2 .= '<div style="width: 100px; display: inline-block;">' . html::select(['id' => 'pages_' . $type, 'options' => $temp, 'value' => $object->offset, 'no_choose' => true, 'onchange' => "\$('#offset').val(this.value); numbers.frontend_list.trigger_submit(this.form);"]) . '</div>';
         $navigation[] = $navigation2;
         // checking for next and last pages
         $flag_next_row_exists = $pages - $current_page - 2 > 0 ? true : false;
         $flag_last_row_exists = $pages - $current_page - 1 > 0 ? true : false;
     } else {
         $navigation[] = i18n(null, 'Page') . ': ' . ($current_page + 1);
     }
     if ($flag_next_row_exists) {
         $next = ($current_page + 1) * $object->limit;
         $navigation[] = html::button2(['value' => i18n(null, 'Next'), 'onclick' => "\$('#offset').val({$next}); numbers.frontend_list.trigger_submit(this.form);"]);
     }
     if ($flag_last_row_exists) {
         $last = ($pages - 1) * $object->limit;
         $navigation[] = html::button2(['value' => i18n(null, 'Last'), 'onclick' => "\$('#offset').val({$last}); numbers.frontend_list.trigger_submit(this.form);"]);
     }
     // generating grid
     $grid = ['options' => [0 => ['Displaying' => ['Displaying' => ['value' => $displaying, 'options' => ['field_size' => 'col-xs-6 col-sm-6 col-lg-2', 'percent' => 15, 'style' => 'height: 40px; line-height: 40px;']]], 'Fetched' => ['Fetched' => ['value' => $fetched, 'options' => ['field_size' => 'col-xs-6 col-sm-6 col-lg-2', 'percent' => 15, 'style' => 'height: 40px; line-height: 40px;']]], 'Sort' => ['Sort' => ['class' => 'list_pagination_sort', 'value' => $sort, 'options' => ['field_size' => 'col-xs-12 col-sm-12 col-lg-3', 'percent' => 15, 'style' => 'height: 40px; line-height: 40px;']]], 'Navigation' => ['Navigation' => ['class' => 'list_pagination_navigation', 'value' => implode(' ', $navigation), 'options' => ['field_size' => 'col-xs-12 col-sm-12 col-lg-5', 'percent' => 50, 'style' => 'height: 40px; line-height: 40px;']]]]]];
     return html::grid($grid);
 }
Beispiel #22
0
 /**
  * Process model
  *
  * @param string $model_class
  * @return array
  * @throws Exception
  */
 public function process_table_model($model_class)
 {
     $result = ['success' => false, 'error' => []];
     do {
         // table model
         $model = is_object($model_class) ? $model_class : factory::model($model_class, true);
         $db = factory::get(['db', $model->db_link]);
         $ddl_object = $db['ddl_object'];
         $owner = $db['object']->connect_options['username'];
         $engine = $model->engine[$db['backend']] ?? null;
         // process columns
         if (empty($model->columns)) {
             $result['error'][] = 'Table ' . $model->name . ' must have atleast one column!';
             break;
         }
         // columns would be here
         $columns = [];
         foreach ($model->columns as $k => $v) {
             $v['column_name'] = $k;
             $column_temp = $ddl_object->is_column_type_supported($v, $model->name);
             $columns[$k] = $column_temp['column'];
             // handle sequence
             if (!empty($column_temp['column']['sequence'])) {
                 $this->object_add(['type' => 'sequence', 'schema' => '', 'name' => $column_temp['column']['sequence'], 'data' => ['owner' => $owner, 'full_sequence_name' => $column_temp['column']['sequence'], 'type' => 'simple', 'prefix' => null, 'length' => 0, 'suffix' => null]], $model->db_link);
             }
         }
         $this->object_add(['type' => 'table', 'schema' => '', 'name' => $model->name, 'data' => ['columns' => $columns, 'owner' => $owner, 'full_table_name' => $model->name, 'engine' => $engine]], $model->db_link);
         // history
         if ($model->history) {
             if (empty($model->who['inserted']) || empty($model->who['updated'])) {
                 $result['error'][] = 'History table ' . $model->name . ' must have inserted and updated who timestamps!';
             }
             // fix columns with serial types
             $columns_history = $columns;
             foreach ($model->pk as $v) {
                 foreach (['serial' => 'integer', 'bigserial' => 'bigint', 'smallserial' => 'smallint'] as $k2 => $v2) {
                     if ($columns_history[$v]['type'] == $k2) {
                         $columns_history[$v]['type'] = $v2;
                     }
                 }
             }
             // add new history table
             $this->object_add(['type' => 'table', 'schema' => '', 'name' => $model->name . '__history', 'data' => ['columns' => $columns_history, 'owner' => $owner, 'full_table_name' => $model->history_name, 'engine' => $engine]], $model->db_link);
         }
         // processing constraints
         if (!empty($model->constraints)) {
             foreach ($model->constraints as $k => $v) {
                 $v['full_table_name'] = $model->name;
                 // additional processing for fk type constraints
                 if ($v['type'] == 'fk') {
                     $temp_object = factory::model($v['foreign_model'], true);
                     $v['foreign_table'] = $temp_object->name;
                 }
                 $this->object_add(['type' => 'constraint', 'schema' => '', 'table' => $model->name, 'name' => $k, 'data' => $v], $model->db_link);
             }
         }
         // processing indexes
         if (!empty($model->indexes)) {
             foreach ($model->indexes as $k => $v) {
                 // we skipp full text indexes for pgsql
                 if ($db['backend'] == 'pgsql' && $v['type'] == 'fulltext') {
                     continue;
                 }
                 $v['full_table_name'] = $model->name;
                 $this->object_add(['type' => 'index', 'schema' => '', 'table' => $model->name, 'name' => $k, 'data' => $v], $model->db_link);
             }
         }
         // if we got here - we are ok
         $result['success'] = true;
     } while (0);
     return $result;
 }
 /**
  * Process models
  *
  * @param array $options
  * @return array
  */
 public static function process_models($options = [])
 {
     $result = ['success' => false, 'error' => [], 'hint' => [], 'data' => []];
     do {
         // we need to process all dependencies first
         $dep = self::process_deps_all($options);
         if (!$dep['success']) {
             $result = $dep;
             $result['error'][] = 'You must fix all dependency related errors first before processing models.';
             break;
         }
         // proccesing models
         if (empty($dep['data']['model_processed'])) {
             $result['error'][] = 'You do not have models to process!';
             break;
         }
         $object_attributes = [];
         $object_relations = [];
         $object_forms = [];
         $flag_relation = application::get('dep.submodule.numbers.data.relations') ? true : false;
         $object_documentation = [];
         $object_import = [];
         $ddl = new numbers_backend_db_class_ddl();
         // run 1 to deterine virtual tables
         $first = true;
         $virtual_models = $dep['data']['model_processed'];
         run_again:
         foreach ($virtual_models as $k => $v) {
             $k2 = str_replace('.', '_', $k);
             if ($v == 'object_table') {
                 $model = factory::model($k2, true);
                 foreach (['attributes', 'audit', 'addresses'] as $v0) {
                     if ($model->{$v0}) {
                         $v01 = $v0 . '_model';
                         $virtual_models[str_replace('_', '.', $model->{$v01})] = 'object_table';
                     }
                 }
             }
         }
         if ($first) {
             $first = false;
             goto run_again;
             // some widgets have attributes
         }
         $dep['data']['model_processed'] = array_merge_hard($dep['data']['model_processed'], $virtual_models);
         $domains = object_data_domains::get_static();
         // run 2
         foreach ($dep['data']['model_processed'] as $k => $v) {
             $k2 = str_replace('.', '_', $k);
             if ($v == 'object_table') {
                 $model = factory::model($k2, true);
                 $temp_result = $ddl->process_table_model($model);
                 if (!$temp_result['success']) {
                     array_merge3($result['error'], $temp_result['error']);
                 }
                 $object_documentation[$v][$k2] = $k2;
                 // relation
                 if ($flag_relation) {
                     if (!empty($model->relation)) {
                         $domain = $model->columns[$model->relation['field']]['domain'] ?? null;
                         if (!empty($domain)) {
                             $domain = str_replace('_sequence', '', $domain);
                             $type = $domains[$domain]['type'];
                         } else {
                             $type = $model->columns[$model->relation['field']]['type'];
                         }
                         $object_relations[$k2] = ['rn_relattr_code' => $model->relation['field'], 'rn_relattr_name' => $model->title, 'rn_relattr_model' => $k2, 'rn_relattr_domain' => $domain, 'rn_relattr_type' => $type, 'rn_relattr_inactive' => !empty($model->relation['inactive']) ? 1 : 0];
                     }
                     if (!empty($model->attributes)) {
                         $object_attributes[$k2] = ['rn_attrmdl_code' => $k2, 'rn_attrmdl_name' => $model->title, 'rn_attrmdl_inactive' => 0];
                     }
                 }
             } else {
                 if ($v == 'object_sequence') {
                     $temp_result = $ddl->process_sequence_model($k2);
                     if (!$temp_result['success']) {
                         array_merge3($result['error'], $temp_result['error']);
                     }
                     $object_documentation[$v][$k2] = $k2;
                 } else {
                     if ($v == 'object_function') {
                         $temp_result = $ddl->process_function_model($k2);
                         if (!$temp_result['success']) {
                             array_merge3($result['error'], $temp_result['error']);
                         }
                         $object_documentation[$v][$k2] = $k2;
                     } else {
                         if ($v == 'object_extension') {
                             $temp_result = $ddl->process_function_extension($k2);
                             if (!$temp_result['success']) {
                                 array_merge3($result['error'], $temp_result['error']);
                             }
                             $object_documentation[$v][$k2] = $k2;
                         } else {
                             if ($v == 'object_import') {
                                 $object_import[$k2] = ['model' => $k2];
                             }
                         }
                     }
                 }
             }
         }
         // if we have erros
         if (!empty($result['error'])) {
             break;
         }
         // db factory
         $db_factory = factory::get('db');
         // we load objects from database
         $loaded_objects = [];
         foreach ($ddl->db_links as $k => $v) {
             $ddl_object = $db_factory[$k]['ddl_object'];
             $temp_result = $ddl_object->load_schema($k);
             if (!$temp_result['success']) {
                 array_merge3($result['error'], $temp_result['error']);
             } else {
                 $loaded_objects[$k] = $temp_result['data'];
             }
         }
         // if we have erros
         if (!empty($result['error'])) {
             break;
         }
         // get a list of all db links
         $db_link_list = array_unique(array_merge(array_keys($ddl->objects), array_keys($loaded_objects)));
         // if we are dropping schema
         if ($options['mode'] == 'drop') {
             $ddl->objects = [];
         }
         // compare schemas per db link
         $schema_diff = [];
         $total_per_db_link = [];
         $total = 0;
         foreach ($db_link_list as $k) {
             // we need to have a back end for comparison
             $compare_options['backend'] = $db_factory[$k]['backend'];
             // comparing
             $temp_result = $ddl->compare_schemas(isset($ddl->objects[$k]) ? $ddl->objects[$k] : [], isset($loaded_objects[$k]) ? $loaded_objects[$k] : [], $compare_options);
             if (!$temp_result['success']) {
                 array_merge3($result['hint'], $temp_result['error']);
             } else {
                 $schema_diff[$k] = $temp_result['data'];
                 if (!isset($total_per_db_link[$k])) {
                     $total_per_db_link[$k] = 0;
                 }
                 $total_per_db_link[$k] += $temp_result['count'];
                 $total += $temp_result['count'];
             }
         }
         // if there's no schema changes
         if ($total == 0) {
             if ($options['mode'] == 'commit') {
                 goto import_data;
             } else {
                 $result['success'] = true;
             }
             break;
         }
         // we need to provide a list of changes
         foreach ($total_per_db_link as $k => $v) {
             $result['hint'][] = '';
             $result['hint'][] = "Db link {$k} requires {$v} changes!";
             // printing summary
             $result['hint'][] = ' * Link ' . $k . ': ';
             foreach ($schema_diff[$k] as $k2 => $v2) {
                 $result['hint'][] = '   * ' . $k2 . ': ';
                 foreach ($v2 as $k3 => $v3) {
                     $result['hint'][] = '    * ' . $k3 . ' - ' . $v3['type'];
                 }
             }
         }
         // if we are in no commit mode we exit
         if (!in_array($options['mode'], ['commit', 'drop'])) {
             break;
         }
         // generating sql
         foreach ($total_per_db_link as $k => $v) {
             if ($v == 0) {
                 continue;
             }
             $ddl_object = $db_factory[$k]['ddl_object'];
             foreach ($schema_diff[$k] as $k2 => $v2) {
                 foreach ($v2 as $k3 => $v3) {
                     // we need to make fk constraints last to sort MySQL issues
                     if ($k2 == 'new_constraints' && $v3['type'] == 'constraint_new' && $v3['data']['type'] == 'fk') {
                         $schema_diff[$k][$k2 . '_fks'][$k3]['sql'] = $ddl_object->render_sql($v3['type'], $v3);
                     } else {
                         $schema_diff[$k][$k2][$k3]['sql'] = $ddl_object->render_sql($v3['type'], $v3, ['mode' => $options['mode']]);
                     }
                 }
             }
         }
         //			print_r($schema_diff);
         //			exit;
         // executing sql
         foreach ($total_per_db_link as $k => $v) {
             if ($v == 0) {
                 continue;
             }
             $db_object = new db($k);
             // if we are dropping we need to disable foregn key checks
             if ($options['mode'] == 'drop') {
                 if ($db_object->backend == 'mysqli') {
                     $db_object->query('SET foreign_key_checks = 0;');
                     // we also need to unset sequences
                     unset($schema_diff[$k]['delete_sequences']);
                 }
             }
             foreach ($schema_diff[$k] as $k2 => $v2) {
                 foreach ($v2 as $k3 => $v3) {
                     if (empty($v3['sql'])) {
                         continue;
                     }
                     if (is_array($v3['sql'])) {
                         $temp = $v3['sql'];
                     } else {
                         $temp = [$v3['sql']];
                     }
                     foreach ($temp as $v4) {
                         $temp_result = $db_object->query($v4);
                         if (!$temp_result['success']) {
                             array_merge3($result['error'], $temp_result['error']);
                             goto error;
                         }
                     }
                 }
             }
         }
         // if we got here - we are ok
         $result['success'] = true;
     } while (0);
     import_data:
     // we need to import data
     if (!empty($object_import) && $options['mode'] == 'commit') {
         $result['hint'][] = '';
         foreach ($object_import as $k => $v) {
             $data_object = new $k();
             $data_result = $data_object->process();
             if (!$data_result['success']) {
                 throw new Exception(implode("\n", $data_result['error']));
             }
             $result['hint'] = array_merge($result['hint'], $data_result['hint']);
         }
     }
     // relation
     if ($flag_relation && $options['mode'] == 'commit') {
         $result['hint'][] = '';
         $model2 = factory::model('numbers_data_relations_model_relation_attributes');
         // insert new models
         if (!empty($object_relations)) {
             foreach ($object_relations as $k => $v) {
                 $result_insert = $model2->save($v, ['pk' => ['rn_relattr_code'], 'ignore_not_set_fields' => true]);
             }
             $result['hint'][] = ' * Imported relation models!';
         }
         // we need to process forms
         foreach ($dep['data']['submodule_dirs'] as $v) {
             $dir = $v . 'model/form/';
             if (!file_exists($dir)) {
                 continue;
             }
             $files = helper_file::iterate($dir, ['only_extensions' => ['php']]);
             foreach ($files as $v2) {
                 $model_name = str_replace(['../libraries/vendor/', '.php'], '', $v2);
                 $model_name = str_replace('/', '_', $model_name);
                 $model = new $model_name(['skip_processing' => true]);
                 if (empty($model->form_object->misc_settings['option_models'])) {
                     continue;
                 }
                 // loop though fields
                 foreach ($model->form_object->misc_settings['option_models'] as $k3 => $v3) {
                     $object_forms[$model_name . '::' . $k3] = ['rn_relfrmfld_form_code' => $model_name, 'rn_relfrmfld_form_name' => $model->title, 'rn_relfrmfld_field_code' => $k3, 'rn_relfrmfld_field_name' => $v3['field_name'], 'rn_relfrmfld_relattr_id' => $v3['model'], 'rn_relfrmfld_inactive' => 0];
                 }
             }
         }
         if (!empty($object_forms)) {
             // load all relation models
             $data = $model2->get(['pk' => ['rn_relattr_model']]);
             $model = factory::model('numbers_data_relations_model_relation_formfields');
             foreach ($object_forms as $k => $v) {
                 if (empty($data[$v['rn_relfrmfld_relattr_id']])) {
                     continue;
                 }
                 $v['rn_relfrmfld_relattr_id'] = $data[$v['rn_relfrmfld_relattr_id']]['rn_relattr_id'];
                 $result_insert = $model->save($v, ['pk' => ['rn_relfrmfld_form_code', 'rn_relfrmfld_field_code'], 'ignore_not_set_fields' => true]);
             }
             $result['hint'][] = ' * Imported relation form fields!';
         }
         // todo: import models
         //print_r2($object_attributes);
         if (!empty($object_attributes)) {
             $model = factory::model('numbers_data_relations_model_attribute_models');
             foreach ($object_attributes as $k => $v) {
                 $result_insert = $model->save($v, ['pk' => ['rn_attrmdl_code'], 'ignore_not_set_fields' => true]);
             }
             $result['hint'][] = ' * Imported attribute models!';
         }
     }
     // we need to generate documentation
     $system_documentation = application::get('system_documentation');
     if (!empty($system_documentation) && $options['mode'] == 'commit') {
         $model = factory::model($system_documentation['model']);
         /*
         print_r2($object_documentation);
         $documentation_result = $model->update($object_documentation, $system_documentation);
         if (!$documentation_result['success']) {
         	$result['error'] = array_merge($result['error'], $documentation_result['error']);
         }
         */
     }
     error:
     return $result;
 }
Beispiel #24
0
 /**
  * Render list
  *
  * @return string
  */
 public final function render()
 {
     $result = '';
     // css & js
     layout::add_css('/numbers/media_submodules/numbers_frontend_html_list_media_css_base.css', 9000);
     layout::add_js('/numbers/media_submodules/numbers_frontend_html_list_media_js_base.js', 9000);
     // load mask
     numbers_frontend_media_libraries_loadmask_base::add();
     // hidden fields
     $result .= html::hidden(['name' => 'offset', 'id' => 'offset', 'value' => $this->offset]);
     $result .= html::hidden(['name' => 'limit', 'id' => 'limit', 'value' => $this->limit]);
     // get total number of rows from count datasource
     if (!empty($this->datasources['count'])) {
         $temp = factory::model($this->datasources['count']['model'])->get($this->datasources['count']['options']);
         $this->total = $temp[0]['count'] ?? 0;
     }
     // get rows
     if (!empty($this->datasources['data'])) {
         $this->rows = factory::model($this->datasources['data']['model'])->get($this->datasources['data']['options']);
         $this->num_rows = count($this->rows);
     }
     // new record
     if (object_controller::can('record_new')) {
         $mvc = application::get('mvc');
         $url = $mvc['controller'] . '/_edit';
         $this->actions['list_new'] = ['value' => 'New', 'sort' => -32000, 'icon' => 'file-o', 'href' => $url];
     }
     // filter
     if (!empty($this->filter)) {
         $this->actions['list_filter'] = ['value' => 'Filter', 'sort' => 1, 'icon' => 'filter', 'onclick' => "numbers.modal.show('list_{$this->list_link}_filter');"];
         $result .= numbers_frontend_html_list_filter::render($this);
     }
     // order by
     $this->actions['list_sort'] = ['value' => 'Sort', 'sort' => 2, 'icon' => 'sort-alpha-asc', 'onclick' => "numbers.modal.show('list_{$this->list_link}_sort');"];
     $result .= numbers_frontend_html_list_sort::render($this);
     // export, before pagination
     if (object_controller::can('list_export')) {
         // add export link to the panel
         $result .= numbers_frontend_html_list_export::render($this);
         $this->actions['list_export'] = ['value' => 'Export/Print', 'sort' => 3, 'icon' => 'print', 'onclick' => "numbers.modal.show('list_{$this->list_link}_export');"];
         // if we are exporting
         if (!empty($this->options['input']['submit_export']) && !empty($this->options['input']['export']['format'])) {
             $result .= numbers_frontend_html_list_export::export($this, $this->options['input']['export']['format']);
             goto finish;
         }
     }
     // refresh
     $this->actions['form_refresh'] = ['value' => 'Refresh', 'sort' => 32000, 'icon' => 'refresh', 'href' => 'javascript:location.reload();', 'internal_action' => true];
     // pagination top
     if (!empty($this->pagination['top'])) {
         $result .= factory::model($this->pagination['top'])->render($this, 'top');
     }
     // data
     $result .= '<hr class="simple"/>';
     if (method_exists($this, 'render_data')) {
         $result .= $this->render_data();
     } else {
         $result .= $this->render_data_default();
     }
     $result .= '<hr class="simple"/>';
     // pagination bottom
     if (!empty($this->pagination['bottom'])) {
         $result .= factory::model($this->pagination['bottom'])->render($this, 'bottom');
     }
     finish:
     $value = '';
     if (!empty($this->actions)) {
         $value .= '<div style="text-align: right;">' . $this->render_actions() . '</div>';
         $value .= '<hr class="simple" />';
     }
     // we add hidden submit element
     $result .= html::submit(['name' => 'submit_hidden', 'value' => 1, 'style' => 'display: none;']);
     // build a form
     $value .= html::form(['name' => "list_{$this->list_link}_form", 'id' => "list_{$this->list_link}_form", 'value' => $result, 'onsubmit' => 'return numbers.frontend_list.on_form_submit(this);']);
     // if we came from ajax we return as json object
     if (!empty($this->options['input']['__ajax'])) {
         $result = ['success' => true, 'html' => $value, 'js' => layout::$onload];
         layout::render_as($result, 'application/json');
     }
     $value = "<div id=\"list_{$this->list_link}_form_mask\"><div id=\"list_{$this->list_link}_form_wrapper\">" . $value . '</div></div>';
     $temp = ['type' => 'primary', 'value' => $value];
     return html::segment($temp);
 }
Beispiel #25
0
 /**
  * Get data as an array of rows
  *
  * @param array $options
  *		no_cache - if we need to skip caching
  *		search - array of search condition
  *		where - array of where conditions
  *		orderby - array of columns to sort by
  *		pk - primary key to be used by query
  *		columns - if we need to get certain columns
  *		limit - set this integer if we need to limit query
  * @return array
  */
 public function get($options = [])
 {
     $data = [];
     $this->acl_get_options = $options;
     // handle acl init
     if (!empty($options['acl'])) {
         $acl_key = get_called_class();
         if (factory::model('object_acl_class', true)->acl_init($acl_key, $data, $this->acl_get_options) === false) {
             return $data;
         }
         $options = $this->acl_get_options;
     }
     $options_query = [];
     // if we are caching
     if (!empty($this->cache) && empty($options['no_cache'])) {
         $options_query['cache'] = true;
     }
     $options_query['cache_tags'] = !empty($this->cache_tags) ? array_values($this->cache_tags) : [];
     $options_query['cache_tags'][] = $this->name;
     $sql = '';
     // pk
     $pk = array_key_exists('pk', $options) ? $options['pk'] : $this->pk;
     // preset columns
     if (!empty($options['__preset'])) {
         $columns = 'DISTINCT ';
         if (!empty($pk) && count($pk) > 1) {
             $temp = $pk;
             unset($temp[array_search('preset_value', $temp)]);
             $columns .= $this->db_object->prepare_expression($temp) . ', ';
         }
         $columns .= "concat_ws(' ', " . $this->db_object->prepare_expression($options['columns']) . ") preset_value";
         $sql .= ' AND coalesce(' . $this->db_object->prepare_expression($options['columns']) . ') IS NOT NULL';
         // if its a preset we cache
         $options_query['cache'] = true;
     } else {
         // regular columns
         if (!empty($options['columns'])) {
             $columns = $this->db_object->prepare_expression($options['columns']);
         } else {
             $columns = '*';
         }
     }
     // where
     $sql .= !empty($options['where']) ? ' AND ' . $this->db_object->prepare_condition($options['where']) : '';
     $sql .= !empty($options['search']) ? ' AND (' . $this->db_object->prepare_condition($options['search'], 'OR') . ')' : '';
     // order by
     $orderby = $options['orderby'] ?? (!empty($this->orderby) ? $this->orderby : null);
     if (!empty($orderby)) {
         $sql .= ' ORDER BY ' . array_key_sort_prepare_keys($orderby, true);
     }
     // limit
     if (!empty($options['limit'])) {
         $sql .= ' LIMIT ' . $options['limit'];
     } else {
         if (!empty($this->limit)) {
             $sql .= ' LIMIT ' . $this->limit;
         }
     }
     // querying
     $sql_full = 'SELECT ' . $columns . ' FROM ' . $this->name . ' a WHERE 1=1' . $sql;
     // memory caching
     if ($this->cache_memory) {
         // hash is query + primary key
         $crypt = new crypt();
         $sql_hash = $crypt->hash($sql_full . serialize($pk));
         if (isset(cache::$memory_storage[$sql_hash])) {
             return cache::$memory_storage[$sql_hash];
         }
     }
     $result = $this->db_object->query($sql_full, $pk, $options_query);
     if (!$result['success']) {
         throw new Exception(implode(", ", $result['error']));
     }
     if ($this->cache_memory) {
         cache::$memory_storage[$sql_hash] =& $result['rows'];
     }
     // single row
     if (!empty($options['single_row'])) {
         $data = current($result['rows']);
     } else {
         $data = $result['rows'];
     }
     // handle acl init
     if (!empty($options['acl'])) {
         if (factory::model('object_acl_class', true)->acl_finish($acl_key, $data, $this->acl_get_options) === false) {
             return $data;
         }
     }
     return $data;
 }
 /**
  * Get data from datasource
  *
  * @param array $options
  * @return array
  * @throws Exception
  */
 public final function get($options = [])
 {
     // check if we have query method
     if (!method_exists($this, 'query')) {
         throw new Exception('You must specify sql in query method!');
     }
     $data = [];
     $this->acl_get_options = $options;
     // handle acl init
     if (!empty($options['acl'])) {
         $acl_key = get_called_class();
         if (factory::model('object_acl_class', true)->acl_init($acl_key, $data, $this->acl_get_options) === false) {
             return $data;
         }
         $options = $this->acl_get_options;
     }
     // get query
     $sql = $this->query($options);
     // process query
     $result = $this->process_query($sql, $this->pk, $options);
     if (method_exists($this, 'process')) {
         // process data
         $data = $this->process($result['rows'], $options);
     } else {
         $data = $result['rows'];
     }
     // handle acl init
     if (!empty($options['acl'])) {
         if (factory::model('object_acl_class', true)->acl_finish($acl_key, $data, $this->acl_get_options) === false) {
             return $data;
         }
     }
     return $data;
 }
Beispiel #27
0
 /**
  * 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%">&nbsp;</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%">&nbsp;</td>';
             $temp .= '<td width="90%">' . $value . '</td>';
             $temp .= '<td width="1%">&nbsp;</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%">&nbsp;</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%">&nbsp;</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;
 }