add scope
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并多个 bitmap(OR 运算)
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user