diff --git a/ext/cache/backend/apc.c b/ext/cache/backend/apc.c index 2d246c5b7bc..83661fa816f 100644 --- a/ext/cache/backend/apc.c +++ b/ext/cache/backend/apc.c @@ -117,8 +117,13 @@ PHP_METHOD(Phalcon_Cache_Backend_Apc, get){ if (PHALCON_IS_FALSE(cached_content)) { RETURN_MM_NULL(); } + + if (phalcon_is_numeric(cached_content)) { + RETURN_CCTOR(cached_content); + } else { + phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); + } - phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); RETURN_MM(); } @@ -163,8 +168,10 @@ PHP_METHOD(Phalcon_Cache_Backend_Apc, save){ cached_content = content; } - PHALCON_OBS_VAR(prepared_content); - phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + if (!phalcon_is_numeric(cached_content)) { + PHALCON_OBS_VAR(prepared_content); + phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + } /** * Take the lifetime from the frontend or read it from the set in start() @@ -187,7 +194,11 @@ PHP_METHOD(Phalcon_Cache_Backend_Apc, save){ * Call apc_store in the PHP userland since most of the time it isn't available at * compile time */ - phalcon_call_func_p3_noret("apc_store", last_key, prepared_content, ttl); + if (phalcon_is_numeric(cached_content)) { + phalcon_call_func_p3_noret("apc_store", last_key, cached_content, ttl); + } else { + phalcon_call_func_p3_noret("apc_store", last_key, prepared_content, ttl); + } PHALCON_OBS_VAR(is_buffering); phalcon_call_method_p0_ex(is_buffering, &is_buffering, frontend, "isbuffering"); @@ -204,6 +215,126 @@ PHP_METHOD(Phalcon_Cache_Backend_Apc, save){ PHALCON_MM_RESTORE(); } +/** + * Increment of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Apc, increment){ + + zval *key_name, *value = NULL, *prefixed_key; + zval *cached_content = NULL, *function_name; + zval *prefix; + + PHALCON_MM_GROW(); + + PHALCON_INIT_VAR(function_name); + ZVAL_STRING(function_name, "apc_inc", 1); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + if (Z_TYPE_P(value) != IS_LONG) { + PHALCON_SEPARATE_PARAM(value); + convert_to_long_ex(&value); + } + + prefix = phalcon_fetch_nproperty_this(this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_VAR(prefixed_key); + PHALCON_CONCAT_SVV(prefixed_key, "_PHCA", prefix, key_name); + phalcon_update_property_this(this_ptr, SL("_lastKey"), prefixed_key TSRMLS_CC); + + if (phalcon_function_exists(function_name TSRMLS_CC)) { + phalcon_call_func_p1(return_value, "apc_inc", value); + } else { + PHALCON_OBS_VAR(cached_content); + phalcon_call_func_p1_ex(cached_content, &cached_content, "apc_fetch", prefixed_key); + + if (Z_TYPE_P(cached_content) != IS_LONG) { + PHALCON_SEPARATE_PARAM(cached_content); + convert_to_long_ex(&cached_content); + } + + if (phalcon_is_numeric(cached_content)) { + add_function(return_value, cached_content, value TSRMLS_CC); + + phalcon_call_method_p2_noret(this_ptr, "save", key_name, return_value); + } + } + + RETURN_MM(); +} + +/** + * Decrement of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Apc, decrement){ + + zval *key_name, *value = NULL, *prefixed_key; + zval *cached_content = NULL, *function_name; + zval *prefix; + + PHALCON_MM_GROW(); + + PHALCON_INIT_VAR(function_name); + ZVAL_STRING(function_name, "apc_dec", 1); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + if (Z_TYPE_P(value) != IS_LONG) { + PHALCON_SEPARATE_PARAM(value); + convert_to_long_ex(&value); + } + + prefix = phalcon_fetch_nproperty_this(this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_VAR(prefixed_key); + PHALCON_CONCAT_SVV(prefixed_key, "_PHCA", prefix, key_name); + phalcon_update_property_this(this_ptr, SL("_lastKey"), prefixed_key TSRMLS_CC); + + if (phalcon_function_exists(function_name TSRMLS_CC)) { + phalcon_call_func_p1(return_value, "apc_dec", value); + } else { + PHALCON_OBS_VAR(cached_content); + phalcon_call_func_p1_ex(cached_content, &cached_content, "apc_fetch", prefixed_key); + + if (Z_TYPE_P(cached_content) != IS_LONG) { + PHALCON_SEPARATE_PARAM(cached_content); + convert_to_long_ex(&cached_content); + } + + if (phalcon_is_numeric(cached_content)) { + sub_function(return_value, cached_content, value TSRMLS_CC); + + phalcon_call_method_p2_noret(this_ptr, "save", key_name, return_value); + } + } + + RETURN_MM(); +} + /** * Deletes a value from the cache by its key * diff --git a/ext/cache/backend/apc.h b/ext/cache/backend/apc.h index a5e4c940df6..8f277f40545 100644 --- a/ext/cache/backend/apc.h +++ b/ext/cache/backend/apc.h @@ -26,6 +26,8 @@ PHP_METHOD(Phalcon_Cache_Backend_Apc, save); PHP_METHOD(Phalcon_Cache_Backend_Apc, delete); PHP_METHOD(Phalcon_Cache_Backend_Apc, queryKeys); PHP_METHOD(Phalcon_Cache_Backend_Apc, exists); +PHP_METHOD(Phalcon_Cache_Backend_Apc, increment); +PHP_METHOD(Phalcon_Cache_Backend_Apc, decrement); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_apc_get, 0, 0, 1) ZEND_ARG_INFO(0, keyName) @@ -52,12 +54,24 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_apc_exists, 0, 0, 0) ZEND_ARG_INFO(0, lifetime) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_apc_increment, 0, 0, 0) + ZEND_ARG_INFO(0, key_name) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_apc_decrement, 0, 0, 0) + ZEND_ARG_INFO(0, key_name) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + PHALCON_INIT_FUNCS(phalcon_cache_backend_apc_method_entry){ PHP_ME(Phalcon_Cache_Backend_Apc, get, arginfo_phalcon_cache_backend_apc_get, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Apc, save, arginfo_phalcon_cache_backend_apc_save, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Apc, delete, arginfo_phalcon_cache_backend_apc_delete, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Apc, queryKeys, arginfo_phalcon_cache_backend_apc_querykeys, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Apc, exists, arginfo_phalcon_cache_backend_apc_exists, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Apc, increment, arginfo_phalcon_cache_backend_apc_increment, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Apc, decrement, arginfo_phalcon_cache_backend_apc_decrement, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/ext/cache/backend/file.c b/ext/cache/backend/file.c index 5e72bc820fa..f35bdbcecb4 100644 --- a/ext/cache/backend/file.c +++ b/ext/cache/backend/file.c @@ -198,11 +198,16 @@ PHP_METHOD(Phalcon_Cache_Backend_File, get){ PHALCON_THROW_EXCEPTION_ZVAL(phalcon_cache_exception_ce, exception_message); return; } + + if (phalcon_is_numeric(cached_content)) { + RETURN_CCTOR(cached_content); + } else { + /** + * Use the frontend to process the content of the cache + */ + phalcon_call_method_p1(return_value, frontend, "afterretrieve", cached_content); + } - /** - * Use the frontend to process the content of the cache - */ - phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); RETURN_MM(); } } @@ -267,7 +272,11 @@ PHP_METHOD(Phalcon_Cache_Backend_File, save){ * We use file_put_contents to respect open-base-dir directive */ PHALCON_INIT_VAR(status); - phalcon_file_put_contents(status, cache_file, prepared_content TSRMLS_CC); + if (!phalcon_is_numeric(cached_content)) { + phalcon_file_put_contents(status, cache_file, prepared_content TSRMLS_CC); + } else { + phalcon_file_put_contents(status, cache_file, cached_content TSRMLS_CC); + } if (PHALCON_IS_FALSE(status)) { PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "Cache directory is not writable"); return; @@ -457,3 +466,241 @@ PHP_METHOD(Phalcon_Cache_Backend_File, exists){ RETURN_MM_FALSE; } + +/** + * Increment of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_File, increment){ + + zval *key_name, *value = NULL, *lifetime = NULL, *options, *prefix, *prefixed_key, *result, *status; + zval *cache_dir, *cache_file, *frontend, *timestamp; + zval *ttl = NULL, *modified_time, *difference, *not_expired; + zval *cached_content, *exception_message; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + } else { + PHALCON_SEPARATE_PARAM(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + PHALCON_OBS_VAR(options); + phalcon_read_property_this(&options, this_ptr, SL("_options"), PH_NOISY_CC); + + PHALCON_OBS_VAR(prefix); + phalcon_read_property_this(&prefix, this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_VAR(prefixed_key); + PHALCON_CONCAT_VV(prefixed_key, prefix, key_name); + phalcon_update_property_this(this_ptr, SL("_lastKey"), prefixed_key TSRMLS_CC); + + PHALCON_OBS_VAR(cache_dir); + phalcon_array_fetch_string(&cache_dir, options, SL("cacheDir"), PH_NOISY); + + PHALCON_INIT_VAR(cache_file); + PHALCON_CONCAT_VV(cache_file, cache_dir, prefixed_key); + + if (phalcon_file_exists(cache_file TSRMLS_CC) == SUCCESS) { + + PHALCON_OBS_VAR(frontend); + phalcon_read_property_this(&frontend, this_ptr, SL("_frontend"), PH_NOISY_CC); + + /** + * Check if the file has expired + */ + PHALCON_INIT_VAR(timestamp); + ZVAL_LONG(timestamp, (long) time(NULL)); + + /** + * Take the lifetime from the frontend or read it from the set in start() + */ + PHALCON_INIT_VAR(lifetime); + if (Z_TYPE_P(lifetime) == IS_NULL) { + + PHALCON_OBS_NVAR(lifetime); + phalcon_read_property_this(&lifetime, this_ptr, SL("_lastLifetime"), PH_NOISY_CC); + if (Z_TYPE_P(lifetime) == IS_NULL) { + PHALCON_INIT_VAR(ttl); + phalcon_call_method(ttl, frontend, "getlifetime"); + } else { + PHALCON_CPY_WRT(ttl, lifetime); + } + } else { + PHALCON_CPY_WRT(ttl, lifetime); + } + + PHALCON_INIT_VAR(modified_time); + phalcon_call_func_p1(modified_time, "filemtime", cache_file); + + PHALCON_INIT_VAR(difference); + sub_function(difference, timestamp, ttl TSRMLS_CC); + + PHALCON_INIT_VAR(not_expired); + is_smaller_function(not_expired, difference, modified_time TSRMLS_CC); + + /** + * The content is only retrieved if the content has not expired + */ + if (PHALCON_IS_TRUE(not_expired)) { + + /** + * Use file-get-contents to control that the openbase_dir can't be skipped + */ + PHALCON_INIT_VAR(cached_content); + phalcon_file_get_contents(cached_content, cache_file TSRMLS_CC); + if (PHALCON_IS_FALSE(cached_content)) { + PHALCON_INIT_VAR(exception_message); + PHALCON_CONCAT_SVS(exception_message, "Cache file ", cache_file, " could not be opened"); + PHALCON_THROW_EXCEPTION_ZVAL(phalcon_cache_exception_ce, exception_message); + return; + } + + if (phalcon_is_numeric(cached_content)) { + PHALCON_INIT_VAR(result); + add_function(result, value, cached_content TSRMLS_CC); + + PHALCON_INIT_VAR(status); + phalcon_file_put_contents(status, cache_file, result TSRMLS_CC); + + if (PHALCON_IS_FALSE(status)) { + PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "Cache directory can't be written"); + return; + } + + RETURN_ZVAL(result, 1, 0); + } + } + } + + RETURN_MM_NULL(); +} + +/** + * Decrement of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_File, decrement){ + + zval *key_name, *value = NULL, *lifetime = NULL, *options, *prefix, *prefixed_key, *result, *status; + zval *cache_dir, *cache_file, *frontend, *timestamp; + zval *ttl = NULL, *modified_time, *difference, *not_expired; + zval *cached_content, *exception_message; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + } else { + PHALCON_SEPARATE_PARAM(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + PHALCON_OBS_VAR(options); + phalcon_read_property_this(&options, this_ptr, SL("_options"), PH_NOISY_CC); + + PHALCON_OBS_VAR(prefix); + phalcon_read_property_this(&prefix, this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_VAR(prefixed_key); + PHALCON_CONCAT_VV(prefixed_key, prefix, key_name); + phalcon_update_property_this(this_ptr, SL("_lastKey"), prefixed_key TSRMLS_CC); + + PHALCON_OBS_VAR(cache_dir); + phalcon_array_fetch_string(&cache_dir, options, SL("cacheDir"), PH_NOISY); + + PHALCON_INIT_VAR(cache_file); + PHALCON_CONCAT_VV(cache_file, cache_dir, prefixed_key); + + if (phalcon_file_exists(cache_file TSRMLS_CC) == SUCCESS) { + + PHALCON_OBS_VAR(frontend); + phalcon_read_property_this(&frontend, this_ptr, SL("_frontend"), PH_NOISY_CC); + + /** + * Check if the file has expired + */ + PHALCON_INIT_VAR(timestamp); + ZVAL_LONG(timestamp, (long) time(NULL)); + + /** + * Take the lifetime from the frontend or read it from the set in start() + */ + PHALCON_INIT_VAR(lifetime); + if (Z_TYPE_P(lifetime) == IS_NULL) { + + PHALCON_OBS_NVAR(lifetime); + phalcon_read_property_this(&lifetime, this_ptr, SL("_lastLifetime"), PH_NOISY_CC); + if (Z_TYPE_P(lifetime) == IS_NULL) { + PHALCON_INIT_VAR(ttl); + phalcon_call_method(ttl, frontend, "getlifetime"); + } else { + PHALCON_CPY_WRT(ttl, lifetime); + } + } else { + PHALCON_CPY_WRT(ttl, lifetime); + } + + PHALCON_INIT_VAR(modified_time); + phalcon_call_func_p1(modified_time, "filemtime", cache_file); + + PHALCON_INIT_VAR(difference); + sub_function(difference, timestamp, ttl TSRMLS_CC); + + PHALCON_INIT_VAR(not_expired); + is_smaller_function(not_expired, difference, modified_time TSRMLS_CC); + + /** + * The content is only retrieved if the content has not expired + */ + if (PHALCON_IS_TRUE(not_expired)) { + + /** + * Use file-get-contents to control that the openbase_dir can't be skipped + */ + PHALCON_INIT_VAR(cached_content); + phalcon_file_get_contents(cached_content, cache_file TSRMLS_CC); + if (PHALCON_IS_FALSE(cached_content)) { + PHALCON_INIT_VAR(exception_message); + PHALCON_CONCAT_SVS(exception_message, "Cache file ", cache_file, " could not be opened"); + PHALCON_THROW_EXCEPTION_ZVAL(phalcon_cache_exception_ce, exception_message); + return; + } + + if (phalcon_is_numeric(cached_content)) { + PHALCON_INIT_VAR(result); + sub_function(result, cached_content, value TSRMLS_CC); + + PHALCON_INIT_VAR(status); + phalcon_file_put_contents(status, cache_file, result TSRMLS_CC); + + if (PHALCON_IS_FALSE(status)) { + PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "Cache directory can't be written"); + return; + } + + RETURN_ZVAL(result, 1, 0); + } + } + } + + RETURN_MM_NULL(); +} diff --git a/ext/cache/backend/file.h b/ext/cache/backend/file.h index b70decaf037..6cc1c9b9c44 100644 --- a/ext/cache/backend/file.h +++ b/ext/cache/backend/file.h @@ -27,6 +27,8 @@ PHP_METHOD(Phalcon_Cache_Backend_File, save); PHP_METHOD(Phalcon_Cache_Backend_File, delete); PHP_METHOD(Phalcon_Cache_Backend_File, queryKeys); PHP_METHOD(Phalcon_Cache_Backend_File, exists); +PHP_METHOD(Phalcon_Cache_Backend_File, increment); +PHP_METHOD(Phalcon_Cache_Backend_File, decrement); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_file___construct, 0, 0, 1) ZEND_ARG_INFO(0, frontend) @@ -58,6 +60,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_file_exists, 0, 0, 0) ZEND_ARG_INFO(0, lifetime) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_file_increment, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_file_decrement, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + PHALCON_INIT_FUNCS(phalcon_cache_backend_file_method_entry){ PHP_ME(Phalcon_Cache_Backend_File, __construct, arginfo_phalcon_cache_backend_file___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(Phalcon_Cache_Backend_File, get, arginfo_phalcon_cache_backend_file_get, ZEND_ACC_PUBLIC) @@ -65,6 +77,8 @@ PHALCON_INIT_FUNCS(phalcon_cache_backend_file_method_entry){ PHP_ME(Phalcon_Cache_Backend_File, delete, arginfo_phalcon_cache_backend_file_delete, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_File, queryKeys, arginfo_phalcon_cache_backend_file_querykeys, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_File, exists, arginfo_phalcon_cache_backend_file_exists, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_File, increment, arginfo_phalcon_cache_backend_file_increment, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_File, decrement, arginfo_phalcon_cache_backend_file_decrement, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/ext/cache/backend/libmemcached.c b/ext/cache/backend/libmemcached.c index bc77c41549a..c4b1e6c09cf 100644 --- a/ext/cache/backend/libmemcached.c +++ b/ext/cache/backend/libmemcached.c @@ -236,7 +236,12 @@ PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, get){ RETURN_MM_NULL(); } - phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); + if (phalcon_is_numeric(cached_content)) { + RETURN_CCTOR(cached_content); + } else { + phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); + } + RETURN_MM(); } @@ -294,8 +299,10 @@ PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, save){ /** * Prepare the content in the frontend */ - PHALCON_OBS_VAR(prepared_content); - phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + if (!phalcon_is_numeric(cached_content)) { + PHALCON_OBS_VAR(prepared_content); + phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + } if (!lifetime || Z_TYPE_P(lifetime) == IS_NULL) { zval *tmp = phalcon_fetch_nproperty_this(this_ptr, SL("_lastLifetime"), PH_NOISY_CC); @@ -312,7 +319,11 @@ PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, save){ } PHALCON_OBS_VAR(success); - phalcon_call_method_p3_ex(success, &success, memcache, "set", last_key, prepared_content, ttl); + if (phalcon_is_numeric(cached_content)) { + phalcon_call_method_p3_ex(success, &success, memcache, "set", last_key, cached_content, ttl); + } else { + phalcon_call_method_p3_ex(success, &success, memcache, "set", last_key, prepared_content, ttl); + } if (!zend_is_true(success)) { PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "Failed storing data in memcached"); return; @@ -356,6 +367,98 @@ PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, save){ PHALCON_MM_RESTORE(); } +/** + * Increment of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, increment){ + zval *key_name, *value = NULL, *memcache, *prefix; + zval *prefixed_key, *cached_content; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + memcache = phalcon_fetch_nproperty_this(this_ptr, SL("_memcache"), PH_NOISY_CC); + if (Z_TYPE_P(memcache) != IS_OBJECT) { + phalcon_call_method_noret(this_ptr, "_connect"); + memcache = phalcon_fetch_nproperty_this(this_ptr, SL("_memcache"), PH_NOISY_CC); + } + + prefix = phalcon_fetch_nproperty_this(this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_VAR(prefixed_key); + PHALCON_CONCAT_VV(prefixed_key, prefix, key_name); + phalcon_update_property_this(this_ptr, SL("_lastKey"), prefixed_key TSRMLS_CC); + + PHALCON_OBS_VAR(cached_content); + phalcon_call_method_p2_ex(cached_content, &cached_content, memcache, "increment", prefixed_key, value); + if (PHALCON_IS_FALSE(cached_content)) { + RETURN_MM_NULL(); + } + + RETURN_CCTOR(cached_content); + + RETURN_MM(); +} + +/** + * Decrement of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, decrement){ + zval *key_name, *value = NULL, *memcache, *prefix; + zval *prefixed_key, *cached_content; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + memcache = phalcon_fetch_nproperty_this(this_ptr, SL("_memcache"), PH_NOISY_CC); + if (Z_TYPE_P(memcache) != IS_OBJECT) { + phalcon_call_method_noret(this_ptr, "_connect"); + memcache = phalcon_fetch_nproperty_this(this_ptr, SL("_memcache"), PH_NOISY_CC); + } + + prefix = phalcon_fetch_nproperty_this(this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_VAR(prefixed_key); + PHALCON_CONCAT_VV(prefixed_key, prefix, key_name); + phalcon_update_property_this(this_ptr, SL("_lastKey"), prefixed_key TSRMLS_CC); + + PHALCON_OBS_VAR(cached_content); + phalcon_call_method_p2_ex(cached_content, &cached_content, memcache, "decrement", prefixed_key, value); + if (PHALCON_IS_FALSE(cached_content)) { + RETURN_MM_NULL(); + } + + RETURN_CCTOR(cached_content); + + RETURN_MM(); +} + /** * Deletes a value from the cache by its key * diff --git a/ext/cache/backend/libmemcached.h b/ext/cache/backend/libmemcached.h index 99f2ec61583..b22a6ae9638 100644 --- a/ext/cache/backend/libmemcached.h +++ b/ext/cache/backend/libmemcached.h @@ -28,6 +28,8 @@ PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, save); PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, delete); PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, queryKeys); PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, exists); +PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, increment); +PHP_METHOD(Phalcon_Cache_Backend_Libmemcached, decrement); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_libmemcached___construct, 0, 0, 1) ZEND_ARG_INFO(0, frontend) @@ -59,6 +61,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_libmemcached_exists, 0, 0, ZEND_ARG_INFO(0, lifetime) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_libmemcached_increment, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_libmemcached_decrement, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + PHALCON_INIT_FUNCS(phalcon_cache_backend_libmemcached_method_entry){ PHP_ME(Phalcon_Cache_Backend_Libmemcached, __construct, arginfo_phalcon_cache_backend_libmemcached___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(Phalcon_Cache_Backend_Libmemcached, _connect, NULL, ZEND_ACC_PROTECTED) @@ -67,6 +79,8 @@ PHALCON_INIT_FUNCS(phalcon_cache_backend_libmemcached_method_entry){ PHP_ME(Phalcon_Cache_Backend_Libmemcached, delete, arginfo_phalcon_cache_backend_libmemcached_delete, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Libmemcached, queryKeys, arginfo_phalcon_cache_backend_libmemcached_querykeys, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Libmemcached, exists, arginfo_phalcon_cache_backend_libmemcached_exists, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Libmemcached, increment, arginfo_phalcon_cache_backend_libmemcached_increment, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Libmemcached, decrement, arginfo_phalcon_cache_backend_libmemcached_decrement, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/ext/cache/backend/memcache.c b/ext/cache/backend/memcache.c index b0e506d3570..dee39a2f9aa 100644 --- a/ext/cache/backend/memcache.c +++ b/ext/cache/backend/memcache.c @@ -212,6 +212,10 @@ PHP_METHOD(Phalcon_Cache_Backend_Memcache, get){ if (PHALCON_IS_FALSE(cached_content)) { RETURN_MM_NULL(); } + + if (phalcon_is_numeric(cached_content)) { + RETURN_CCTOR(cached_content); + } phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); RETURN_MM(); @@ -295,7 +299,11 @@ PHP_METHOD(Phalcon_Cache_Backend_Memcache, save){ * We store without flags */ PHALCON_OBS_VAR(success); - phalcon_call_method_p4_ex(success, &success, memcache, "set", last_key, prepared_content, flags, ttl); + if(phalcon_is_numeric(cached_content)) { + phalcon_call_method_p4_ex(success, &success, memcache, "set", last_key, cached_content, flags, ttl); + } else { + phalcon_call_method_p4_ex(success, &success, memcache, "set", last_key, prepared_content, flags, ttl); + } if (!zend_is_true(success)) { PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "Failed to store data in memcached"); return; @@ -485,3 +493,87 @@ PHP_METHOD(Phalcon_Cache_Backend_Memcache, exists){ PHALCON_MM_RESTORE(); } + +/** + * Atomic increment of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Memcache, increment){ + + zval *key_name = NULL, *value = NULL, *memcache = NULL; + zval *newVal; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 0, 2, &key_name, &value); + + if (!key_name) { + PHALCON_INIT_VAR(key_name); + } + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + if (Z_TYPE_P(value) != IS_LONG) { + PHALCON_SEPARATE_PARAM(value); + convert_to_long_ex(&value); + } + + PHALCON_OBS_VAR(memcache); + phalcon_read_property_this(&memcache, this_ptr, SL("_memcache"), PH_NOISY_CC); + + PHALCON_INIT_VAR(newVal); + phalcon_call_method_p2(newVal, memcache, "increment", key_name, value); + + RETURN_CTOR(newVal); +} + +/** + * Atomic decrement of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Memcache, decrement){ + + zval *key_name = NULL, *value = NULL, *memcache = NULL; + zval *newVal; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 0, 2, &key_name, &value); + + if (!key_name) { + PHALCON_INIT_VAR(key_name); + } + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + if (Z_TYPE_P(value) != IS_LONG) { + PHALCON_SEPARATE_PARAM(value); + convert_to_long_ex(&value); + } + + PHALCON_OBS_VAR(memcache); + phalcon_read_property_this(&memcache, this_ptr, SL("_memcache"), PH_NOISY_CC); + + PHALCON_INIT_VAR(newVal); + phalcon_call_method_p2(newVal, memcache, "decrement", key_name, value); + + RETURN_CTOR(newVal); +} diff --git a/ext/cache/backend/memcache.h b/ext/cache/backend/memcache.h index ec67afcf9cb..da5f7d3c0ec 100644 --- a/ext/cache/backend/memcache.h +++ b/ext/cache/backend/memcache.h @@ -28,6 +28,8 @@ PHP_METHOD(Phalcon_Cache_Backend_Memcache, save); PHP_METHOD(Phalcon_Cache_Backend_Memcache, delete); PHP_METHOD(Phalcon_Cache_Backend_Memcache, queryKeys); PHP_METHOD(Phalcon_Cache_Backend_Memcache, exists); +PHP_METHOD(Phalcon_Cache_Backend_Memcache, increment); +PHP_METHOD(Phalcon_Cache_Backend_Memcache, decrement); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_memcache___construct, 0, 0, 1) ZEND_ARG_INFO(0, frontend) @@ -59,6 +61,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_memcache_exists, 0, 0, 0) ZEND_ARG_INFO(0, lifetime) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_memcache_increment, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_memcache_decrement, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + PHALCON_INIT_FUNCS(phalcon_cache_backend_memcache_method_entry){ PHP_ME(Phalcon_Cache_Backend_Memcache, __construct, arginfo_phalcon_cache_backend_memcache___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(Phalcon_Cache_Backend_Memcache, _connect, NULL, ZEND_ACC_PROTECTED) @@ -67,6 +79,8 @@ PHALCON_INIT_FUNCS(phalcon_cache_backend_memcache_method_entry){ PHP_ME(Phalcon_Cache_Backend_Memcache, delete, arginfo_phalcon_cache_backend_memcache_delete, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Memcache, queryKeys, arginfo_phalcon_cache_backend_memcache_querykeys, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Memcache, exists, arginfo_phalcon_cache_backend_memcache_exists, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Memcache, increment, arginfo_phalcon_cache_backend_memcache_increment, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Memcache, decrement, arginfo_phalcon_cache_backend_memcache_decrement, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/ext/cache/backend/memory.c b/ext/cache/backend/memory.c index 42a478628a1..f8bed21c18c 100644 --- a/ext/cache/backend/memory.c +++ b/ext/cache/backend/memory.c @@ -102,8 +102,12 @@ PHP_METHOD(Phalcon_Cache_Backend_Memory, get){ data = phalcon_fetch_nproperty_this(this_ptr, SL("_data"), PH_NOISY_CC); if (phalcon_array_isset_fetch(&cached_content, data, last_key)) { if (Z_TYPE_P(cached_content) != IS_NULL) { - frontend = phalcon_fetch_nproperty_this(this_ptr, SL("_frontend"), PH_NOISY_CC); - phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); + if (phalcon_is_numeric(cached_content)) { + RETURN_ZVAL(cached_content, 1, 0); + } else { + frontend = phalcon_fetch_nproperty_this(this_ptr, SL("_frontend"), PH_NOISY_CC); + phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); + } } } @@ -149,10 +153,14 @@ PHP_METHOD(Phalcon_Cache_Backend_Memory, save){ } else { cached_content = content; } - - PHALCON_OBS_VAR(prepared_content); - phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); - phalcon_update_property_array(this_ptr, SL("_data"), last_key, prepared_content TSRMLS_CC); + + if (phalcon_is_numeric(cached_content)) { + phalcon_update_property_array(this_ptr, SL("_data"), last_key, cached_content TSRMLS_CC); + } else { + PHALCON_OBS_VAR(prepared_content); + phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + phalcon_update_property_array(this_ptr, SL("_data"), last_key, prepared_content TSRMLS_CC); + } PHALCON_OBS_VAR(is_buffering); phalcon_call_method_p0_ex(is_buffering, &is_buffering, frontend, "isbuffering"); @@ -288,3 +296,113 @@ PHP_METHOD(Phalcon_Cache_Backend_Memory, exists){ RETURN_MM_FALSE; } + +/** + * Increment of given $keyName by $value + * + * @param string $keyName + * @param long $lifetime + * @return boolean + */ +PHP_METHOD(Phalcon_Cache_Backend_Memory, increment){ + + zval *key_name, *value = NULL, *last_key = NULL, *prefix, *data; + zval *cached_content, *result; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(key_name) == IS_NULL) { + PHALCON_OBS_VAR(last_key); + phalcon_read_property_this(&last_key, this_ptr, SL("_lastKey"), PH_NOISY_CC); + } else { + PHALCON_OBS_VAR(prefix); + phalcon_read_property_this(&prefix, this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_NVAR(last_key); + PHALCON_CONCAT_VV(last_key, prefix, key_name); + } + + PHALCON_OBS_VAR(data); + phalcon_read_property_this(&data, this_ptr, SL("_data"), PH_NOISY_CC); + if (!phalcon_array_isset(data, last_key)) { + RETURN_MM_NULL(); + } + + PHALCON_OBS_VAR(cached_content); + phalcon_array_fetch(&cached_content, data, last_key, PH_NOISY); + if (Z_TYPE_P(cached_content) == IS_NULL) { + RETURN_MM_NULL(); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + PHALCON_INIT_VAR(result); + add_function(result, cached_content, value TSRMLS_CC); + phalcon_update_property_array(this_ptr, SL("_data"), last_key, result TSRMLS_CC); + RETURN_ZVAL(result, 1, 0); + + RETURN_MM(); +} + +/** + * Decrement of $keyName by given $value + * + * @param string $keyName + * @param long $value + * @return long + */ +PHP_METHOD(Phalcon_Cache_Backend_Memory, decrement){ + + zval *key_name, *value = NULL, *last_key = NULL, *prefix, *data; + zval *cached_content, *result; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(key_name) == IS_NULL) { + PHALCON_OBS_VAR(last_key); + phalcon_read_property_this(&last_key, this_ptr, SL("_lastKey"), PH_NOISY_CC); + } else { + PHALCON_OBS_VAR(prefix); + phalcon_read_property_this(&prefix, this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_NVAR(last_key); + PHALCON_CONCAT_VV(last_key, prefix, key_name); + } + + PHALCON_OBS_VAR(data); + phalcon_read_property_this(&data, this_ptr, SL("_data"), PH_NOISY_CC); + if (!phalcon_array_isset(data, last_key)) { + RETURN_MM_NULL(); + } + + PHALCON_OBS_VAR(cached_content); + phalcon_array_fetch(&cached_content, data, last_key, PH_NOISY); + if (Z_TYPE_P(cached_content) == IS_NULL) { + RETURN_MM_NULL(); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + PHALCON_INIT_VAR(result); + sub_function(result, cached_content, value TSRMLS_CC); + phalcon_update_property_array(this_ptr, SL("_data"), last_key, result TSRMLS_CC); + RETURN_ZVAL(result, 1, 0); + + RETURN_MM(); +} diff --git a/ext/cache/backend/memory.h b/ext/cache/backend/memory.h index b9ea180456b..61ad31bf7af 100644 --- a/ext/cache/backend/memory.h +++ b/ext/cache/backend/memory.h @@ -26,6 +26,8 @@ PHP_METHOD(Phalcon_Cache_Backend_Memory, save); PHP_METHOD(Phalcon_Cache_Backend_Memory, delete); PHP_METHOD(Phalcon_Cache_Backend_Memory, queryKeys); PHP_METHOD(Phalcon_Cache_Backend_Memory, exists); +PHP_METHOD(Phalcon_Cache_Backend_Memory, increment); +PHP_METHOD(Phalcon_Cache_Backend_Memory, decrement); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_memory_get, 0, 0, 1) ZEND_ARG_INFO(0, keyName) @@ -52,12 +54,24 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_memory_exists, 0, 0, 0) ZEND_ARG_INFO(0, lifetime) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_memory_increment, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_memory_decrement, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + PHALCON_INIT_FUNCS(phalcon_cache_backend_memory_method_entry){ PHP_ME(Phalcon_Cache_Backend_Memory, get, arginfo_phalcon_cache_backend_memory_get, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Memory, save, arginfo_phalcon_cache_backend_memory_save, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Memory, delete, arginfo_phalcon_cache_backend_memory_delete, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Memory, queryKeys, arginfo_phalcon_cache_backend_memory_querykeys, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Memory, exists, arginfo_phalcon_cache_backend_memory_exists, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Memory, increment, arginfo_phalcon_cache_backend_memory_increment, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Memory, decrement, arginfo_phalcon_cache_backend_memory_decrement, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/ext/cache/backend/mongo.c b/ext/cache/backend/mongo.c index b4997e0717c..f357c3af995 100644 --- a/ext/cache/backend/mongo.c +++ b/ext/cache/backend/mongo.c @@ -241,16 +241,20 @@ PHP_METHOD(Phalcon_Cache_Backend_Mongo, get){ phalcon_call_method_p1_ex(document, &document, collection, "findone", conditions); if (Z_TYPE_P(document) == IS_ARRAY) { if (likely(phalcon_array_isset_string_fetch(&cached_content, document, SS("data")))) { - phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); - RETURN_MM(); - } - else { + if (phalcon_is_numeric(cached_content)) { + RETURN_CCTOR(cached_content); + } else { + phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); + RETURN_MM(); + } + } else { PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "The cache is corrupt"); return; } + } else { + RETURN_MM_NULL(); } - RETURN_MM_NULL(); } /** @@ -293,9 +297,11 @@ PHP_METHOD(Phalcon_Cache_Backend_Mongo, save){ } else { cached_content = content; } - - PHALCON_OBS_VAR(prepared_content); - phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + + if (!phalcon_is_numeric(cached_content)) { + PHALCON_OBS_VAR(prepared_content); + phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + } if (!lifetime || Z_TYPE_P(lifetime) == IS_NULL) { zval *tmp = phalcon_fetch_nproperty_this(this_ptr, SL("_lastLifetime"), PH_NOISY_CC); @@ -326,14 +332,24 @@ PHP_METHOD(Phalcon_Cache_Backend_Mongo, save){ if (Z_TYPE_P(document) == IS_ARRAY) { phalcon_array_update_string(&document, SL("time"), ×tamp, PH_COPY); - phalcon_array_update_string(&document, SL("data"), &prepared_content, PH_COPY); + if (!phalcon_is_numeric(cached_content)) { + phalcon_array_update_string(&document, SL("data"), &prepared_content, PH_COPY); + } else { + phalcon_array_update_string(&document, SL("data"), &cached_content, PH_COPY); + } phalcon_call_method_p1_noret(collection, "save", document); } else { PHALCON_INIT_VAR(data); array_init_size(data, 3); phalcon_array_update_string(&data, SL("key"), &last_key, PH_COPY); phalcon_array_update_string(&data, SL("time"), ×tamp, PH_COPY); - phalcon_array_update_string(&data, SL("data"), &prepared_content, PH_COPY); + + if (!phalcon_is_numeric(cached_content)) { + phalcon_array_update_string(&data, SL("data"), &prepared_content, PH_COPY); + } else { + phalcon_array_update_string(&data, SL("data"), &cached_content, PH_COPY); + } + phalcon_call_method_p1_noret(collection, "save", data); } @@ -533,3 +549,233 @@ PHP_METHOD(Phalcon_Cache_Backend_Mongo, gc) { PHALCON_MM_RESTORE(); } + +/** + * Increment of a given key by $value + * + * @param int|string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Mongo, increment){ + + zval *key_name, *lifetime = NULL, *frontend, *prefix, *prefixed_key, *value = NULL; + zval *collection, *conditions, *document, *timestamp; + zval *ttl = NULL, *modified_time, *difference, *not_expired; + zval *cached_content; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + ZVAL_LONG(value, 1); + } + + if(Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + if (Z_TYPE_P(value) != IS_LONG) { + PHALCON_SEPARATE_PARAM(value); + convert_to_long_ex(&value); + } + + PHALCON_OBS_VAR(frontend); + phalcon_read_property_this(&frontend, this_ptr, SL("_frontend"), PH_NOISY_CC); + + PHALCON_OBS_VAR(prefix); + phalcon_read_property_this(&prefix, this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_VAR(prefixed_key); + PHALCON_CONCAT_VV(prefixed_key, prefix, key_name); + phalcon_update_property_this(this_ptr, SL("_lastKey"), prefixed_key TSRMLS_CC); + + PHALCON_INIT_VAR(collection); + phalcon_call_method(collection, this_ptr, "_getcollection"); + + PHALCON_INIT_VAR(conditions); + array_init_size(conditions, 1); + phalcon_array_update_string(&conditions, SL("key"), &prefixed_key, PH_COPY | PH_SEPARATE); + + PHALCON_INIT_VAR(document); + phalcon_call_method_p1(document, collection, "findone", conditions); + + PHALCON_INIT_VAR(timestamp); + PHALCON_INIT_VAR(lifetime); + ZVAL_LONG(timestamp, (long) time(NULL)); + + PHALCON_OBS_NVAR(lifetime); + phalcon_read_property_this(&lifetime, this_ptr, SL("_lastLifetime"), PH_NOISY_CC); + if (Z_TYPE_P(lifetime) == IS_NULL) { + PHALCON_INIT_VAR(ttl); + phalcon_call_method(ttl, frontend, "getlifetime"); + } else { + PHALCON_CPY_WRT(ttl, lifetime); + } + + /* + * phalcon_add_function(newlifetime, ttl, timestamp TSRMLS_CC); + */ + + if (!phalcon_array_isset_string(document, SS("time"))) { + PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "The cache is currupted"); + return; + } + + PHALCON_OBS_VAR(modified_time); + phalcon_array_fetch_string(&modified_time, document, SL("time"), PH_NOISY); + + PHALCON_INIT_VAR(difference); + sub_function(difference, timestamp, ttl TSRMLS_CC); + + PHALCON_INIT_VAR(not_expired); + is_smaller_function(not_expired, difference, modified_time TSRMLS_CC); + + /** + * The expiration is based on the column 'time' + */ + if (PHALCON_IS_TRUE(not_expired)) { + if (!phalcon_array_isset_string(document, SS("data"))) { + PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "The cache is currupted"); + return; + } + + PHALCON_OBS_VAR(cached_content); + phalcon_array_fetch_string(&cached_content, document, SL("data"), PH_NOISY); + + if(Z_TYPE_P(cached_content) != IS_LONG) { + PHALCON_SEPARATE_PARAM(cached_content); + convert_to_long_ex(&cached_content); + } + + if (phalcon_is_numeric(cached_content)) { + add_function(return_value, cached_content, value TSRMLS_CC); + + PHALCON_INIT_NVAR(ttl); + phalcon_add_function(ttl, lifetime, timestamp TSRMLS_CC); + + phalcon_call_method_p2_noret(this_ptr, "save", prefixed_key, return_value); + } + + RETURN_MM(); + } + + RETURN_MM_NULL(); +} + +/** + * Decrement of a given key by $value + * + * @param int|string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Mongo, decrement){ + + zval *key_name, *lifetime = NULL, *frontend, *prefix, *prefixed_key, *value = NULL; + zval *collection, *conditions, *document, *timestamp; + zval *ttl = NULL, *modified_time, *difference, *not_expired; + zval *cached_content; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 1, 1, &key_name, &value); + + if (!value) { + PHALCON_INIT_VAR(value); + ZVAL_LONG(value, 1); + } + + if(Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + if (Z_TYPE_P(value) != IS_LONG) { + PHALCON_SEPARATE_PARAM(value); + convert_to_long_ex(&value); + } + + PHALCON_OBS_VAR(frontend); + phalcon_read_property_this(&frontend, this_ptr, SL("_frontend"), PH_NOISY_CC); + + PHALCON_OBS_VAR(prefix); + phalcon_read_property_this(&prefix, this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_VAR(prefixed_key); + PHALCON_CONCAT_VV(prefixed_key, prefix, key_name); + phalcon_update_property_this(this_ptr, SL("_lastKey"), prefixed_key TSRMLS_CC); + + PHALCON_INIT_VAR(collection); + phalcon_call_method(collection, this_ptr, "_getcollection"); + + PHALCON_INIT_VAR(conditions); + array_init_size(conditions, 1); + phalcon_array_update_string(&conditions, SL("key"), &prefixed_key, PH_COPY | PH_SEPARATE); + + PHALCON_INIT_VAR(document); + phalcon_call_method_p1(document, collection, "findone", conditions); + + PHALCON_INIT_VAR(timestamp); + PHALCON_INIT_VAR(lifetime); + ZVAL_LONG(timestamp, (long) time(NULL)); + + PHALCON_OBS_NVAR(lifetime); + phalcon_read_property_this(&lifetime, this_ptr, SL("_lastLifetime"), PH_NOISY_CC); + if (Z_TYPE_P(lifetime) == IS_NULL) { + PHALCON_INIT_VAR(ttl); + phalcon_call_method(ttl, frontend, "getlifetime"); + } else { + PHALCON_CPY_WRT(ttl, lifetime); + } + + /* + * phalcon_add_function(newlifetime, ttl, timestamp TSRMLS_CC); + */ + + if (!phalcon_array_isset_string(document, SS("time"))) { + PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "The cache is currupted"); + return; + } + + PHALCON_OBS_VAR(modified_time); + phalcon_array_fetch_string(&modified_time, document, SL("time"), PH_NOISY); + + PHALCON_INIT_VAR(difference); + sub_function(difference, timestamp, ttl TSRMLS_CC); + + PHALCON_INIT_VAR(not_expired); + is_smaller_function(not_expired, difference, modified_time TSRMLS_CC); + + /** + * The expiration is based on the column 'time' + */ + if (PHALCON_IS_TRUE(not_expired)) { + if (!phalcon_array_isset_string(document, SS("data"))) { + PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "The cache is currupted"); + return; + } + + PHALCON_OBS_VAR(cached_content); + phalcon_array_fetch_string(&cached_content, document, SL("data"), PH_NOISY); + + if(Z_TYPE_P(cached_content) != IS_LONG) { + PHALCON_SEPARATE_PARAM(cached_content); + convert_to_long_ex(&cached_content); + } + + if (phalcon_is_numeric(cached_content)) { + sub_function(return_value, cached_content, value TSRMLS_CC); + + PHALCON_INIT_NVAR(ttl); + phalcon_add_function(ttl, lifetime, timestamp TSRMLS_CC); + + phalcon_call_method_p2_noret(this_ptr, "save", prefixed_key, return_value); + } + + RETURN_MM(); + } + + RETURN_MM_NULL(); +} diff --git a/ext/cache/backend/mongo.h b/ext/cache/backend/mongo.h index 965ee8d6e0f..ad879e038d7 100644 --- a/ext/cache/backend/mongo.h +++ b/ext/cache/backend/mongo.h @@ -29,6 +29,8 @@ PHP_METHOD(Phalcon_Cache_Backend_Mongo, delete); PHP_METHOD(Phalcon_Cache_Backend_Mongo, queryKeys); PHP_METHOD(Phalcon_Cache_Backend_Mongo, exists); PHP_METHOD(Phalcon_Cache_Backend_Mongo, gc); +PHP_METHOD(Phalcon_Cache_Backend_Mongo, increment); +PHP_METHOD(Phalcon_Cache_Backend_Mongo, decrement); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_mongo___construct, 0, 0, 1) ZEND_ARG_INFO(0, frontend) @@ -60,6 +62,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_mongo_exists, 0, 0, 0) ZEND_ARG_INFO(0, lifetime) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_mongo_increment, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_mongo_decrement, 0, 0, 0) + ZEND_ARG_INFO(0, keyName) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_mongo_empty, 0, 0, 0) ZEND_END_ARG_INFO() @@ -72,6 +84,8 @@ PHALCON_INIT_FUNCS(phalcon_cache_backend_mongo_method_entry){ PHP_ME(Phalcon_Cache_Backend_Mongo, queryKeys, arginfo_phalcon_cache_backend_mongo_querykeys, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Mongo, exists, arginfo_phalcon_cache_backend_mongo_exists, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Mongo, gc, arginfo_phalcon_cache_backend_mongo_empty, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Mongo, increment, arginfo_phalcon_cache_backend_mongo_increment, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Mongo, decrement, arginfo_phalcon_cache_backend_mongo_decrement, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/ext/cache/backend/xcache.c b/ext/cache/backend/xcache.c index 896a3d2f499..ed4574850f2 100644 --- a/ext/cache/backend/xcache.c +++ b/ext/cache/backend/xcache.c @@ -141,8 +141,13 @@ PHP_METHOD(Phalcon_Cache_Backend_Xcache, get){ if (Z_TYPE_P(cached_content) == IS_NULL) { RETURN_MM_NULL(); } + + if (phalcon_is_numeric(cached_content)) { + RETURN_CCTOR(cached_content); + } else { + phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); + } - phalcon_return_call_method_p1(frontend, "afterretrieve", cached_content); RETURN_MM(); } @@ -186,8 +191,10 @@ PHP_METHOD(Phalcon_Cache_Backend_Xcache, save){ cached_content = content; } - PHALCON_OBS_VAR(prepared_content); - phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + if (!phalcon_is_numeric(cached_content)) { + PHALCON_OBS_VAR(prepared_content); + phalcon_call_method_p1_ex(prepared_content, &prepared_content, frontend, "beforestore", cached_content); + } /** * Take the lifetime from the frontend or read it from the set in start() @@ -207,7 +214,12 @@ PHP_METHOD(Phalcon_Cache_Backend_Xcache, save){ } PHALCON_OBS_VAR(success); - phalcon_call_func_p3_ex(success, &success, "xcache_set", last_key, prepared_content, ttl); + + if (phalcon_is_numeric(cached_content)) { + phalcon_call_func_p3_ex(success, &success, "xcache_set", last_key, cached_content, ttl); + } else { + phalcon_call_func_p3_ex(success, &success, "xcache_set", last_key, prepared_content, ttl); + } PHALCON_OBS_VAR(is_buffering); phalcon_call_method_p0_ex(is_buffering, &is_buffering, frontend, "isbuffering"); @@ -386,3 +398,138 @@ PHP_METHOD(Phalcon_Cache_Backend_Xcache, exists){ PHALCON_MM_RESTORE(); } + +/** + * Atomic increment of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Xcache, increment){ + + zval *key_name = NULL, *value = NULL, *last_key = NULL; + zval *newVal, *prefix, *origVal, *success, *function_name; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 0, 2, &key_name, &value); + + if (!key_name) { + PHALCON_INIT_VAR(key_name); + } + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + if (Z_TYPE_P(value) != IS_LONG) { + convert_to_long_ex(&value); + } + + if (Z_TYPE_P(key_name) == IS_NULL) { + PHALCON_OBS_VAR(last_key); + phalcon_read_property_this(&last_key, this_ptr, SL("_lastKey"), PH_NOISY_CC); + } else { + PHALCON_OBS_VAR(prefix); + phalcon_read_property_this(&prefix, this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_NVAR(last_key); + PHALCON_CONCAT_SVV(last_key, "_PHCX", prefix, key_name); + } + if (!zend_is_true(last_key)) { + PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "The cache must be started first"); + return; + } + + PHALCON_INIT_VAR(newVal); + PHALCON_INIT_VAR(function_name); + ZVAL_STRING(function_name, "xcache_inc", 1); + if (phalcon_function_exists(function_name TSRMLS_CC) == SUCCESS) { + phalcon_call_func_p2(newVal, "xcache_inc", last_key, value); + + RETURN_CTOR(newVal); + } else { + PHALCON_INIT_VAR(origVal); + PHALCON_INIT_VAR(success); + phalcon_call_func_p1(origVal, "xcache_get", last_key); + PHALCON_SEPARATE_PARAM(origVal); + convert_to_long_ex(&origVal); + add_function(newVal, origVal, value TSRMLS_CC); + phalcon_call_func_p2(success, "xcache_set", last_key, newVal); + + RETURN_CTOR(newVal); + } +} + +/** + * Atomic decrement of a given key, by number $value + * + * @param string $keyName + * @param long $value + * @return mixed + */ +PHP_METHOD(Phalcon_Cache_Backend_Xcache, decrement){ + + zval *key_name = NULL, *value = NULL, *last_key = NULL; + zval *newVal, *prefix, *origVal, *success, *function_name; + + PHALCON_MM_GROW(); + + phalcon_fetch_params(1, 0, 2, &key_name, &value); + + if (!key_name) { + PHALCON_INIT_VAR(key_name); + } + + if (!value) { + PHALCON_INIT_VAR(value); + } + + if (Z_TYPE_P(value) == IS_NULL) { + ZVAL_LONG(value, 1); + } + + if (Z_TYPE_P(value) != IS_LONG) { + convert_to_long_ex(&value); + } + + if (Z_TYPE_P(key_name) == IS_NULL) { + PHALCON_OBS_VAR(last_key); + phalcon_read_property_this(&last_key, this_ptr, SL("_lastKey"), PH_NOISY_CC); + } else { + PHALCON_OBS_VAR(prefix); + phalcon_read_property_this(&prefix, this_ptr, SL("_prefix"), PH_NOISY_CC); + + PHALCON_INIT_NVAR(last_key); + PHALCON_CONCAT_SVV(last_key, "_PHCX", prefix, key_name); + } + if (!zend_is_true(last_key)) { + PHALCON_THROW_EXCEPTION_STR(phalcon_cache_exception_ce, "The cache must be started first"); + return; + } + + PHALCON_INIT_VAR(newVal); + PHALCON_INIT_VAR(function_name); + ZVAL_STRING(function_name, "xcache_dec", 1); + + if (phalcon_function_exists(function_name TSRMLS_CC) == SUCCESS) { + phalcon_call_func_p2(newVal, "xcache_dec", last_key, value); + + RETURN_CTOR(newVal); + } else { + PHALCON_INIT_VAR(origVal); + PHALCON_INIT_VAR(success); + phalcon_call_func_p1(origVal, "xcache_get", last_key); + PHALCON_SEPARATE_PARAM(origVal); + convert_to_long_ex(&origVal); + sub_function(newVal, origVal, value TSRMLS_CC); + phalcon_call_func_p2(success, "xcache_set", last_key, newVal); + + RETURN_CTOR(newVal); + } +} diff --git a/ext/cache/backend/xcache.h b/ext/cache/backend/xcache.h index d1987eafb6e..bb5fc6ed8ac 100644 --- a/ext/cache/backend/xcache.h +++ b/ext/cache/backend/xcache.h @@ -28,6 +28,8 @@ PHP_METHOD(Phalcon_Cache_Backend_Xcache, save); PHP_METHOD(Phalcon_Cache_Backend_Xcache, delete); PHP_METHOD(Phalcon_Cache_Backend_Xcache, queryKeys); PHP_METHOD(Phalcon_Cache_Backend_Xcache, exists); +PHP_METHOD(Phalcon_Cache_Backend_Xcache, increment); +PHP_METHOD(Phalcon_Cache_Backend_Xcache, decrement); ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_xcache___construct, 0, 0, 1) ZEND_ARG_INFO(0, frontend) @@ -59,6 +61,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_xcache_exists, 0, 0, 0) ZEND_ARG_INFO(0, lifetime) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_xcache_increment, 0, 0, 0) + ZEND_ARG_INFO(0, key_name) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_cache_backend_xcache_decrement, 0, 0, 0) + ZEND_ARG_INFO(0, key_name) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + PHALCON_INIT_FUNCS(phalcon_cache_backend_xcache_method_entry){ PHP_ME(Phalcon_Cache_Backend_Xcache, __construct, arginfo_phalcon_cache_backend_xcache___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(Phalcon_Cache_Backend_Xcache, get, arginfo_phalcon_cache_backend_xcache_get, ZEND_ACC_PUBLIC) @@ -66,6 +78,8 @@ PHALCON_INIT_FUNCS(phalcon_cache_backend_xcache_method_entry){ PHP_ME(Phalcon_Cache_Backend_Xcache, delete, arginfo_phalcon_cache_backend_xcache_delete, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Xcache, queryKeys, arginfo_phalcon_cache_backend_xcache_querykeys, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Cache_Backend_Xcache, exists, arginfo_phalcon_cache_backend_xcache_exists, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Xcache, increment, arginfo_phalcon_cache_backend_xcache_increment, ZEND_ACC_PUBLIC) + PHP_ME(Phalcon_Cache_Backend_Xcache, decrement, arginfo_phalcon_cache_backend_xcache_decrement, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/unit-tests/CacheTest.php b/unit-tests/CacheTest.php index 5598c81fcd0..e6408bd3446 100644 --- a/unit-tests/CacheTest.php +++ b/unit-tests/CacheTest.php @@ -153,6 +153,36 @@ public function testDataFileCache() $this->assertTrue($cache->delete('test-data')); } + + public function testDataFileCacheIncrement() + { + $frontCache = new Phalcon\Cache\Frontend\Data(); + + $cache = new Phalcon\Cache\Backend\File($frontCache, array( + 'cacheDir' => 'unit-tests/cache/' + )); + $cache->delete('foo'); + $cache->save('foo', "1"); + $this->assertEquals(2, $cache->increment('foo')); + + $this->assertEquals($cache->get('foo'), 2); + + $this->assertEquals($cache->increment('foo', 5), 7); + } + + public function testDataFileCacheDecrement() + { + $frontCache = new Phalcon\Cache\Frontend\Data(); + + $cache = new Phalcon\Cache\Backend\File($frontCache, array( + 'cacheDir' => 'unit-tests/cache/' + )); + $cache->delete('foo'); + $cache->save('foo', "100"); + $this->assertEquals(99, $cache->decrement('foo')); + + $this->assertEquals(95, $cache->decrement('foo', 4)); + } public function testMemoryCache() { @@ -213,6 +243,26 @@ public function testMemoryCache() $this->assertEquals($s1, $string); //echo $r1, ' ', $r2, ' ', $r3, ' ', $r4, "\n"; } + + public function testMemoryCacheIncrAndDecr() + { + $frontCache = new Phalcon\Cache\Frontend\Output(array( + 'lifetime' => 2 + )); + + $cache = new Phalcon\Cache\Backend\Memory($frontCache); + $cache->delete('foo'); + + $cache->save('foo', 20); + + $this->assertEquals('21', $cache->increment('foo')); + $this->assertEquals('24', $cache->increment('foo', 3)); + + $this->assertEquals('23', $cache->decrement('foo')); + $this->assertEquals('3', $cache->decrement('foo', 20)); + + $this->assertEquals(3, $cache->get('foo')); + } private function _prepareIgbinary() { @@ -375,6 +425,29 @@ public function testOutputMemcacheCache() $memcache->close(); } + + public function testIncrAndDecrMemcacheCache() + { + $memcache = $this->_prepareMemcached(); + if (!$memcache) { + return false; + } + + $memcache->delete('test-incr'); + + $memcache->set('test-incr', 1); + $newValue = $memcache->increment('test-incr'); + $this->assertEquals('2', $newValue); + + $newValue = $memcache->increment('test-incr', 5); + $this->assertEquals('7', $newValue); + + $newValue = $memcache->decrement('test-incr'); + $this->assertEquals('6', $newValue); + + $newValue = $memcache->decrement('test-incr', '3'); + $this->assertEquals('3', $newValue); + } public function testDataMemcachedCache() { @@ -428,6 +501,40 @@ protected function _prepareApc() return true; } + public function testApcIncrement() + { + $ready = $this->_prepareApc(); + if (!$ready) { + return false; + } + + $frontCache = new Phalcon\Cache\Frontend\Data(array('lifetime' => 20)); + $cache = new Phalcon\Cache\Backend\Apc($frontCache); + $cache->delete('increment'); + + $cache->save('increment', 1); + $this->assertEquals(2, $cache->increment('increment')); + $this->assertEquals(4, $cache->increment('increment', 2)); + $this->assertEquals(14, $cache->increment('increment', 10)); + } + + public function testApcDecrement() + { + $ready = $this->_prepareApc(); + if (!$ready) { + return false; + } + + $frontCache = new Phalcon\Cache\Frontend\Data(array('lifetime' => 20)); + $cache = new Phalcon\Cache\Backend\Apc($frontCache); + $cache->delete('decrement'); + + $cache->save('decrement', 100); + $this->assertEquals(99, $cache->decrement('decrement')); + $this->assertEquals(97, $cache->decrement('decrement', 2)); + $this->assertEquals(87, $cache->decrement('decrement', 10)); + } + public function testOutputApcCache() { @@ -477,6 +584,8 @@ public function testOutputApcCache() $keys = $cache->queryKeys(); $this->assertEquals($keys, array( 0 => 'test-output', + 1 => 'decrement', + 2 => 'increment' )); //Delete entry from cache @@ -516,7 +625,7 @@ public function testDataApcCache() $cache->save('bcd', 3); $keys = $cache->queryKeys(); sort($keys); - $this->assertEquals($keys, array('a', 'bcd', 'long-key')); + $this->assertEquals($keys, array('a', 'bcd', 'decrement', 'increment', 'long-key')); $this->assertEquals($cache->queryKeys('long'), array('long-key')); $this->assertTrue($cache->delete('a')); @@ -641,18 +750,66 @@ public function testDataMongoCache() $this->assertTrue($cache->delete('test-data')); } + + public function testMongoIncrement() + { + $ready = $this->_prepareMongo(); + if (!$ready) { + return false; + } + + $frontCache = new Phalcon\Cache\Frontend\Data(array('lifetime' => 200)); + + $cache = new Phalcon\Cache\Backend\Mongo($frontCache, array( + 'mongo' => new Mongo(), + 'db' => 'phalcon_test', + 'collection' => 'caches' + )); + $cache->delete('foo'); + $cache->save('foo', 1); + $this->assertEquals(1, $cache->get('foo')); + + $this->assertEquals(2, $cache->increment('foo')); + $this->assertEquals(4, $cache->increment('foo', 2)); + $this->assertEquals(4, $cache->get('foo')); + + $this->assertEquals(14, $cache->increment('foo', 10)); + } + + public function testMongoDecrement() + { + $ready = $this->_prepareMongo(); + if (!$ready) { + return false; + } + + $frontCache = new Phalcon\Cache\Frontend\Data(array('lifetime' => 200)); + + $cache = new Phalcon\Cache\Backend\Mongo($frontCache, array( + 'mongo' => new Mongo(), + 'db' => 'phalcon_test', + 'collection' => 'caches' + )); + $cache->delete('foo'); + $cache->save('foo', 100); + + $this->assertEquals(99, $cache->decrement('foo')); + $this->assertEquals(89, $cache->decrement('foo', 10)); + $this->assertEquals(89, $cache->get('foo')); + $this->assertEquals(1, $cache->decrement('foo', 88)); + } protected function _prepareXcache() { if (function_exists('xcache_emulation')) { return true; } - + if (!extension_loaded('xcache') || 'cli' == PHP_SAPI) { $this->markTestSkipped('xcache extension is not loaded'); return false; } - + return true; } @@ -738,6 +895,56 @@ public function testDataXcache() $this->assertTrue($cache->delete('test-data')); } + + public function testXcacheIncrement() + { + $ready = $this->_prepareXcache(); + if (!$ready) { + return false; + } + + $frontCache = new Phalcon\Cache\Frontend\Output(array( + 'lifetime' => 20 + )); + + $cache = new Phalcon\Cache\Backend\Xcache($frontCache); + $cache->delete('foo'); + + $cache->save('foo', 1); + $newValue = $cache->increment('foo'); + $this->assertEquals('2', $newValue); + + $newValue = $cache->increment('foo'); + $this->assertEquals('3', $newValue); + + $newValue = $cache->increment('foo', 4); + $this->assertEquals('7', $newValue); + } + + public function testXcacheDecr() + { + $ready = $this->_prepareXcache(); + if (!$ready) { + return false; + } + + $frontCache = new Phalcon\Cache\Frontend\Output(array( + 'lifetime' => 20 + )); + + $cache = new Phalcon\Cache\Backend\Xcache($frontCache); + $cache->delete('foo'); + + $cache->save('foo', 20); + $newValue = $cache->decrement('foo'); + $this->assertEquals('19', $newValue); + + $newValue = $cache->decrement('foo'); + $this->assertEquals('18', $newValue); + + $newValue = $cache->decrement('foo', 4); + $this->assertEquals('14', $newValue); + } private function _prepareLibmemcached() { @@ -830,6 +1037,56 @@ public function testOutputLibmemcachedCache() } + public function testLibMemcachedIncrement() { + $memcache = $this->_prepareLibmemcached(); + if (!$memcache) { + return false; + } + + $frontCache = new Phalcon\Cache\Frontend\Data(); + + $cache = new Phalcon\Cache\Backend\Libmemcached($frontCache, array( + 'servers' => array( + array( + 'host' => '127.0.0.1', + 'port' => '11211', + 'weight' => '1'), + ) + )); + $cache->delete('foo'); + $cache->save('foo', 1); + $this->assertEquals(2, $cache->increment('foo')); + $this->assertEquals(4, $cache->increment('foo', 2)); + $cache->increment('foo', 10); + $this->assertEquals(14, $cache->get('foo')); + $cache->delete('foo'); + } + + public function testLibMemcachedDecrement() { + $memcache = $this->_prepareLibmemcached(); + if (!$memcache) { + return false; + } + + $frontCache = new Phalcon\Cache\Frontend\Data(); + + $cache = new Phalcon\Cache\Backend\Libmemcached($frontCache, array( + 'servers' => array( + array( + 'host' => '127.0.0.1', + 'port' => '11211', + 'weight' => '1'), + ) + )); + $cache->delete('foo'); + $cache->save('foo', 100); + $this->assertEquals(99, $cache->decrement('foo')); + $this->assertEquals(97, $cache->decrement('foo', 2)); + $cache->decrement('foo', 10); + $this->assertEquals(87, $cache->get('foo')); + $cache->delete('foo'); + } + public function testDataLibmemcachedCache() {