Global Boomarks
This commit is contained in:
@@ -12,8 +12,6 @@ use MintyPHP\Repository\User\UserListQueryRepository;
|
||||
use MintyPHP\Repository\User\UserListQueryRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserReadRepository;
|
||||
use MintyPHP\Repository\User\UserReadRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserSavedFilterRepository;
|
||||
use MintyPHP\Repository\User\UserSavedFilterRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserWriteRepository;
|
||||
use MintyPHP\Repository\User\UserWriteRepositoryInterface;
|
||||
|
||||
@@ -22,7 +20,6 @@ class UserRepositoryFactory
|
||||
private ?UserReadRepository $userReadRepository = null;
|
||||
private ?UserWriteRepository $userWriteRepository = null;
|
||||
private ?UserListQueryRepository $userListQueryRepository = null;
|
||||
private ?UserSavedFilterRepository $userSavedFilterRepository = null;
|
||||
private ?UserTenantRepository $userTenantRepository = null;
|
||||
private ?UserRoleRepository $userRoleRepository = null;
|
||||
private ?UserDepartmentRepository $userDepartmentRepository = null;
|
||||
@@ -42,11 +39,6 @@ class UserRepositoryFactory
|
||||
return $this->userListQueryRepository ??= new UserListQueryRepository();
|
||||
}
|
||||
|
||||
public function createUserSavedFilterRepository(): UserSavedFilterRepositoryInterface
|
||||
{
|
||||
return $this->userSavedFilterRepository ??= new UserSavedFilterRepository();
|
||||
}
|
||||
|
||||
public function createUserTenantRepository(): UserTenantRepositoryInterface
|
||||
{
|
||||
return $this->userTenantRepository ??= new UserTenantRepository();
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Service\User;
|
||||
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
use MintyPHP\Repository\User\UserSavedFilterRepositoryInterface;
|
||||
|
||||
class UserSavedFilterService
|
||||
{
|
||||
public const CONTEXT_ADDRESS_BOOK = 'address_book';
|
||||
private const NAME_MAX_LENGTH = 120;
|
||||
private const SEARCH_MAX_LENGTH = 200;
|
||||
private const MAX_PER_USER_CONTEXT = 20;
|
||||
|
||||
public function __construct(private readonly UserSavedFilterRepositoryInterface $userSavedFilterRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function listForAddressBook(int $userId): array
|
||||
{
|
||||
return $this->listByContext($userId, self::CONTEXT_ADDRESS_BOOK);
|
||||
}
|
||||
|
||||
public function saveAddressBookFilter(int $userId, string $name, array $rawQuery): array
|
||||
{
|
||||
return $this->saveByContext($userId, self::CONTEXT_ADDRESS_BOOK, $name, $rawQuery);
|
||||
}
|
||||
|
||||
public function deleteAddressBookFilter(int $userId, string $uuid): bool
|
||||
{
|
||||
return $this->deleteByContext($userId, self::CONTEXT_ADDRESS_BOOK, $uuid);
|
||||
}
|
||||
|
||||
public function listByContext(int $userId, string $context): array
|
||||
{
|
||||
if ($userId <= 0 || $context === '') {
|
||||
return [];
|
||||
}
|
||||
$rows = $this->userSavedFilterRepository->listByUserAndContext($userId, $context);
|
||||
$list = [];
|
||||
foreach ($rows as $row) {
|
||||
$name = trim((string) ($row['name'] ?? ''));
|
||||
$uuid = trim((string) ($row['uuid'] ?? ''));
|
||||
if ($name === '' || $uuid === '') {
|
||||
continue;
|
||||
}
|
||||
$query = $this->normalizeQuery($this->decodeQuery((string) ($row['query_json'] ?? '')));
|
||||
$list[] = [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'uuid' => $uuid,
|
||||
'name' => $name,
|
||||
'query' => $query,
|
||||
'created' => (string) ($row['created'] ?? ''),
|
||||
];
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function saveByContext(int $userId, string $context, string $name, array $rawQuery): array
|
||||
{
|
||||
$name = $this->truncate(trim($name), self::NAME_MAX_LENGTH);
|
||||
if ($userId <= 0 || $context === '') {
|
||||
return ['ok' => false, 'error' => 'invalid_user_or_context'];
|
||||
}
|
||||
if ($name === '') {
|
||||
return ['ok' => false, 'error' => 'name_required'];
|
||||
}
|
||||
$count = $this->userSavedFilterRepository->countByUserAndContext($userId, $context);
|
||||
if ($count >= self::MAX_PER_USER_CONTEXT) {
|
||||
return ['ok' => false, 'error' => 'max_reached'];
|
||||
}
|
||||
$query = $this->normalizeQuery($rawQuery);
|
||||
$queryJson = json_encode($query, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($queryJson)) {
|
||||
$queryJson = '{}';
|
||||
}
|
||||
$id = $this->userSavedFilterRepository->create([
|
||||
'user_id' => $userId,
|
||||
'context' => $context,
|
||||
'name' => $name,
|
||||
'query_json' => $queryJson,
|
||||
]);
|
||||
if (!$id) {
|
||||
return ['ok' => false, 'error' => 'create_failed'];
|
||||
}
|
||||
return ['ok' => true, 'id' => (int) $id, 'name' => $name, 'query' => $query];
|
||||
}
|
||||
|
||||
public function deleteByContext(int $userId, string $context, string $uuid): bool
|
||||
{
|
||||
if ($userId <= 0 || $context === '' || trim($uuid) === '') {
|
||||
return false;
|
||||
}
|
||||
return $this->userSavedFilterRepository->deleteByUuidForUserAndContext($uuid, $userId, $context);
|
||||
}
|
||||
|
||||
private function decodeQuery(string $json): array
|
||||
{
|
||||
$decoded = json_decode($json, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
private function normalizeQuery(array $rawQuery): array
|
||||
{
|
||||
$search = $this->truncate(trim((string) ($rawQuery['search'] ?? '')), self::SEARCH_MAX_LENGTH);
|
||||
$tenants = $this->normalizeUuidList($rawQuery['tenants'] ?? []);
|
||||
$departments = RepoQuery::normalizeIdList($rawQuery['departments'] ?? []);
|
||||
$roles = RepoQuery::normalizeIdList($rawQuery['roles'] ?? []);
|
||||
$custom = $this->normalizeCustomFieldQuery($rawQuery);
|
||||
|
||||
$query = [];
|
||||
if ($search !== '') {
|
||||
$query['search'] = $search;
|
||||
}
|
||||
if ($tenants) {
|
||||
$query['tenants'] = $tenants;
|
||||
}
|
||||
if ($departments) {
|
||||
$query['departments'] = $departments;
|
||||
}
|
||||
if ($roles) {
|
||||
$query['roles'] = $roles;
|
||||
}
|
||||
foreach ($custom as $key => $value) {
|
||||
$query[$key] = $value;
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
private function normalizeCustomFieldQuery(array $rawQuery): array
|
||||
{
|
||||
$normalized = [];
|
||||
foreach ($rawQuery as $rawKey => $rawValue) {
|
||||
$key = strtolower(trim((string) $rawKey));
|
||||
if ($key === '') {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^cf_[a-f0-9-]{36}$/', $key)) {
|
||||
$value = trim((string) $rawValue);
|
||||
if ($value !== '' && preg_match('/^[a-z0-9_-]{1,64}$/i', $value)) {
|
||||
$normalized[$key] = $value;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^cfm_[a-f0-9-]{36}$/', $key)) {
|
||||
$ids = RepoQuery::normalizeIdList($rawValue);
|
||||
if ($ids) {
|
||||
$normalized[$key] = $ids;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^cfd_[a-f0-9-]{36}_(from|to)$/', $key)) {
|
||||
$value = trim((string) $rawValue);
|
||||
$dt = \DateTimeImmutable::createFromFormat('Y-m-d', $value);
|
||||
if ($dt && $dt->format('Y-m-d') === $value) {
|
||||
$normalized[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
ksort($normalized, SORT_STRING);
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
private function normalizeUuidList($value): array
|
||||
{
|
||||
$items = $this->normalizeStringList($value);
|
||||
$list = [];
|
||||
foreach ($items as $item) {
|
||||
$item = strtolower($item);
|
||||
if (preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/', $item)) {
|
||||
$list[] = $item;
|
||||
}
|
||||
}
|
||||
$list = array_values(array_unique($list));
|
||||
sort($list, SORT_STRING);
|
||||
return $list;
|
||||
}
|
||||
|
||||
private function normalizeStringList($value): array
|
||||
{
|
||||
$raw = is_array($value) ? $value : [$value];
|
||||
$flat = [];
|
||||
$collect = static function ($item) use (&$collect, &$flat): void {
|
||||
if (is_array($item)) {
|
||||
foreach ($item as $nested) {
|
||||
$collect($nested);
|
||||
}
|
||||
return;
|
||||
}
|
||||
$text = trim((string) $item);
|
||||
if ($text === '') {
|
||||
return;
|
||||
}
|
||||
if (str_contains($text, ',')) {
|
||||
foreach (explode(',', $text) as $part) {
|
||||
$part = trim($part);
|
||||
if ($part !== '') {
|
||||
$flat[] = $part;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
$flat[] = $text;
|
||||
};
|
||||
foreach ($raw as $item) {
|
||||
$collect($item);
|
||||
}
|
||||
return array_values(array_unique($flat));
|
||||
}
|
||||
|
||||
private function truncate(string $value, int $maxLength): string
|
||||
{
|
||||
if ($maxLength <= 0 || $value === '') {
|
||||
return $value;
|
||||
}
|
||||
if (function_exists('mb_strlen') && function_exists('mb_substr')) {
|
||||
if (mb_strlen($value) > $maxLength) {
|
||||
return mb_substr($value, 0, $maxLength);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
if (strlen($value) > $maxLength) {
|
||||
return substr($value, 0, $maxLength);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ use MintyPHP\Repository\Support\DatabaseSessionRepository;
|
||||
use MintyPHP\Repository\Tenant\UserTenantRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserListQueryRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserReadRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserSavedFilterRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserWriteRepositoryInterface;
|
||||
use MintyPHP\Service\Access\AssignableRoleService;
|
||||
use MintyPHP\Service\Audit\AuditServicesFactory;
|
||||
@@ -19,7 +18,6 @@ class UserServicesFactory
|
||||
private ?UserPasswordPolicyService $userPasswordPolicyService = null;
|
||||
private ?UserPasswordService $userPasswordService = null;
|
||||
private ?UserAvatarService $userAvatarService = null;
|
||||
private ?UserSavedFilterService $userSavedFilterService = null;
|
||||
private ?UserAssignmentService $userAssignmentService = null;
|
||||
private ?UserTenantContextService $userTenantContextService = null;
|
||||
private ?UserAccountService $userAccountService = null;
|
||||
@@ -93,13 +91,6 @@ class UserServicesFactory
|
||||
return $this->userAvatarService ??= new UserAvatarService();
|
||||
}
|
||||
|
||||
public function createUserSavedFilterService(): UserSavedFilterService
|
||||
{
|
||||
return $this->userSavedFilterService ??= new UserSavedFilterService(
|
||||
$this->createUserSavedFilterRepository()
|
||||
);
|
||||
}
|
||||
|
||||
public function createUserReadRepository(): UserReadRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createUserReadRepository();
|
||||
@@ -115,11 +106,6 @@ class UserServicesFactory
|
||||
return $this->userRepositoryFactory->createUserListQueryRepository();
|
||||
}
|
||||
|
||||
public function createUserSavedFilterRepository(): UserSavedFilterRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createUserSavedFilterRepository();
|
||||
}
|
||||
|
||||
public function createUserTenantRepository(): UserTenantRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createUserTenantRepository();
|
||||
|
||||
Reference in New Issue
Block a user