Files
admin_hura_8/inc/Hura8/System/Controller/aExcelUploadController.php
2024-01-29 10:39:53 +07:00

356 lines
10 KiB
PHP

<?php
namespace Hura8\System\Controller;
use Hura8\System\ReadExcel;
use PhpOffice\PhpSpreadsheet\Shared\Date;
abstract class aExcelUploadController
{
protected $update_option = [];
protected static $column_names = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
//...
];
protected $file_input_name = "file_excel"; //
protected $client_excel_col_config = [
/*"A" => array(
'name' => 'ID Sản phẩm Web',
'width' => '10',
'data_field_name' => 'id',
),
"B" => array(
'name' => 'Mã kho (SKU)',
'width' => '10',
'data_field_name' => 'storeSKU',
),*/
//...
];
protected $field_column_mappings = [
//'name' => "A",
//'price' => "B",
];
// hold cache for some operations
protected $cache = [];
protected $format_item_middlewares = []; // list of middleware object to format item
public function __construct($client_config_file_name = '', $file_input_name = '', array $update_option = [])
{
if(!$client_config_file_name) {
return true;
}
//this from a config file for each client
$client_config_file = "config/client/excel/" . $client_config_file_name;
if (!file_exists(ROOT_DIR . '/' . $client_config_file)) {
die("Please create config file: " . $client_config_file);
}
$client_fields_config = include ROOT_DIR . '/' . $client_config_file;
if($file_input_name) {
$this->file_input_name = $file_input_name;
}
// auto add excel column names based on fields' index
$this->client_excel_col_config = $this->_make_columns(array_values($client_fields_config));
// create field-col map
$field_column_mappings = [];
foreach ($this->client_excel_col_config as $column_name => $_prop) {
if(!$_prop['data_field_name']) continue;
// skip column which is not for upload
if(isset($_prop['for_upload']) && !$_prop['for_upload']) continue;
$field_column_mappings[$_prop['data_field_name']] = $column_name;
}
$this->field_column_mappings = $field_column_mappings;
$this->update_option = $update_option;
return true;
}
public function updateUpdateOptions(array $update_option = []) {
foreach ($update_option as $key => $value) {
$this->update_option[$key] = $value;
}
}
public function getColumnNotForUpload() {
$result = [];
foreach ($this->client_excel_col_config as $column_name => $_prop) {
// skip column which is not for upload
if(isset($_prop['for_upload']) && !$_prop['for_upload']) $result[$column_name] = $_prop['name'] ;
}
return $result;
}
public function getColumnCanUpdate() {
$result = [];
foreach ($this->client_excel_col_config as $column_name => $_prop) {
// skip column which is not for upload
if(isset($_prop['for_upload']) && !$_prop['for_upload']) continue;
// skip column which is not for update
if(isset($_prop['can_update']) && !$_prop['can_update']) continue;
$result[] = $_prop ;
}
return $result;
}
protected function getRequiredFields() {
$result = [];
foreach ($this->client_excel_col_config as $column_name => $_prop) {
// skip column which is not for upload
if(isset($_prop['required']) && $_prop['required']) $result[] = $_prop['data_field_name'] ;
}
return $result;
}
protected function _make_columns($fields_config)
{
$new_array = [];
$total_names = sizeof(static::$column_names);
foreach ($fields_config as $index => $config) {
if ($index >= $total_names) break;
$new_array[static::$column_names[$index]] = $config;
}
return $new_array;
}
protected function getExcelFileExt($excel_file){
$ext = substr(strrchr($excel_file, "."), 1);
return (in_array($ext, ["xls", "xlsx"])) ? $ext : false;
}
public function start($sheet_start_row = 3, $batch_mode = false, $batch_size=100)
{
$ext = $this->getExcelFileExt($_FILES[$this->file_input_name]["name"]);
if(!$ext) {
return [
'status' => 'error',
'message' => 'Invalid excel file',
];
}
$objReadExcel = new ReadExcel($ext);
$all_rows = $objReadExcel->read(
$_FILES[$this->file_input_name]["tmp_name"],
$sheet_start_row,
$this->field_column_mappings,
'',
true
);
$this->beforeProcessRows($all_rows);
$success_row_counter = 0;
if($batch_mode) {
// batch mode
$small_batch = [];
$counter = 0;
foreach ($all_rows as $sheet_index => $sheet_content) {
foreach ($sheet_content as $row_id => $row_content) {
$formatted_info = $this->formatItemInfo($this->convertColToField($row_content));
if(!$formatted_info) continue;
$counter += 1;
$small_batch[] = $formatted_info;
if($counter % $batch_size == 0) {
$success_row_counter += $this->processBatchItems($small_batch);
// reset
$counter = 0;
$small_batch = [];
}
}
}
// process the remain
if(sizeof($small_batch)) {
$success_row_counter += $this->processBatchItems($small_batch);
}
} else {
// single item mode
foreach ($all_rows as $sheet_index => $sheet_content) {
foreach ($sheet_content as $row_index => $row_content) {
$formatted_info = $this->formatItemInfo($this->convertColToField($row_content));
if(!$formatted_info) continue;
if($this->processItem($formatted_info, $row_index)){
$success_row_counter += 1;
}
}
}
}
//unset($all_rows);
return [
'status' => 'success',
'message' => '',
'success_counter' => $success_row_counter,
];
}
protected function convertExcelDateValue($value) {
// Date value in Excel's cell can be displayed as text or date value, we need to check for both
$format_value = $this->formatExcelUploadDate($value);
if(!$format_value) {
// check if it's excel date
try {
$format_value = (is_numeric($value)) ? date("d-m-Y", Date::excelToTimestamp($value, date_default_timezone_get())) : '';
}catch (\Exception $e) {
$format_value = '';
}
}
return $format_value;
}
protected function formatExcelUploadDate($input_date) {
$check_date_pattern = "/\d{1,2}-\d{1,2}-\d{4}/i";
$format_date = str_replace("/", "-", $input_date);
if(preg_match($check_date_pattern, $format_date)) {
return date("d-m-Y", strtotime($format_date));
}
return null;
}
protected function convertExcelHourMinuteValue($value) {
$format_value = $this->formatExcelUploadHourMinute($value);
if(!$format_value) {
// check if it's excel date
try {
$format_value = (is_numeric($value)) ? date("H:i", Date::excelToTimestamp($value, date_default_timezone_get())) : '';
}catch (\Exception $e) {
$format_value = '';
}
}
return $format_value;
}
protected function formatExcelUploadHourMinute($input_date) {
$check_date_pattern = "/\d{1,2}:\d{1,2}/i";
//$format_date = str_replace("/", "-", $input_date);
if(preg_match($check_date_pattern, $input_date)) {
return date("H:i", strtotime($input_date));
}
return null;
}
// ['A' => '12', 'B' => 'ten sp'] => ['id' => '12', 'product_name' => 'ten sp']
protected function convertColToField(array $row_content ) {
if(!$this->field_column_mappings) {
return array_values($row_content);
}
$item_info = [];
foreach ($this->field_column_mappings as $field => $col) {
//if(!isset($row_content[$col])) continue;
$item_info[$field] = $row_content[$col];
}
return $item_info;
}
// abstract methods
protected function beforeProcessRows(array &$all_read_rows){
// default nothing
// derived class should overwrite this method
}
abstract protected function processItem(array $item_info, $row_index=0);
abstract protected function processBatchItems(array $item_list);
/**
* @param array $item_info
* @return array|null
*/
abstract protected function formatItemInfoBeforeProcess(array $item_info);
public function registerFormatItemInfoMiddleware($middleware_ojb)
{
$this->format_item_middlewares[] = $middleware_ojb;
}
protected $date_fields = [];
public function setDateFields(array $date_fields) {
$this->date_fields = $date_fields;
}
protected $hour_minute_fields = [];
public function setHourMinuteFields(array $hour_minute_fields) {
$this->hour_minute_fields = $hour_minute_fields;
}
/**
* @param array $item_info
* @return array|null
*/
protected function formatItemInfo(array $item_info)
{
$copy = $item_info;
// apply middleware
if (sizeof($this->format_item_middlewares)) {
foreach ($this->format_item_middlewares as $_middleware) {
$copy = call_user_func($_middleware, $copy);
}
}
foreach ($this->date_fields as $field) {
$copy[$field] = $this->convertExcelDateValue($item_info[$field]);
}
foreach ($this->hour_minute_fields as $field) {
$copy[$field] = $this->convertExcelHourMinuteValue($item_info[$field]);
}
return $this->formatItemInfoBeforeProcess($copy);
}
}