浏览代码

Merge pull request #352 from viest/dev

Feat: validation
viest 4 年之前
父节点
当前提交
8e9c66a8a0

+ 1 - 0
config.m4

@@ -21,6 +21,7 @@ if test "$PHP_XLSWRITER" != "no"; then
     kernel/format.c \
     kernel/chart.c \
     kernel/help.c \
+    kernel/validation.c \
     "
 
     xls_read_sources="

+ 1 - 0
config.w32

@@ -28,6 +28,7 @@ if (PHP_XLSWRITER != "no") {
                 read.c \
                 csv.c \
                 help.c \
+                validation.c \
                 ", "xlswriter");
 
         ADD_SOURCES(configure_module_dirname + "\\library\\libxlsxwriter\\third_party\\minizip", "\

+ 20 - 0
include/validation.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_WRITER_VALIDATION_H
+#define PHP_EXT_XLS_WRITER_VALIDATION_H
+
+extern zend_class_entry *vtiful_validation_ce;
+
+VTIFUL_STARTUP_FUNCTION(validation);
+
+#endif // PHP_EXT_XLS_WRITER_VALIDATION_H

+ 22 - 3
include/xlswriter.h

@@ -18,6 +18,7 @@
 #endif
 
 #include <php.h>
+#include "ext/date/php_date.h"
 
 #include "zend_smart_str.h"
 #include "zend_exceptions.h"
@@ -31,6 +32,7 @@
 
 #include "php_xlswriter.h"
 #include "excel.h"
+#include "validation.h"
 #include "exception.h"
 #include "format.h"
 #include "chart.h"
@@ -84,6 +86,10 @@ typedef struct {
     lxw_format  *format;
 } xls_resource_format_t;
 
+typedef struct {
+    lxw_data_validation *validation;
+} xls_resource_validation_t;
+
 typedef struct {
     lxw_chart *chart;
     lxw_chart_series *series;
@@ -107,6 +113,11 @@ typedef struct _vtiful_chart_object {
     zend_object zo;
 } chart_object;
 
+typedef struct _vtiful_validation_object {
+    xls_resource_validation_t ptr;
+    zend_object zo;
+} validation_object;
+
 static inline xls_object *php_vtiful_xls_fetch_object(zend_object *obj) {
     return (xls_object *)((char *)(obj) - XtOffsetOf(xls_object, zo));
 }
@@ -119,15 +130,20 @@ static inline chart_object *php_vtiful_chart_fetch_object(zend_object *obj) {
     return (chart_object *)((char *)(obj) - XtOffsetOf(chart_object, zo));
 }
 
+static inline validation_object *php_vtiful_validation_fetch_object(zend_object *obj) {
+    return (validation_object *)((char *)(obj) - XtOffsetOf(validation_object, zo));
+}
+
 #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_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 WORKBOOK_NOT_INITIALIZED(xls_object_t)                                                                       \
     do {                                                                                                             \
@@ -209,6 +225,7 @@ static inline chart_object *php_vtiful_chart_fetch_object(zend_object *obj) {
 
 
 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);
 
@@ -235,6 +252,7 @@ void printed_direction(xls_resource_write_t *res, unsigned int direction);
 void xls_file_path(zend_string *file_name, zval *dir_path, zval *file_path);
 void freeze_panes(xls_resource_write_t *res, zend_long row, zend_long column);
 void set_row(zend_string *range, double height, xls_resource_write_t *res, lxw_format *format);
+void validation(xls_resource_write_t *res, zend_string *range, lxw_data_validation *validation);
 void set_column(zend_string *range, double width, xls_resource_write_t *res, lxw_format *format);
 void merge_cells(zend_string *range, zval *value, xls_resource_write_t *res, lxw_format *format);
 void comment_writer(zend_string *comment, zend_long row, zend_long columns, xls_resource_write_t *res);
@@ -249,6 +267,7 @@ void url_writer(zend_long row, zend_long columns, xls_resource_write_t *res, zen
 
 lxw_error workbook_file(xls_resource_write_t *self);
 
+lxw_datetime timestamp_to_datetime(zend_long timestamp);
 zend_string* str_pick_up(zend_string *left, const char *right, size_t len);
 
 #endif

+ 17 - 1
kernel/common.c

@@ -69,4 +69,20 @@ void call_object_method(zval *object, const char *function_name, uint32_t param_
 
     zval_ptr_dtor(&z_f_name);
 }
-/* }}} */
+/* }}} */
+
+lxw_datetime timestamp_to_datetime(zend_long timestamp)
+{
+    int yearLocal   = php_idate('Y', timestamp, 0);
+    int monthLocal  = php_idate('m', timestamp, 0);
+    int dayLocal    = php_idate('d', timestamp, 0);
+    int hourLocal   = php_idate('H', timestamp, 0);
+    int minuteLocal = php_idate('i', timestamp, 0);
+    int secondLocal = php_idate('s', timestamp, 0);
+
+    lxw_datetime datetime = {
+            yearLocal, monthLocal, dayLocal, hourLocal, minuteLocal, secondLocal
+    };
+
+    return datetime;
+}

+ 29 - 11
kernel/excel.c

@@ -11,7 +11,6 @@
 */
 
 #include "xlswriter.h"
-#include "ext/date/php_date.h"
 
 zend_class_entry *vtiful_xls_ce;
 
@@ -267,6 +266,11 @@ ZEND_BEGIN_ARG_INFO_EX(xls_protection_arginfo, 0, 0, 0)
                 ZEND_ARG_INFO(0, password)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO_EX(xls_validation_arginfo, 0, 0, 2)
+                ZEND_ARG_INFO(0, range)
+                ZEND_ARG_INFO(0, validation_resource)
+ZEND_END_ARG_INFO()
+
 ZEND_BEGIN_ARG_INFO_EX(xls_set_printed_portrait_arginfo, 0, 0, 0)
 ZEND_END_ARG_INFO()
 
@@ -640,16 +644,7 @@ PHP_METHOD(vtiful_xls, insertDate)
         format = zend_string_init(ZEND_STRL("yyyy-mm-dd hh:mm:ss"), 0);
     }
 
-    int yearLocal   = php_idate('Y', data->value.lval, 0);
-    int monthLocal  = php_idate('m', data->value.lval, 0);
-    int dayLocal    = php_idate('d', data->value.lval, 0);
-    int hourLocal   = php_idate('H', data->value.lval, 0);
-    int minuteLocal = php_idate('i', data->value.lval, 0);
-    int secondLocal = php_idate('s', data->value.lval, 0);
-
-    lxw_datetime datetime = {
-            yearLocal, monthLocal, dayLocal, hourLocal, minuteLocal, secondLocal
-    };
+    lxw_datetime datetime = timestamp_to_datetime(data->value.lval);
 
     if (format_handle) {
         datetime_writer(&datetime, row, column, format, &obj->write_ptr, zval_get_format(format_handle));
@@ -1172,6 +1167,28 @@ PHP_METHOD(vtiful_xls, setCurrentSheetIsFirst)
 }
 /* }}} */
 
+/** {{{ \Vtiful\Kernel\Excel::validation()
+ */
+PHP_METHOD(vtiful_xls, validation)
+{
+    zend_string *range = NULL;
+    zval *validation_handle = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(2, 2)
+            Z_PARAM_STR(range)
+            Z_PARAM_RESOURCE(validation_handle)
+    ZEND_PARSE_PARAMETERS_END();
+
+    ZVAL_COPY(return_value, getThis());
+
+    xls_object *obj = Z_XLS_P(getThis());
+
+    WORKBOOK_NOT_INITIALIZED(obj);
+
+    validation(&obj->write_ptr, range, zval_get_validation(validation_handle));
+}
+/* }}} */
+
 #ifdef ENABLE_READER
 
 /** {{{ \Vtiful\Kernel\Excel::openFile()
@@ -1497,6 +1514,7 @@ zend_function_entry xls_methods[] = {
         PHP_ME(vtiful_xls, freezePanes,   xls_freeze_panes_arginfo,   ZEND_ACC_PUBLIC)
 
         PHP_ME(vtiful_xls, protection,    xls_protection_arginfo,     ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_xls, validation,    xls_validation_arginfo,     ZEND_ACC_PUBLIC)
 
         PHP_ME(vtiful_xls, zoom,          xls_sheet_zoom_arginfo,     ZEND_ACC_PUBLIC)
         PHP_ME(vtiful_xls, gridline,      xls_sheet_gridline_arginfo, ZEND_ACC_PUBLIC)

+ 16 - 1
kernel/resource.c

@@ -38,6 +38,7 @@ lxw_format * zval_get_format(zval *handle)
 }
 /* }}} */
 
+/* {{{ */
 xls_resource_chart_t *zval_get_chart(zval *resource)
 {
     xls_resource_chart_t *res;
@@ -47,4 +48,18 @@ xls_resource_chart_t *zval_get_chart(zval *resource)
     }
 
     return res;
-}
+}
+/* }}} */
+
+/* {{{ */
+lxw_data_validation *zval_get_validation(zval *resource)
+{
+    lxw_data_validation *res;
+
+    if((res = (lxw_data_validation *)zend_fetch_resource(Z_RES_P(resource), VTIFUL_RESOURCE_NAME, le_xls_writer)) == NULL) {
+        zend_throw_exception(vtiful_exception_ce, "validation resources resolution fail", 210);
+    }
+
+    return res;
+}
+/* }}} */

+ 826 - 0
kernel/validation.c

@@ -0,0 +1,826 @@
+/*
+  +----------------------------------------------------------------------+
+  | XlsWriter Extension                                                  |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2017-2018 The Viest                                    |
+  +----------------------------------------------------------------------+
+  | http://www.viest.me                                                  |
+  +----------------------------------------------------------------------+
+  | Author: viest <[email protected]>                                 |
+  +----------------------------------------------------------------------+
+*/
+
+#include "xlswriter.h"
+
+zend_class_entry *vtiful_validation_ce;
+
+/* {{{ validation_objects_new
+ */
+static zend_object_handlers validation_handlers;
+
+static zend_always_inline void *vtiful_validation_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 *validation_objects_new(zend_class_entry *ce)
+{
+    validation_object *validation = vtiful_validation_object_alloc(sizeof(validation_object), ce);
+
+    zend_object_std_init(&validation->zo, ce);
+    object_properties_init(&validation->zo, ce);
+
+    validation->ptr.validation = NULL;
+
+    validation->zo.handlers = &validation_handlers;
+
+    return &validation->zo;
+}
+/* }}} */
+
+/* {{{ validation_objects_free
+ */
+static void validation_objects_free(zend_object *object)
+{
+    validation_object *intern = php_vtiful_validation_fetch_object(object);
+
+    if (intern->ptr.validation->value_list != NULL) {
+        int index = 0;
+
+        do {
+            if (intern->ptr.validation->value_list[index] == NULL) {
+                break;
+            }
+
+            efree(intern->ptr.validation->value_list[index]);
+            index++;
+        } while (1);
+
+        efree(intern->ptr.validation->value_list);
+    }
+
+    if (intern->ptr.validation != NULL) {
+        efree(intern->ptr.validation);
+    }
+
+    zend_object_std_dtor(&intern->zo);
+}
+/* }}} */
+
+/* {{{ ARG_INFO
+ */
+ZEND_BEGIN_ARG_INFO_EX(validation_construct_arginfo, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_type_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, type)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_criteria_type_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, type)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_ignore_blank_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, ignore_blank)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_show_input_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, show_input)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_show_error_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, show_error)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_error_type_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, error_type)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_dropdown_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, dropdown)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_value_number_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, value_number)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_value_formula_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, value_formula)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_value_list_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, value_list)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_value_date_time_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, timestamp)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_minimum_number_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, minimum_number)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_minimum_formula_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, minimum_formula)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_minimum_datetime_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, timestamp)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_maximum_number_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, maximum_number)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_maximum_formula_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, maximum_formula)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_maximum_datetime_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, maximum_datetime)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_input_title_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, input_title)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_input_message_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, input_message)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_error_title_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, error_titile)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_error_message_arginfo, 0, 0, 1)
+                ZEND_ARG_INFO(0, error_message)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(validation_to_resource_arginfo, 0, 0, 1)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::__construct()
+ */
+PHP_METHOD(vtiful_validation, __construct)
+{
+    validation_object *obj = NULL;
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        obj->ptr.validation = ecalloc(1, sizeof(lxw_data_validation));
+    }
+
+    obj->ptr.validation->value_list = NULL;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::validationType()
+ */
+PHP_METHOD(vtiful_validation, validationType)
+{
+    zend_long zl_validate_type = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_LONG(zl_validate_type)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    if (zl_validate_type < LXW_VALIDATION_TYPE_NONE || zl_validate_type > LXW_VALIDATION_TYPE_ANY) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->validate = zl_validate_type;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::criteriaType()
+ */
+PHP_METHOD(vtiful_validation, criteriaType)
+{
+    zend_long zl_criteria_type = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_LONG(zl_criteria_type)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    if (zl_criteria_type < LXW_VALIDATION_CRITERIA_NONE || zl_criteria_type > LXW_VALIDATION_CRITERIA_LESS_THAN_OR_EQUAL_TO) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->criteria = zl_criteria_type;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::ignoreBlank()
+ */
+PHP_METHOD(vtiful_validation, ignoreBlank)
+{
+    zend_bool zb_ignore_blank = 1;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(0, 1)
+            Z_PARAM_OPTIONAL
+            Z_PARAM_BOOL(zb_ignore_blank)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    if (zb_ignore_blank) {
+        obj->ptr.validation->ignore_blank = LXW_VALIDATION_ON;
+
+        return;
+    }
+
+    obj->ptr.validation->ignore_blank = LXW_VALIDATION_OFF;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::showInput()
+ */
+PHP_METHOD(vtiful_validation, showInput)
+{
+    zend_bool zb_show_input = 1;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(0, 1)
+            Z_PARAM_OPTIONAL
+            Z_PARAM_BOOL(zb_show_input)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    if (zb_show_input) {
+        obj->ptr.validation->show_input = LXW_VALIDATION_ON;
+
+        return;
+    }
+
+    obj->ptr.validation->show_input = LXW_VALIDATION_OFF;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::showError()
+ */
+PHP_METHOD(vtiful_validation, showError)
+{
+    zend_bool zb_show_error = 1;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(0, 1)
+            Z_PARAM_OPTIONAL
+            Z_PARAM_BOOL(zb_show_error)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    if (zb_show_error) {
+        obj->ptr.validation->show_error = LXW_VALIDATION_ON;
+
+        return;
+    }
+
+    obj->ptr.validation->show_error = LXW_VALIDATION_OFF;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::errorType()
+ */
+PHP_METHOD(vtiful_validation, errorType)
+{
+    zend_long zl_error_type = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_LONG(zl_error_type)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    if (zl_error_type < LXW_VALIDATION_ERROR_TYPE_STOP || zl_error_type > LXW_VALIDATION_ERROR_TYPE_INFORMATION) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->error_type = zl_error_type;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::dropdown()
+ */
+PHP_METHOD(vtiful_validation, dropdown)
+{
+    zend_bool zb_dropdown = 1;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(0, 1)
+            Z_PARAM_OPTIONAL
+            Z_PARAM_BOOL(zb_dropdown)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    if (zb_dropdown) {
+        obj->ptr.validation->dropdown = LXW_VALIDATION_ON;
+
+        return;
+    }
+
+    obj->ptr.validation->dropdown = LXW_VALIDATION_OFF;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::valueNumber()
+ */
+PHP_METHOD(vtiful_validation, valueNumber)
+{
+    zend_long zl_value_number = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_LONG(zl_value_number)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->value_number = zl_value_number;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::valueFormula()
+ */
+PHP_METHOD(vtiful_validation, valueFormula)
+{
+    zend_string *zs_value_formula = NULL;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_STR(zs_value_formula)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->value_formula = ZSTR_VAL(zs_value_formula);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::valueList()
+ */
+PHP_METHOD(vtiful_validation, valueList)
+{
+    int index = 0;
+    char **list = NULL;
+
+    Bucket *bucket;
+    zval *zv_value_list = NULL;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_ARRAY(zv_value_list)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    if (obj->ptr.validation->value_list != NULL) {
+        do {
+            if (obj->ptr.validation->value_list[index] == NULL) {
+                break;
+            }
+
+            efree(obj->ptr.validation->value_list[index]);
+            index++;
+        } while (1);
+
+        efree(obj->ptr.validation->value_list);
+        obj->ptr.validation->value_list = NULL;
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    zend_array *za_value_list = Z_ARR_P(zv_value_list);
+
+    ZEND_HASH_FOREACH_BUCKET(za_value_list, bucket)
+            if (Z_TYPE(bucket->val) != IS_STRING) {
+                zend_throw_exception(vtiful_exception_ce, "Arrays can only consist of strings.", 300);
+                return;
+            }
+            if (ZSTR_LEN(bucket->val.value.str) == 0 ) {
+                zend_throw_exception(vtiful_exception_ce, "Array value is empty string.", 301);
+                return;
+            }
+    ZEND_HASH_FOREACH_END();
+
+    index = 0;
+    list = ecalloc(za_value_list->nNumOfElements + 1, sizeof(char *));
+
+    ZEND_HASH_FOREACH_BUCKET(za_value_list, bucket)
+            list[index] = ecalloc(1, bucket->val.value.str->len + 1);
+            strcpy(list[index],bucket->val.value.str->val);
+            index++;
+    ZEND_HASH_FOREACH_END();
+
+    list[index] = NULL;
+
+    obj->ptr.validation->value_list = list;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::valueDatetime(int $timestamp)
+ */
+PHP_METHOD(vtiful_validation, valueDatetime)
+{
+    zend_long timestamp = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_LONG(timestamp)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    obj->ptr.validation->value_datetime = timestamp_to_datetime(timestamp);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::minimumNumber(double $minimumNumber)
+ */
+PHP_METHOD(vtiful_validation, minimumNumber)
+{
+    double minimum_number = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_DOUBLE(minimum_number)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->minimum_number = minimum_number;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::minimumFormula()
+ */
+PHP_METHOD(vtiful_validation, minimumFormula)
+{
+    zend_string *zs_minimum_formula = NULL;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_STR(zs_minimum_formula)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->minimum_formula = ZSTR_VAL(zs_minimum_formula);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::minimumDatetime(int $timestamp)
+ */
+PHP_METHOD(vtiful_validation, minimumDatetime)
+{
+    zend_long timestamp = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_LONG(timestamp)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    obj->ptr.validation->minimum_datetime = timestamp_to_datetime(timestamp);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::maximumNumber(double $maximumNumber)
+ */
+PHP_METHOD(vtiful_validation, maximumNumber)
+{
+    double maximum_number = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_DOUBLE(maximum_number)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->maximum_number = maximum_number;
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::maximumFormula()
+ */
+PHP_METHOD(vtiful_validation, maximumFormula)
+{
+    zend_string *zs_maximum_formula = NULL;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_STR(zs_maximum_formula)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->maximum_formula = ZSTR_VAL(zs_maximum_formula);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::maximumDatetime(int $timestamp)
+ */
+PHP_METHOD(vtiful_validation, maximumDatetime)
+{
+    zend_long timestamp = 0;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_LONG(timestamp)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    obj->ptr.validation->maximum_datetime = timestamp_to_datetime(timestamp);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::inputTitle()
+ */
+PHP_METHOD(vtiful_validation, inputTitle)
+{
+    zend_string *zs_input_title = NULL;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_STR(zs_input_title)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->input_title = ZSTR_VAL(zs_input_title);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::inputMessage()
+ */
+PHP_METHOD(vtiful_validation, inputMessage)
+{
+    zend_string *zs_input_message = NULL;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_STR(zs_input_message)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->input_message = ZSTR_VAL(zs_input_message);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::errorTitle()
+ */
+PHP_METHOD(vtiful_validation, errorTitle)
+{
+    zend_string *zs_error_title = NULL;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_STR(zs_error_title)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->error_title = ZSTR_VAL(zs_error_title);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::errorMessage()
+ */
+PHP_METHOD(vtiful_validation, errorMessage)
+{
+    zend_string *zs_error_message = NULL;
+    validation_object *obj = NULL;
+
+    ZEND_PARSE_PARAMETERS_START(1, 1)
+            Z_PARAM_STR(zs_error_message)
+    ZEND_PARSE_PARAMETERS_END();
+
+    obj = Z_VALIDATION_P(getThis());
+
+    if (obj->ptr.validation == NULL) {
+        RETURN_NULL();
+    }
+
+    ZVAL_COPY(return_value, getThis());
+
+    obj->ptr.validation->error_message = ZSTR_VAL(zs_error_message);
+}
+/* }}} */
+
+/** {{{ \Vtiful\Kernel\Validation::toResource()
+ */
+PHP_METHOD(vtiful_validation, toResource)
+{
+    validation_object *obj = Z_VALIDATION_P(getThis());
+
+    RETURN_RES(zend_register_resource(obj->ptr.validation, le_xls_writer));
+}
+/* }}} */
+
+/** {{{ validation_methods
+*/
+zend_function_entry validation_methods[] = {
+        PHP_ME(vtiful_validation, __construct,     validation_construct_arginfo,        ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, validationType,  validation_type_arginfo,             ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, criteriaType,    validation_criteria_type_arginfo,    ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, ignoreBlank,     validation_ignore_blank_arginfo,     ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, showInput,       validation_show_input_arginfo,       ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, showError ,      validation_show_error_arginfo,       ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, errorType ,      validation_error_type_arginfo,       ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, dropdown ,       validation_dropdown_arginfo,         ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, valueNumber,     validation_value_number_arginfo,     ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, valueFormula,    validation_value_formula_arginfo,    ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, valueList,       validation_value_list_arginfo,       ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, valueDatetime,   validation_value_date_time_arginfo,  ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, minimumNumber,   validation_minimum_number_arginfo,   ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, minimumFormula,  validation_minimum_formula_arginfo,  ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, minimumDatetime, validation_minimum_datetime_arginfo, ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, maximumNumber,   validation_maximum_number_arginfo,   ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, maximumFormula,  validation_maximum_formula_arginfo,  ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, maximumDatetime, validation_maximum_datetime_arginfo, ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, inputTitle,      validation_input_title_arginfo,      ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, inputMessage,    validation_input_message_arginfo,    ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, errorTitle,      validation_error_title_arginfo,      ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, errorMessage,    validation_error_message_arginfo,    ZEND_ACC_PUBLIC)
+        PHP_ME(vtiful_validation, toResource,      validation_to_resource_arginfo,      ZEND_ACC_PUBLIC)
+        PHP_FE_END
+};
+/* }}} */
+
+/** {{{ VTIFUL_STARTUP_FUNCTION
+*/
+VTIFUL_STARTUP_FUNCTION(validation) {
+    zend_class_entry ce;
+
+    INIT_NS_CLASS_ENTRY(ce, "Vtiful\\Kernel", "Validation", validation_methods);
+    ce.create_object     = validation_objects_new;
+    vtiful_validation_ce = zend_register_internal_class(&ce);
+
+    memcpy(&validation_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+    validation_handlers.offset   = XtOffsetOf(validation_object, zo);
+    validation_handlers.free_obj = validation_objects_free;
+
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_INTEGER",         LXW_VALIDATION_TYPE_INTEGER)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_INTEGER_FORMULA", LXW_VALIDATION_TYPE_INTEGER_FORMULA)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_DECIMAL",         LXW_VALIDATION_TYPE_DECIMAL)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_DECIMAL_FORMULA", LXW_VALIDATION_TYPE_DECIMAL_FORMULA)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_LIST",            LXW_VALIDATION_TYPE_LIST)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_LIST_FORMULA",    LXW_VALIDATION_TYPE_LIST_FORMULA)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_DATE",            LXW_VALIDATION_TYPE_DATE)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_DATE_FORMULA",    LXW_VALIDATION_TYPE_DATE_FORMULA)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_DATE_NUMBER",     LXW_VALIDATION_TYPE_DATE_NUMBER)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_TIME",            LXW_VALIDATION_TYPE_TIME)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_TIME_FORMULA",    LXW_VALIDATION_TYPE_TIME_FORMULA)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_TIME_NUMBER",     LXW_VALIDATION_TYPE_TIME_NUMBER)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_LENGTH",          LXW_VALIDATION_TYPE_LENGTH)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_LENGTH_FORMULA",  LXW_VALIDATION_TYPE_LENGTH_FORMULA)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_CUSTOM_FORMULA",  LXW_VALIDATION_TYPE_CUSTOM_FORMULA)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "TYPE_ANY",             LXW_VALIDATION_TYPE_ANY)
+
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "CRITERIA_BETWEEN",                  LXW_VALIDATION_CRITERIA_BETWEEN)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "CRITERIA_NOT_BETWEEN",              LXW_VALIDATION_CRITERIA_NOT_BETWEEN)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "CRITERIA_EQUAL_TO",                 LXW_VALIDATION_CRITERIA_EQUAL_TO)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "CRITERIA_NOT_EQUAL_TO",             LXW_VALIDATION_CRITERIA_NOT_EQUAL_TO)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "CRITERIA_GREATER_THAN",             LXW_VALIDATION_CRITERIA_GREATER_THAN)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "CRITERIA_LESS_THAN",                LXW_VALIDATION_CRITERIA_LESS_THAN)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "CRITERIA_GREATER_THAN_OR_EQUAL_TO", LXW_VALIDATION_CRITERIA_GREATER_THAN_OR_EQUAL_TO)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "CRITERIA_LESS_THAN_OR_EQUAL_TO",    LXW_VALIDATION_CRITERIA_LESS_THAN_OR_EQUAL_TO)
+
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "ERROR_TYPE_STOP",        LXW_VALIDATION_ERROR_TYPE_STOP)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "ERROR_TYPE_WARNING",     LXW_VALIDATION_ERROR_TYPE_WARNING)
+    REGISTER_CLASS_CONST_LONG(vtiful_validation_ce, "ERROR_TYPE_INFORMATION", LXW_VALIDATION_ERROR_TYPE_INFORMATION)
+
+    return SUCCESS;
+}
+/* }}} */

+ 8 - 0
kernel/write.c

@@ -302,6 +302,14 @@ void set_row(zend_string *range, double height, xls_resource_write_t *res, lxw_f
     }
 }
 
+/*
+ * Add data validations to a worksheet
+ */
+void validation(xls_resource_write_t *res, zend_string *range, lxw_data_validation *validation)
+{
+    worksheet_data_validation_cell(res->worksheet, CELL(ZSTR_VAL(range)), validation);
+}
+
 /*
  * Set rows format
  */

+ 25 - 0
tests/validation_limiting_input_to_a_value_in_a_dropdown_list.phpt

@@ -0,0 +1,25 @@
+--TEST--
+Check for vtiful presence
+--SKIPIF--
+<?php if (!extension_loaded("xlswriter")) print "skip"; ?>
+--FILE--
+<?php
+$config = ['path' => './tests'];
+
+$validation = new \Vtiful\Kernel\Validation();
+$validation->validationType(\Vtiful\Kernel\Validation::TYPE_LIST)
+    ->valueList(['wjx', 'viest'])
+    ->valueList(['wjx', 'viest']);
+
+$excel    = new \Vtiful\Kernel\Excel($config);
+$filePath = $excel->fileName('tutorial.xlsx')
+    ->validation('A1', $validation->toResource())
+    ->output();
+
+var_dump($validation, $filePath);
+?>
+--EXPECT--
+object(Vtiful\Kernel\Validation)#1 (0) {
+}
+string(21) "./tests/tutorial.xlsx"
+

+ 26 - 0
tests/validation_limiting_input_to_an_integer_greater_than_a_fixed_value.phpt

@@ -0,0 +1,26 @@
+--TEST--
+Check for vtiful presence
+--SKIPIF--
+<?php if (!extension_loaded("xlswriter")) print "skip"; ?>
+--FILE--
+<?php
+$config = ['path' => './tests'];
+
+$validation = new \Vtiful\Kernel\Validation();
+$validation->validationType(\Vtiful\Kernel\Validation::TYPE_INTEGER)
+    ->criteriaType(\Vtiful\Kernel\Validation::CRITERIA_GREATER_THAN)
+    ->valueNumber(20);
+
+$excel    = new \Vtiful\Kernel\Excel($config);
+$filePath = $excel->fileName('tutorial.xlsx')
+    ->validation('A1', $validation->toResource())
+    ->insertText(0, 0, 21)
+    ->output();
+
+var_dump($validation, $filePath);
+?>
+--EXPECT--
+object(Vtiful\Kernel\Validation)#1 (0) {
+}
+string(21) "./tests/tutorial.xlsx"
+

+ 28 - 0
tests/validation_limiting_input_to_an_integer_in_a_fixed_range..phpt

@@ -0,0 +1,28 @@
+--TEST--
+Check for vtiful presence
+--SKIPIF--
+<?php if (!extension_loaded("xlswriter")) print "skip"; ?>
+--FILE--
+<?php
+$config = ['path' => './tests'];
+
+$validation = new \Vtiful\Kernel\Validation();
+$validation->validationType(\Vtiful\Kernel\Validation::TYPE_INTEGER)
+    ->criteriaType(\Vtiful\Kernel\Validation::CRITERIA_BETWEEN)
+    ->minimumNumber(1)
+    ->maximumNumber(10);
+
+$excel    = new \Vtiful\Kernel\Excel($config);
+$filePath = $excel->fileName('tutorial.xlsx')
+    ->header(['Value'])
+    ->validation('A1', $validation->toResource())
+    ->insertText(0, 0, 20)
+    ->output();
+
+var_dump($validation, $filePath);
+?>
+--EXPECT--
+object(Vtiful\Kernel\Validation)#1 (0) {
+}
+string(21) "./tests/tutorial.xlsx"
+

+ 28 - 0
tests/validation_limiting_input_to_an_integer_outside_a_fixed_range.phpt

@@ -0,0 +1,28 @@
+--TEST--
+Check for vtiful presence
+--SKIPIF--
+<?php if (!extension_loaded("xlswriter")) print "skip"; ?>
+--FILE--
+<?php
+$config = ['path' => './tests'];
+
+$validation = new \Vtiful\Kernel\Validation();
+$validation->validationType(\Vtiful\Kernel\Validation::TYPE_INTEGER)
+    ->criteriaType(\Vtiful\Kernel\Validation::CRITERIA_BETWEEN)
+    ->minimumFormula('=A1')
+    ->maximumFormula('=B1');
+
+$excel    = new \Vtiful\Kernel\Excel($config);
+$filePath = $excel->fileName('tutorial.xlsx')
+    ->header([1, 10])
+    ->validation('C1', $validation->toResource())
+    ->insertText(0, 2, 20)
+    ->output();
+
+var_dump($validation, $filePath);
+?>
+--EXPECT--
+object(Vtiful\Kernel\Validation)#1 (0) {
+}
+string(21) "./tests/tutorial.xlsx"
+

+ 1 - 0
xlswriter.c

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