Skip to content

Commit 8519a01

Browse files
Intl: Add IntlNumberRangeFormatter
1 parent fffe642 commit 8519a01

File tree

8 files changed

+389
-0
lines changed

8 files changed

+389
-0
lines changed

ext/intl/config.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ if test "$PHP_INTL" != "no"; then
7373
dateformat/datepatterngenerator_class.cpp \
7474
dateformat/datepatterngenerator_methods.cpp \
7575
msgformat/msgformat_helpers.cpp \
76+
rangeformatter/rangeformatter_class.cpp \
7677
timezone/timezone_class.cpp \
7778
timezone/timezone_methods.cpp \
7879
calendar/calendar_class.cpp \
@@ -123,6 +124,7 @@ if test "$PHP_INTL" != "no"; then
123124
$ext_builddir/listformatter
124125
$ext_builddir/msgformat
125126
$ext_builddir/normalizer
127+
$ext_builddir/rangeformatter
126128
$ext_builddir/resourcebundle
127129
$ext_builddir/spoofchecker
128130
$ext_builddir/timezone

ext/intl/config.w32

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ if (PHP_INTL != "no") {
6363
normalizer_class.c \
6464
normalizer_normalize.c \
6565
", "intl");
66+
ADD_SOURCES(configure_module_dirname + "/rangeformatter", "\
67+
rangeformatter_class.cpp \
68+
", "intl");
6669
ADD_SOURCES(configure_module_dirname + "/dateformat", "\
6770
dateformat.c \
6871
dateformat_class.c \

ext/intl/php_intl.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "locale/locale_class.h"
4343

4444
#include "listformatter/listformatter_class.h"
45+
#include "rangeformatter/rangeformatter_class.h"
4546

4647
#include "dateformat/dateformat.h"
4748
#include "dateformat/dateformat_class.h"
@@ -161,6 +162,9 @@ PHP_MINIT_FUNCTION( intl )
161162
/* Register 'ListFormatter' PHP class */
162163
listformatter_register_class( );
163164

165+
/* Register 'NumberRangeFormatter' PHP class */
166+
rangeformatter_register_class( );
167+
164168
/* Register 'Normalizer' PHP class */
165169
normalizer_register_Normalizer_class( );
166170

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/** @generate-class-entries */
4+
5+
/**
6+
* @not-serializable
7+
* @strict-properties
8+
*/
9+
final class IntlNumberRangeFormatter {
10+
11+
/** @cvalue UNUM_RANGE_COLLAPSE_AUTO */
12+
public const int COLLAPSE_AUTO = UNKNOWN;
13+
14+
/** @cvalue UNUM_RANGE_COLLAPSE_NONE */
15+
public const int COLLAPSE_NONE = UNKNOWN;
16+
17+
/** @cvalue UNUM_RANGE_COLLAPSE_UNIT */
18+
public const int COLLAPSE_UNIT = UNKNOWN;
19+
20+
/** @cvalue UNUM_RANGE_COLLAPSE_ALL */
21+
public const int COLLAPSE_ALL = UNKNOWN;
22+
23+
/** @cvalue UNUM_IDENTITY_FALLBACK_SINGLE_VALUE */
24+
public const int IDENTITY_FALLBACK_SINGLE_VALUE = UNKNOWN;
25+
26+
/** @cvalue UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE */
27+
public const int IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE = UNKNOWN;
28+
29+
/** @cvalue UNUM_IDENTITY_FALLBACK_APPROXIMATELY */
30+
public const int IDENTITY_FALLBACK_APPROXIMATELY = UNKNOWN;
31+
32+
/** @cvalue UNUM_IDENTITY_FALLBACK_RANGE */
33+
public const int IDENTITY_FALLBACK_RANGE = UNKNOWN;
34+
35+
private function __construct() {}
36+
37+
public static function createFromSkeleton(string $skeleton, string $locale, int $collapse, int $identityFallback): IntlNumberRangeFormatter {}
38+
39+
public function format(float|int $start, float|int $end): string {}
40+
}

ext/intl/rangeformatter/rangeformatter_arginfo.h

Lines changed: 86 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| This source file is subject to version 3.01 of the PHP license, |
4+
| that is bundled with this package in the file LICENSE, and is |
5+
| available through the world-wide-web at the following url: |
6+
| https://www.php.net/license/3_01.txt |
7+
| If you did not receive a copy of the PHP license and are unable to |
8+
| obtain it through the world-wide-web, please send a note to |
9+
| license@php.net so we can mail you a copy immediately. |
10+
+----------------------------------------------------------------------+
11+
| Authors: Bogdan Ungureanu <bogdanungureanu21@gmail.com> |
12+
+----------------------------------------------------------------------+
13+
*/
14+
15+
#include <unicode/numberrangeformatter.h>
16+
#include <unicode/unumberrangeformatter.h>
17+
#include <unicode/numberformatter.h>
18+
#include <unicode/unistr.h>
19+
#include "../intl_convertcpp.h"
20+
21+
extern "C" {
22+
#include "php.h"
23+
#include "../php_intl.h"
24+
#include "../intl_data.h"
25+
#include "rangeformatter_arginfo.h"
26+
#include "rangeformatter_class.h"
27+
#include "intl_convert.h"
28+
}
29+
30+
using icu::number::NumberRangeFormatter;
31+
using icu::number::NumberFormatter;
32+
using icu::number::UnlocalizedNumberFormatter;
33+
using icu::number::LocalizedNumberRangeFormatter;
34+
using icu::UnicodeString;
35+
using icu::MeasureUnit;
36+
37+
static zend_object_handlers rangeformatter_handlers;
38+
zend_class_entry *class_entry_IntlNumberRangeFormatter;
39+
40+
zend_object *IntlNumberRangeFormatter_object_create(zend_class_entry *ce)
41+
{
42+
IntlNumberRangeFormatter_object* intern;
43+
44+
intern = (IntlNumberRangeFormatter_object*)zend_object_alloc(sizeof(IntlNumberRangeFormatter_object), ce);
45+
zend_object_std_init(&intern->zo, ce);
46+
object_properties_init(&intern->zo, ce);
47+
48+
return &intern->zo;
49+
}
50+
51+
U_CFUNC PHP_METHOD(IntlNumberRangeFormatter, __construct)
52+
{
53+
54+
}
55+
56+
U_CFUNC PHP_METHOD(IntlNumberRangeFormatter, createFromSkeleton)
57+
{
58+
char* skeleton;
59+
char* locale;
60+
size_t locale_len;
61+
size_t skeleton_len;
62+
zend_long collapse;
63+
zend_long identityFallback;
64+
65+
ZEND_PARSE_PARAMETERS_START(4,4)
66+
Z_PARAM_STRING(skeleton, skeleton_len)
67+
Z_PARAM_STRING(locale, locale_len)
68+
Z_PARAM_LONG(collapse)
69+
Z_PARAM_LONG(identityFallback)
70+
ZEND_PARSE_PARAMETERS_END();
71+
72+
if (locale_len == 0) {
73+
locale = (char *)intl_locale_get_default();
74+
}
75+
76+
if (skeleton_len == 0) {
77+
zend_argument_value_error(1, "Skeleton string cannot be empty");
78+
RETURN_THROWS();
79+
}
80+
81+
if (locale_len > INTL_MAX_LOCALE_LEN) {
82+
zend_argument_value_error(2, "Locale string too long, should be no longer than %d characters", INTL_MAX_LOCALE_LEN);
83+
RETURN_THROWS();
84+
}
85+
86+
if (strlen(uloc_getISO3Language(locale)) == 0) {
87+
zend_argument_value_error(2, "\"%s\" is invalid", locale);
88+
RETURN_THROWS();
89+
}
90+
91+
if (collapse != UNUM_RANGE_COLLAPSE_AUTO && collapse != UNUM_RANGE_COLLAPSE_NONE && collapse != UNUM_RANGE_COLLAPSE_UNIT && collapse != UNUM_RANGE_COLLAPSE_ALL) {
92+
zend_argument_value_error(3, "Invalid collapse value");
93+
RETURN_THROWS();
94+
}
95+
96+
if (identityFallback != UNUM_IDENTITY_FALLBACK_SINGLE_VALUE && identityFallback != UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE && identityFallback != UNUM_IDENTITY_FALLBACK_APPROXIMATELY && identityFallback != UNUM_IDENTITY_FALLBACK_RANGE) {
97+
zend_argument_value_error(4, "Invalid identity fallback value");
98+
RETURN_THROWS();
99+
}
100+
101+
UErrorCode error = U_ZERO_ERROR;
102+
103+
UnicodeString skeleton_ustr(skeleton, skeleton_len);
104+
105+
UnlocalizedNumberFormatter nf = NumberFormatter::forSkeleton(skeleton_ustr, error);
106+
107+
LocalizedNumberRangeFormatter* nrf = new LocalizedNumberRangeFormatter(
108+
NumberRangeFormatter::with()
109+
.locale(locale)
110+
.numberFormatterBoth(nf)
111+
.collapse(static_cast<UNumberRangeCollapse>(collapse))
112+
.identityFallback(static_cast<UNumberRangeIdentityFallback>(identityFallback))
113+
);
114+
115+
zend_object* obj = IntlNumberRangeFormatter_object_create(class_entry_IntlNumberRangeFormatter);
116+
obj->handlers = &rangeformatter_handlers;
117+
118+
RANGEFORMATTER_OBJECT(php_intl_numberrangeformatter_fetch_object(obj)) = nrf;
119+
120+
RETURN_OBJ(obj);
121+
122+
}
123+
124+
U_CFUNC PHP_METHOD(IntlNumberRangeFormatter, format)
125+
{
126+
double start;
127+
double end;
128+
129+
IntlNumberRangeFormatter_object* obj = Z_INTL_RANGEFORMATTER_P(ZEND_THIS);
130+
131+
ZEND_PARSE_PARAMETERS_START(2, 2)
132+
Z_PARAM_DOUBLE(start)
133+
Z_PARAM_DOUBLE(end)
134+
ZEND_PARSE_PARAMETERS_END();
135+
136+
UErrorCode error = U_ZERO_ERROR;
137+
138+
UnicodeString result = RANGEFORMATTER_OBJECT(obj)->formatFormattableRange(start, end, error).toString(error);
139+
140+
if (U_FAILURE(error)) {
141+
intl_error_set(NULL, error, "Failed to format number range", 0);
142+
143+
return;
144+
}
145+
146+
zend_string *ret = intl_charFromString(result, &error);
147+
148+
if (!ret) {
149+
intl_error_set(NULL, error, "Failed to convert result to UTF-8", 0);
150+
// RETVAL_FALSE;
151+
return;
152+
}
153+
154+
RETVAL_NEW_STR(ret);
155+
}
156+
157+
void IntlNumberRangeFormatter_object_free(zend_object *object)
158+
{
159+
IntlNumberRangeFormatter_object* nfo = php_intl_numberrangeformatter_fetch_object(object);
160+
161+
if (nfo->nrf_data.unumrf) {
162+
delete nfo->nrf_data.unumrf;
163+
nfo->nrf_data.unumrf = nullptr;
164+
}
165+
166+
intl_error_reset(&nfo->nrf_data.error);
167+
168+
zend_object_std_dtor(&nfo->zo);
169+
}
170+
171+
void rangeformatter_register_class(void)
172+
{
173+
class_entry_IntlNumberRangeFormatter = register_class_IntlNumberRangeFormatter();
174+
class_entry_IntlNumberRangeFormatter->create_object = IntlNumberRangeFormatter_object_create;
175+
176+
memcpy(&rangeformatter_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
177+
rangeformatter_handlers.offset = XtOffsetOf(IntlNumberRangeFormatter_object, zo);
178+
rangeformatter_handlers.free_obj = IntlNumberRangeFormatter_object_free;
179+
rangeformatter_handlers.clone_obj = NULL;
180+
}

0 commit comments

Comments
 (0)