setAccessible(true); $scanUpdateFields = (new ReflectionClass(MediaChannelService::class)) ->getReflectionConstant('SCAN_DUPLICATE_UPDATE_FIELDS') ?->getValue(); if (!is_array($scanUpdateFields) || array_intersect(['channel_name', 'source_tag_name', 'status'], $scanUpdateFields) !== []) { throw new RuntimeException('Channel scan would overwrite rename aliases, manual labels, or disabled status'); } $configuredRows = [ [ 'id' => 1, 'channel_code' => 'stable-a', 'channel_name' => 'Old tag name', 'source_tag_id' => 'tag-a', 'source_tag_name' => 'Old tag name', 'source_group_name' => 'Old group', 'status' => 1, ], [ 'id' => 2, 'channel_code' => 'manual-name', 'channel_name' => 'Manual campaign label', 'source_tag_id' => 'tag-manual', 'source_tag_name' => 'Old manual tag', 'source_group_name' => 'Old group', 'status' => 1, ], [ 'id' => 3, 'channel_code' => 'disabled-tag', 'channel_name' => 'Disabled tag', 'source_tag_id' => 'tag-disabled', 'source_tag_name' => 'Disabled tag', 'source_group_name' => 'Group', 'status' => 0, ], [ 'id' => 4, 'channel_code' => 'legacy-name-only', 'channel_name' => 'Legacy name-only channel', 'source_tag_id' => '', 'source_tag_name' => 'Legacy name-only channel', 'source_group_name' => 'Legacy', 'status' => 1, ], ]; $tagRows = [ [ 'source_tag_id' => 'tag-a', 'source_tag_name' => 'Renamed tag', 'source_group_name' => 'New group', ], [ 'source_tag_id' => 'tag-manual', 'source_tag_name' => 'Renamed manual tag', 'source_group_name' => 'New group', ], [ 'source_tag_id' => 'tag-disabled', 'source_tag_name' => 'Disabled tag returned by relation table', 'source_group_name' => 'Group', ], [ 'source_tag_id' => 'tag-new', 'source_tag_name' => 'Newly discovered tag', 'source_group_name' => 'New group', ], ]; /** @var array> $mergedRows */ $mergedRows = $mergeMethod->invoke(null, $configuredRows, $tagRows); $byCode = []; foreach ($mergedRows as $row) { $byCode[(string) ($row['channel_code'] ?? '')] = $row; } $renamed = $byCode['stable-a'] ?? null; if (!is_array($renamed) || ($renamed['channel_name'] ?? '') !== 'Renamed tag' || ($renamed['source_tag_name'] ?? '') !== 'Renamed tag' || ($renamed['source_group_name'] ?? '') !== 'New group' || ($renamed['legacy_channel_name'] ?? '') !== 'Old tag name' || ($renamed['legacy_source_tag_name'] ?? '') !== 'Old tag name') { throw new RuntimeException('Automatic channel name was not refreshed with backward-compatible aliases'); } $manual = $byCode['manual-name'] ?? null; if (!is_array($manual) || ($manual['channel_name'] ?? '') !== 'Manual campaign label' || ($manual['source_tag_name'] ?? '') !== 'Renamed manual tag' || ($manual['legacy_source_tag_name'] ?? '') !== 'Old manual tag') { throw new RuntimeException('Manual display name or refreshed tag metadata was not preserved'); } if (isset($byCode['disabled-tag']) || isset($byCode['tag_tag-disabled'])) { throw new RuntimeException('Explicitly disabled tag was reintroduced'); } $newTag = $byCode['tag_tag-new'] ?? null; if (!is_array($newTag) || ($newTag['channel_name'] ?? '') !== 'Newly discovered tag' || ($newTag['source_tag_id'] ?? '') !== 'tag-new') { throw new RuntimeException('New relation-table tag was not added with a deterministic channel code'); } if (!isset($byCode['legacy-name-only'])) { throw new RuntimeException('Historical name-only channel was removed'); } if (in_array('--integration', $argv, true)) { $app = new think\App(); $app->initialize(); $loadTagsMethod = new ReflectionMethod(MediaChannelService::class, 'loadCurrentTagRows'); $loadTagsMethod->setAccessible(true); $activeRowsMethod = new ReflectionMethod(MediaChannelService::class, 'getActiveChannelRows'); $activeRowsMethod->setAccessible(true); $startedAt = microtime(true); /** @var array> $currentTags */ $currentTags = $loadTagsMethod->invoke(null, null); /** @var array> $activeRows */ $activeRows = $activeRowsMethod->invoke(null); $options = MediaChannelService::getOptions(); $elapsedMs = round((microtime(true) - $startedAt) * 1000, 1); $activeByTagId = []; foreach ($activeRows as $row) { $tagId = trim((string) ($row['source_tag_id'] ?? '')); if ($tagId !== '') { $activeByTagId[$tagId] = $row; } } $disabledTagIds = array_fill_keys(array_map( 'strval', Db::name('qywx_media_channel') ->where('status', 0) ->where('source_tag_id', '<>', '') ->column('source_tag_id') ), true); foreach ($currentTags as $tag) { $tagId = (string) ($tag['source_tag_id'] ?? ''); if ($tagId === '' || isset($disabledTagIds[$tagId])) { continue; } $channel = $activeByTagId[$tagId] ?? null; if (!is_array($channel)) { throw new RuntimeException("Current relation-table tag {$tagId} is absent from channel options"); } $currentName = (string) ($tag['source_tag_name'] ?? ''); if ($currentName !== '' && ($channel['source_tag_name'] ?? '') !== $currentName) { throw new RuntimeException("Current tag name for {$tagId} was not refreshed"); } } if (count($options) !== count($activeRows)) { throw new RuntimeException('Public option count differs from merged active channel count'); } $matchingNames = array_values(array_map( static fn (array $option): string => (string) ($option['name'] ?? ''), array_filter( $options, static fn (array $option): bool => mb_strpos((string) ($option['name'] ?? ''), '4') !== false ) )); echo json_encode([ 'current_tag_count' => count($currentTags), 'channel_option_count' => count($options), 'elapsed_ms' => $elapsedMs, 'matching_4' => $matchingNames, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n"; } echo "MEDIA_CHANNEL_OPTIONS_MERGE_OK\n";