Skip to content

Commit 2a3a9d8

Browse files
authored
PHPC-2245, PHPC-2246: Add array and property accessors to BSON types (#1472)
* PHPC-2246: Implement array and property access for BSON documents * PHPC-2245: Implement array access for BSON arrays * Remove trailing periods from exception messages * Make exception messages more descriptive
1 parent cf125e3 commit 2a3a9d8

24 files changed

+1068
-52
lines changed

src/BSON/Document.c

Lines changed: 181 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -165,28 +165,41 @@ static PHP_METHOD(MongoDB_BSON_Document, fromPHP)
165165
RETURN_ZVAL(&zv, 1, 1);
166166
}
167167

168+
static bool php_phongo_document_get(php_phongo_document_t* intern, char* key, size_t key_len, zval* return_value)
169+
{
170+
bson_iter_t iter;
171+
172+
if (!bson_iter_init(&iter, intern->bson)) {
173+
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not initialize BSON iterator");
174+
return false;
175+
}
176+
177+
if (!bson_iter_find_w_len(&iter, key, key_len)) {
178+
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key \"%s\" in BSON document", key);
179+
return false;
180+
}
181+
182+
phongo_bson_value_to_zval(bson_iter_value(&iter), return_value);
183+
184+
return true;
185+
}
186+
168187
static PHP_METHOD(MongoDB_BSON_Document, get)
169188
{
170189
php_phongo_document_t* intern;
171190
char* key;
172191
size_t key_len;
173-
bson_iter_t iter;
174192

175193
PHONGO_PARSE_PARAMETERS_START(1, 1)
176194
Z_PARAM_STRING(key, key_len)
177195
PHONGO_PARSE_PARAMETERS_END();
178196

179197
intern = Z_DOCUMENT_OBJ_P(getThis());
180-
if (!bson_iter_init(&iter, intern->bson)) {
181-
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not initialize BSON iterator.");
182-
}
183198

184-
if (!bson_iter_find_w_len(&iter, key, key_len)) {
185-
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key \"%s\" in BSON data", key);
199+
if (!php_phongo_document_get(intern, key, key_len, return_value)) {
200+
// Exception already thrown
186201
RETURN_NULL();
187202
}
188-
189-
phongo_bson_value_to_zval(bson_iter_value(&iter), return_value);
190203
}
191204

192205
static PHP_METHOD(MongoDB_BSON_Document, getIterator)
@@ -196,23 +209,31 @@ static PHP_METHOD(MongoDB_BSON_Document, getIterator)
196209
phongo_iterator_init(return_value, getThis());
197210
}
198211

212+
static bool php_phongo_document_has(php_phongo_document_t* intern, char* key, size_t key_len)
213+
{
214+
bson_iter_t iter;
215+
216+
if (!bson_iter_init(&iter, intern->bson)) {
217+
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not initialize BSON iterator");
218+
return false;
219+
}
220+
221+
return bson_iter_find_w_len(&iter, key, key_len);
222+
}
223+
199224
static PHP_METHOD(MongoDB_BSON_Document, has)
200225
{
201226
php_phongo_document_t* intern;
202227
char* key;
203228
size_t key_len;
204-
bson_iter_t iter;
205229

206230
PHONGO_PARSE_PARAMETERS_START(1, 1)
207231
Z_PARAM_STRING(key, key_len)
208232
PHONGO_PARSE_PARAMETERS_END();
209233

210234
intern = Z_DOCUMENT_OBJ_P(getThis());
211-
if (!bson_iter_init(&iter, intern->bson)) {
212-
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not initialize BSON iterator.");
213-
}
214235

215-
RETURN_BOOL(bson_iter_find_w_len(&iter, key, key_len));
236+
RETURN_BOOL(php_phongo_document_has(intern, key, key_len));
216237
}
217238

218239
static PHP_METHOD(MongoDB_BSON_Document, toCanonicalExtendedJSON)
@@ -269,6 +290,54 @@ static PHP_METHOD(MongoDB_BSON_Document, toPHP)
269290
RETURN_ZVAL(&state.zchild, 0, 1);
270291
}
271292

