trafficmonitor init...2

This commit is contained in:
최준흠 2025-11-06 21:23:06 +09:00
parent c79db51fac
commit 13d63450c3
8 changed files with 91 additions and 35 deletions

View File

@ -395,5 +395,5 @@ define("ROLE", [
'DIRECTOR' => "director",
'MASTER' => "master",
],
['CLIENT'] => []
'CLIENT' => [],
]);

View File

@ -76,4 +76,13 @@ abstract class AuthController extends CommonController
return redirect()->back()->withInput()->with('error', "로그아웃 중 오류가 발생했습니다.");
}
}
protected function create_form_process(): void {}
protected function create_process(): RedirectResponse
{
return redirect()->to('/');
}
protected function modify_form_process($uid): mixed
{
return new UserEntity();
}
}

View File

@ -3,13 +3,16 @@
namespace App\DTOs;
use App\Services\Auth\AuthService;
use CodeIgniter\Entity\Entity; // DTO가 Entity를 상속받지 않는 경우, 필요한 경우 CommonDTO 또는 Entity 상속을 유지합니다.
class CertificationDTO extends CommonDTO
class CertificationDTO extends Entity // DTO가 Entity를 상속받는 것으로 가정합니다.
{
public bool $isLogin = false;
public ?int $uid = null;
// 💡 role의 타입을 ?string에서 ?array로 변경합니다.
public ?string $uid = null;
public ?bool $isLogin = null;
public ?string $name = null;
public ?string $role = null;
public ?array $role = null;
public function __construct(array $datas = [])
{
parent::__construct();
@ -19,6 +22,7 @@ class CertificationDTO extends CommonDTO
}
}
}
public static function fromByAuthService(AuthService $service): self
{
return new self(
@ -26,7 +30,7 @@ class CertificationDTO extends CommonDTO
'isLogin' => $service->isLoggedIn(),
'uid' => $service->getUID(),
'name' => $service->getName(),
'role' => $service->getRole(),
'role' => $service->getRole(), //배열(array|null)을 반환합니다.
]
);
}

View File

@ -4,6 +4,7 @@ namespace App\Entities;
use App\Entities\CommonEntity;
use App\Models\UserModel as Model;
use CodeIgniter\Entity\Entity; // Entity 클래스를 명시적으로 use 하는 것이 좋습니다.
class UserEntity extends CommonEntity
{
@ -11,9 +12,12 @@ class UserEntity extends CommonEntity
const TITLE = Model::TITLE;
const DEFAULT_STATUS = STATUS['AVAILABLE'];
// 💡 1. $casts 속성 추가:
// DB에 JSON 형태로 저장된 'role' 컬럼을 PHP에서 배열로 자동 변환합니다.
/**
* @var array Entity 속성을 DB에 저장하거나 DB에서 로드할 때의 변환 규칙
*/
protected $casts = [
// 'role' 컬럼에 배열을 할당하면 DB에 JSON 문자열로 저장되며,
// DB에서 로드할 때 JSON 문자열이 자동으로 PHP 배열로 변환됩니다.
'role' => 'json-array',
];
@ -26,21 +30,45 @@ class UserEntity extends CommonEntity
{
return $this->attributes['passwd'];
}
// $formDatas['passwd']에 평문 비밀번호가 들어있으면,
//Model->insert시 Entity 생성자($formDatas)가 setPasswd()를 자동으로 호출합니다.
// Model->insert시 Entity 생성자($formDatas)가 setPasswd()를 자동으로 호출합니다.
public function setPasswd(string $password)
{
// 비밀번호를 암호화하여 저장합니다.
$this->attributes['passwd'] = password_hash($password, PASSWORD_BCRYPT);
}
/**
* 사용자의 역할을 배열 형태로 반환합니다.
* $casts에 의해 DB에서 읽어올 이미 배열로 변환되어 있습니다.
* $casts에 의해 DB에서 읽어올 이미 배열로 변환것을 기대합니다.
* @return array
*/
public function getRole(): array
{
// 💡 2. 반환 타입을 array로 변경하고,
// null일 경우를 대비해 빈 배열을 반환하도록 처리합니다.
return $this->attributes['role'] ?? [];
$role = $this->attributes['role'] ?? [];
// 1. $casts가 성공적으로 작동했거나, 이미 배열인 경우 바로 반환합니다.
if (is_array($role)) {
return $role;
}
// 2. 캐스팅에 실패했으나 원본이 문자열로 남아있는 경우 (JSON 또는 CSV)
if (is_string($role) && !empty($role)) {
// 2-a. JSON 디코딩을 시도합니다.
$decodedRole = json_decode($role, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decodedRole)) {
return $decodedRole; // 유효한 JSON 배열인 경우
}
// 2-b. JSON이 아니면 레거시 CSV 형식이라고 가정하고 explode로 변환합니다.
if (defined('DEFAULTS') && isset(DEFAULTS['DELIMITER_ROLE'])) {
return explode(DEFAULTS['DELIMITER_ROLE'], $role);
}
}
// 3. 변환에 실패했거나 데이터가 없는 경우 빈 배열 반환
return [];
}
}

