1 /**
2  * Copyright 2015-2017 DataStax, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "php_driver.h"
18 #include "php_driver_types.h"
19 #include "util/types.h"
20 
21 #include "src/Type/Tuple.h"
22 #include "src/Type/UserType.h"
23 
24 zend_class_entry *php_driver_type_ce = NULL;
25 
26 #define XX_SCALAR_METHOD(name, value) PHP_METHOD(Type, name) \
27 { \
28   php5to7_zval ztype; \
29   if (zend_parse_parameters_none() == FAILURE) { \
30     return; \
31   } \
32   ztype = php_driver_type_scalar(value TSRMLS_CC); \
33   RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(ztype), 1, 1); \
34 }
35 
36 PHP_DRIVER_SCALAR_TYPES_MAP(XX_SCALAR_METHOD)
37 #undef XX_SCALAR_METHOD
38 
PHP_METHOD(Type,collection)39 PHP_METHOD(Type, collection)
40 {
41   php5to7_zval ztype;
42   zval *value_type;
43 
44   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O",
45                             &value_type, php_driver_type_ce) == FAILURE) {
46     return;
47   }
48 
49   if (!php_driver_type_validate(value_type, "type" TSRMLS_CC)) {
50     return;
51   }
52 
53   ztype  = php_driver_type_collection(value_type TSRMLS_CC);
54   Z_ADDREF_P(value_type);
55   RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(ztype), 0, 1);
56 }
57 
PHP_METHOD(Type,tuple)58 PHP_METHOD(Type, tuple)
59 {
60   php5to7_zval ztype;
61   php_driver_type *type;
62   php5to7_zval_args args = NULL;
63   int argc = 0, i;
64 
65   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+",
66                             &args, &argc) == FAILURE) {
67     return;
68   }
69 
70   for (i = 0; i < argc; ++i) {
71     zval *sub_type = PHP5TO7_ZVAL_ARG(args[i]);
72     if (!php_driver_type_validate(sub_type, "type" TSRMLS_CC)) {
73       PHP5TO7_MAYBE_EFREE(args);
74       return;
75     }
76   }
77 
78   ztype = php_driver_type_tuple(TSRMLS_C);
79   type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
80 
81   for (i = 0; i < argc; ++i) {
82     zval *sub_type = PHP5TO7_ZVAL_ARG(args[i]);
83     if (php_driver_type_tuple_add(type, sub_type TSRMLS_CC)) {
84       Z_ADDREF_P(sub_type);
85     } else {
86       break;
87     }
88   }
89 
90   PHP5TO7_MAYBE_EFREE(args);
91   RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(ztype), 0, 1);
92 }
93 
PHP_METHOD(Type,userType)94 PHP_METHOD(Type, userType)
95 {
96   php5to7_zval ztype;
97   php_driver_type *type;
98   php5to7_zval_args args = NULL;
99   int argc = 0, i;
100 
101   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+",
102                             &args, &argc) == FAILURE) {
103     return;
104   }
105 
106   if (argc % 2 == 1) {
107     zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
108                             "Not enough name/type pairs, user types can only be created " \
109                             "from an even number of name/type pairs, where each odd " \
110                             "argument is a name and each even argument is a type, " \
111                             "e.g userType(name, type, name, type, name, type)");
112     PHP5TO7_MAYBE_EFREE(args);
113     return;
114   }
115 
116   for (i = 0; i < argc; i += 2) {
117     zval *name = PHP5TO7_ZVAL_ARG(args[i]);
118     zval *sub_type = PHP5TO7_ZVAL_ARG(args[i + 1]);
119     if (Z_TYPE_P(name) != IS_STRING) {
120       zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
121                               "Argument %d is not a string", i + 1);
122       PHP5TO7_MAYBE_EFREE(args);
123       return;
124     }
125     if (!php_driver_type_validate(sub_type, "type" TSRMLS_CC)) {
126       PHP5TO7_MAYBE_EFREE(args);
127       return;
128     }
129   }
130 
131   ztype = php_driver_type_user_type(TSRMLS_C);
132   type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
133 
134   for (i = 0; i < argc; i += 2) {
135     zval *name = PHP5TO7_ZVAL_ARG(args[i]);
136     zval *sub_type = PHP5TO7_ZVAL_ARG(args[i + 1]);
137     if (php_driver_type_user_type_add(type,
138                                          Z_STRVAL_P(name), Z_STRLEN_P(name),
139                                          sub_type TSRMLS_CC)) {
140       Z_ADDREF_P(sub_type);
141     } else {
142       break;
143     }
144   }
145 
146 
147   PHP5TO7_MAYBE_EFREE(args);
148   RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(ztype), 0, 1);
149 }
150 
PHP_METHOD(Type,set)151 PHP_METHOD(Type, set)
152 {
153   php5to7_zval ztype;
154   zval *value_type;
155 
156   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O",
157                             &value_type, php_driver_type_ce) == FAILURE) {
158     return;
159   }
160 
161   if (!php_driver_type_validate(value_type, "type" TSRMLS_CC)) {
162     return;
163   }
164 
165   ztype = php_driver_type_set(value_type TSRMLS_CC);
166   Z_ADDREF_P(value_type);
167   RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(ztype), 0, 1);
168 }
169 
PHP_METHOD(Type,map)170 PHP_METHOD(Type, map)
171 {
172   php5to7_zval ztype;
173   zval *key_type;
174   zval *value_type;
175 
176   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO",
177                             &key_type, php_driver_type_ce,
178                             &value_type, php_driver_type_ce) == FAILURE) {
179     return;
180   }
181 
182   if (!php_driver_type_validate(key_type, "keyType" TSRMLS_CC)) {
183     return;
184   }
185 
186   if (!php_driver_type_validate(value_type, "valueType" TSRMLS_CC)) {
187     return;
188   }
189 
190   ztype = php_driver_type_map(key_type, value_type TSRMLS_CC);
191   Z_ADDREF_P(key_type);
192   Z_ADDREF_P(value_type);
193   RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(ztype), 0, 1);
194 }
195 
196 ZEND_BEGIN_ARG_INFO_EX(arginfo_none, 0, ZEND_RETURN_VALUE, 0)
197 ZEND_END_ARG_INFO()
198 
199 ZEND_BEGIN_ARG_INFO_EX(arginfo_types, 0, ZEND_RETURN_VALUE, 0)
200   ZEND_ARG_INFO(0, types)
201 ZEND_END_ARG_INFO()
202 
203 ZEND_BEGIN_ARG_INFO_EX(arginfo_type, 0, ZEND_RETURN_VALUE, 1)
204   PHP_DRIVER_NAMESPACE_ZEND_ARG_OBJ_INFO(0, type, Type, 0)
205 ZEND_END_ARG_INFO()
206 
207 ZEND_BEGIN_ARG_INFO_EX(arginfo_map, 0, ZEND_RETURN_VALUE, 2)
208   PHP_DRIVER_NAMESPACE_ZEND_ARG_OBJ_INFO(0, keyType,   Type, 0)
209   PHP_DRIVER_NAMESPACE_ZEND_ARG_OBJ_INFO(0, valueType, Type, 0)
210 ZEND_END_ARG_INFO()
211 
212 static zend_function_entry php_driver_type_methods[] = {
213   PHP_ABSTRACT_ME(Type, name,       arginfo_none)
214   PHP_ABSTRACT_ME(Type, __toString, arginfo_none)
215 
216 #define XX_SCALAR_METHOD(name, _) PHP_ME(Type, name, arginfo_none, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
217   PHP_DRIVER_SCALAR_TYPES_MAP(XX_SCALAR_METHOD)
218 #undef XX_SCALAR_METHOD
219   PHP_ME(Type, collection, arginfo_type,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
220   PHP_ME(Type, set,        arginfo_type,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
221   PHP_ME(Type, map,        arginfo_map,   ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
222   PHP_ME(Type, tuple,      arginfo_types, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
223   PHP_ME(Type, userType,   arginfo_types, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
224   PHP_FE_END
225 };
226 
php_driver_define_Type(TSRMLS_D)227 void php_driver_define_Type(TSRMLS_D)
228 {
229   zend_class_entry ce;
230 
231   INIT_CLASS_ENTRY(ce, PHP_DRIVER_NAMESPACE "\\Type", php_driver_type_methods);
232   php_driver_type_ce = zend_register_internal_class(&ce TSRMLS_CC);
233   php_driver_type_ce->ce_flags |= ZEND_ACC_ABSTRACT;
234 }
235