293+
static PHP_METHOD(MongoDB_BSON_Document, offsetExists)
294+
{
295+
php_phongo_document_t* intern;
296+
zval* offset;
297+
298+
PHONGO_PARSE_PARAMETERS_START(1, 1)
299+
Z_PARAM_ZVAL(offset)
300+
PHONGO_PARSE_PARAMETERS_END();
301+
302+
intern = Z_DOCUMENT_OBJ_P(getThis());
303+
304+
if (Z_TYPE_P(offset) != IS_STRING) {
305+
RETURN_FALSE;
306+
}
307+
308+
RETURN_BOOL(php_phongo_document_has(intern, Z_STRVAL_P(offset), Z_STRLEN_P(offset)));
309+
}
310+
311+
static PHP_METHOD(MongoDB_BSON_Document, offsetGet)
312+
{
313+
php_phongo_document_t* intern;
314+
zval* offset;
315+
316+
PHONGO_PARSE_PARAMETERS_START(1, 1)
317+
Z_PARAM_ZVAL(offset)
318+
PHONGO_PARSE_PARAMETERS_END();
319+
320+
intern = Z_DOCUMENT_OBJ_P(getThis());
321+
322+
if (Z_TYPE_P(offset) != IS_STRING) {
323+
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key of type \"%s\" in BSON document", PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(offset));
324+
return;
325+
}
326+
327+
// May throw, in which case we do nothing
328+
php_phongo_document_get(intern, Z_STRVAL_P(offset), Z_STRLEN_P(offset), return_value);
329+
}
330+
331+
static PHP_METHOD(MongoDB_BSON_Document, offsetSet)
332+
{
333+
phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot write to %s property", ZSTR_VAL(php_phongo_document_ce->name));
334+
}
335+
336+
static PHP_METHOD(MongoDB_BSON_Document, offsetUnset)
337+
{
338+
phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot unset %s property", ZSTR_VAL(php_phongo_document_ce->name));
339+
}
340+
272341
static PHP_METHOD(MongoDB_BSON_Document, __toString)
273342
{
274343
php_phongo_document_t* intern;
@@ -471,9 +540,94 @@ static HashTable* php_phongo_document_get_properties(phongo_compat_object_handle
471540
return php_phongo_document_get_properties_hash(object, false, 1);
472541
}
473542

543+
zval* php_phongo_document_read_property(phongo_compat_object_handler_type* object, phongo_compat_property_accessor_name_type* member, int type, void** cache_slot, zval* rv)
544+
{
545+
php_phongo_document_t* intern;
546+
char* key;
547+
size_t key_len;
548+
549+
intern = Z_OBJ_DOCUMENT(PHONGO_COMPAT_GET_OBJ(object));
550+
551+
PHONGO_COMPAT_PROPERTY_ACCESSOR_NAME_TO_STRING(member, key, key_len);
552+
553+
if (!php_phongo_document_get(intern, key, key_len, rv)) {
554+
// Exception already thrown
555+
return &EG(uninitialized_zval);
556+
}
557+
558+
return rv;
559+
}
560+
561+
zval* php_phongo_document_write_property(phongo_compat_object_handler_type* object, phongo_compat_property_accessor_name_type* member, zval* value, void** cache_slot)
562+
{
563+
phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot write to %s property", ZSTR_VAL(php_phongo_document_ce->name));
564+
return value;
565+
}
566+
567+
int php_phongo_document_has_property(phongo_compat_object_handler_type* object, phongo_compat_property_accessor_name_type* name, int has_set_exists, void** cache_slot)
568+
{
569+
php_phongo_document_t* intern;
570+
char* key;
571+
size_t key_len;
572+
573+
intern = Z_OBJ_DOCUMENT(PHONGO_COMPAT_GET_OBJ(object));
574+
575+
PHONGO_COMPAT_PROPERTY_ACCESSOR_NAME_TO_STRING(name, key, key_len);
576+
577+
return php_phongo_document_has(intern, key, key_len);
578+
}
579+
580+
void php_phongo_document_unset_property(phongo_compat_object_handler_type* object, phongo_compat_property_accessor_name_type* member, void** cache_slot)
581+
{
582+
phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot unset %s property", ZSTR_VAL(php_phongo_document_ce->name));
583+
}
584+
585+
zval* php_phongo_document_read_dimension(phongo_compat_object_handler_type* object, zval* offset, int type, zval* rv)
586+
{
587+
php_phongo_document_t* intern;
588+
589+
intern = Z_OBJ_DOCUMENT(PHONGO_COMPAT_GET_OBJ(object));
590+
591+
if (Z_TYPE_P(offset) != IS_STRING) {
592+
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key of type \"%s\" in BSON document", PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(offset));
593+
return &EG(uninitialized_zval);
594+
}
595+
596+
if (!php_phongo_document_get(intern, Z_STRVAL_P(offset), Z_STRLEN_P(offset), rv)) {
597+
// Exception already thrown
598+
return &EG(uninitialized_zval);
599+
}
600+
601+
return rv;
602+
}
603+
604+
void php_phongo_document_write_dimension(phongo_compat_object_handler_type* object, zval* offset, zval* value)
605+
{
606+
phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot write to %s property", ZSTR_VAL(php_phongo_document_ce->name));
607+
}
608+
609+
int php_phongo_document_has_dimension(phongo_compat_object_handler_type* object, zval* member, int check_empty)
610+
{
611+
php_phongo_document_t* intern;
612+
613+
intern = Z_OBJ_DOCUMENT(PHONGO_COMPAT_GET_OBJ(object));
614+
615+
if (Z_TYPE_P(member) != IS_STRING) {
616+
phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key of type \"%s\" in BSON document", PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(member));
617+
return false;
618+
}
619+
620+
return php_phongo_document_has(intern, Z_STRVAL_P(member), Z_STRLEN_P(member));
621+
}
622+
623+
void php_phongo_document_unset_dimension(phongo_compat_object_handler_type* object, zval* offset)
624+
{
625+
phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot unset %s property", ZSTR_VAL(php_phongo_document_ce->name));
626+
}
627+
474628
void php_phongo_document_init_ce(INIT_FUNC_ARGS)
475629
{
476-
php_phongo_document_ce = register_class_MongoDB_BSON_Document(zend_ce_aggregate, zend_ce_serializable, php_phongo_type_ce);
630+
php_phongo_document_ce = register_class_MongoDB_BSON_Document(zend_ce_aggregate, zend_ce_serializable, zend_ce_arrayaccess, php_phongo_type_ce);
477631
php_phongo_document_ce->create_object = php_phongo_document_create_object;
478632

479633
#if PHP_VERSION_ID >= 80000
@@ -482,11 +636,19 @@ void php_phongo_document_init_ce(INIT_FUNC_ARGS)
482636

483637
memcpy(&php_phongo_handler_document, phongo_get_std_object_handlers(), sizeof(zend_object_handlers));
484638
PHONGO_COMPAT_SET_COMPARE_OBJECTS_HANDLER(document);
485-
php_phongo_handler_document.clone_obj = php_phongo_document_clone_object;
486-
php_phongo_handler_document.get_debug_info = php_phongo_document_get_debug_info;
487-
php_phongo_handler_document.get_properties = php_phongo_document_get_properties;
488-
php_phongo_handler_document.free_obj = php_phongo_document_free_object;
489-
php_phongo_handler_document.offset = XtOffsetOf(php_phongo_document_t, std);
639+
php_phongo_handler_document.clone_obj = php_phongo_document_clone_object;
640+
php_phongo_handler_document.get_debug_info = php_phongo_document_get_debug_info;
641+
php_phongo_handler_document.get_properties = php_phongo_document_get_properties;
642+
php_phongo_handler_document.free_obj = php_phongo_document_free_object;
643+
php_phongo_handler_document.read_property = php_phongo_document_read_property;
644+
php_phongo_handler_document.write_property = php_phongo_document_write_property;
645+
php_phongo_handler_document.has_property = php_phongo_document_has_property;
646+
php_phongo_handler_document.unset_property = php_phongo_document_unset_property;
647+
php_phongo_handler_document.read_dimension = php_phongo_document_read_dimension;
648+
php_phongo_handler_document.write_dimension = php_phongo_document_write_dimension;
649+
php_phongo_handler_document.has_dimension = php_phongo_document_has_dimension;
650+
php_phongo_handler_document.unset_dimension = php_phongo_document_unset_dimension;
651+
php_phongo_handler_document.offset = XtOffsetOf(php_phongo_document_t, std);
490652
}
491653

