Browse Source

Merge pull request #170 from viest/dev

Feat: nextCellCallback with data type
viest 5 years ago
parent
commit
442b53346c

+ 14 - 0
ide-helper/helper.php

@@ -343,6 +343,20 @@ class Excel
         return $this;
     }
 
+    /**
+     * Set row cell data type
+     *
+     * @param array $types
+     *
+     * @return Excel
+     *
+     * @author viest
+     */
+    public function setType(array $types): self
+    {
+        return $this;
+    }
+
     /**
      * Read values from the sheet
      *

+ 2 - 1
include/read.h

@@ -17,7 +17,8 @@
 #define READ_ROW 0x01
 
 int sheet_read_row(xlsxioreadersheet sheet_t);
-int is_number(char *value);
+int is_number(const char *value);
+void data_to_custom_type(const char *string_value, zend_ulong type, zval *zv_result_t);
 xlsxioreader file_open(const char *directory, const char *file_name);
 void load_sheet_all_data(xlsxioreadersheet sheet_t, zval *zv_type_t, zval *zv_result_t);
 xlsxioreadersheet sheet_open(xlsxioreader file_t, const zend_string *zs_sheet_name_t, const zend_long zl_flag);

+ 1 - 0
include/xlswriter.h

@@ -44,6 +44,7 @@ typedef struct {
 } xls_resource_read_t;
 
 typedef struct {
+    zval                  *zv_type_t;
     zend_fcall_info       *fci;
     zend_fcall_info_cache *fci_cache;
 } xls_read_callback_data;

+ 2 - 0
kernel/excel.c

@@ -843,6 +843,8 @@ PHP_METHOD(vtiful_xls, nextCellCallback)
 
     xls_read_callback_data callback_data;
 
+    callback_data.zv_type_t = zend_read_property(vtiful_xls_ce, getThis(), ZEND_STRL(V_XLS_TYPE), 0, NULL);
+
     callback_data.fci = &fci;
     callback_data.fci_cache = &fci_cache;
 

+ 89 - 46
kernel/read.c

@@ -42,7 +42,7 @@ xlsxioreadersheet sheet_open(xlsxioreader file_t, const zend_string *zs_sheet_na
 /* }}} */
 
 /* {{{ */
