Files
datahub/backend/app/Service/ScopeBitmapService.php
T
2026-03-09 14:15:29 +08:00

177 lines
4.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Service;
use App\Model\Platform;
use App\Model\Store;
use App\Model\UserDataScope;
class ScopeBitmapService
{
/**
* 将 store_id 数组编码为 bitmap 二进制串
* store_id=N → bit N-1 置 1
*
* @param int[] $store_ids
* @return string
*/
public function encode(array $store_ids): string
{
if (empty($store_ids)) {
return '';
}
$max_id = max($store_ids);
$byte_length = intdiv($max_id - 1, 8) + 1;
$bitmap = str_repeat("\0", $byte_length);
foreach ($store_ids as $store_id) {
$bit_pos = $store_id - 1;
$byte_index = intdiv($bit_pos, 8);
$bit_offset = $bit_pos % 8;
$bitmap[$byte_index] = chr(ord($bitmap[$byte_index]) | (1 << $bit_offset));
}
return $bitmap;
}
/**
* 将 bitmap 解码为 store_id 数组
*
* @param string $bitmap
* @return int[]
*/
public function decode(string $bitmap): array
{
$store_ids = [];
$length = strlen($bitmap);
for ($i = 0; $i < $length; $i++) {
$byte = ord($bitmap[$i]);
if ($byte === 0) {
continue;
}
for ($bit = 0; $bit < 8; $bit++) {
if (($byte >> $bit) & 1) {
$store_ids[] = $i * 8 + $bit + 1;
}
}
}
return $store_ids;
}
/**
* 检查 bitmap 中是否包含指定 store_id
*
* @param string $bitmap
* @param int $store_id
* @return bool
*/
public function has(string $bitmap, int $store_id): bool
{
$bit_pos = $store_id - 1;
$byte_index = intdiv($bit_pos, 8);
if ($byte_index >= strlen($bitmap)) {
return false;
}
$bit_offset = $bit_pos % 8;
return (bool) ((ord($bitmap[$byte_index]) >> $bit_offset) & 1);
}
/**
* 合并多个 bitmapOR 运算)
*
* @param string ...$bitmaps
* @return string
*/
public function merge(string ...$bitmaps): string
{
$bitmaps = array_filter($bitmaps, fn(string $b): bool => $b !== '');
if (empty($bitmaps)) {
return '';
}
$max_len = max(array_map('strlen', $bitmaps));
$result = str_repeat("\0", $max_len);
foreach ($bitmaps as $bitmap) {
for ($i = 0; $i < strlen($bitmap); $i++) {
$result[$i] = chr(ord($result[$i]) | ord($bitmap[$i]));
}
}
return $result;
}
/**
* 根据用户的 user_data_scopes 记录构建 scope bitmap
* 处理 company/platform/store 三种 scope_type 的解析和合并
*
* @param int $user_id
* @return string
*/
public function buildForUser(int $user_id): string
{
$scopes = UserDataScope::query()->where('user_id', $user_id)->get();
if ($scopes->isEmpty()) {
return '';
}
$store_ids = [];
$grouped = $scopes->groupBy('scope_type');
// company 类型:查该 company 下所有 store
if ($company_scopes = $grouped->get('company')) {
$company_ids = $company_scopes->pluck('scope_id')->toArray();
$store_ids = array_merge(
$store_ids,
Store::query()->whereIn('company_id', $company_ids)->pluck('id')->toArray()
);
}
// platform 类型:查该 platform 下所有 store
if ($platform_scopes = $grouped->get('platform')) {
$platform_ids = $platform_scopes->pluck('scope_id')->toArray();
$store_ids = array_merge(
$store_ids,
Store::query()->whereIn('platform_id', $platform_ids)->pluck('id')->toArray()
);
}
// store 类型:直接使用
if ($store_scopes = $grouped->get('store')) {
$store_ids = array_merge($store_ids, $store_scopes->pluck('scope_id')->toArray());
}
$store_ids = array_unique(array_map('intval', $store_ids));
return $this->encode($store_ids);
}
/**
* 根据 developer 维护的 platform 构建 scope bitmap
*
* @param int $user_id
* @return string
*/
public function buildForDeveloper(int $user_id): string
{
$platform_ids = Platform::query()->where('developer_id', $user_id)->pluck('id')->toArray();
if (empty($platform_ids)) {
return '';
}
$store_ids = Store::query()->whereIn('platform_id', $platform_ids)->pluck('id')->toArray();
$store_ids = array_map('intval', $store_ids);
return $this->encode($store_ids);
}
}