Files
alrahma_sunday_school/app/Controllers/BaseController.php
T
root feb1b29a32
Tests / PHPUnit (push) Failing after 1m19s
apply the school year concept
2026-07-14 00:59:00 -04:00

216 lines
6.2 KiB
PHP

<?php
namespace App\Controllers;
use CodeIgniter\Controller;
use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
use App\Services\ApiClient;
use App\Exceptions\SchoolYear\SchoolYearConfigurationException;
use App\Support\SchoolYear\SchoolYearContext;
use Throwable;
/**
* Class BaseController
*
* BaseController provides a convenient place for loading components
* and performing functions that are needed by all your controllers.
* Extend this class in any new controllers:
* class Home extends BaseController
*
* For security be sure to declare any new methods as protected or private.
*/
abstract class BaseController extends Controller
{
/**
* Instance of the main Request object.
*
* @var CLIRequest|IncomingRequest
*/
protected $request;
/**
* An array of helpers to be loaded automatically upon
* class instantiation. These helpers will be available
* to all other controllers that extend BaseController.
*
* @var list<string>
*/
protected $helpers = ['security'];
/** @var ApiClient */
protected ApiClient $api;
/**
* Be sure to declare properties for any property fetch you initialized.
* The creation of dynamic property is deprecated in PHP 8.2.
*/
// protected $session;
/**
* @return void
*/
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
// Do Not Edit This Line
parent::initController($request, $response, $logger);
// Preload any models, libraries, etc, here.
// E.g.: $this->session = \Config\Services::session();
session();
$this->syncSchoolYearPropertyFromContext();
$this->injectSchoolYearViewData();
// Shared API client available to all controllers
$this->api = service('apiClient');
}
/**
* Get the user role from the session or database
*
* @return string|null
*/
protected function getUserRole()
{
// Assuming the user role is stored in the session
return session()->get('role');
}
protected function validated(array $rules, ?array $data = null): array
{
$validation = service('validation');
$payload = $data ?? ($this->request->getJSON(true) ?: $this->request->getPost());
$payload = sanitize_request_value($payload);
$validation->setRules($rules);
if (! $validation->run($payload)) {
throw new \InvalidArgumentException(json_encode($validation->getErrors(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: 'Validation failed');
}
return $payload;
}
protected function resolveSchoolYearContext(?int $routeSchoolYearId = null): SchoolYearContext
{
try {
return service('schoolYearContext')->resolve($this->request, $routeSchoolYearId);
} catch (Throwable $e) {
log_message('warning', 'School-year resolution failed: {message}', [
'message' => $e->getMessage(),
]);
throw $e;
}
}
protected function currentSchoolYearName(?string $fallback = null): string
{
try {
return $this->resolveSchoolYearContext()->yearName();
} catch (Throwable $e) {
if ($fallback !== null && $fallback !== '') {
return $fallback;
}
try {
return (string) ((new \App\Models\ConfigurationModel())->getConfig('school_year') ?? '');
} catch (Throwable) {
return '';
}
}
}
protected function assertSchoolYearWritable(
SchoolYearContext $context,
bool $allowDraftForAdmin = false,
bool $isAdmin = false
): void {
service('schoolYearWriteGuard')->assertWritable($context, $allowDraftForAdmin, $isAdmin);
}
private function syncSchoolYearPropertyFromContext(): void
{
if (! property_exists($this, 'schoolYear')) {
return;
}
if (! $this->request instanceof IncomingRequest || is_cli()) {
return;
}
if (! session()->get('user_id')) {
return;
}
try {
$this->schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
} catch (Throwable $e) {
log_message('warning', 'Unable to sync controller school-year property: {message}', [
'message' => $e->getMessage(),
]);
}
}
private function injectSchoolYearViewData(): void
{
if (! config('Feature')->globalSchoolYearSelector) {
return;
}
if (! $this->request instanceof IncomingRequest || is_cli()) {
return;
}
if (! session()->get('user_id')) {
return;
}
if (! $this->shouldShowSchoolYearSelector()) {
return;
}
$accept = strtolower($this->request->getHeaderLine('Accept'));
if ($this->request->isAJAX() || str_contains($accept, 'application/json')) {
return;
}
try {
service('renderer')->setData(service('schoolYearViewData')->forCurrentRequest($this->request));
} catch (SchoolYearConfigurationException $e) {
throw $e;
} catch (Throwable $e) {
log_message('warning', 'Unable to inject school-year view data: {message}', [
'message' => $e->getMessage(),
]);
}
}
private function shouldShowSchoolYearSelector(): bool
{
$roles = (array) session()->get('roles');
$singleRole = session()->get('role');
if ($singleRole !== null && $singleRole !== '') {
$roles[] = $singleRole;
}
$roles = array_map(
static fn ($role): string => strtolower(trim((string) $role)),
$roles
);
return (bool) array_intersect($roles, [
'admin',
'administrator',
'administrative staff',
'principal',
'vice principal',
]);
}
}
?>