Browse Source

Feat: rich string

viest 3 years ago
parent
commit
fd6dfb743d
12 changed files with 339 additions and 20 deletions
  1. 1 1
      .travis.yml
  2. 5 4
      config.m4
  3. 7 6
      config.w32
  4. 20 0
      include/rich_string.h
  5. 29 8
      include/xlswriter.h
  6. 39 0
      kernel/excel.c
  7. 0 1
      kernel/format.c
  8. 13 0
      kernel/resource.c
  9. 125 0
      kernel/rich_string.c
  10. 43 0
      kernel/write.c
  11. 56 0
      tests/rich_string.phpt
  12. 1 0
      xlswriter.c

+ 1 - 1
.travis.yml

@@ -41,4 +41,4 @@ script:
     - ./travis/run-test.sh
     - make clean && phpize --clean
     - phpize && ./configure --enable-reader && make clean && make
-    - if [ -n "$USE_VALGRIND" ]; then REPORT_EXIT_STATUS=1 php -n run-tests.php -m -n -d extension_dir=./modules/ -d extension=xlswriter.so -P --show-diff --set-timeout 120; fi
+    - if [ -n "$USE_VALGRIND" ]; then REPORT_EXIT_STATUS=1 php -n run-tests.php -m -n -d extension_dir=./modules/ -d extension=xlswriter.so -P --show-all --set-timeout 120; fi

+ 5 - 4
config.m4

