|
|
<?php
|
|
|
|
|
|
namespace App\Support;
|
|
|
|
|
|
final class SignupOptionCatalog
|
|
|
{
|
|
|
/**
|
|
|
* @return array<string, array{zh-CN: string, en: string}>
|
|
|
*/
|
|
|
public static function degrees(): array
|
|
|
{
|
|
|
return [
|
|
|
'associate' => ['zh-CN' => '大专', 'en' => 'Associate Degree'],
|
|
|
'bachelor' => ['zh-CN' => '本科', 'en' => "Bachelor’s Degree"],
|
|
|
'master' => ['zh-CN' => '硕士', 'en' => "Master’s Degree"],
|
|
|
'doctorate' => ['zh-CN' => '博士', 'en' => 'Doctorate'],
|
|
|
'other' => ['zh-CN' => '其他', 'en' => 'Other'],
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @return array<string, array{zh-CN: string, en: string}>
|
|
|
*/
|
|
|
public static function locationCountries(): array
|
|
|
{
|
|
|
return [
|
|
|
'cn' => ['zh-CN' => '中国', 'en' => 'China'],
|
|
|
'overseas' => ['zh-CN' => '海外', 'en' => 'Outside China'],
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @return array<string, array{zh-CN: string, en: string}>
|
|
|
*/
|
|
|
public static function eventLocations(): array
|
|
|
{
|
|
|
return [
|
|
|
'shanghai' => ['zh-CN' => '上海', 'en' => 'Shanghai'],
|
|
|
'suzhou' => ['zh-CN' => '苏州', 'en' => 'Suzhou'],
|
|
|
'shenzhen' => ['zh-CN' => '深圳', 'en' => 'Shenzhen'],
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @return array<string, array{zh-CN: string, en: string}>
|
|
|
*/
|
|
|
public static function audiencePurposes(): array
|
|
|
{
|
|
|
return [
|
|
|
'networking' => ['zh-CN' => '项目交流', 'en' => 'Project Networking'],
|
|
|
'collaboration' => ['zh-CN' => '产业合作', 'en' => 'Industry Collaboration'],
|
|
|
'investment' => ['zh-CN' => '投资对接', 'en' => 'Investor Meetings'],
|
|
|
'study' => ['zh-CN' => '学习参访', 'en' => 'Study Visit'],
|
|
|
'media' => ['zh-CN' => '媒体报道', 'en' => 'Media Coverage'],
|
|
|
'other' => ['zh-CN' => '其他', 'en' => 'Other'],
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @return array<string, string>
|
|
|
*/
|
|
|
public static function legacyMap(string $kind): array
|
|
|
{
|
|
|
return match ($kind) {
|
|
|
'degree' => [
|
|
|
'大专' => 'associate',
|
|
|
'本科' => 'bachelor',
|
|
|
'硕士' => 'master',
|
|
|
'博士' => 'doctorate',
|
|
|
'其他' => 'other',
|
|
|
],
|
|
|
'location_country' => [
|
|
|
'中国' => 'cn',
|
|
|
'海外' => 'overseas',
|
|
|
],
|
|
|
'event_location' => [
|
|
|
'上海' => 'shanghai',
|
|
|
'苏州' => 'suzhou',
|
|
|
'深圳' => 'shenzhen',
|
|
|
'上海赛区' => 'shanghai',
|
|
|
'苏州赛区' => 'suzhou',
|
|
|
'深圳赛区' => 'shenzhen',
|
|
|
'Shanghai' => 'shanghai',
|
|
|
'Suzhou' => 'suzhou',
|
|
|
'Shenzhen' => 'shenzhen',
|
|
|
],
|
|
|
'purpose', 'audience_purpose' => [
|
|
|
'项目交流' => 'networking',
|
|
|
'产业合作' => 'collaboration',
|
|
|
'投资对接' => 'investment',
|
|
|
'学习参访' => 'study',
|
|
|
'媒体报道' => 'media',
|
|
|
'其他' => 'other',
|
|
|
],
|
|
|
default => [],
|
|
|
};
|
|
|
}
|
|
|
|
|
|
public static function normalize(string $kind, ?string $raw): ?string
|
|
|
{
|
|
|
if ($raw === null) {
|
|
|
return null;
|
|
|
}
|
|
|
$value = trim($raw);
|
|
|
if ($value === '') {
|
|
|
return '';
|
|
|
}
|
|
|
$map = self::legacyMap($kind);
|
|
|
if (isset($map[$value])) {
|
|
|
return $map[$value];
|
|
|
}
|
|
|
$lower = mb_strtolower($value);
|
|
|
foreach ($map as $alias => $code) {
|
|
|
if (mb_strtolower((string) $alias) === $lower) {
|
|
|
return $code;
|
|
|
}
|
|
|
}
|
|
|
$catalog = self::catalogForKind($kind);
|
|
|
if ($catalog !== null) {
|
|
|
foreach ($catalog as $code => $labels) {
|
|
|
if (mb_strtolower($code) === $lower) {
|
|
|
return $code;
|
|
|
}
|
|
|
if (mb_strtolower((string) ($labels['en'] ?? '')) === $lower) {
|
|
|
return $code;
|
|
|
}
|
|
|
if ((string) ($labels['zh-CN'] ?? '') === $value) {
|
|
|
return $code;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return $value;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 同一选项的全部等价写法(编码 / 中文 / 英文),用于评审筛查等精确匹配。
|
|
|
*
|
|
|
* @return list<string>
|
|
|
*/
|
|
|
public static function aliases(string $kind, string $raw): array
|
|
|
{
|
|
|
$value = trim($raw);
|
|
|
$normalized = self::normalize($kind, $value);
|
|
|
if ($normalized === null || $normalized === '') {
|
|
|
return $value !== '' ? [$value] : [];
|
|
|
}
|
|
|
$out = [$normalized];
|
|
|
if ($value !== '') {
|
|
|
$out[] = $value;
|
|
|
}
|
|
|
$catalog = self::catalogForKind($kind) ?? [];
|
|
|
if (isset($catalog[$normalized])) {
|
|
|
$zh = trim((string) ($catalog[$normalized]['zh-CN'] ?? ''));
|
|
|
$en = trim((string) ($catalog[$normalized]['en'] ?? ''));
|
|
|
if ($zh !== '') {
|
|
|
$out[] = $zh;
|
|
|
if ($kind === 'event_location' && ! str_contains($zh, '赛区')) {
|
|
|
$out[] = $zh.'赛区';
|
|
|
}
|
|
|
}
|
|
|
if ($en !== '') {
|
|
|
$out[] = $en;
|
|
|
}
|
|
|
}
|
|
|
foreach (self::legacyMap($kind) as $alias => $code) {
|
|
|
if ($code === $normalized) {
|
|
|
$out[] = (string) $alias;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return array_values(array_unique(array_filter(
|
|
|
array_map(static fn ($v) => trim((string) $v), $out),
|
|
|
static fn ($v) => $v !== '',
|
|
|
)));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @param iterable<int|string, mixed> $values
|
|
|
* @return list<string>
|
|
|
*/
|
|
|
public static function expandAliases(string $kind, iterable $values): array
|
|
|
{
|
|
|
$out = [];
|
|
|
foreach ($values as $value) {
|
|
|
foreach (self::aliases($kind, trim((string) $value)) as $alias) {
|
|
|
$out[$alias] = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return array_keys($out);
|
|
|
}
|
|
|
|
|
|
public static function same(string $kind, ?string $left, ?string $right): bool
|
|
|
{
|
|
|
$a = self::normalize($kind, $left);
|
|
|
$b = self::normalize($kind, $right);
|
|
|
if ($a === null || $a === '' || $b === null || $b === '') {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return $a === $b;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @return array<string, array{zh-CN: string, en: string}>|null
|
|
|
*/
|
|
|
private static function catalogForKind(string $kind): ?array
|
|
|
{
|
|
|
return match ($kind) {
|
|
|
'degree' => self::degrees(),
|
|
|
'location_country' => self::locationCountries(),
|
|
|
'event_location' => self::eventLocations(),
|
|
|
'purpose', 'audience_purpose' => self::audiencePurposes(),
|
|
|
default => null,
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @param array<string, array{zh-CN: string, en: string}> $catalog
|
|
|
* @return list<string>
|
|
|
*/
|
|
|
public static function codes(array $catalog): array
|
|
|
{
|
|
|
return array_keys($catalog);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @param array<string, array{zh-CN: string, en: string}> $catalog
|
|
|
* @return list<string>
|
|
|
*/
|
|
|
public static function acceptedValues(array $catalog, string $kind): array
|
|
|
{
|
|
|
return array_values(array_unique([
|
|
|
...self::codes($catalog),
|
|
|
...array_keys(self::legacyMap($kind)),
|
|
|
]));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @param array<string, array{zh-CN: string, en: string}> $catalog
|
|
|
*/
|
|
|
public static function label(array $catalog, string $code, string $locale = PortalLocale::ZH): string
|
|
|
{
|
|
|
$normalized = self::normalize(
|
|
|
$catalog === self::degrees() ? 'degree'
|
|
|
: ($catalog === self::locationCountries() ? 'location_country'
|
|
|
: ($catalog === self::eventLocations() ? 'event_location' : 'purpose')),
|
|
|
$code
|
|
|
) ?? $code;
|
|
|
$row = $catalog[$normalized] ?? null;
|
|
|
if ($row === null) {
|
|
|
return $code;
|
|
|
}
|
|
|
|
|
|
return $locale === PortalLocale::EN
|
|
|
? ($row['en'] ?? $row['zh-CN'])
|
|
|
: ($row['zh-CN'] ?? $row['en'] ?? $code);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @param array<string, array{zh-CN: string, en: string}> $catalog
|
|
|
* @return list<array{value: string, label: string, label_i18n: array{en: string}}>
|
|
|
*/
|
|
|
public static function schemaOptions(array $catalog): array
|
|
|
{
|
|
|
$out = [];
|
|
|
foreach ($catalog as $code => $labels) {
|
|
|
$out[] = [
|
|
|
'value' => $code,
|
|
|
'label' => $labels['zh-CN'],
|
|
|
'label_i18n' => ['en' => $labels['en']],
|
|
|
];
|
|
|
}
|
|
|
|
|
|
return $out;
|
|
|
}
|
|
|
}
|