Пример #1
0
 /**
  * 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;
 }
Пример #2
0
 /**
  * test extract_keys
  */
 public function testExtractKeys()
 {
     $this->assertEquals([10, 20], extract_keys(['foo' => 20, 'bar' => 10, 'qux' => 99], ['bar', 'foo']));
     $this->assertEquals([null, 20, 300], extract_keys(['foo' => 20, 'qux' => 99], ['bar', 'foo' => 0, 'jazz' => 300]));
 }
Пример #3
0
 /**
  * Data default renderer
  *
  * @return string
  */
 private final function render_data_default()
 {
     $result = '';
     // if we have no rows we display a messsage
     if ($this->num_rows == 0) {
         return html::message(['type' => 'warning', 'options' => [i18n(null, object_content_messages::no_rows_found)]]);
     }
     $counter = 1;
     $table = ['header' => [], 'options' => []];
     // action flags
     $actions = [];
     if (object_controller::can('record_view')) {
         $actions['view'] = true;
     }
     // generate columns
     foreach ($this->columns as $k => $v) {
         // if we can not view we skip action column
         if (empty($actions) && $k == 'action') {
             continue;
         }
         $table['header'][$k] = ['value' => i18n(null, $v['name']), 'nowrap' => true, 'width' => $v['width'] ?? null];
     }
     // generate rows
     foreach ($this->rows as $k => $v) {
         // process all columns first
         $row = [];
         foreach ($this->columns as $k2 => $v2) {
             // if we can not view we skip action column
             if (empty($actions) && $k2 == 'action') {
                 continue;
             }
             $value = [];
             // create cell properties
             foreach (['width', 'align'] as $v3) {
                 if (isset($v2[$v3])) {
                     $value[$v3] = $v2[$v3];
                 }
             }
             // process rows
             if ($k2 == 'action') {
                 $value['value'] = [];
                 if (!empty($actions['view'])) {
                     $mvc = application::get('mvc');
                     $pk = extract_keys($this->model_object->pk, $v);
                     $url = $mvc['controller'] . '/_edit?' . http_build_query2($pk);
                     $value['value'][] = html::a(['value' => i18n(null, 'View'), 'href' => $url]);
                 }
                 $value['value'] = implode(' ', $value['value']);
             } else {
                 if ($k2 == 'row_number') {
                     $value['value'] = format::id($counter) . '.';
                 } else {
                     if ($k2 == 'offset_number') {
                         $value['value'] = format::id($this->offset + $counter) . '.';
                     } else {
                         if (!empty($v2['options_model'])) {
                             if (strpos($v2['options_model'], '::') === false) {
                                 $v2['options_model'] .= '::options';
                             }
                             $params = $v2['options_params'] ?? [];
                             if (!empty($v2['options_depends'])) {
                                 foreach ($v2['options_depends'] as $k0 => $v0) {
                                     $params[$k0] = $v[$v0];
                                 }
                             }
                             $crypt_object = new crypt();
                             $hash = $crypt_object->hash($v2['options_model'] . serialize($params));
                             if (!isset($this->cached_options[$hash])) {
                                 $method = factory::method($v2['options_model'], null, true);
                                 $this->cached_options[$hash] = call_user_func_array($method, [['where' => $params]]);
                             }
                             if (isset($this->cached_options[$hash][$v[$k2]])) {
                                 $value['value'] = $this->cached_options[$hash][$v[$k2]]['name'];
                             } else {
                                 $value['value'] = null;
                             }
                         } else {
                             if (!empty($v2['options']) && !is_array($v[$k2])) {
                                 if (isset($v2['options'][$v[$k2]])) {
                                     $value['value'] = $v2['options'][$v[$k2]]['name'];
                                 } else {
                                     $value['value'] = null;
                                 }
                             } else {
                                 if (isset($v[$k2])) {
                                     $value['value'] = $v[$k2];
                                 } else {
                                     $value['value'] = null;
                                 }
                             }
                         }
                     }
                 }
             }
             // put value into row
             if (!empty($v2['format'])) {
                 $format_options = $v2['format_options'] ?? [];
                 if (!empty($v2['format_depends'])) {
                     $format_depends = $v2['format_depends'];
                     $this->process_params_and_depends($format_depends, $v);
                     $format_options = array_merge_hard($format_options, $format_depends);
                 }
                 $method = factory::method($v2['format'], 'format');
                 $value['value'] = call_user_func_array([$method[0], $method[1]], [$value['value'], $format_options]);
             }
             $row[$k2] = $value;
         }
         // put processed columns though user defined function
         if (method_exists($this, 'render_data_rows')) {
             $table['options'][$counter] = $this->render_data_rows($row, $v);
         } else {
             $table['options'][$counter] = $row;
         }
         $counter++;
     }
     return html::table($table);
 }