@@ -13,15 +13,16 @@ PHP_ARG_ENABLE(reader, enable xlsx reader support,
 if test "$PHP_XLSWRITER" != "no"; then
     xls_writer_sources="
     xlswriter.c \
-    kernel/exception.c \
-    kernel/resource.c \
+    kernel/chart.c \
     kernel/common.c \
     kernel/excel.c \
-    kernel/write.c \
+    kernel/exception.c \
     kernel/format.c \
-    kernel/chart.c \
     kernel/help.c \
+    kernel/resource.c \
+    kernel/rich_string.c \
     kernel/validation.c \
+    kernel/write.c \
     "
 
     xls_read_sources="

+ 7 - 6
config.w32

@@ -18,17 +18,18 @@ if (PHP_XLSWRITER != "no") {
         AC_DEFINE("HAVE_LXW_VERSION", 1, "lxw_version available in 0.7.7");
 
         ADD_SOURCES(configure_module_dirname + "\\kernel", "\
-                exception.c \
-                resource.c \
+                chart.c \
                 common.c \
+                csv.c \
                 excel.c \
-                write.c \
+                exception.c \
                 format.c \
-                chart.c \
-                read.c \
-                csv.c \
                 help.c \
+                read.c \
+                resource.c \
+                rich_string.c \
                 validation.c \
+                write.c \
                 ", "xlswriter");
 
         ADD_SOURCES(configure_module_dirname + "\\library\\libxlsxwriter\\third_party\\minizip", "\

+ 20 - 0
include/rich_string.h

@@ -0,0 +1,20 @@
+/*
+  +----------------------------------------------------------------------+
+  | XlsWriter Extension                                                  |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2017-2018 The Viest                                    |
+  +----------------------------------------------------------------------+
+  | http://www.viest.me                                                  |
+  +----------------------------------------------------------------------+
+  | Author: viest <[email protected]>                                 |
+  +----------------------------------------------------------------------+
+*/
+
+#ifndef PHP_EXT_XLS_EXPORT_RICH_STRING_H
+#define PHP_EXT_XLS_EXPORT_RICH_STRING_H
+
+extern zend_class_entry *vtiful_rich_string_ce;
+
+VTIFUL_STARTUP_FUNCTION(rich_string);
+
+#endif

+ 29 - 8
include/xlswriter.h

@@ -36,6 +36,7 @@
 #include "exception.h"
 #include "format.h"
 #include "chart.h"
+#include "rich_string.h"
 #include "help.h"
 
 #ifdef ENABLE_READER
@@ -95,6 +96,10 @@ typedef struct {
     lxw_chart_series *series;
 } xls_resource_chart_t;
 
+typedef struct {
+    lxw_rich_string_tuple *tuple;
+} xls_resource_rich_string_t;
+
 typedef struct _vtiful_xls_object {
     xls_resource_read_t   read_ptr;
     xls_resource_write_t  write_ptr;
@@ -118,16 +123,22 @@ typedef struct _vtiful_validation_object {
     zend_object zo;
 } validation_object;
 
+typedef struct _vtiful_rich_string_object {
+    xls_resource_rich_string_t ptr;
+    zend_object zo;
+} rich_string_object;
+
 #define REGISTER_CLASS_CONST_LONG(class_name, const_name, value) \
     zend_declare_class_constant_long(class_name, const_name, sizeof(const_name)-1, (zend_long)value);
 
 #define REGISTER_CLASS_PROPERTY_NULL(class_name, property_name, acc) \
     zend_declare_property_null(class_name, ZEND_STRL(property_name), acc);
 
-#define Z_XLS_P(zv)        php_vtiful_xls_fetch_object(Z_OBJ_P(zv));
-#define Z_CHART_P(zv)      php_vtiful_chart_fetch_object(Z_OBJ_P(zv));
-#define Z_FORMAT_P(zv)     php_vtiful_format_fetch_object(Z_OBJ_P(zv));
-#define Z_VALIDATION_P(zv) php_vtiful_validation_fetch_object(Z_OBJ_P(zv));
+#define Z_XLS_P(zv)         php_vtiful_xls_fetch_object(Z_OBJ_P(zv));
+#define Z_CHART_P(zv)       php_vtiful_chart_fetch_object(Z_OBJ_P(zv));
+#define Z_FORMAT_P(zv)      php_vtiful_format_fetch_object(Z_OBJ_P(zv));
+#define Z_VALIDATION_P(zv)  php_vtiful_validation_fetch_object(Z_OBJ_P(zv));
+#define Z_RICH_STR_P(zv)    php_vtiful_rich_string_fetch_object(Z_OBJ_P(zv));
 
 #define WORKBOOK_NOT_INITIALIZED(xls_object_t)                                                                       \
     do {                                                                                                             \
@@ -254,6 +265,14 @@ static inline validation_object *php_vtiful_validation_fetch_object(zend_object
     return (validation_object *)((char *)(obj) - XtOffsetOf(validation_object, zo));
 }
 
+static inline rich_string_object *php_vtiful_rich_string_fetch_object(zend_object *obj) {
+    if (obj == NULL) {
+        return NULL;
+    }
+
+    return (rich_string_object *)((char *)(obj) - XtOffsetOf(validation_object, zo));
+}
+
 static inline void php_vtiful_close_resource(zend_object *obj) {
     if (obj == NULL) {
         return;
@@ -287,10 +306,11 @@ static inline void php_vtiful_close_resource(zend_object *obj) {
     intern->read_ptr.data_type_default = READ_TYPE_EMPTY;
 }
 
-lxw_format           * zval_get_format(zval *handle);
-lxw_data_validation  * zval_get_validation(zval *resource);
-xls_resource_write_t * zval_get_resource(zval *handle);
-xls_resource_chart_t * zval_get_chart(zval *resource);
+lxw_format            * zval_get_format(zval *handle);
+lxw_data_validation   * zval_get_validation(zval *resource);
+lxw_rich_string_tuple * zval_get_rich_string(zval *resource);
+xls_resource_write_t  * zval_get_resource(zval *handle);
+xls_resource_chart_t  * zval_get_chart(zval *resource);
 
 STATIC lxw_error _store_defined_name(lxw_workbook *self, const char *name, const char *app_name, const char *formula, int16_t index, uint8_t hidden);
 
@@ -327,6 +347,7 @@ void worksheet_set_rows(lxw_row_t start, lxw_row_t end, double height, xls_resou
 void image_writer(zval *value, zend_long row, zend_long columns, double width, double height, xls_resource_write_t *res);
 void formula_writer(zend_string *value, zend_long row, zend_long columns, xls_resource_write_t *res, lxw_format *format);
 void type_writer(zval *value, zend_long row, zend_long columns, xls_resource_write_t *res, zend_string *format, lxw_format *format_handle);
+void rich_string_writer(zend_long row, zend_long columns, xls_resource_write_t *res, zval *rich_strings, lxw_format *format);
 void datetime_writer(lxw_datetime *datetime, zend_long row, zend_long columns, zend_string *format, xls_resource_write_t *res, lxw_format *format_handle);
 void url_writer(zend_long row, zend_long columns, xls_resource_write_t *res, zend_string *url, zend_string *text, zend_string *tool_tip, lxw_format *format);
 

+ 39 - 0
kernel/excel.c

@@ -117,6 +117,13 @@ ZEND_BEGIN_ARG_INFO_EX(xls_insert_text_arginfo, 0, 0, 3)
                 ZEND_ARG_INFO(0, format_handle)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO_EX(xls_insert_rtext_arginfo, 0, 0, 3)
+                ZEND_ARG_INFO(0, row)
+                ZEND_ARG_INFO(0, column)
+                ZEND_ARG_INFO(0, rich_strings)
+                ZEND_ARG_INFO(0, format_handle)
+ZEND_END_ARG_INFO()
+
 ZEND_BEGIN_ARG_INFO_EX(xls_insert_date_arginfo, 0, 0, 3)
                 ZEND_ARG_INFO(0, row)
                 ZEND_ARG_INFO(0, column)
@@ -700,6 +707,37 @@ PHP_METHOD(vtiful_xls, insertText)
 }
 /* }}} */
 
+/** {{{ \Vtiful\Kernel\Excel::insertRichText(int $row, int $column, array $richString[, resource $formatHandle])
+ */
+PHP_METHOD(vtiful_xls, insertRichText)
+{
+    zend_long row = 0, column = 0;
+    zval *rich_strings = NULL, *format_handle = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(3, 4)
+            Z_PARAM_LONG(row)
+            Z_PARAM_LONG(column)
+            Z_PARAM_ARRAY(rich_strings)
+            Z_PARAM_OPTIONAL
+            Z_PARAM_RESOURCE_OR_NULL(format_handle)
+    ZEND_PARSE_PARAMETERS_END();
+
+    ZVAL_COPY(return_value, getThis());
+
+    xls_object *obj = Z_XLS_P(getThis());
+
+    WORKBOOK_NOT_INITIALIZED(obj);
+
+    SHEET_LINE_SET(obj, row);
+
+    if (format_handle != NULL) {
+        rich_string_writer(row, column, &obj->write_ptr, rich_strings, zval_get_format(format_handle));
+    } else {
+        rich_string_writer(row, column, &obj->write_ptr, rich_strings, obj->format_ptr.format);
+    }
+}
+/* }}} */
+
 /** {{{ \Vtiful\Kernel\Excel::insertDate(int $row, int $column, int $timestamp[, string $format, resource $formatHandle])
  */
 PHP_METHOD(vtiful_xls, insertDate)
@@ -1632,6 +1670,7 @@ zend_function_entry xls_methods[] = {
         PHP_ME(vtiful_xls, getHandle,      xls_get_handle_arginfo,     ZEND_ACC_PUBLIC)
         PHP_ME(vtiful_xls, autoFilter,     xls_auto_filter_arginfo,    ZEND_ACC_PUBLIC)
         PHP_ME(vtiful_xls, insertText,     xls_insert_text_arginfo,    ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_xls, insertRichText, xls_insert_rtext_arginfo,   ZEND_ACC_PUBLIC)
         PHP_ME(vtiful_xls, insertDate,     xls_insert_date_arginfo,    ZEND_ACC_PUBLIC)
         PHP_ME(vtiful_xls, insertChart,    xls_insert_chart_arginfo,   ZEND_ACC_PUBLIC)
         PHP_ME(vtiful_xls, insertUrl,      xls_insert_url_arginfo,     ZEND_ACC_PUBLIC)

+ 0 - 1
kernel/format.c

@@ -386,7 +386,6 @@ PHP_METHOD(vtiful_format, toResource)
 }
 /* }}} */
 
-
 /** {{{ format_methods
 */
 zend_function_entry format_methods[] = {

+ 13 - 0
kernel/resource.c

@@ -59,6 +59,19 @@ xls_resource_chart_t *zval_get_chart(zval *resource)
 }
 /* }}} */
 
+/* {{{ */
+lxw_rich_string_tuple *zval_get_rich_string(zval *resource)
+{
+    lxw_rich_string_tuple *res;
+
+    if((res = (lxw_rich_string_tuple *)zend_fetch_resource(Z_RES_P(resource), VTIFUL_RESOURCE_NAME, le_xls_writer)) == NULL) {
+        zend_throw_exception(vtiful_exception_ce, "rich string resources resolution fail", 210);
+    }
+
+    return res;
+}
+/* }}} */
+
 /* {{{ */
 lxw_data_validation *zval_get_validation(zval *resource)
 {

+ 125 - 0
kernel/rich_string.c

@@ -0,0 +1,125 @@
+/*
+  +----------------------------------------------------------------------+
+  | XlsWriter Extension                                                  |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2017-2018 The Viest                                    |
+  +----------------------------------------------------------------------+
+  | http://www.viest.me                                                  |
+  +----------------------------------------------------------------------+
+  | Author: viest <[email protected]>                                 |
+  +----------------------------------------------------------------------+
+*/
+
+#include "xlswriter.h"
+
+zend_class_entry *vtiful_rich_string_ce;
+
+/* {{{ rich_string_objects_new
+ */
+static zend_object_handlers rich_string_handlers;
+
+static zend_always_inline void *vtiful_rich_string_object_alloc(size_t obj_size, zend_class_entry *ce) {
+    void *obj = emalloc(obj_size);
+    memset(obj, 0, obj_size);
+    return obj;
+}
+
+PHP_VTIFUL_API zend_object *rich_string_objects_new(zend_class_entry *ce)
+{
+    rich_string_object *rich_string = vtiful_rich_string_object_alloc(sizeof(rich_string_object), ce);
+
+    zend_object_std_init(&rich_string->zo, ce);
+    object_properties_init(&rich_string->zo, ce);
+
+    rich_string->ptr.tuple = NULL;
+    rich_string->zo.handlers = &rich_string_handlers;
+
+    return &rich_string->zo;
+}
+/* }}} */
+
+/* {{{ rich_string_objects_free
+ */
+static void rich_string_objects_free(zend_object *object)
+{
+    rich_string_object *intern = php_vtiful_rich_string_fetch_object(object);
+
+    if (intern->ptr.tuple != NULL) {
+        efree(intern->ptr.tuple);
+        intern->ptr.tuple = NULL;
+    }
+
+    zend_object_std_dtor(&intern->zo);
+}
+/* }}} */
+
+/* {{{ ARG_INFO
+ */
+ZEND_BEGIN_ARG_INFO_EX(rich_string_construct_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, text)
+                ZEND_ARG_INFO(0, format_handle)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\RichString::__construct(string $text, resource $format)
+ */
+PHP_METHOD(vtiful_rich_string, __construct)
+{
+    zend_string *text = NULL;
+    zval *format_handle = NULL;
+    rich_string_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 2)
+            Z_PARAM_STR(text)
+            Z_PARAM_OPTIONAL
+            Z_PARAM_RESOURCE_OR_NULL(format_handle)
+    ZEND_PARSE_PARAMETERS_END();
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj = Z_RICH_STR_P(getThis());
+
+    if (obj->ptr.tuple != NULL) {
+        return;
+    }
+
+    lxw_rich_string_tuple *instance = (lxw_rich_string_tuple *)ecalloc(1, sizeof(lxw_rich_string_tuple));
+
+    zend_string *zstr = zend_string_copy(text);
+
+    if (format_handle == NULL) {
+        instance->format = NULL;
+        instance->string = ZSTR_VAL(zstr);
+    } else {
+        instance->format = zval_get_format(format_handle);
+        instance->string = ZSTR_VAL(zstr);
+    }
+
+    obj->ptr.tuple = instance;
+}
+/* }}} */
+
+/** {{{ rich_string_methods
+*/
+zend_function_entry rich_string_methods[] = {
+        PHP_ME(vtiful_rich_string, __construct, rich_string_construct_arginfo,   ZEND_ACC_PUBLIC)
+        PHP_FE_END
+};
+/* }}} */
+
+/** {{{ VTIFUL_STARTUP_FUNCTION
+*/
+VTIFUL_STARTUP_FUNCTION(rich_string) {
+        zend_class_entry ce;
+
+        INIT_NS_CLASS_ENTRY(ce, "Vtiful\\Kernel", "RichString", rich_string_methods);
+        ce.create_object = rich_string_objects_new;
+        vtiful_rich_string_ce = zend_register_internal_class(&ce);
+
+        memcpy(&rich_string_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+        rich_string_handlers.offset   = XtOffsetOf(rich_string_object, zo);
+        rich_string_handlers.free_obj = rich_string_objects_free;
+
+        return SUCCESS;
+}
+/* }}} */

+ 43 - 0
kernel/write.c

@@ -90,6 +90,49 @@ void type_writer(zval *value, zend_long row, zend_long columns, xls_resource_wri
     }
 }
 
+/*
+ * Write the rich string to the file
+ */
+void rich_string_writer(zend_long row, zend_long columns, xls_resource_write_t *res, zval *rich_strings, lxw_format *format)
+{
+    int index = 0, resource_count = 0;
+    zval *zv_rich_string = NULL;
+
+    lxw_col_t lxw_col = (lxw_col_t)columns;
+    lxw_row_t lxw_row = (lxw_row_t)row;
+
+    if (Z_TYPE_P(rich_strings) != IS_ARRAY) {
+        return;
+    }
+
+    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(rich_strings), zv_rich_string)
+        if (Z_TYPE_P(zv_rich_string) != IS_OBJECT) {
+            continue;
+        }
+
+        if (!instanceof_function(Z_OBJCE_P(zv_rich_string), vtiful_rich_string_ce)) {
+            zend_throw_exception(vtiful_exception_ce, "The parameter must be an instance of Vtiful\\Kernel\\RichString.", 500);
+            return;
+        }
+
+        resource_count++;
+    ZEND_HASH_FOREACH_END();
+
+    lxw_rich_string_tuple **rich_string_list = (lxw_rich_string_tuple **)ecalloc(resource_count + 1,sizeof(lxw_rich_string_tuple *));
+
+    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(rich_strings), zv_rich_string)
+        rich_string_object *obj = Z_RICH_STR_P(zv_rich_string);
+        rich_string_list[index] = obj->ptr.tuple;
+        index++;
+    ZEND_HASH_FOREACH_END();
+
+    rich_string_list[index] = NULL;
+
+    WORKSHEET_WRITER_EXCEPTION(worksheet_write_rich_string(res->worksheet, lxw_row, lxw_col, rich_string_list, format));
+
+    efree(rich_string_list);
+}
+
 void format_copy(lxw_format *new_format, lxw_format *other_format)
 {
     new_format->bold = other_format->bold;

+ 56 - 0
tests/rich_string.phpt

@@ -0,0 +1,56 @@
+--TEST--
+Check for vtiful presence
+--SKIPIF--
+<?php if (!extension_loaded("xlswriter")) print "skip"; ?>
+--FILE--
+<?php
+$config = ['path' => './tests'];
+$fileObject = new \Vtiful\Kernel\Excel($config);
+
+$fileObject = $fileObject->fileName("rich_string.xlsx")
+    ->header(['rich string']);
+
+$fileHandle = $fileObject->getHandle();
+
+$format1  = new \Vtiful\Kernel\Format($fileHandle);
+$colorRed = $format1->fontColor(\Vtiful\Kernel\Format::COLOR_GREEN)->toResource();
+
+$format2     = new \Vtiful\Kernel\Format($fileHandle);
+$colorOrange = $format2->fontColor(\Vtiful\Kernel\Format::COLOR_ORANGE)->toResource();
+
+$richStringOne = new \Vtiful\Kernel\RichString('red ', $colorRed);
+$richStringTwo = new \Vtiful\Kernel\RichString('orange', $colorOrange);
+
+$fileObject->insertRichText(1, 0, [
+    $richStringOne,
+    $richStringTwo
+]);
+
+$filePath = $fileObject->output();
+
+$data = $fileObject->openFile('rich_string.xlsx')
+    ->openSheet()
+    ->getSheetData();
+
+var_dump($filePath);
+var_dump($data);
+?>
+--CLEAN--
+<?php
+@unlink(__DIR__ . '/rich_string.xlsx');
+?>
+--EXPECT--
+string(24) "./tests/rich_string.xlsx"
+array(2) {
+  [0]=>
+  array(1) {
+    [0]=>
+    string(11) "rich string"
+  }
+  [1]=>
+  array(1) {
+    [0]=>
+    string(10) "red orange"
+  }
+}
+

+ 1 - 0
xlswriter.c

@@ -56,6 +56,7 @@ PHP_MINIT_FUNCTION(xlswriter)
 	VTIFUL_STARTUP_MODULE(format);
 	VTIFUL_STARTUP_MODULE(chart);
     VTIFUL_STARTUP_MODULE(validation);
+    VTIFUL_STARTUP_MODULE(rich_string);
 
 	le_xls_writer = zend_register_list_destructors_ex(_php_vtiful_xls_close, NULL, VTIFUL_RESOURCE_NAME, module_number);