diff --git a/include/xlswriter.h b/include/xlswriter.h index bbdc398..5dcf4c3 100644 --- a/include/xlswriter.h +++ b/include/xlswriter.h @@ -88,6 +88,10 @@ typedef struct { lxw_format *format; } xls_resource_format_t; +typedef struct { + HashTable *maps; +} xls_resource_formats_cache_t; + typedef struct { lxw_data_validation *validation; } xls_resource_validation_t; @@ -102,11 +106,12 @@ typedef struct { } xls_resource_rich_string_t; typedef struct _vtiful_xls_object { - xls_resource_read_t read_ptr; - xls_resource_write_t write_ptr; - zend_long write_line; - xls_resource_format_t format_ptr; - zend_object zo; + xls_resource_read_t read_ptr; + xls_resource_write_t write_ptr; + zend_long write_line; + xls_resource_format_t format_ptr; + xls_resource_formats_cache_t formats_cache_ptr; + zend_object zo; } xls_object; typedef struct _vtiful_format_object { @@ -294,6 +299,10 @@ static inline void php_vtiful_close_resource(zend_object *obj) { intern->format_ptr.format = NULL; } + if (intern->formats_cache_ptr.maps != NULL) { + zend_hash_destroy(intern->formats_cache_ptr.maps); + } + #ifdef ENABLE_READER if (intern->read_ptr.sheet_t != NULL) { xlsxioread_sheet_close(intern->read_ptr.sheet_t); @@ -361,4 +370,6 @@ lxw_datetime timestamp_to_datetime(zend_long timestamp); zend_string* char_join_to_zend_str(const char *left, const char *right); zend_string* str_pick_up(zend_string *left, const char *right, size_t len); +lxw_format* object_format(xls_object *obj, zend_string *format, lxw_format *format_handle); + #endif diff --git a/kernel/common.c b/kernel/common.c index d2e1878..06e3a99 100644 --- a/kernel/common.c +++ b/kernel/common.c @@ -88,6 +88,7 @@ void call_object_method(zval *object, const char *function_name, uint32_t param_ } /* }}} */ +/* {{{ */ lxw_datetime timestamp_to_datetime(zend_long timestamp) { int yearLocal = php_idate('Y', timestamp, 0); @@ -102,4 +103,53 @@ lxw_datetime timestamp_to_datetime(zend_long timestamp) }; return datetime; -} \ No newline at end of file +} +/* }}} */ + +/* {{{ */ +lxw_format* object_format(xls_object *obj, zend_string *format, lxw_format *format_handle) +{ + if (format == NULL && format_handle == NULL) { + return NULL; + } + + if (format != NULL && format_handle != NULL) { + zend_string *_format_key = strpprintf(0, "%p|%s", format_handle, format->val); + + void *exit_format = zend_hash_str_find_ptr(obj->formats_cache_ptr.maps, ZEND_STRL(_format_key->val)); + + if (exit_format != NULL) { + zend_string_release(_format_key); + + return (lxw_format *)exit_format; + } + + lxw_format *new_format = workbook_add_format((&obj->write_ptr)->workbook); + format_copy(new_format, format_handle); + format_set_num_format(new_format, ZSTR_VAL(format)); + + zend_hash_str_add_ptr(obj->formats_cache_ptr.maps, ZEND_STRL(_format_key->val), new_format); + + zend_string_release(_format_key); + + return new_format; + } + + if (format != NULL) { + void *exit_format = zend_hash_str_find_ptr(obj->formats_cache_ptr.maps, ZEND_STRL(format->val)); + + if (exit_format != NULL) { + return (lxw_format *)exit_format; + } + + lxw_format *new_format = workbook_add_format((&obj->write_ptr)->workbook); + format_set_num_format(new_format, ZSTR_VAL(format)); + + zend_hash_str_add_ptr(obj->formats_cache_ptr.maps, ZEND_STRL(format->val), new_format); + + return new_format; + } + + return format_handle; +} +/* }}} */ \ No newline at end of file diff --git a/kernel/excel.c b/kernel/excel.c index 7c1febd..0f078a7 100644 --- a/kernel/excel.c +++ b/kernel/excel.c @@ -35,12 +35,17 @@ PHP_VTIFUL_API zend_object *vtiful_xls_objects_new(zend_class_entry *ce) intern->zo.handlers = &vtiful_xls_handlers; - intern->read_ptr.file_t = NULL; - intern->read_ptr.sheet_t = NULL; + HashTable *formats_cache_ht = emalloc(sizeof(HashTable)); + zend_hash_init(formats_cache_ht, 0, NULL, ZVAL_PTR_DTOR, 0); + + intern->read_ptr.file_t = NULL; + intern->read_ptr.sheet_t = NULL; intern->format_ptr.format = NULL; intern->write_ptr.workbook = NULL; + intern->formats_cache_ptr.maps = formats_cache_ht; + intern->read_ptr.data_type_default = READ_TYPE_EMPTY; return &intern->zo; @@ -612,7 +617,7 @@ PHP_METHOD(vtiful_xls, header) } ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(header), header_l_key, header_value) - type_writer(header_value, 0, header_l_key, &obj->write_ptr, NULL, format_handle); + type_writer(header_value, 0, header_l_key, &obj->write_ptr, NULL, object_format(obj, NULL, format_handle)); ZEND_HASH_FOREACH_END(); // When inserting the header for the first time, the row number is incremented by one, @@ -657,7 +662,7 @@ PHP_METHOD(vtiful_xls, data) if (key == NULL) { column_index = index; } - type_writer(data, SHEET_CURRENT_LINE(obj), column_index, &obj->write_ptr, NULL, obj->format_ptr.format); + type_writer(data, SHEET_CURRENT_LINE(obj), column_index, &obj->write_ptr, NULL, object_format(obj, NULL, obj->format_ptr.format)); // next number index ++column_index; @@ -724,9 +729,9 @@ PHP_METHOD(vtiful_xls, insertText) SHEET_LINE_SET(obj, row); if (format_handle != NULL) { - type_writer(data, row, column, &obj->write_ptr, format, zval_get_format(format_handle)); + type_writer(data, row, column, &obj->write_ptr, format, object_format(obj, format, zval_get_format(format_handle))); } else { - type_writer(data, row, column, &obj->write_ptr, format, obj->format_ptr.format); + type_writer(data, row, column, &obj->write_ptr, format, object_format(obj, format, obj->format_ptr.format)); } } /* }}} */ @@ -799,9 +804,9 @@ PHP_METHOD(vtiful_xls, insertDate) lxw_datetime datetime = timestamp_to_datetime(data->value.lval); if (format_handle != NULL) { - datetime_writer(&datetime, row, column, format, &obj->write_ptr, zval_get_format(format_handle)); + datetime_writer(&datetime, row, column, format, &obj->write_ptr, object_format(obj, format, zval_get_format(format_handle))); } else { - datetime_writer(&datetime, row, column, format, &obj->write_ptr, obj->format_ptr.format); + datetime_writer(&datetime, row, column, format, &obj->write_ptr, object_format(obj, format, obj->format_ptr.format)); } // Release default format @@ -1007,9 +1012,9 @@ PHP_METHOD(vtiful_xls, mergeCells) WORKBOOK_NOT_INITIALIZED(obj); if (argc == 3 && format_handle != NULL) { - merge_cells(range, data, &obj->write_ptr, zval_get_format(format_handle)); + merge_cells(range, data, &obj->write_ptr, object_format(obj, NULL, zval_get_format(format_handle))); } else { - merge_cells(range, data, &obj->write_ptr, obj->format_ptr.format); + merge_cells(range, data, &obj->write_ptr, object_format(obj, NULL, obj->format_ptr.format)); } } /* }}} */ diff --git a/kernel/write.c b/kernel/write.c index 6c77f5f..0887502 100644 --- a/kernel/write.c +++ b/kernel/write.c @@ -36,10 +36,7 @@ void type_writer(zval *value, zend_long row, zend_long columns, xls_resource_wri if (value_type == IS_LONG) { if (format != NULL && format_handle == NULL) { - value_format = workbook_add_format(res->workbook); - - format_set_num_format(value_format, ZSTR_VAL(format)); - WORKSHEET_WRITER_EXCEPTION(worksheet_write_number(res->worksheet, lxw_row, lxw_col, (double)zval_get_long(value), value_format)); + WORKSHEET_WRITER_EXCEPTION(worksheet_write_number(res->worksheet, lxw_row, lxw_col, (double)zval_get_long(value), format_handle)); return; } @@ -49,12 +46,7 @@ void type_writer(zval *value, zend_long row, zend_long columns, xls_resource_wri } if(format != NULL && format_handle != NULL) { - value_format = workbook_add_format(res->workbook); - - format_copy(value_format, format_handle); - format_set_num_format(value_format, ZSTR_VAL(format)); - - WORKSHEET_WRITER_EXCEPTION(worksheet_write_number(res->worksheet, lxw_row, lxw_col, (double)zval_get_long(value), value_format)); + WORKSHEET_WRITER_EXCEPTION(worksheet_write_number(res->worksheet, lxw_row, lxw_col, (double)zval_get_long(value), format_handle)); return; } @@ -63,10 +55,7 @@ void type_writer(zval *value, zend_long row, zend_long columns, xls_resource_wri if (value_type == IS_DOUBLE) { if (format != NULL && format_handle == NULL) { - value_format = workbook_add_format(res->workbook); - format_set_num_format(value_format, ZSTR_VAL(format)); - - WORKSHEET_WRITER_EXCEPTION(worksheet_write_number(res->worksheet, lxw_row, lxw_col, zval_get_double(value), value_format)); + WORKSHEET_WRITER_EXCEPTION(worksheet_write_number(res->worksheet, lxw_row, lxw_col, zval_get_double(value), format_handle)); return; } @@ -76,12 +65,7 @@ void type_writer(zval *value, zend_long row, zend_long columns, xls_resource_wri } if(format != NULL && format_handle != NULL) { - value_format = workbook_add_format(res->workbook); - - format_copy(value_format, format_handle); - format_set_num_format(value_format, ZSTR_VAL(format)); - - WORKSHEET_WRITER_EXCEPTION(worksheet_write_number(res->worksheet, lxw_row, lxw_col, zval_get_double(value), value_format)); + WORKSHEET_WRITER_EXCEPTION(worksheet_write_number(res->worksheet, lxw_row, lxw_col, zval_get_double(value), format_handle)); return; } @@ -255,14 +239,7 @@ void chart_writer(zend_long row, zend_long columns, xls_resource_chart_t *chart_ */ void datetime_writer(lxw_datetime *datetime, zend_long row, zend_long columns, zend_string *format, xls_resource_write_t *res, lxw_format *format_handle) { - lxw_format *value_format = workbook_add_format(res->workbook); - - if (format_handle != NULL) { - format_copy(value_format, format_handle); - } - - format_set_num_format(value_format, ZSTR_VAL(format)); - worksheet_write_datetime(res->worksheet, (lxw_row_t)row, (lxw_col_t)columns, datetime, value_format); + worksheet_write_datetime(res->worksheet, (lxw_row_t)row, (lxw_col_t)columns, datetime, format_handle); } /* diff --git a/tests/open_xlsx_next_row_with_data_type_date_array_index.phpt b/tests/open_xlsx_next_row_with_data_type_date_array_index.phpt index b88d7e7..0d9ee59 100644 --- a/tests/open_xlsx_next_row_with_data_type_date_array_index.phpt +++ b/tests/open_xlsx_next_row_with_data_type_date_array_index.phpt @@ -36,11 +36,7 @@ array(2) { [1]=> string(4) "Cost" } -array(2) { - [0]=> - string(0) "" - [1]=> - string(0) "" +array(0) { } array(5) { [0]=>