492654
bool phongo_document_new(zval* object, bson_t* bson, bool copy)

src/BSON/Document.stub.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace MongoDB\BSON;
99

10-
final class Document implements \IteratorAggregate, \Serializable, Type
10+
final class Document implements \IteratorAggregate, \Serializable, \ArrayAccess, Type
1111
{
1212
private function __construct() {}
1313

@@ -44,6 +44,40 @@ final public function toCanonicalExtendedJSON(): string {}
4444

4545
final public function toRelaxedExtendedJSON(): string {}
4646

47+
#if PHP_VERSION_ID >= 80000
48+
public function offsetExists(mixed $key): bool {}
49+
# else
50+
/** @param mixed $key */
51+
public function offsetExists($key): bool {}
52+
# endif
53+
54+
#if PHP_VERSION_ID >= 80000
55+
public function offsetGet(mixed $key): mixed {}
56+
# else
57+
/**
58+
* @param mixed $key
59+
* @return mixed
60+
*/
61+
public function offsetGet($key) {}
62+
# endif
63+
64+
#if PHP_VERSION_ID >= 80000
65+
public function offsetSet(mixed $key, mixed $value): void {}
66+
# else
67+
/**
68+
* @param mixed $key
69+
* @param mixed $value
70+
*/
71+
public function offsetSet($key, $value): void {}
72+
# endif
73+
74+
#if PHP_VERSION_ID >= 80000
75+
public function offsetUnset(mixed $key): void {}
76+
# else
77+
/** @param mixed $key */
78+
public function offsetUnset($key): void {}
79+
# endif
80+
4781
final public function __toString(): string {}
4882

4983
final public static function __set_state(array $properties): Document {}

0 commit comments

Comments
 (0)