184 lines
5.6 KiB
PHP
184 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class UserRole extends BaseModel
|
|
{
|
|
public $timestamps = true;
|
|
|
|
use SoftDeletes;
|
|
|
|
protected $table = 'user_roles';
|
|
|
|
protected $fillable = [
|
|
'user_id',
|
|
'role_id',
|
|
'semester',
|
|
'school_year',
|
|
'created_at',
|
|
'updated_at',
|
|
'updated_by',
|
|
'deleted_at',
|
|
];
|
|
|
|
protected $casts = [
|
|
'user_id' => 'integer',
|
|
'role_id' => 'integer',
|
|
'updated_by' => 'integer',
|
|
'created_at' => 'datetime',
|
|
'updated_at' => 'datetime',
|
|
'deleted_at' => 'datetime',
|
|
];
|
|
|
|
/* ============================================================
|
|
* Relationships
|
|
* ============================================================
|
|
*/
|
|
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'user_id');
|
|
}
|
|
|
|
public function role(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Role::class, 'role_id');
|
|
}
|
|
|
|
/* ============================================================
|
|
* Scopes
|
|
* ============================================================
|
|
*/
|
|
|
|
public function scopeForUser(Builder $q, int $userId): Builder
|
|
{
|
|
return $q->where('user_id', $userId);
|
|
}
|
|
|
|
public function scopeForRole(Builder $q, int $roleId): Builder
|
|
{
|
|
return $q->where('role_id', $roleId);
|
|
}
|
|
|
|
public function scopeForSchoolYear(Builder $q, ?string $schoolYear): Builder
|
|
{
|
|
if ($schoolYear === null || trim($schoolYear) === '') {
|
|
return $q;
|
|
}
|
|
|
|
return $q->where('school_year', $schoolYear);
|
|
}
|
|
|
|
/* ============================================================
|
|
* legacy-compatible methods (converted)
|
|
* ============================================================
|
|
*/
|
|
|
|
/**
|
|
* legacy: getRolesByUserId($userId)
|
|
* Returns: [ ['role_name' => 'parent'], ['role_name' => 'teacher'] ]
|
|
*/
|
|
public static function getRolesByUserId(int $userId): array
|
|
{
|
|
return static::query()
|
|
->selectRaw('roles.name as role_name')
|
|
->join('roles', 'roles.id', '=', 'user_roles.role_id')
|
|
->where('user_roles.user_id', $userId)
|
|
->whereNull('user_roles.deleted_at')
|
|
->orderBy('roles.priority', 'asc')
|
|
->orderBy('roles.name', 'asc')
|
|
->get()
|
|
->map(fn ($r) => ['role_name' => (string) $r->role_name])
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* legacy: updateOrInsertRole($userId, $roleId)
|
|
* Idempotent (does nothing if already exists and not soft-deleted).
|
|
* If the row exists but is soft-deleted, restores it.
|
|
*/
|
|
public static function updateOrInsertRole(int $userId, int $roleId, ?int $editorId = null): bool
|
|
{
|
|
$editorId = $editorId ?? (auth()->id() ?? null);
|
|
|
|
$existing = static::withTrashed()
|
|
->where('user_id', $userId)
|
|
->where('role_id', $roleId)
|
|
->first();
|
|
|
|
if ($existing) {
|
|
if ($existing->trashed()) {
|
|
$existing->restore();
|
|
}
|
|
// keep updated_by fresh
|
|
if ($editorId !== null) {
|
|
$existing->updated_by = $editorId;
|
|
$existing->save();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static::query()->create([
|
|
'user_id' => $userId,
|
|
'role_id' => $roleId,
|
|
'updated_by' => $editorId,
|
|
]);
|
|
|
|
return true;
|
|
}
|
|
|
|
/* ============================================================
|
|
* Replacement for the legacy "create()" method (query only)
|
|
* ============================================================
|
|
* In Laravel, view rendering belongs in Controllers, not Models.
|
|
* This returns the user list that your legacy method was building.
|
|
*
|
|
* legacy logic:
|
|
* users joined to roles through user_roles, excluding parent/teacher,
|
|
* groupBy users.id to avoid duplicates.
|
|
*/
|
|
public static function usersExcludingRoles(array $excludedRoleNames = ['parent', 'teacher']): array
|
|
{
|
|
$excluded = array_values(array_unique(array_filter(array_map('strval', $excludedRoleNames))));
|
|
$excludedLower = array_map('strtolower', $excluded);
|
|
|
|
$placeholders = implode(',', array_fill(0, count($excludedLower), '?'));
|
|
|
|
return DB::table('users')
|
|
->select('users.*')
|
|
->join('user_roles', 'user_roles.user_id', '=', 'users.id')
|
|
->join('roles', 'roles.id', '=', 'user_roles.role_id')
|
|
->whereNull('user_roles.deleted_at')
|
|
->whereRaw("LOWER(roles.name) NOT IN ($placeholders)", $excludedLower)
|
|
->groupBy('users.id')
|
|
->orderBy('users.lastname', 'asc')
|
|
->orderBy('users.firstname', 'asc')
|
|
->get()
|
|
->map(fn ($r) => (array) $r)
|
|
->all();
|
|
}
|
|
|
|
/* ============================================================
|
|
* Optional validation helper
|
|
* ============================================================
|
|
*/
|
|
public static function rules(bool $updating = false): array
|
|
{
|
|
$req = $updating ? 'sometimes' : 'required';
|
|
|
|
return [
|
|
'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'],
|
|
'role_id' => [$req, 'integer', 'min:1', 'exists:roles,id'],
|
|
'semester' => ['nullable', 'string', 'max:20'],
|
|
'school_year' => ['nullable', 'string', 'max:20'],
|
|
'updated_by' => ['nullable', 'integer'],
|
|
];
|
|
}
|
|
}
|