Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions WebFiori/Framework/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@
'\\WebFiori\\Framework\\Cli\\Commands\\MigrationsStatusCommand',
'\\WebFiori\\Framework\\Cli\\Commands\\FreshMigrationsCommand',
'\\WebFiori\\Framework\\Cli\\Commands\\SkipMigrationsCommand',
'\\WebFiori\\Framework\\Cli\\Commands\\StepMigrationsCommand',
];

foreach ($commands as $c) {
Expand Down Expand Up @@ -700,9 +701,9 @@
*/
private function setHandlers() {
Handler::registerHandler(new CLIErrHandler());
// Handler::registerHandler(new APICallErrHandler());
// Handler::registerHandler(new HTTPErrHandler());
// Handler::unregisterHandler(Handler::getHandler('Default'));

Check warning on line 706 in WebFiori/Framework/App.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=WebFiori_framework&issues=AZ7CfxyzlFS2SonGdmop&open=AZ7CfxyzlFS2SonGdmop&pullRequest=393
Handler::setConfig(HandlerConfig::createDevelopmentConfig());
}
}
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/DownCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@

use WebFiori\Cli\Command;
use WebFiori\Cli\Argument;
use WebFiori\Cli\Attributes\Group;

/**
* A command to put the application in maintenance mode.
*/
#[Group('maintenance')]
class DownCommand extends Command {
public function __construct() {
parent::__construct('down', [
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/FreshMigrationsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use Throwable;
use WebFiori\Cli\Argument;
use WebFiori\Cli\Attributes\SingleInstance;
use WebFiori\Cli\Command;
use WebFiori\Database\ConnectionInfo;
use WebFiori\Database\Schema\SchemaRunner;
Expand All @@ -23,6 +24,7 @@
*
* @author Ibrahim
*/
#[SingleInstance]
class FreshMigrationsCommand extends Command {

private ?SchemaRunner $runner = null;
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/QueueRetryCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Argument;
use WebFiori\Cli\Attributes\SingleInstance;
use WebFiori\Cli\Command;
use WebFiori\Queue\QueueFacade;

/**
* CLI command to retry failed jobs or flush them.
*/
#[SingleInstance]
class QueueRetryCommand extends Command {
public function __construct() {
parent::__construct('queue:retry', [
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/QueueWorkCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
*/
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Attributes\SingleInstance;
use WebFiori\Cli\Command;
use WebFiori\Queue\QueueFacade;

/**
* CLI command to process queue jobs continuously.
*/
#[SingleInstance]
class QueueWorkCommand extends Command {
public function __construct() {
parent::__construct('queue:work', [], 'Process queue jobs continuously.');
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/RunMigrationsCommandNew.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Throwable;
use WebFiori\Cli\Argument;
use WebFiori\Cli\Attributes\SingleInstance;
use WebFiori\Cli\Command;
use WebFiori\Database\ConnectionInfo;
use WebFiori\Database\Schema\SchemaRunner;
Expand All @@ -24,6 +25,7 @@
*
* @author Ibrahim
*/
#[SingleInstance]
class RunMigrationsCommandNew extends Command {
private ?SchemaRunner $runner = null;

Expand All @@ -35,7 +37,7 @@
], 'Execute pending database migrations.');
}

public function exec(): int {

Check warning on line 40 in WebFiori/Framework/Cli/Commands/RunMigrationsCommandNew.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This method has 7 returns, which is more than the 5 allowed.

See more on https://sonarcloud.io/project/issues?id=WebFiori_framework&issues=AZ7CfxrdlFS2SonGdmoG&open=AZ7CfxrdlFS2SonGdmoG&pullRequest=393
if ($this->isArgProvided('--all-connections') && $this->isArgProvided('--connection')) {
$this->error('Cannot use --all-connections and --connection together.');

Expand Down Expand Up @@ -77,7 +79,7 @@
} catch (Throwable $e) {
$msg = $e->getMessage();

if ((str_contains($msg, ".schema_changes' doesn't exist") && $e->getCode() == 1146)) {

Check warning on line 82 in WebFiori/Framework/Cli/Commands/RunMigrationsCommandNew.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove these useless parentheses.

See more on https://sonarcloud.io/project/issues?id=WebFiori_framework&issues=AZ7CfxrdlFS2SonGdmoH&open=AZ7CfxrdlFS2SonGdmoH&pullRequest=393
$this->warning('Table "schema_changes" does not exist. No migrations executed.');
$this->info('Run "migrations:ini" to create the table.');

Expand Down Expand Up @@ -138,7 +140,7 @@
$this->println('=== Connection: '.$name.' ===');

try {
$runner = new SchemaRunner($connection, $env);

Check warning on line 143 in WebFiori/Framework/Cli/Commands/RunMigrationsCommandNew.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename "$runner" which has the same name as the field declared at line 30.

See more on https://sonarcloud.io/project/issues?id=WebFiori_framework&issues=AZ7CfxrdlFS2SonGdmoI&open=AZ7CfxrdlFS2SonGdmoI&pullRequest=393

$migrationsPath = APP_PATH.'Database'.DS.'Migrations';
$namespace = APP_DIR.'\\Database\\Migrations';
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/SchedulerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Argument;
use WebFiori\Cli\Attributes\SingleInstance;
use WebFiori\Cli\Command;
use WebFiori\Framework\Cli\CLIUtils;
use WebFiori\Framework\Scheduler\AbstractTask;
Expand All @@ -22,6 +23,7 @@
* @author Ibrahim
* @version 1.0
*/
#[SingleInstance]
class SchedulerCommand extends Command {
/**
* Creates new instance of the class.
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/SchedulerDaemonCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Argument;
use WebFiori\Cli\Attributes\SingleInstance;
use WebFiori\Cli\Command;
use WebFiori\Framework\Cli\CLIUtils;
use WebFiori\Framework\Scheduler\TasksManager;
Expand All @@ -30,6 +31,7 @@
*
* @author Ibrahim
*/
#[SingleInstance]
class SchedulerDaemonCommand extends Command {
/**
* Creates a new instance of the command.
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/SchedulerRunCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Argument;
use WebFiori\Cli\Attributes\SingleInstance;
use WebFiori\Cli\Command;
use WebFiori\Framework\Cli\CLIUtils;
use WebFiori\Framework\Scheduler\TasksManager;
Expand All @@ -23,6 +24,7 @@
*
* @author Ibrahim
*/
#[SingleInstance]
class SchedulerRunCommand extends Command {

public function __construct() {
Expand Down
122 changes: 122 additions & 0 deletions WebFiori/Framework/Cli/Commands/StepMigrationsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

/**
* This file is licensed under MIT License.
*
* Copyright (c) 2026 Ibrahim BinAlshikh
*
* For more information on the license, please visit:
* https://github.com/WebFiori/.github/blob/main/LICENSE
*
*/
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Argument;
use WebFiori\Cli\Attributes\SingleInstance;
use WebFiori\Cli\Command;
use WebFiori\Database\ConnectionInfo;
use WebFiori\Database\Schema\SchemaRunner;
use WebFiori\Framework\App;
use WebFiori\Framework\Cli\CLIUtils;

/**
* Command for stepping through migrations one at a time with user confirmation.
*
* @author Ibrahim
*/
#[SingleInstance]
class StepMigrationsCommand extends Command {
public function __construct() {
parent::__construct('migrations:step', [
new Argument('--connection', 'The name of database connection to use.', true),
new Argument('--env', 'Environment name (dev, staging, production). Default: dev', true),
], 'Interactively apply or skip migrations one at a time.');
}

public function exec(): int {
$connection = $this->getConnection();

if ($connection === null) {
return 1;
}

$env = $this->getArgValue('--env') ?? 'dev';
$runner = new SchemaRunner($connection, $env);
$runner->discoverFromPath(APP_PATH.'Database'.DS.'Migrations', APP_DIR.'\\Database\\Migrations', true);

$pending = $runner->getPendingChanges(true);

if (empty($pending)) {
$this->info('No pending migrations.');

return 0;
}

$applied = 0;
$skipped = 0;

foreach ($pending as $item) {
$change = $item['change'];
$queries = $item['queries'];

$this->println('');
$this->println('Migration: '.$change->getName());
$this->println('');

if (!empty($queries)) {
$this->println('SQL:');

foreach ($queries as $q) {
$this->println(' '.$q);
}

$this->println('');
}

$action = $this->select('Action:', ['Apply', 'Skip', 'Quit'], 0);

if ($action === 'Apply') {
$runner->applyOne();
$applied++;
$this->success('Applied: '.$change->getName());
} else if ($action === 'Skip') {
$runner->skip($change);
$skipped++;
$this->warning('Skipped: '.$change->getName());
} else {
break;
}
}

$this->println('');
$this->info("Summary: $applied applied, $skipped skipped.");

return 0;
}

private function getConnection(): ?ConnectionInfo {
$connections = App::getConfig()->getDBConnections();

if (empty($connections)) {
$this->info('No database connections configured.');

return null;
}

$connectionName = $this->getArgValue('--connection');

if ($connectionName !== null) {
$connection = App::getConfig()->getDBConnection($connectionName);

if ($connection === null) {
$this->error("Connection '$connectionName' not found.");

return null;
}

return $connection;
}

return CLIUtils::getConnectionName($this);
}
}
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/UpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
*/
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Attributes\Group;
use WebFiori\Cli\Command;

/**
* A command to bring the application out of maintenance mode.
*/
#[Group('maintenance')]
class UpCommand extends Command {
public function __construct() {
parent::__construct('up', [], 'Bring the application out of maintenance mode.');
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/VersionCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
*/
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Attributes\Group;
use WebFiori\Cli\Command;
/**
* Description of VersionCommand
*
* @author Ibrahim
*/
#[Group('other')]
class VersionCommand extends Command {
public function __construct() {
parent::__construct('v', [], 'Display framework version info.');
Expand Down
2 changes: 2 additions & 0 deletions WebFiori/Framework/Cli/Commands/WHelpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
*/
namespace WebFiori\Framework\Cli\Commands;

use WebFiori\Cli\Attributes\Group;
use WebFiori\Cli\Commands\HelpCommand;
/**
* Description of WHelpCommand
*
* @author Ibrahim
*/
#[Group('other')]
class WHelpCommand extends HelpCommand {
public function exec() : int {
$argV = $this->getOwner()->getArgsVector();
Expand Down
33 changes: 32 additions & 1 deletion WebFiori/Framework/Health/HealthCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class HealthCheck {
* @var array Registered checks indexed by name.
*/
private static array $checks = [];
/**
* @var array Callbacks to execute after runAll() completes.
*/
private static array $afterAllCallbacks = [];
/**
* Register a health check.
*
Expand Down Expand Up @@ -68,17 +72,24 @@ public static function runAll(): array {
}
}

return [
$aggregate = [
'status' => $allOk ? 'ok' : 'fail',
'timestamp' => date('c'),
'checks' => $results,
];

foreach (self::$afterAllCallbacks as $cb) {
$cb($aggregate);
}

return $aggregate;
}
/**
* Remove all registered checks.
*/
public static function reset(): void {
self::$checks = [];
self::$afterAllCallbacks = [];
}
/**
* Returns the number of registered checks.
Expand All @@ -88,4 +99,24 @@ public static function reset(): void {
public static function getCheckCount(): int {
return count(self::$checks);
}
/**
* Returns all registered checks.
*
* @return array Associative array keyed by check name. Values are
* HealthCheckInterface instances or callables.
*/
public static function getChecks(): array {
return self::$checks;
}
/**
* Register a callback to execute after all checks complete.
*
* The callback receives the aggregate result array with 'status',
* 'timestamp', and 'checks' keys.
*
* @param callable $callback A function that accepts the aggregate results array.
*/
public static function afterAll(callable $callback): void {
self::$afterAllCallbacks[] = $callback;
}
}
7 changes: 4 additions & 3 deletions WebFiori/Framework/Middleware/CacheMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function __construct() {
$this->setPriority(50);
$this->addToGroups(['web']);
$this->fromCache = false;
$this->cache = new Cache(new FileStorage());
$this->cache = new Cache(new FileStorage(sys_get_temp_dir().DS.'wf-cache'));
}
/**
* Checks if the response is loaded from the cache or caching must be performed.
Expand Down Expand Up @@ -101,14 +101,15 @@ public function before(Request $request, Response $response) {
* @return string
*/
public function getKey() : string {
$key = Request::getUri()->getUri(true, true);
$request = \WebFiori\Framework\App::getRequest();
$key = $request->getUri()->getUri(true, true);

//Following steps are used to make cached response unique per user.
$session = SessionsManager::getActiveSession();
if ($session !== null) {
$key .= $session->getId();
}
$authHeader = Request::getAuthHeader();
$authHeader = $request->getAuthHeader();
if ($authHeader !== null) {
$key .= $authHeader->getScheme().$authHeader->getCredentials();
}
Expand Down
4 changes: 3 additions & 1 deletion WebFiori/Framework/Session/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -668,9 +668,11 @@ public function start() {
if (!$this->isRunning()) {
$sessionStr = SessionsManager::getStorage()->read($this->getId());

if ($this->getStatus() == SessionStatus::KILLED || $sessionStr === null || !$this->deserialize($sessionStr)) {
if ($this->getStatus() == SessionStatus::KILLED) {
$this->reGenerateID();
$this->initNewSessionVars();
} else if ($sessionStr === null || !$this->deserialize($sessionStr)) {
$this->initNewSessionVars();
} else {
$this->checkIfExpired();
}
Expand Down
Loading
Loading