-int is_number(char *value)
+int is_number(const char *value)
 {
     if (strspn(value, ".0123456789") == strlen(value)) {
         return XLSWRITER_TRUE;
@@ -52,6 +52,71 @@ int is_number(char *value)
 }
 /* }}} */
 
+/* {{{ */
+void data_to_custom_type(const char *string_value, zend_ulong type, zval *zv_result_t)
+{
+    if (type & READ_TYPE_DATETIME) {
+        if (!is_number(string_value)) {
+            goto STRING;
+        }
+
+        double value = strtod(string_value, NULL);
+
+        if (value != 0) {
+            value = (value - 25569) * 86400;
+        }
+
+        if (Z_TYPE_P(zv_result_t) == IS_ARRAY) {
+            add_next_index_long(zv_result_t, (zend_long)(value + 0.5));
+        } else {
+            ZVAL_LONG(zv_result_t, (zend_long)(value + 0.5));
+        }
+
+        return;
+    }
+
+    if (type & READ_TYPE_DOUBLE) {
+        if (!is_number(string_value)) {
+            goto STRING;
+        }
+
+        if (Z_TYPE_P(zv_result_t) == IS_ARRAY) {
+            add_next_index_double(zv_result_t, strtod(string_value, NULL));
+        } else {
+            ZVAL_DOUBLE(zv_result_t, strtod(string_value, NULL));
+        }
+
+        return;
+    }
+
+    if (type & READ_TYPE_INT) {
+        if (!is_number(string_value)) {
+            goto STRING;
+        }
+
+        zend_long _long_value;
+
+        sscanf(string_value, "%" PRIi64, &_long_value);
+
+        if (Z_TYPE_P(zv_result_t) == IS_ARRAY) {
+            add_next_index_long(zv_result_t, _long_value);
+        } else {
+            ZVAL_LONG(zv_result_t, _long_value);
+        }
+
+        return;
+    }
+
+    STRING:
+
+    if (Z_TYPE_P(zv_result_t) == IS_ARRAY) {
+        add_next_index_stringl(zv_result_t, string_value, strlen(string_value));
+    } else {
+        ZVAL_STRINGL(zv_result_t, string_value, strlen(string_value));
+    }
+}
+/* }}} */
+
 /* {{{ */
 int sheet_read_row(xlsxioreadersheet sheet_t)
 {
@@ -62,7 +127,7 @@ int sheet_read_row(xlsxioreadersheet sheet_t)
 /* {{{ */
 unsigned int load_sheet_current_row_data(xlsxioreadersheet sheet_t, zval *zv_result_t, zval *zv_type_arr_t, unsigned int flag)
 {
-    zend_ulong _type = READ_TYPE_EMPTY, _cell_index = 0;
+    zend_ulong _type, _cell_index = 0;
     zend_array *_za_type_t = NULL;
     char *_string_value = NULL;
     zval *_current_type = NULL;
@@ -93,45 +158,7 @@ unsigned int load_sheet_current_row_data(xlsxioreadersheet sheet_t, zval *zv_res
             _cell_index++;
         }
 
-        if (_type & READ_TYPE_DATETIME) {
-            if (!is_number(_string_value)) {
-                goto STRING;
-            }
-
-            double value = strtod(_string_value, NULL);
-
-            if (value != 0) {
-                value = (value - 25569) * 86400;
-            }
-
-            add_next_index_long(zv_result_t, (zend_long)(value + 0.5));
-            continue;
-        }
-
-        if (_type & READ_TYPE_DOUBLE) {
-            if (!is_number(_string_value)) {
-                goto STRING;
-            }
-
-            add_next_index_double(zv_result_t, strtod(_string_value, NULL));
-            continue;
-        }
-
-        if (_type & READ_TYPE_INT) {
-            if (!is_number(_string_value)) {
-                goto STRING;
-            }
-
-            zend_long _long_value;
-
-            sscanf(_string_value, "%" PRIi64, &_long_value);
-            add_next_index_long(zv_result_t, _long_value);
-            continue;
-        }
-
-        STRING:
-
-        add_next_index_stringl(zv_result_t, _string_value, strlen(_string_value));
+        data_to_custom_type(_string_value, _type, zv_result_t);
     }
 
     return XLSWRITER_TRUE;
@@ -153,8 +180,8 @@ int sheet_row_callback (size_t row, size_t max_col, void* callback_data)
     _callback_data->fci->params      = args;
     _callback_data->fci->param_count = 3;
 
-    ZVAL_LONG(&args[0], row);
-    ZVAL_LONG(&args[1], max_col);
+    ZVAL_LONG(&args[0], (row - 1));
+    ZVAL_LONG(&args[1], (max_col - 1));
     ZVAL_STRING(&args[2], "XLSX_ROW_END");
 
     zend_call_function(_callback_data->fci, _callback_data->fci_cache);
@@ -185,9 +212,25 @@ int sheet_cell_callback (size_t row, size_t col, const char *value, void *callba
     _callback_data->fci->params      = args;
     _callback_data->fci->param_count = 3;
 
-    ZVAL_LONG(&args[0], row);
-    ZVAL_LONG(&args[1], col);
-    ZVAL_STRING(&args[2], value);
+    ZVAL_LONG(&args[0], (row - 1));
+    ZVAL_LONG(&args[1], (col - 1));
+
+    if (Z_TYPE_P(_callback_data->zv_type_t) != IS_ARRAY) {
+        ZVAL_STRING(&args[2], value);
+    }
+
+    if (Z_TYPE_P(_callback_data->zv_type_t) == IS_ARRAY) {
+        zval *_current_type = NULL;
+        zend_ulong _type = READ_TYPE_EMPTY;
+
+        if ((_current_type = zend_hash_index_find(Z_ARR_P(_callback_data->zv_type_t), (col - 1))) != NULL) {
+            if (Z_TYPE_P(_current_type) == IS_LONG) {
+                _type = Z_LVAL_P(_current_type);
+            }
+        }
+
+        data_to_custom_type(value, _type, &args[2]);
+    }
 
     zend_call_function(_callback_data->fci, _callback_data->fci_cache);
 

+ 6 - 6
tests/open_xlsx_next_cell_callback.phpt

@@ -25,9 +25,9 @@ $excel->openFile('tutorial.xlsx')->nextCellCallback(function ($row, $cell, $data
 @unlink(__DIR__ . '/tutorial.xlsx');
 ?>
 --EXPECT--
-cell:1, row:1, value:Item
-cell:2, row:1, value:Cost
-cell:2, row:1, value:XLSX_ROW_END
-cell:1, row:2, value:Item_1
-cell:2, row:2, value:Cost_1
-cell:2, row:2, value:XLSX_ROW_END
+cell:0, row:0, value:Item
+cell:1, row:0, value:Cost
+cell:1, row:0, value:XLSX_ROW_END
+cell:0, row:1, value:Item_1
+cell:1, row:1, value:Cost_1
+cell:1, row:1, value:XLSX_ROW_END

+ 61 - 0
tests/open_xlsx_next_cell_callback_with_data_type.phpt

@@ -0,0 +1,61 @@
+--TEST--
+Check for vtiful presence
+--SKIPIF--
+<?php
+require __DIR__ . '/include/skipif.inc';
+skip_disable_reader();
+?>
+--FILE--
+<?php
+$config   = ['path' => './tests'];
+$excel    = new \Vtiful\Kernel\Excel($config);
+$filePath = $excel->fileName('tutorial.xlsx')
+    ->header(['Item', 'Cost', 'Int', 'Double', 'Date'])
+    ->data([
+        ['Item_1', 'Cost_1', 10, 10.9999995],
+    ])
+    ->insertDate(1, 4, 1568904314)
+    ->output();
+
+$excel->openFile('tutorial.xlsx')
+    ->setType([
+        \Vtiful\Kernel\Excel::TYPE_STRING,
+        \Vtiful\Kernel\Excel::TYPE_STRING,
+        \Vtiful\Kernel\Excel::TYPE_INT,
+        \Vtiful\Kernel\Excel::TYPE_DOUBLE,
+        \Vtiful\Kernel\Excel::TYPE_TIMESTAMP,
+    ])
+    ->nextCellCallback(function ($row, $cell, $data) {
+        echo 'cell:' . $cell . ', row:' . $row . PHP_EOL;
+        var_dump($data);
+    });
+?>
+--CLEAN--
+<?php
+@unlink(__DIR__ . '/tutorial.xlsx');
+?>
+--EXPECT--
+cell:0, row:0
+string(4) "Item"
+cell:1, row:0
+string(4) "Cost"
+cell:2, row:0
+string(3) "Int"
+cell:3, row:0
+string(6) "Double"
+cell:4, row:0
+string(4) "Date"
+cell:4, row:0
+string(12) "XLSX_ROW_END"
+cell:0, row:1
+string(6) "Item_1"
+cell:1, row:1
+string(6) "Cost_1"
+cell:2, row:1
+int(10)
+cell:3, row:1
+float(10.9999995)
+cell:4, row:1
+int(1568904314)
+cell:4, row:1
+string(12) "XLSX_ROW_END"