add scope

This commit is contained in:
2026-03-09 14:15:29 +08:00
parent d4bb96fbcb
commit c2af36760b
2 changed files with 275 additions and 0 deletions
+176
View File
@@ -0,0 +1,176 @@
<?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);
}
}