From c6660ccafa417163bb5c23be22aec387e08ed643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Je=C5=BC?= Date: Sun, 22 Jun 2025 17:02:22 +0200 Subject: [PATCH 1/6] Replace `CliTypo` with custom `Cli` implementation, update error handling, and refactor console structure. --- Engine/Console/Cli.php | 261 ++++++++++++++++++++++++++++++ Engine/Console/Commands/Help.php | 14 +- Engine/Console/Commands/Serve.php | 8 +- Engine/Console/Console.php | 26 ++- Engine/Console/Shift.php | 15 +- composer.json | 9 +- shift.php | 8 +- 7 files changed, 316 insertions(+), 25 deletions(-) create mode 100644 Engine/Console/Cli.php diff --git a/Engine/Console/Cli.php b/Engine/Console/Cli.php new file mode 100644 index 0000000..1100041 --- /dev/null +++ b/Engine/Console/Cli.php @@ -0,0 +1,261 @@ +output(self::COLOR_BLUE . $message . self::COLOR_DEFAULT, $newLine); + } + + /** + * Wyświetla informację debugowania w standardowym kolorze + * + * @param string $message Treść wiadomości + * @param bool $newLine Czy dodać nową linię na końcu + * @return void + */ + public function debug(string $message, bool $newLine = true): void + { + $this->output($message, $newLine); + } + + /** + * Wyświetla informację o błędzie w kolorze czerwonym + * + * @param string $message Treść wiadomości + * @param bool $newLine Czy dodać nową linię na końcu + * @return void + */ + public function error(string $message, bool $newLine = true): void + { + $this->output(self::COLOR_RED . $message . self::COLOR_DEFAULT, $newLine); + } + + /** + * Wyświetla informację o sukcesie w kolorze zielonym + * + * @param string $message Treść wiadomości + * @param bool $newLine Czy dodać nową linię na końcu + * @return void + */ + public function success(string $message, bool $newLine = true): void + { + $this->output(self::COLOR_GREEN . $message . self::COLOR_DEFAULT, $newLine); + } + + /** + * Wyświetla ostrzeżenie w kolorze żółtym + * + * @param string $message Treść wiadomości + * @param bool $newLine Czy dodać nową linię na końcu + * @return void + */ + public function warning(string $message, bool $newLine = true): void + { + $this->output(self::COLOR_YELLOW . $message . self::COLOR_DEFAULT, $newLine); + } + + /** + * Wyświetla linię separatora + * + * @param int $length Długość linii + * @param string $char Znak używany do narysowania linii + * @return void + */ + public function line(int $length = 50, string $char = '-'): void + { + $this->output(str_repeat($char, $length)); + } + + /** + * Wyświetla tekst z tabulacją + * + * @param string $message Treść wiadomości + * @param int $level Poziom wcięcia + * @param bool $newLine Czy dodać nową linię na końcu + * @return void + */ + public function indent(string $message, int $level = 1, bool $newLine = true): void + { + $indent = str_repeat(" ", $level); // dwa spacje na poziom + $this->output($indent . $message, $newLine); + } + + /** + * Wyświetla tabelę danych + * + * @param array $headers Nagłówki tabeli + * @param array $rows Wiersze z danymi + * @return void + */ + public function table(array $headers, array $rows): void + { + // Obliczanie szerokości kolumn + $columnWidths = []; + foreach ($headers as $i => $header) { + $columnWidths[$i] = strlen($header); + foreach ($rows as $row) { + if (isset($row[$i]) && strlen($row[$i]) > $columnWidths[$i]) { + $columnWidths[$i] = strlen($row[$i]); + } + } + } + + // Rysowanie górnej granicy + $this->drawTableBorder($columnWidths); + + // Rysowanie nagłówków + $this->drawTableRow($headers, $columnWidths); + + // Rysowanie linii rozdzielającej + $this->drawTableBorder($columnWidths); + + // Rysowanie wierszy z danymi + foreach ($rows as $row) { + $this->drawTableRow($row, $columnWidths); + } + + // Rysowanie dolnej granicy + $this->drawTableBorder($columnWidths); + } + + /** + * Wyświetla postęp operacji + * + * @param int $current Aktualna wartość + * @param int $total Całkowita wartość + * @param int $barWidth Szerokość paska postępu + * @return void + */ + public function progressBar(int $current, int $total, int $barWidth = 50): void + { + $percent = $current / $total; + $bar = floor($percent * $barWidth); + $status = str_pad("[", 1); + $status .= str_repeat("=", $bar); + if ($bar < $barWidth) { + $status .= ">"; + $status .= str_repeat(" ", $barWidth - $bar - 1); + } else { + $status .= "="; + } + $status .= "]"; + $status .= " " . number_format($percent * 100, 0) . "%"; + $status .= " $current/$total"; + + echo "\r"; // Powrót karetki + $this->output($status, false); + + if ($current === $total) { + echo "\n"; // Nowa linia na końcu postępu + } + + // Flush output + ob_flush(); + flush(); + } + + /** + * Pobiera wejście od użytkownika + * + * @param string $prompt Zapytanie wyświetlane użytkownikowi + * @param string|null $default Domyślna wartość + * @return string Wprowadzona wartość + */ + public function input(string $prompt, ?string $default = null): string + { + $promptText = $prompt; + if ($default !== null) { + $promptText .= " [" . $default . "]"; + } + $promptText .= ": "; + + $this->output($promptText, false); + $input = trim(fgets(STDIN)); + + if ($input === '' && $default !== null) { + return $default; + } + + return $input; + } + + /** + * Pobiera potwierdzenie od użytkownika + * + * @param string $prompt Zapytanie wyświetlane użytkownikowi + * @param bool $default Domyślna wartość + * @return bool Wynik potwierdzenia + */ + public function confirm(string $prompt, bool $default = true): bool + { + $defaultText = $default ? 'T' : 'N'; + $options = $default ? '[T/n]' : '[t/N]'; + + $input = $this->input("$prompt $options", $defaultText); + return in_array(strtolower($input), ['t', 'tak', 'y', 'yes']); + } + + /** + * Wyświetla wiadomość + * + * @param string $message Treść wiadomości + * @param bool $newLine Czy dodać nową linię + * @return void + */ + private function output(string $message, bool $newLine = true): void + { + echo $message . ($newLine ? PHP_EOL : ''); + } + + /** + * Rysuje wiersz tabeli + * + * @param array $data Dane wiersza + * @param array $columnWidths Szerokości kolumn + * @return void + */ + private function drawTableRow(array $data, array $columnWidths): void + { + echo "|"; + foreach ($columnWidths as $i => $width) { + $value = $data[$i] ?? ''; + echo " " . str_pad($value, $width) . " |"; + } + echo PHP_EOL; + } + + /** + * Rysuje granicę tabeli + * + * @param array $columnWidths Szerokości kolumn + * @return void + */ + private function drawTableBorder(array $columnWidths): void + { + echo "+"; + foreach ($columnWidths as $width) { + echo "-" . str_repeat("-", $width) . "-+"; + } + echo PHP_EOL; + } +} diff --git a/Engine/Console/Commands/Help.php b/Engine/Console/Commands/Help.php index 0265efb..767e575 100644 --- a/Engine/Console/Commands/Help.php +++ b/Engine/Console/Commands/Help.php @@ -39,7 +39,7 @@ public function execute(...$args): void } } - private function displayHelpForCommand($command) + private function displayHelpForCommand($command): void { $found = false; @@ -52,8 +52,18 @@ private function displayHelpForCommand($command) } } - private function displayFullHelp() + private function displayFullHelp(): void { } + + public function getHelp() + { + // TODO: Implement getHelp() method. + } + + public function getDescription() + { + // TODO: Implement getDescription() method. + } } diff --git a/Engine/Console/Commands/Serve.php b/Engine/Console/Commands/Serve.php index 63002d5..f4aea7e 100644 --- a/Engine/Console/Commands/Serve.php +++ b/Engine/Console/Commands/Serve.php @@ -18,10 +18,8 @@ class Serve implements CommandInterface public function execute(...$args): void { $host = 'localhost:8000'; - if (count($args)) { - if (isset($args[0])) { - $host = $args[0]; - } + if (count($args) && isset($args[0])) { + $host = $args[0]; } $command = $this->getOpenCommand() . ' http://' . $host . ';php -S ' . $host; @@ -29,7 +27,7 @@ public function execute(...$args): void exec($command); } - private final function getOpenCommand(): string + private function getOpenCommand(): string { $command = 'open'; diff --git a/Engine/Console/Console.php b/Engine/Console/Console.php index f45c060..fe4e82a 100644 --- a/Engine/Console/Console.php +++ b/Engine/Console/Console.php @@ -4,17 +4,39 @@ * User: dawidjez * Date: 14/12/2018 * Time: 12:09 + * Updated: 2025-06-22 */ namespace Engine\Console; - +/** + * Główna klasa konsolowa + */ class Console { + /** + * Instancja klasy Cli do operacji terminalowych + * + * @var Cli + */ + private Cli $cli; - public function __constructor() + /** + * Konstruktor klasy Console + */ + public function __construct() { + $this->cli = new Cli(); + } + /** + * Zwraca instancję klasy Cli + * + * @return Cli + */ + public function cli(): Cli + { + return $this->cli; } } diff --git a/Engine/Console/Shift.php b/Engine/Console/Shift.php index 2a99a13..acb9dc5 100644 --- a/Engine/Console/Shift.php +++ b/Engine/Console/Shift.php @@ -9,8 +9,8 @@ namespace Engine\Console; -use Grabower\CliTypo\CliTypo; use ReflectionClass; +use ReflectionException; class Shift { @@ -28,7 +28,7 @@ public function __construct(array $argv) */ public function getArg(string $name) { - return isset($this->_args[$name]) ? $this->_args[$name] : null; + return $this->_args[$name] ?? null; } /** @@ -47,15 +47,18 @@ public function setArgs(array $args): void $this->_args = $args; } + /** + * @throws ReflectionException + */ public function run(): void { - $cliTypo = new CliTypo(); + $cli = new Cli(); if (count($this->_args) < 2) { - $cliTypo->alert()->error('Shift CLI needs at least one parameter'); + $cli->error('Shift CLI needs at least one parameter'); exit(); } $commandName = ucfirst($this->_args[1]); - $cliTypo->text()->write($commandName); + $cli->info($commandName); $mappings = [ [ @@ -75,7 +78,7 @@ public function run(): void } } if (!$found) { - $cliTypo->alert()->error('Command ' . $commandName . ' not found'); + $cli->error('Command ' . $commandName . ' not found'); exit(); } diff --git a/composer.json b/composer.json index 9756a36..10e6283 100644 --- a/composer.json +++ b/composer.json @@ -11,16 +11,9 @@ ], "minimum-stability": "dev", "require": { - "php": ">=7.1", - "grabower/clitypo": "dev-master", + "php": ">=8.0", "ext-json": "*" }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/adriangrabowski/clitypo.git" - } - ], "autoload": { "psr-4": { "View\\": "Engine/View", diff --git a/shift.php b/shift.php index 3f904d3..5493e67 100755 --- a/shift.php +++ b/shift.php @@ -1,6 +1,10 @@ #!/usr/bin/php run(); From 9f5d1a182c59b27cc297f68d5b4ddf4c8a44419f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Je=C5=BC?= Date: Sun, 22 Jun 2025 17:05:33 +0200 Subject: [PATCH 2/6] Add buffer level check before calling `ob_flush` in CLI output. --- Engine/Console/Cli.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Engine/Console/Cli.php b/Engine/Console/Cli.php index 1100041..9664bf3 100644 --- a/Engine/Console/Cli.php +++ b/Engine/Console/Cli.php @@ -169,8 +169,10 @@ public function progressBar(int $current, int $total, int $barWidth = 50): void echo "\n"; // Nowa linia na końcu postępu } - // Flush output - ob_flush(); + // Sprawdzamy czy bufor jest aktywny przed próbą jego opróżnienia + if (ob_get_level() > 0) { + ob_flush(); + } flush(); } From a0b72eb691a32ab62d2bb356a465f8fee7154a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Je=C5=BC?= Date: Sun, 22 Jun 2025 17:20:44 +0200 Subject: [PATCH 3/6] Update type declarations, enforce strict types, and adjust PHP version requirement to 8.3 --- Engine/Console/CommandInterface.php | 6 ++--- Engine/Console/Commands/Help.php | 26 +++++++++++++------- Engine/Console/Commands/Serve.php | 8 +++--- Engine/Console/Shift.php | 7 +++--- Engine/Error/ShiftError.php | 7 +++--- Engine/Error/ShiftError/ErrorHighlighter.php | 8 +++--- Engine/Error/StorageError.php | 1 + Engine/View.php | 9 ++++--- composer.json | 2 +- 9 files changed, 44 insertions(+), 30 deletions(-) diff --git a/Engine/Console/CommandInterface.php b/Engine/Console/CommandInterface.php index 1deff85..65d9db3 100644 --- a/Engine/Console/CommandInterface.php +++ b/Engine/Console/CommandInterface.php @@ -11,9 +11,9 @@ interface CommandInterface { - public function execute(...$args): void; + public function execute(mixed ...$args): void; - public function getHelp(); + public function getHelp(): string; - public function getDescription(); + public function getDescription(): string; } diff --git a/Engine/Console/Commands/Help.php b/Engine/Console/Commands/Help.php index 767e575..8429b74 100644 --- a/Engine/Console/Commands/Help.php +++ b/Engine/Console/Commands/Help.php @@ -8,13 +8,12 @@ namespace Console\Commands; - use Engine\Console\CommandInterface; class Help implements CommandInterface { - - private $mappings = [ + /** @var array */ + private array $mappings = [ [ 'dir' => APP_PATH . '/console/', 'namespace' => 'AppConsole\\Commands\\' @@ -28,7 +27,7 @@ class Help implements CommandInterface /** * @param mixed ...$args */ - public function execute(...$args): void + public function execute(mixed ...$args): void { $commandName = $args[0] ?? ''; @@ -39,9 +38,11 @@ public function execute(...$args): void } } - private function displayHelpForCommand($command): void + /** + * @param string $command + */ + private function displayHelpForCommand(string $command): void { - $found = false; foreach ($this->mappings as $mapping) { @@ -54,16 +55,23 @@ private function displayHelpForCommand($command): void private function displayFullHelp(): void { - } - public function getHelp() + /** + * @return string + */ + public function getHelp(): string { // TODO: Implement getHelp() method. + return ''; } - public function getDescription() + /** + * @return string + */ + public function getDescription(): string { // TODO: Implement getDescription() method. + return ''; } } diff --git a/Engine/Console/Commands/Serve.php b/Engine/Console/Commands/Serve.php index f4aea7e..f0682cb 100644 --- a/Engine/Console/Commands/Serve.php +++ b/Engine/Console/Commands/Serve.php @@ -15,7 +15,7 @@ class Serve implements CommandInterface { - public function execute(...$args): void + public function execute(mixed ...$args): void { $host = 'localhost:8000'; if (count($args) && isset($args[0])) { @@ -43,13 +43,15 @@ private function getOpenCommand(): string return $command; } - public function getHelp() + public function getHelp(): string { // TODO: Implement getHelp() method. + return ''; } - public function getDescription() + public function getDescription(): string { // TODO: Implement getDescription() method. + return ''; } } diff --git a/Engine/Console/Shift.php b/Engine/Console/Shift.php index acb9dc5..84eb320 100644 --- a/Engine/Console/Shift.php +++ b/Engine/Console/Shift.php @@ -14,8 +14,8 @@ class Shift { - protected $_description = 'xd'; - private $_args = []; + protected string $_description = 'xd'; + private array $_args = []; public function __construct(array $argv) { @@ -26,7 +26,7 @@ public function __construct(array $argv) * @param string $name * @return mixed|null */ - public function getArg(string $name) + public function getArg(string $name): mixed { return $this->_args[$name] ?? null; } @@ -49,6 +49,7 @@ public function setArgs(array $args): void /** * @throws ReflectionException + * @return void */ public function run(): void { diff --git a/Engine/Error/ShiftError.php b/Engine/Error/ShiftError.php index c4ad1b3..e333ca2 100644 --- a/Engine/Error/ShiftError.php +++ b/Engine/Error/ShiftError.php @@ -24,6 +24,7 @@ class ShiftError extends \Error * @param string $message * @param int $code * @param Throwable|null $previous + * @return void */ public function __construct(string $message = "", int $code = 0, Throwable $previous = null) { @@ -78,17 +79,17 @@ public function __construct(string $message = "", int $code = 0, Throwable $prev '; @@ -110,7 +109,6 @@ private function buildScripts(): self } } $this->html = str_replace('{{ $scripts }}', $scripts, $this->html); - return $this; } /** @@ -142,25 +140,14 @@ private function replacePHPCode(): void */ private function compileStatement(array $match): string { - switch ($match[1]) { - case 'include': - return ''; - break; - case 'if': - return ''; - break; - case 'for': - return ''; - break; - case 'foreach': - return ''; - break; - case 'while': - return ''; - break; - default: - return ''; - } + return match ($match[1]) { + 'include' => '', + 'if' => '', + 'for' => '', + 'foreach' => '', + 'while' => '', + default => '', + }; } /** @@ -169,8 +156,8 @@ private function compileStatement(array $match): string private function replacePHPVariables(): void { $pattern = '/{{ \$(\w+) }}/'; - $replcement = ''; - $this->html = preg_replace($pattern, $replcement, $this->html); + $replacement = ''; + $this->html = preg_replace($pattern, $replacement, $this->html); } /** diff --git a/application/view/controller/hello/index.php b/application/view/controller/hello/index.php index 5e46d0e..5a6c9aa 100644 --- a/application/view/controller/hello/index.php +++ b/application/view/controller/hello/index.php @@ -11,3 +11,5 @@ {{ $i }} @endfor + +{{ $dd }} From 44192e91f77c8cfbb08edba2f74f338c6fc8380d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Je=C5=BC?= Date: Sat, 5 Jul 2025 22:08:31 +0200 Subject: [PATCH 5/6] =?UTF-8?q?Refaktoryzacja=20frameworka=20ShiftPHP:=20w?= =?UTF-8?q?prowadzenie=20systemu=20dependency=20injection,=20poprawa=20obs?= =?UTF-8?q?=C5=82ugi=20b=C5=82=C4=99d=C3=B3w,=20oraz=20zmiana=20architektu?= =?UTF-8?q?ry=20klas=20Request=20i=20App=20na=20instancje.=20Ulepszono=20s?= =?UTF-8?q?ystem=20widok=C3=B3w=20oraz=20dodano=20nowy=20kontener=20serwis?= =?UTF-8?q?=C3=B3w.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Engine/App.php | 118 ++++++++--- Engine/Controller.php | 50 ++++- Engine/Error/ErrorHandler.php | 111 +++++++++++ Engine/Error/ShiftError.php | 40 +++- Engine/Request.php | 157 ++++++--------- Engine/ServiceContainer.php | 110 +++++++++++ Engine/ServiceInterface.php | 25 +++ Engine/Utils/Storage.php | 81 ++++++-- Engine/View.php | 111 +++++++---- REFACTORING.md | 216 +++++++++++++++++++++ application/controller/HelloController.php | 27 ++- bootstrap.php | 15 ++ index.php | 7 +- 13 files changed, 875 insertions(+), 193 deletions(-) create mode 100644 Engine/Error/ErrorHandler.php create mode 100644 Engine/ServiceContainer.php create mode 100644 Engine/ServiceInterface.php create mode 100644 REFACTORING.md diff --git a/Engine/App.php b/Engine/App.php index 7d331b2..e9c5720 100755 --- a/Engine/App.php +++ b/Engine/App.php @@ -4,6 +4,7 @@ use Engine\Error\ShiftError; use ReflectionClass; +use ReflectionException; /** * Class App @@ -11,47 +12,77 @@ */ final class App { - /** - * @var - */ - public static $controller; - public static $defaultController = 'index'; - public static $action; - public static $defaultAction = 'index'; - + private Request $request; + private ServiceContainer $container; + private string $defaultController = 'index'; + private string $defaultAction = 'index'; + private bool $isRunning = false; - /** - * App constructor. - */ - public function __construct() + public function __construct(Request $request) { + $this->request = $request; + $this->container = new ServiceContainer(); + $this->registerDefaultServices(); } /** - * @throws \ReflectionException + * @throws ShiftError */ - public static function start(): void + public function start(): void { - static $run; - if ($run === TRUE) return; - - Request::setup(); - $controller = 'Controllers\\' . ucfirst(Request::getController()) . 'Controller'; + if ($this->isRunning) { + return; + } try { - self::$controller = new $controller(); + $controller = $this->resolveController(); + $this->executeController($controller); + $this->isRunning = true; + } catch (ReflectionException $exception) { + throw new ShiftError( + 'Controller method not found: ' . $exception->getMessage(), + $exception->getCode(), + $exception->getPrevious() + ); } catch (\Throwable $exception) { - throw new ShiftError($exception->getMessage(), $exception->getCode(), $exception->getPrevious()); + throw new ShiftError( + 'Application error: ' . $exception->getMessage(), + $exception->getCode(), + $exception->getPrevious() + ); } + } - $class = new ReflectionClass(self::$controller); + /** + * @throws ShiftError + */ + private function resolveController(): object + { + $controllerName = ucfirst($this->request->getController()) . 'Controller'; + $controllerClass = 'Controllers\\' . $controllerName; - $method = $class->getMethod(Request::getAction()); + if (!class_exists($controllerClass)) { + throw new ShiftError("Controller class '{$controllerClass}' not found"); + } - $method->invokeArgs(self::$controller, Request::getArguments()); - $run = TRUE; + return new $controllerClass(); } + /** + * @throws ReflectionException + */ + private function executeController(object $controller): void + { + $reflectionClass = new ReflectionClass($controller); + $methodName = $this->request->getAction(); + + if (!$reflectionClass->hasMethod($methodName)) { + throw new ReflectionException("Method '{$methodName}' not found in controller"); + } + + $method = $reflectionClass->getMethod($methodName); + $method->invokeArgs($controller, $this->request->getArguments()); + } /** * @param string $class_name @@ -77,11 +108,46 @@ public static function autoload(string $class_name): void require_once($location . $class . '.php'); } } - } public static function setHelpers(): void { require_once 'Utils/helpers.php'; } + + public function getRequest(): Request + { + return $this->request; + } + + public function setDefaultController(string $controller): void + { + $this->defaultController = $controller; + } + + public function setDefaultAction(string $action): void + { + $this->defaultAction = $action; + } + + private function registerDefaultServices(): void + { + $this->container->singleton('request', $this->request); + $this->container->singleton('view', function() { + return new View(); + }); + $this->container->singleton('storage', function() { + return new \Engine\Utils\Storage(); + }); + } + + public function getContainer(): ServiceContainer + { + return $this->container; + } + + public function resolve(string $service) + { + return $this->container->resolve($service); + } } diff --git a/Engine/Controller.php b/Engine/Controller.php index b2087a4..d00c6fc 100755 --- a/Engine/Controller.php +++ b/Engine/Controller.php @@ -6,8 +6,16 @@ * Class Controller * @package Engine */ -class Controller +abstract class Controller { + protected Request $request; + protected View $view; + + public function __construct() + { + $this->request = new Request(); + $this->view = new View(); + } /** * @param string $view @@ -17,8 +25,44 @@ class Controller * @param array $scripts * @return void */ - public function render(string $view, array $data = [], string $title = '', array $styles = [], array $scripts = []): void + protected function render(string $view, array $data = [], string $title = '', array $styles = [], array $scripts = []): void + { + $this->view->make($view, $data, $title, $styles, $scripts); + } + + /** + * @param array $data + * @return void + */ + protected function json(array $data): void + { + header('Content-Type: application/json'); + echo json_encode($data); + } + + /** + * @param string $url + * @return void + */ + protected function redirect(string $url): void + { + header("Location: {$url}"); + exit; + } + + /** + * @return Request + */ + protected function getRequest(): Request + { + return $this->request; + } + + /** + * @return View + */ + protected function getView(): View { - (new View)->make($view, $data, $title, $styles, $scripts); + return $this->view; } } diff --git a/Engine/Error/ErrorHandler.php b/Engine/Error/ErrorHandler.php new file mode 100644 index 0000000..f491448 --- /dev/null +++ b/Engine/Error/ErrorHandler.php @@ -0,0 +1,111 @@ +setFile($file); + $exception->setLine($line); + + self::handleException($exception); + return true; + } + + return false; + } + + public static function handleException(Throwable $exception): void + { + if (self::$customHandler) { + call_user_func(self::$customHandler, $exception); + return; + } + + if (php_sapi_name() === 'cli') { + self::renderCliError($exception); + } else { + self::renderWebError($exception); + } + } + + public static function handleShutdown(): void + { + $error = error_get_last(); + + if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) { + $exception = new ShiftError($error['message'], $error['type']); + $exception->setFile($error['file']); + $exception->setLine($error['line']); + + self::handleException($exception); + } + } + + private static function renderCliError(Throwable $exception): void + { + echo "\n"; + echo "Fatal Error: " . $exception->getMessage() . "\n"; + echo "File: " . $exception->getFile() . "\n"; + echo "Line: " . $exception->getLine() . "\n"; + echo "\nStack Trace:\n"; + echo $exception->getTraceAsString() . "\n"; + echo "\n"; + } + + private static function renderWebError(Throwable $exception): void + { + if ($exception instanceof ShiftError) { + // Use the existing ShiftError rendering + return; + } + + // Simple error rendering for other exceptions + http_response_code(500); + + if (ini_get('display_errors')) { + echo '

Application Error

'; + echo '

Message: ' . htmlspecialchars($exception->getMessage()) . '

'; + echo '

File: ' . htmlspecialchars($exception->getFile()) . '

'; + echo '

Line: ' . $exception->getLine() . '

'; + + if (ini_get('display_errors') === '1') { + echo '

Stack Trace:

'; + echo '
' . htmlspecialchars($exception->getTraceAsString()) . '
'; + } + } else { + echo '

Internal Server Error

'; + echo '

An error occurred while processing your request.

'; + } + } +} \ No newline at end of file diff --git a/Engine/Error/ShiftError.php b/Engine/Error/ShiftError.php index fd680c4..803dcf7 100644 --- a/Engine/Error/ShiftError.php +++ b/Engine/Error/ShiftError.php @@ -18,6 +18,8 @@ */ class ShiftError extends \Error { + private string $customFile = ''; + private int $customLine = 0; /** * ShiftError constructor. @@ -29,8 +31,35 @@ class ShiftError extends \Error public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); - $line = (int)$this->getLine(); - $errorHighlighter = new ErrorHighlighter($this->getFile(), $line); + $this->renderError(); + } + + public function setFile(string $file): void + { + $this->customFile = $file; + } + + public function setLine(int $line): void + { + $this->customLine = $line; + } + + public function getCustomFile(): string + { + return $this->customFile ?: $this->getFile(); + } + + public function getCustomLine(): int + { + return $this->customLine ?: $this->getLine(); + } + + private function renderError(): void + { + $line = (int)$this->getCustomLine(); + $file = $this->getCustomFile(); + + $errorHighlighter = new ErrorHighlighter($file, $line); $highlighted = $errorHighlighter->highlighted; $stackTrace = $errorHighlighter->getBeautyStackTrace($this->getTrace()); @@ -57,18 +86,18 @@ public function __construct(string $message = "", int $code = 0, ?Throwable $pre
' . $this->getMessage() . '
-
' . $this->getFile() . ': ' . $line . '
+
' . $file . ': ' . $line . '
' . $highlighted . $stackTrace->traceItemsCode . '

Stack trace:
- + @@ -99,5 +128,4 @@ public function __construct(string $message = "", int $code = 0, ?Throwable $pre } '; } - } diff --git a/Engine/Request.php b/Engine/Request.php index 0fc0e2a..a77d9f8 100755 --- a/Engine/Request.php +++ b/Engine/Request.php @@ -8,138 +8,101 @@ */ class Request { - - /** - * @var - */ - protected static $array; - - /** - * @var - */ - protected static $controller; - - /** - * @var - */ - protected static $action; - - /** - * @var - */ - protected static $arguments = []; - - /** - * @var - */ - protected static $path; - - /** - * - */ - public static function setup(): void + private string $path; + private string $controller; + private string $action; + private array $arguments = []; + private array $queryParams = []; + private array $postData = []; + private array $serverData = []; + + public function __construct() { + $this->serverData = $_SERVER; + $this->queryParams = $_GET; + $this->postData = $_POST; + $this->parseRequest(); + } - self::$path = $_SERVER['REQUEST_URI']; - - $get = $_GET; - $post = $_POST; - - if (strpos(self::$path, '?') !== false) { - $arr = explode('?', self::$path); - self::$path = $arr[0]; + private function parseRequest(): void + { + $this->path = $this->serverData['REQUEST_URI'] ?? '/'; + + // Remove query string from path + if (strpos($this->path, '?') !== false) { + $parts = explode('?', $this->path); + $this->path = $parts[0]; } - self::$array = explode('/', trim(self::$path, '/')); - - self::$controller = (self::$array[0] ?? App::$defaultController) ?: App::$defaultController; - self::$action = (self::$array[1] ?? App::$defaultAction) ?: App::$defaultAction; - - if (count(self::$array) > 2) { - $tmp = array_slice(self::$array, 2, count(self::$array)); - self::$arguments = $tmp; + $pathSegments = explode('/', trim($this->path, '/')); + + $this->controller = $pathSegments[0] ?? 'index'; + $this->action = $pathSegments[1] ?? 'index'; + + // Extract arguments from path segments + if (count($pathSegments) > 2) { + $this->arguments = array_slice($pathSegments, 2); } + } + + public function getPath(): string + { + return $this->path; + } -// dd(Request::getArray(), Request::getArguments() , 'sdad', $get, $post); + public function getController(): string + { + return $this->controller; } - /** - * @return array - */ - public static function getArray(): array + public function getAction(): string { - return self::$array; + return $this->action; } - /** - * @param array $array - */ - public static function setArray(array $array): void + public function getArguments(): array { - self::$array = $array; + return $this->arguments; } - /** - * @return string - */ - public static function getController(): string + public function getQueryParams(): array { - return self::$controller; + return $this->queryParams; } - /** - * @param string $controller - */ - public static function setController(string $controller): void + public function getPostData(): array { - self::$controller = $controller; + return $this->postData; } - /** - * @return string - */ - public static function getAction(): string + public function getMethod(): string { - return self::$action; + return $this->serverData['REQUEST_METHOD'] ?? 'GET'; } - /** - * @param string $action - */ - public static function setAction($action): void + public function isPost(): bool { - self::$action = $action; + return $this->getMethod() === 'POST'; } - /** - * @return array - */ - public static function getArguments(): array + public function isGet(): bool { - return self::$arguments; + return $this->getMethod() === 'GET'; } - /** - * @param string $arguments - */ - public static function setArguments($arguments): void + public function getHeader(string $name): ?string { - self::$arguments = $arguments; + $headerKey = 'HTTP_' . strtoupper(str_replace('-', '_', $name)); + return $this->serverData[$headerKey] ?? null; } - /** - * @return string - */ - public static function getPath(): string + public function getUserAgent(): ?string { - return self::$path; + return $this->serverData['HTTP_USER_AGENT'] ?? null; } - /** - * @param string $path - */ - public static function setPath($path): void + public function getIpAddress(): ?string { - self::$path = $path; + return $this->serverData['REMOTE_ADDR'] ?? null; } } diff --git a/Engine/ServiceContainer.php b/Engine/ServiceContainer.php new file mode 100644 index 0000000..91ff3e1 --- /dev/null +++ b/Engine/ServiceContainer.php @@ -0,0 +1,110 @@ +services[$name] = $service; + } + + /** + * Register a singleton service + */ + public function singleton(string $name, $service): void + { + $this->singletons[$name] = $service; + } + + /** + * Resolve a service + */ + public function resolve(string $name) + { + // Check if already resolved + if (isset($this->resolved[$name])) { + return $this->resolved[$name]; + } + + // Check singletons first + if (isset($this->singletons[$name])) { + $service = $this->singletons[$name]; + $instance = $this->createInstance($service); + $this->resolved[$name] = $instance; + return $instance; + } + + // Check regular services + if (isset($this->services[$name])) { + $service = $this->services[$name]; + return $this->createInstance($service); + } + + throw new InvalidArgumentException("Service '{$name}' not found"); + } + + /** + * Check if service exists + */ + public function has(string $name): bool + { + return isset($this->services[$name]) || isset($this->singletons[$name]); + } + + /** + * Create instance from service definition + */ + private function createInstance($service) + { + if ($service instanceof Closure) { + return $service($this); + } + + if (is_string($service) && class_exists($service)) { + return new $service(); + } + + return $service; + } + + /** + * Clear all services + */ + public function clear(): void + { + $this->services = []; + $this->singletons = []; + $this->resolved = []; + } + + /** + * Get all registered service names + */ + public function getRegisteredServices(): array + { + return array_keys($this->services); + } + + /** + * Get all singleton service names + */ + public function getSingletonServices(): array + { + return array_keys($this->singletons); + } +} \ No newline at end of file diff --git a/Engine/ServiceInterface.php b/Engine/ServiceInterface.php new file mode 100644 index 0000000..ab55e72 --- /dev/null +++ b/Engine/ServiceInterface.php @@ -0,0 +1,25 @@ +initializePaths(); + $this->ensureDirectoriesExist(); + } + + private function initializePaths(): void { $storageParentDir = dirname(__DIR__) . '/'; - $this->storageDir = $storageParentDir . '/storage/'; - $this->storageViewsDir = $this->storageDir . '/views/'; - $this->checkDir($this->storageViewsDir); + $this->storageDir = $storageParentDir . 'storage/'; + $this->storageViewsDir = $this->storageDir . 'views/'; + } + + private function ensureDirectoriesExist(): void + { + $this->createDirectoryIfNotExists($this->storageDir); + $this->createDirectoryIfNotExists($this->storageViewsDir); } - private function checkDir(string $dir): void + /** + * @throws StorageError + */ + private function createDirectoryIfNotExists(string $dir): void { - if (!file_exists($dir) && !mkdir($dir, 0777, true) && !is_dir($dir)) { - throw new RuntimeException(sprintf('Directory "%s" was not created', $dir)); + if (file_exists($dir)) { + $this->validateDirectory($dir); + return; } - if (!file_exists($dir)) { - throw new StorageError('Directory ' . $dir . ' does not exists'); + + if (!mkdir($dir, 0755, true)) { + throw new StorageError("Failed to create directory: {$dir}"); } + + $this->validateDirectory($dir); + } + + /** + * @throws StorageError + */ + private function validateDirectory(string $dir): void + { + if (!is_dir($dir)) { + throw new StorageError("Path '{$dir}' is not a directory"); + } + if (!is_writable($dir)) { - throw new StorageError('Directory ' . $dir . ' is not writable'); + throw new StorageError("Directory '{$dir}' is not writable"); } } + /** + * @throws StorageError + */ public function saveView(string $name, string $content): void { - if (!file_exists($this->storageViewsDir) && !mkdir($concurrentDirectory = $this->storageViewsDir, 0777, true) && !is_dir($concurrentDirectory)) { - throw new RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory)); + $filePath = $this->storageViewsDir . $name; + + if (file_put_contents($filePath, $content) === false) { + throw new StorageError("Failed to save view file: {$filePath}"); } + } + + public function getStorageDir(): string + { + return $this->storageDir; + } - file_put_contents($this->storageViewsDir . $name, $content); + public function getStorageViewsDir(): string + { + return $this->storageViewsDir; + } + + public function clearViews(): void + { + $files = glob($this->storageViewsDir . '*.php'); + foreach ($files as $file) { + if (is_file($file)) { + unlink($file); + } + } } } diff --git a/Engine/View.php b/Engine/View.php index 692f870..15ab3f6 100755 --- a/Engine/View.php +++ b/Engine/View.php @@ -19,17 +19,22 @@ */ class View { + private string $title = ''; + private array $scripts = []; + private array $styles = []; + private Storage $storage; + private string $templatePath; + private string $viewPath; + + public function __construct() + { + $this->storage = new Storage(); + $this->templatePath = __DIR__ . '/../application/view/template/index.php'; + $this->viewPath = __DIR__ . '/../application/view/controller/'; + } /** - * @var string - */ - private string $_title = ''; - private array $_scripts = []; - private array $_styles = []; - - - /** - * @param null|string $view + * @param string|null $view * @param array $data * @param string $title * @param array $styles @@ -42,45 +47,69 @@ public function make(?string $view, array $data = [], string $title = '', array $this->setScripts($scripts); $this->setStyles($styles); - if (!$view) { - $view = 'default'; - } - - $storage = new Storage(); + $viewName = $this->resolveViewName($view); + $viewContent = $this->loadViewContent($viewName); + $templateContent = $this->loadTemplateContent(); + + $fullView = $this->buildFullView($templateContent, $viewContent); + $this->renderView($fullView, $viewName, $data); + } - if (!file_exists(__DIR__ . '/../application/view/template/index.php')) { - throw new ShiftError('Template ' . $view . ' does not exists'); + private function resolveViewName(?string $view): string + { + if (!$view || $view === 'default') { + return Request::getController() . '/' . Request::getAction(); } - $template = file_get_contents(__DIR__ . '/../application/view/template/index.php'); + return $view; + } - if ($view === 'default') { - $view = Request::getController() . '/' . Request::getAction(); + /** + * @throws ShiftError + */ + private function loadViewContent(string $viewName): string + { + $viewFile = $this->viewPath . $viewName . '.php'; + + if (!file_exists($viewFile)) { + throw new ShiftError("View '{$viewName}' does not exist at path: {$viewFile}"); } + + return file_get_contents($viewFile); + } - if (!file_exists(__DIR__ . '/../application/view/controller/' . $view . '.php')) { - throw new ShiftError('View ' . $view . ' does not exists'); + /** + * @throws ShiftError + */ + private function loadTemplateContent(): string + { + if (!file_exists($this->templatePath)) { + throw new ShiftError("Template does not exist at path: {$this->templatePath}"); } - $viewContent = file_get_contents(__DIR__ . '/../application/view/controller/' . $view . '.php'); - - $viewName = md5($view) . '.php'; + + return file_get_contents($this->templatePath); + } - $fullView = str_replace('{{ $view }}', $viewContent, $template); + private function buildFullView(string $template, string $viewContent): string + { + return str_replace('{{ $view }}', $viewContent, $template); + } + private function renderView(string $fullView, string $viewName, array $data): void + { $builder = new ViewBuilder($fullView); - $builder - ->setScripts($this->_scripts) - ->setStyles($this->_styles) - ->setTitle($this->_title) + ->setScripts($this->scripts) + ->setStyles($this->styles) + ->setTitle($this->title) ->build(); - $storage->saveView( - $viewName, - $builder->getView() - ); - - require_once $storage->storageViewsDir . $viewName; + $viewFileName = md5($viewName) . '.php'; + $this->storage->saveView($viewFileName, $builder->getView()); + // Extract variables for view + extract($data); + + require_once $this->storage->storageViewsDir . $viewFileName; } /** @@ -88,7 +117,7 @@ public function make(?string $view, array $data = [], string $title = '', array */ public function getTitle(): string { - return $this->_title; + return $this->title; } /** @@ -96,7 +125,7 @@ public function getTitle(): string */ public function setTitle(string $title): void { - $this->_title = $title; + $this->title = $title; } /** @@ -104,7 +133,7 @@ public function setTitle(string $title): void */ public function getScripts(): array { - return $this->_scripts; + return $this->scripts; } /** @@ -112,7 +141,7 @@ public function getScripts(): array */ public function setScripts(array $scripts): void { - $this->_scripts = $scripts; + $this->scripts = $scripts; } /** @@ -120,7 +149,7 @@ public function setScripts(array $scripts): void */ public function getStyles(): array { - return $this->_styles; + return $this->styles; } /** @@ -128,6 +157,6 @@ public function getStyles(): array */ public function setStyles(array $styles): void { - $this->_styles = $styles; + $this->styles = $styles; } } diff --git a/REFACTORING.md b/REFACTORING.md new file mode 100644 index 0000000..164b850 --- /dev/null +++ b/REFACTORING.md @@ -0,0 +1,216 @@ +# ShiftPHP Framework - Refaktoryzacja + +## 🎯 **Przegląd zmian** + +Ten dokument opisuje kompleksową refaktoryzację frameworka ShiftPHP, która wprowadza nowoczesne wzorce projektowe, poprawia architekturę i zwiększa możliwości testowania. + +## 📋 **Lista zmian** + +### 1. **Refaktoryzacja klasy Request** +- **Przed**: Statyczne metody i właściwości +- **Po**: Instancje klas z dependency injection +- **Korzyści**: + - Łatwiejsze testowanie + - Lepsze zarządzanie stanem + - Dodatkowe metody (isPost, isGet, getHeader, etc.) + +### 2. **Refaktoryzacja klasy App** +- **Przed**: Statyczne metody, globalny stan +- **Po**: Instancje z dependency injection +- **Korzyści**: + - Kontrola cyklu życia aplikacji + - Możliwość testowania + - Lepsze zarządzanie błędami + +### 3. **Ulepszenie systemu widoków** +- **Przed**: Monolityczna klasa View +- **Po**: Podzielona na mniejsze, wyspecjalizowane metody +- **Korzyści**: + - Lepsze separation of concerns + - Łatwiejsze utrzymanie + - Czytelniejszy kod + +### 4. **Poprawa klasy Storage** +- **Przed**: Podstawowa walidacja, publiczne właściwości +- **Po**: Zaawansowana walidacja, enkapsulacja +- **Korzyści**: + - Bezpieczniejsze operacje na plikach + - Lepsze zarządzanie błędami + - Dodatkowe funkcje (clearViews) + +### 5. **Nowy system obsługi błędów** +- **Nowe**: Klasa ErrorHandler z centralnym zarządzaniem +- **Korzyści**: + - Spójna obsługa błędów + - Wsparcie dla CLI i web + - Możliwość customizacji + +### 6. **Service Container** +- **Nowe**: System dependency injection +- **Korzyści**: + - Loose coupling + - Łatwiejsze testowanie + - Zarządzanie zależnościami + +## 🔧 **Szczegóły techniczne** + +### Dependency Injection + +```php +// Przed +$app = new App(); +App::start(); + +// Po +$request = new Request(); +$app = new App($request); +$app->start(); +``` + +### Service Container + +```php +// Rejestracja serwisów +$app->getContainer()->singleton('database', function() { + return new Database(); +}); + +// Resolwowanie serwisów +$database = $app->resolve('database'); +``` + +### Obsługa błędów + +```php +// Automatyczna rejestracja w bootstrap.php +\Engine\Error\ErrorHandler::register(); + +// Custom handler +\Engine\Error\ErrorHandler::setCustomHandler(function($exception) { + // Custom error handling +}); +``` + +## 📁 **Struktura plików** + +``` +Engine/ +├── App.php # Główna klasa aplikacji (refaktoryzowana) +├── Request.php # Obsługa żądań (refaktoryzowana) +├── Controller.php # Bazowa klasa kontrolera (ulepszona) +├── View.php # System widoków (refaktoryzowany) +├── ServiceContainer.php # NOWY: Container dla DI +├── ServiceInterface.php # NOWY: Interfejs dla serwisów +├── Error/ +│ ├── ErrorHandler.php # NOWY: Centralny system błędów +│ └── ShiftError.php # Ulepszona obsługa błędów +└── Utils/ + └── Storage.php # Ulepszona klasa Storage +``` + +## 🚀 **Korzyści z refaktoryzacji** + +### 1. **Testowalność** +- Wszystkie klasy można teraz łatwo testować +- Dependency injection umożliwia mockowanie +- Brak globalnego stanu + +### 2. **Maintainability** +- Czytelniejszy kod +- Lepsze separation of concerns +- Mniejsze klasy z jedną odpowiedzialnością + +### 3. **Extensibility** +- Service container umożliwia łatwe dodawanie nowych serwisów +- Modularna architektura +- Interfejsy dla rozszerzeń + +### 4. **Error Handling** +- Centralny system obsługi błędów +- Lepsze logowanie +- Wsparcie dla różnych środowisk + +## 🔄 **Migracja** + +### Dla istniejących kontrolerów: + +```php +// Przed +class MyController extends \Engine\Controller +{ + public function index() + { + $this->render('view', ['data' => 'value']); + } +} + +// Po (bez zmian w API!) +class MyController extends \Engine\Controller +{ + public function index() + { + $this->render('view', ['data' => 'value']); + // Dodatkowo dostępne: + $this->json(['status' => 'success']); + $this->redirect('/home'); + } +} +``` + +### Dla punktu wejścia: + +```php +// Przed +require_once 'bootstrap.php'; +Engine\App::start(); + +// Po +require_once 'bootstrap.php'; +$request = new Engine\Request(); +$app = new Engine\App($request); +$app->start(); +``` + +## 🧪 **Testowanie** + +Framework jest teraz w pełni testowalny: + +```php +// Przykład testu +$request = $this->createMock(Engine\Request::class); +$request->method('getController')->willReturn('test'); +$request->method('getAction')->willReturn('index'); + +$app = new Engine\App($request); +// Test aplikacji... +``` + +## 📈 **Wydajność** + +- Brak statycznych właściwości = lepsze zarządzanie pamięcią +- Service container z singletonami = optymalizacja zasobów +- Lepsze zarządzanie błędami = szybsze debugowanie + +## 🔮 **Przyszłe rozszerzenia** + +Refaktoryzacja przygotowuje framework na: + +1. **Middleware system** +2. **Event system** +3. **Database abstraction layer** +4. **Caching system** +5. **CLI commands** +6. **API routing** + +## 📝 **Podsumowanie** + +Refaktoryzacja ShiftPHP wprowadza: + +- ✅ **Dependency Injection** +- ✅ **Service Container** +- ✅ **Lepsze zarządzanie błędami** +- ✅ **Testowalność** +- ✅ **Maintainability** +- ✅ **Extensibility** + +Framework jest teraz gotowy na przyszłe rozszerzenia i łatwiejszy w utrzymaniu. \ No newline at end of file diff --git a/application/controller/HelloController.php b/application/controller/HelloController.php index 297bb99..5dc2ef6 100755 --- a/application/controller/HelloController.php +++ b/application/controller/HelloController.php @@ -8,9 +8,32 @@ */ class HelloController extends \Engine\Controller { - public function index(): void { - $this->render('default', ['dd' => 'asd'], 'ssadfg'); + $this->render('default', [ + 'message' => 'Hello from ShiftPHP!', + 'timestamp' => date('Y-m-d H:i:s') + ], 'Welcome to ShiftPHP'); + } + + public function about(): void + { + $this->render('hello/about', [ + 'title' => 'About ShiftPHP', + 'version' => '1.0.0' + ], 'About - ShiftPHP'); + } + + public function api(): void + { + $this->json([ + 'status' => 'success', + 'message' => 'API endpoint working!', + 'data' => [ + 'controller' => $this->request->getController(), + 'action' => $this->request->getAction(), + 'arguments' => $this->request->getArguments() + ] + ]); } } diff --git a/bootstrap.php b/bootstrap.php index e0081b7..8282e3a 100755 --- a/bootstrap.php +++ b/bootstrap.php @@ -1,7 +1,22 @@ start(); From 53b22e856e00e12aa1b74791b337fa1c730f22d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Je=C5=BC?= Date: Sat, 5 Jul 2025 22:11:13 +0200 Subject: [PATCH 6/6] =?UTF-8?q?Zmiana=20sta=C5=82ych=20kolor=C3=B3w=20ANSI?= =?UTF-8?q?=20z=20`const`=20na=20`static`=20w=20klasie=20`Cli`=20dla=20pop?= =?UTF-8?q?rawy=20zgodno=C5=9Bci=20z=20PHP=208.3=20oraz=20refaktoryzacja?= =?UTF-8?q?=20metod=20wyj=C5=9Bciowych.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Engine/Console/Cli.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Engine/Console/Cli.php b/Engine/Console/Cli.php index 9664bf3..5a35cfc 100644 --- a/Engine/Console/Cli.php +++ b/Engine/Console/Cli.php @@ -8,11 +8,11 @@ class Cli { // Kody kolorów ANSI - private const string COLOR_DEFAULT = "\033[0m"; - private const string COLOR_BLUE = "\033[0;34m"; - private const string COLOR_RED = "\033[0;31m"; - private const string COLOR_GREEN = "\033[0;32m"; - private const string COLOR_YELLOW = "\033[0;33m"; + private static $COLOR_DEFAULT = "\033[0m"; + private static $COLOR_BLUE = "\033[0;34m"; + private static $COLOR_RED = "\033[0;31m"; + private static $COLOR_GREEN = "\033[0;32m"; + private static $COLOR_YELLOW = "\033[0;33m"; /** * Wyświetla informację w kolorze niebieskim @@ -23,7 +23,7 @@ class Cli */ public function info(string $message, bool $newLine = true): void { - $this->output(self::COLOR_BLUE . $message . self::COLOR_DEFAULT, $newLine); + $this->output(self::$COLOR_BLUE . $message . self::$COLOR_DEFAULT, $newLine); } /** @@ -47,7 +47,7 @@ public function debug(string $message, bool $newLine = true): void */ public function error(string $message, bool $newLine = true): void { - $this->output(self::COLOR_RED . $message . self::COLOR_DEFAULT, $newLine); + $this->output(self::$COLOR_RED . $message . self::$COLOR_DEFAULT, $newLine); } /** @@ -59,7 +59,7 @@ public function error(string $message, bool $newLine = true): void */ public function success(string $message, bool $newLine = true): void { - $this->output(self::COLOR_GREEN . $message . self::COLOR_DEFAULT, $newLine); + $this->output(self::$COLOR_GREEN . $message . self::$COLOR_DEFAULT, $newLine); } /** @@ -71,7 +71,7 @@ public function success(string $message, bool $newLine = true): void */ public function warning(string $message, bool $newLine = true): void { - $this->output(self::COLOR_YELLOW . $message . self::COLOR_DEFAULT, $newLine); + $this->output(self::$COLOR_YELLOW . $message . self::$COLOR_DEFAULT, $newLine); } /**
' . $line . ' - ' . str_replace(APP_ROOT . '/', '', $this->getFile()) . ' + ' . str_replace(APP_ROOT . '/', '', $file) . '