View File

@ -39,7 +39,7 @@ class AuthFilter implements FilterInterface
if (!$auth->isAccessRole($arguments)) {
return redirect()->back()->with(
'error',
"회원[{$auth->getNameByAuthInfo()}]님은 접속에 필요한 권한이 없습니다. "
"회원[{$auth->getName()}]님은 접속에 필요한 권한이 없습니다. "
);
}
}

View File

@ -2,6 +2,8 @@
namespace App\Helpers;
use App\Entities\UserEntity;
class UserHelper extends CommonHelper
{
public function __construct()
@ -16,23 +18,19 @@ class UserHelper extends CommonHelper
$form = form_password($field, "", [...$extras]);
break;
case 'role':
// 💡 $value는 수정 폼 로드시 현재 Entity의 'role' 배열입니다.
// (old() 값이 있다면 old() 배열이 됩니다.)
$currentRoles = is_array($value) ? $value : [];
// 사용 가능한 모든 역할 목록 (Service 등에서 가져온다고 가정)
$allRoles = $viewDatas['control']['formOptions']['role'] ?? ROLE['USER'];
//$viewDatas['control']['entity']->$field에서 getRole()로 캐스팅이 되지 않아서 대체함
if (($viewDatas['control']['entity'] ?? null) instanceof UserEntity) {
$value = $viewDatas['control']['entity']->getRole();
}
$currentRoles = is_array($value)
? array_map('strtolower', array_map('trim', $value))
: [];
$form = '';
// 2. 각 역할에 대한 체크박스를 순회하며 생성
foreach ($allRoles as $roleValue => $roleLabel) {
// $roleLabel이 배열이 아닌 문자열만 있는 경우를 대비
if (is_int($roleValue)) {
$roleValue = $roleLabel;
$roleLabel = ucfirst($roleValue);
}
$checked = in_array($roleValue, $currentRoles);
// 3. name="role[]" 형태로 배열 데이터 전송 준비
//체크박스를 순회하며 생성
foreach ($viewDatas['control']['formOptions']['role'] as $roleValue => $roleLabel) {
$checked = in_array(strtolower(trim($roleValue)), $currentRoles);
$form .= '<label class="me-3">';
// form_checkbox에 들어가는 값($roleValue)은 원본 값을 유지(저장용).
$form .= form_checkbox('role[]', $roleValue, $checked, array_merge(['id' => "role_{$roleValue}"], $extras));
$form .= " {$roleLabel}";
$form .= '</label>';

View File

@ -66,23 +66,41 @@ abstract class AuthService extends CommonService
{
return $this->getAuthInfo('name');
}
final public function getRole(): string|null
/**
* 현재 로그인된 사용자의 역할을 배열 형태로 반환합니다.
* UserEntity::getRole() 반환 타입과 일치시킵니다.
* @return array|null
*/
final public function getRole(): array|null // <-- 타입 힌트를 array|null로 변경
{
// getAuthInfo는 UserEntity에서 배열을 받아옵니다.
return $this->getAuthInfo('role');
}
final public function isLoggedIn(): bool
{
return $this->getSession()->has(SESSION_NAMES['ISLOGIN']);
}
/**
* 사용자가 필요한 접근 권한($roles) 가지고 있는지 확인합니다.
* @param array $roles 요구되는 권한 목록
* @return bool
*/
final public function isAccessRole(array $roles): bool
{
$role = $this->getRole();
if ($role === "") {
// (1) getRole()의 반환 타입이 이제 배열이므로 바로 받습니다.
$userRoles = $this->getRole();
// 역할 정보 자체가 없거나 빈 배열인 경우 접근 불가
if (empty($userRoles) || !is_array($userRoles)) {
return false;
}
// (2) 문자열 explode() 대신 array_intersect를 사용하여 배열 간의 공통점을 찾습니다.
// 교집합이 없으면 false
return !empty(array_intersect(explode(DEFAULTS['DELIMITER_ROLE'], $role), $roles));
return !empty(array_intersect($userRoles, $roles));
}
final public function pushCurrentUrl(string $url): void
{
$this->getSession()->set($this->url_stack_name, $url);
@ -103,7 +121,7 @@ abstract class AuthService extends CommonService
'uid' => $entity->getPK(),
'id' => $entity->getID(),
'name' => $entity->getTitle(),
'role' => $entity->role
'role' => $entity->getRole()
]);
return $entity;
}

View File

@ -9,7 +9,6 @@
<?php foreach ($viewDatas['control']['formFields'] as $field): ?>
<tr>
<th nowrap class="text-end"><?= $viewDatas['control']['helper']->getFieldLabel($field, "", $viewDatas) ?></th>
<?= dd($viewDatas); ?>
<td nowrap class="text-start">
<?= $viewDatas['control']['helper']->getFieldForm($field, old($field) ?? ($viewDatas['control']['entity']->$field ?? null), $viewDatas) ?>
<span><?= validation_show_error($field); ?></span>