diff --git a/NEWS b/NEWS index 7dd05a2b1c72..33c232d8c962 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ PHP NEWS . Added gmp_powm_sec(). (Weilin Du) - Intl: + . Added static methods IntlDatePatternGenerator::getSkeleton() and + IntlDatePatternGenerator::getBaseSkeleton(). (Weilin Du) . Fixed Collator::sort(), collator_sort(), Collator::asort(), and collator_asort() to report UTF-8/UTF-16 conversion errors through the intl error handler instead of emitting a warning and continuing with an empty diff --git a/UPGRADING b/UPGRADING index 9389c7b04b20..171bd52fa49e 100644 --- a/UPGRADING +++ b/UPGRADING @@ -314,6 +314,9 @@ PHP 8.6 UPGRADE NOTES on official Windows builds using MPIR. - Intl: + . Added the static methods IntlDatePatternGenerator::getSkeleton() and + IntlDatePatternGenerator::getBaseSkeleton() to generate the unique skeleton + and base skeleton for a date/time pattern. . Added Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue(), with the alias of locale_get_display_keyword() and locale_get_display_keyword_value() respectively. @@ -489,6 +492,8 @@ PHP 8.6 UPGRADE NOTES - Intl: . grapheme_strrev() RFC: https://wiki.php.net/rfc/grapheme_strrev + . IntlDatePatternGenerator::getSkeleton() + . IntlDatePatternGenerator::getBaseSkeleton() . Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue() RFC: https://wiki.php.net/rfc/getdisplaykeyword_and_getdisplaykeywordvalue . SpoofChecker::areBidiConfusable() diff --git a/ext/intl/dateformat/datepatterngenerator.stub.php b/ext/intl/dateformat/datepatterngenerator.stub.php index a9ce7c146312..b97e8d9a86a4 100644 --- a/ext/intl/dateformat/datepatterngenerator.stub.php +++ b/ext/intl/dateformat/datepatterngenerator.stub.php @@ -10,4 +10,8 @@ public function __construct(?string $locale = null) {} public static function create(?string $locale = null): ?IntlDatePatternGenerator {} public function getBestPattern(string $skeleton): string|false {} + + public static function getSkeleton(string $pattern): string|false {} + + public static function getBaseSkeleton(string $pattern): string|false {} } diff --git a/ext/intl/dateformat/datepatterngenerator_arginfo.h b/ext/intl/dateformat/datepatterngenerator_arginfo.h index 01debdbe5fa6..acf6a4695929 100644 --- a/ext/intl/dateformat/datepatterngenerator_arginfo.h +++ b/ext/intl/dateformat/datepatterngenerator_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit datepatterngenerator.stub.php instead. - * Stub hash: 4456b13f7ed59847bbf129cd45b0d1f63ce70108 */ + * Stub hash: cea997295023d9f6f6451150bf19867e7dac8c90 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDatePatternGenerator___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, locale, IS_STRING, 1, "null") @@ -13,14 +13,24 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_IntlDatePatternGenerator_g ZEND_ARG_TYPE_INFO(0, skeleton, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_IntlDatePatternGenerator_getSkeleton, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_IntlDatePatternGenerator_getBaseSkeleton arginfo_class_IntlDatePatternGenerator_getSkeleton + ZEND_METHOD(IntlDatePatternGenerator, __construct); ZEND_METHOD(IntlDatePatternGenerator, create); ZEND_METHOD(IntlDatePatternGenerator, getBestPattern); +ZEND_METHOD(IntlDatePatternGenerator, getSkeleton); +ZEND_METHOD(IntlDatePatternGenerator, getBaseSkeleton); static const zend_function_entry class_IntlDatePatternGenerator_methods[] = { ZEND_ME(IntlDatePatternGenerator, __construct, arginfo_class_IntlDatePatternGenerator___construct, ZEND_ACC_PUBLIC) ZEND_ME(IntlDatePatternGenerator, create, arginfo_class_IntlDatePatternGenerator_create, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(IntlDatePatternGenerator, getBestPattern, arginfo_class_IntlDatePatternGenerator_getBestPattern, ZEND_ACC_PUBLIC) + ZEND_ME(IntlDatePatternGenerator, getSkeleton, arginfo_class_IntlDatePatternGenerator_getSkeleton, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(IntlDatePatternGenerator, getBaseSkeleton, arginfo_class_IntlDatePatternGenerator_getBaseSkeleton, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_FE_END }; diff --git a/ext/intl/dateformat/datepatterngenerator_methods.cpp b/ext/intl/dateformat/datepatterngenerator_methods.cpp index f22be1c21fc1..24943d4ec9b4 100644 --- a/ext/intl/dateformat/datepatterngenerator_methods.cpp +++ b/ext/intl/dateformat/datepatterngenerator_methods.cpp @@ -118,7 +118,8 @@ U_CFUNC PHP_METHOD( IntlDatePatternGenerator, getBestPattern ) INTL_METHOD_CHECK_STATUS(dtpgo, "Skeleton is not a valid UTF-8 string"); - UnicodeString skeleton = dtpgo->dtpg->getSkeleton(skeleton_uncleaned, DTPATTERNGEN_ERROR_CODE(dtpgo)); + UnicodeString skeleton = DateTimePatternGenerator::staticGetSkeleton( + skeleton_uncleaned, DTPATTERNGEN_ERROR_CODE(dtpgo)); INTL_METHOD_CHECK_STATUS(dtpgo, "Error getting cleaned skeleton"); @@ -132,3 +133,49 @@ U_CFUNC PHP_METHOD( IntlDatePatternGenerator, getBestPattern ) RETVAL_STR(u8str); } + +template +static void dtpg_get_skeleton(INTERNAL_FUNCTION_PARAMETERS, F&& skeletonfn, const char *errmsg) +{ + zend_string *pattern_str; + UnicodeString pattern; + UErrorCode status = U_ZERO_ERROR; + + intl_error_reset(NULL); + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(pattern_str) + ZEND_PARSE_PARAMETERS_END(); + + intl_stringFromChar(pattern, ZSTR_VAL(pattern_str), ZSTR_LEN(pattern_str), &status); + + INTL_CHECK_STATUS(status, "Pattern is not a valid UTF-8 string"); + + UnicodeString result = skeletonfn(pattern, status); + + INTL_CHECK_STATUS(status, errmsg); + + zend_string *u8str = intl_charFromString(result, &status); + + INTL_CHECK_STATUS(status, "Error converting result to UTF-8"); + + RETVAL_STR(u8str); +} + +U_CFUNC PHP_METHOD(IntlDatePatternGenerator, getSkeleton) +{ + dtpg_get_skeleton(INTERNAL_FUNCTION_PARAM_PASSTHRU, + [](const UnicodeString &pattern, UErrorCode &status) { + return DateTimePatternGenerator::staticGetSkeleton(pattern, status); + }, + "Error getting skeleton"); +} + +U_CFUNC PHP_METHOD(IntlDatePatternGenerator, getBaseSkeleton) +{ + dtpg_get_skeleton(INTERNAL_FUNCTION_PARAM_PASSTHRU, + [](const UnicodeString &pattern, UErrorCode &status) { + return DateTimePatternGenerator::staticGetBaseSkeleton(pattern, status); + }, + "Error getting base skeleton"); +} diff --git a/ext/intl/tests/datepatterngenerator_get_skeleton.phpt b/ext/intl/tests/datepatterngenerator_get_skeleton.phpt new file mode 100644 index 000000000000..de425fc1667a --- /dev/null +++ b/ext/intl/tests/datepatterngenerator_get_skeleton.phpt @@ -0,0 +1,48 @@ +--TEST-- +IntlDatePatternGenerator::getSkeleton() and getBaseSkeleton() +--EXTENSIONS-- +intl +--FILE-- + [%s] [%s]\n", + $pattern, + IntlDatePatternGenerator::getSkeleton($pattern), + IntlDatePatternGenerator::getBaseSkeleton($pattern), + ); +} + +?> +--EXPECT-- +string(5) "MMMdd" +string(5) "MMMdd" +string(4) "MMMd" +string(4) "MMMd" +string(0) "" +string(0) "" +'at' HH:mm => [HHmm] [Hm] +y年M月d日 => [yMd] [yMd] +yyyy-MM-dd => [yyyyMMdd] [yMd] +MMMMM => [MMMMM] [MMMMM] +MMM => [MMM] [MMM] +HH:mm:ss zzz dd/MM/y => [yMMddHHmmsszzz] [yMdHmsz] +'at HH:mm => [] [] diff --git a/ext/intl/tests/datepatterngenerator_skeleton_error.phpt b/ext/intl/tests/datepatterngenerator_skeleton_error.phpt new file mode 100644 index 000000000000..06a351ecd1bc --- /dev/null +++ b/ext/intl/tests/datepatterngenerator_skeleton_error.phpt @@ -0,0 +1,18 @@ +--TEST-- +IntlDatePatternGenerator::getSkeleton() and getBaseSkeleton(): errors +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +bool(false) +IntlDatePatternGenerator::getSkeleton(): Pattern is not a valid UTF-8 string: U_INVALID_CHAR_FOUND +bool(false) +IntlDatePatternGenerator::getBaseSkeleton(): Pattern is not a valid UTF-8 string: U_INVALID_CHAR_FOUND