feat: add validation and use opencart logger
This commit is contained in:
@@ -8,6 +8,7 @@ use Cart\Currency;
|
||||
use Cart\Tax;
|
||||
use Openguru\OpenCartFramework\ImageTool\ImageTool;
|
||||
use Openguru\OpenCartFramework\ImageTool\ImageToolInterface;
|
||||
use Openguru\OpenCartFramework\Logger\OpenCartLogAdapter;
|
||||
|
||||
$sysLibPath = rtrim(DIR_SYSTEM, '/') . '/library/oc_telegram_shop';
|
||||
$basePath = rtrim(DIR_APPLICATION, '/') . '/..';
|
||||
@@ -26,6 +27,9 @@ class Controllerextensiontgshophandle extends Controller
|
||||
{
|
||||
public function index(): void
|
||||
{
|
||||
$this->load->model('checkout/order');
|
||||
$this->session->data['language'] = $this->config->get('config_language');
|
||||
|
||||
$app = ApplicationFactory::create([
|
||||
'app_enabled' => filter_var($this->config->get('module_tgshop_status'), FILTER_VALIDATE_BOOLEAN),
|
||||
'oc_config_tax' => $this->config->get('config_tax'),
|
||||
@@ -69,40 +73,22 @@ class Controllerextensiontgshophandle extends Controller
|
||||
'cache_products_main' => 60 * 10,
|
||||
]);
|
||||
|
||||
$app->bind(Url::class, function () {
|
||||
return $this->url;
|
||||
});
|
||||
|
||||
$app->bind(Currency::class, function () {
|
||||
return $this->currency;
|
||||
});
|
||||
|
||||
$app->bind(Tax::class, function () {
|
||||
return $this->tax;
|
||||
});
|
||||
|
||||
$app->bind(OcModelCatalogProductAdapter::class, function () {
|
||||
$this->load->model('catalog/product');
|
||||
return new OcModelCatalogProductAdapter($this->model_catalog_product);
|
||||
});
|
||||
|
||||
$app->bind(ImageToolInterface::class, function () {
|
||||
return new ImageTool(DIR_IMAGE, HTTPS_SERVER);
|
||||
});
|
||||
$app->bind(Url::class, fn () => $this->url);
|
||||
$app->bind(Currency::class, fn () => $this->currency);
|
||||
$app->bind(Tax::class, fn () => $this->tax);
|
||||
$app->bind(ImageToolInterface::class, fn () => new ImageTool(DIR_IMAGE, HTTPS_SERVER));
|
||||
$app->bind(Cart::class, fn () => $this->cart);
|
||||
$app->bind(OcRegistryDecorator::class, fn () => new OcRegistryDecorator($this->registry));
|
||||
$app->singleton(Log::class, fn () => $this->log);
|
||||
|
||||
$app->bind(Cart::class, function () {
|
||||
return $this->cart;
|
||||
});
|
||||
|
||||
$app->bind(OcRegistryDecorator::class, function () {
|
||||
return new OcRegistryDecorator($this->registry);
|
||||
});
|
||||
|
||||
$this->load->model('checkout/order');
|
||||
|
||||
$this->session->data['language'] = $this->config->get('config_language');
|
||||
|
||||
$app->bootAndHandleRequest();
|
||||
$app
|
||||
->withLogger(fn () => new OpenCartLogAdapter($this->log, 'TeleCart'))
|
||||
->bootAndHandleRequest();
|
||||
}
|
||||
|
||||
function extractPureJs($input)
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Openguru\\OpenCartFramework\\": "framework/",
|
||||
"App\\": "src/"
|
||||
"App\\": "src/",
|
||||
"Tests\\": "tests/"
|
||||
},
|
||||
"files": [
|
||||
"framework/Support/helpers.php"
|
||||
@@ -21,13 +22,13 @@
|
||||
"psr/container": "^2.0",
|
||||
"ext-json": "*",
|
||||
"intervention/image": "^2.7",
|
||||
"rakit/validation": "^1.4",
|
||||
"vlucas/phpdotenv": "^5.6",
|
||||
"guzzlehttp/guzzle": "^7.9",
|
||||
"symfony/cache": "^5.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"phpstan/phpstan": "^2.1"
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^9.6"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Openguru\OpenCartFramework;
|
||||
|
||||
use Closure;
|
||||
use Dotenv\Dotenv;
|
||||
use InvalidArgumentException;
|
||||
use Openguru\OpenCartFramework\Config\Settings;
|
||||
@@ -9,6 +10,7 @@ use Openguru\OpenCartFramework\Container\Container;
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Http\Request;
|
||||
use Openguru\OpenCartFramework\Logger\Logger;
|
||||
use Openguru\OpenCartFramework\Logger\LoggerInterface;
|
||||
use Openguru\OpenCartFramework\Router\Router;
|
||||
use Openguru\OpenCartFramework\Support\ExecutionTimeProfiler;
|
||||
|
||||
@@ -18,6 +20,16 @@ class Application extends Container
|
||||
private static array $events = [];
|
||||
private array $serviceProviders = [];
|
||||
private array $middlewareStack = [];
|
||||
private LoggerInterface $logger;
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
// Fallback logger
|
||||
$path = rtrim($this->getConfigValue('logs.path'), '/') . '/oc_telegram_shop.log';
|
||||
$this->logger = new Logger($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ExecutionTimeProfiler
|
||||
@@ -42,10 +54,7 @@ class Application extends Container
|
||||
return $container;
|
||||
});
|
||||
|
||||
$this->singleton(Logger::class, function (Container $container) {
|
||||
$path = $container->getConfigValue('logs.path') . '/oc_telegram_shop.log';
|
||||
return new Logger($path, Logger::LEVEL_INFO);
|
||||
});
|
||||
$this->singleton(LoggerInterface::class, fn () => $this->logger);
|
||||
|
||||
$this->singleton(Settings::class, function (Container $container) {
|
||||
return new Settings($container->getConfigValue());
|
||||
@@ -55,7 +64,7 @@ class Application extends Container
|
||||
$dotenv->load();
|
||||
|
||||
$errorHandler = new ErrorHandler(
|
||||
$this->get(Logger::class),
|
||||
$this->get(LoggerInterface::class),
|
||||
$this,
|
||||
);
|
||||
|
||||
@@ -89,17 +98,17 @@ class Application extends Container
|
||||
|
||||
[$controller, $method] = $action;
|
||||
|
||||
if (!class_exists($controller) || !method_exists($controller, $method)) {
|
||||
if (! class_exists($controller) || ! method_exists($controller, $method)) {
|
||||
throw new InvalidArgumentException('Invalid action: ' . $controller . '->' . $method);
|
||||
}
|
||||
|
||||
$this->profiler->addCheckpoint('Handle Middlewares.');
|
||||
|
||||
$next = fn($req) => $this->call($controller, $method);
|
||||
$next = fn ($req) => $this->call($controller, $method);
|
||||
|
||||
foreach (array_reverse($this->middlewareStack) as $class) {
|
||||
$instance = $this->get($class);
|
||||
$next = static fn($req) => $instance->handle($req, $next);
|
||||
$next = static fn ($req) => $instance->handle($req, $next);
|
||||
}
|
||||
|
||||
$response = $next($request);
|
||||
@@ -130,4 +139,11 @@ class Application extends Container
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withLogger(Closure $closure): Application
|
||||
{
|
||||
$this->logger = $closure();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use Openguru\OpenCartFramework\Contracts\ExceptionHandlerInterface;
|
||||
use Openguru\OpenCartFramework\Exceptions\NonLoggableExceptionInterface;
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Http\Response;
|
||||
use Openguru\OpenCartFramework\Logger\Logger;
|
||||
use Openguru\OpenCartFramework\Logger\LoggerInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
@@ -15,10 +15,10 @@ use Throwable;
|
||||
*/
|
||||
class ErrorHandler
|
||||
{
|
||||
private $logger;
|
||||
private LoggerInterface $logger;
|
||||
private Application $app;
|
||||
|
||||
public function __construct(Logger $logger, Application $application)
|
||||
public function __construct(LoggerInterface $logger, Application $application)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->app = $application;
|
||||
|
||||
@@ -4,24 +4,20 @@ namespace Openguru\OpenCartFramework\Logger;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Logger
|
||||
class Logger implements LoggerInterface
|
||||
{
|
||||
private $logFile;
|
||||
private $logLevel;
|
||||
private $maxFileSize; // Максимальный размер файла в байтах
|
||||
|
||||
public const LEVEL_INFO = 1;
|
||||
public const LEVEL_WARNING = 2;
|
||||
public const LEVEL_ERROR = 3;
|
||||
|
||||
public function __construct($logFile, $logLevel = self::LEVEL_INFO, $maxFileSize = 1048576)
|
||||
public function __construct($logFile, $logLevel = LoggerInterface::LEVEL_INFO, $maxFileSize = 1048576)
|
||||
{
|
||||
$this->logFile = $logFile;
|
||||
$this->logLevel = $logLevel;
|
||||
$this->maxFileSize = $maxFileSize;
|
||||
}
|
||||
|
||||
public function log($message, $level = self::LEVEL_INFO)
|
||||
public function log($message, $level = LoggerInterface::LEVEL_INFO)
|
||||
{
|
||||
if ($level < $this->logLevel) {
|
||||
return; // Не логируем, если уровень ниже установленного
|
||||
@@ -39,11 +35,11 @@ class Logger
|
||||
private function getLevelString($level): string
|
||||
{
|
||||
switch ($level) {
|
||||
case self::LEVEL_INFO:
|
||||
case LoggerInterface::LEVEL_INFO:
|
||||
return 'INFO';
|
||||
case self::LEVEL_WARNING:
|
||||
case LoggerInterface::LEVEL_WARNING:
|
||||
return 'WARNING';
|
||||
case self::LEVEL_ERROR:
|
||||
case LoggerInterface::LEVEL_ERROR:
|
||||
return 'ERROR';
|
||||
default:
|
||||
return 'UNKNOWN';
|
||||
@@ -52,17 +48,17 @@ class Logger
|
||||
|
||||
public function info(string $message): void
|
||||
{
|
||||
$this->log($message, self::LEVEL_INFO);
|
||||
$this->log($message, LoggerInterface::LEVEL_INFO);
|
||||
}
|
||||
|
||||
public function warning(string $message): void
|
||||
{
|
||||
$this->log($message, self::LEVEL_WARNING);
|
||||
$this->log($message, LoggerInterface::LEVEL_WARNING);
|
||||
}
|
||||
|
||||
public function error(string $message): void
|
||||
{
|
||||
$this->log($message, self::LEVEL_ERROR);
|
||||
$this->log($message, LoggerInterface::LEVEL_ERROR);
|
||||
}
|
||||
|
||||
private function rotateLogs(): void
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Logger;
|
||||
|
||||
use Throwable;
|
||||
|
||||
interface LoggerInterface
|
||||
{
|
||||
public const LEVEL_INFO = 1;
|
||||
public const LEVEL_WARNING = 2;
|
||||
public const LEVEL_ERROR = 3;
|
||||
|
||||
public function log($message, $level = self::LEVEL_INFO);
|
||||
|
||||
public function info(string $message): void;
|
||||
|
||||
public function warning(string $message): void;
|
||||
|
||||
public function error(string $message): void;
|
||||
|
||||
public function logException(Throwable $exception): void;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Logger;
|
||||
|
||||
use Log;
|
||||
use Throwable;
|
||||
|
||||
class OpenCartLogAdapter implements LoggerInterface
|
||||
{
|
||||
private Log $ocLogger;
|
||||
private string $namespace;
|
||||
|
||||
public function __construct(Log $ocLogger, string $namespace)
|
||||
{
|
||||
$this->ocLogger = $ocLogger;
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
public function log($message, $level = self::LEVEL_INFO): void
|
||||
{
|
||||
$this->ocLogger->write(
|
||||
sprintf(
|
||||
"[%s] [%s] %s\n",
|
||||
$this->namespace,
|
||||
$this->getLevelString($level),
|
||||
$message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function info(string $message): void
|
||||
{
|
||||
$this->log($message);
|
||||
}
|
||||
|
||||
public function warning(string $message): void
|
||||
{
|
||||
$this->log($message, self::LEVEL_WARNING);
|
||||
}
|
||||
|
||||
public function error(string $message): void
|
||||
{
|
||||
$this->log($message, self::LEVEL_ERROR);
|
||||
}
|
||||
|
||||
public function logException(Throwable $exception): void
|
||||
{
|
||||
$this->error(
|
||||
sprintf(
|
||||
"Fatal error %s in %s on line %d\n%s",
|
||||
$exception->getMessage(),
|
||||
$exception->getFile(),
|
||||
$exception->getLine(),
|
||||
$exception->getTraceAsString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function getLevelString($level): string
|
||||
{
|
||||
switch ($level) {
|
||||
case LoggerInterface::LEVEL_INFO:
|
||||
return 'INFO';
|
||||
case LoggerInterface::LEVEL_WARNING:
|
||||
return 'WARNING';
|
||||
case LoggerInterface::LEVEL_ERROR:
|
||||
return 'ERROR';
|
||||
default:
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,14 @@
|
||||
namespace Openguru\OpenCartFramework\Telegram;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use Openguru\OpenCartFramework\Logger\Logger;
|
||||
|
||||
class TelegramService
|
||||
{
|
||||
private Logger $logger;
|
||||
private Client $client;
|
||||
private ?string $botToken;
|
||||
|
||||
public function __construct(Logger $logger, ?string $botToken = null)
|
||||
public function __construct(?string $botToken = null)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->botToken = $botToken;
|
||||
$this->client = $this->createGuzzleClient("https://api.telegram.org/bot{$botToken}/");
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Openguru\OpenCartFramework\Telegram;
|
||||
|
||||
use Openguru\OpenCartFramework\Application;
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
use Openguru\OpenCartFramework\Logger\Logger;
|
||||
|
||||
class TelegramServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -12,10 +11,7 @@ class TelegramServiceProvider extends ServiceProvider
|
||||
{
|
||||
$this->container->singleton(TelegramService::class, function (Application $app) {
|
||||
$botToken = $app->getConfigValue('telegram.bot_token');
|
||||
return new TelegramService(
|
||||
$app->get(Logger::class),
|
||||
$botToken,
|
||||
);
|
||||
return new TelegramService($botToken);
|
||||
});
|
||||
|
||||
$this->container->singleton(SignatureValidator::class, function (Application $app) {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator;
|
||||
|
||||
class ErrorBag
|
||||
{
|
||||
private array $errors;
|
||||
|
||||
public function __construct(array $errors = [])
|
||||
{
|
||||
$this->errors = $errors;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->errors);
|
||||
}
|
||||
|
||||
public function put(string $field, string $message): void
|
||||
{
|
||||
$this->errors[$field][] = $message;
|
||||
}
|
||||
|
||||
public function first(): array
|
||||
{
|
||||
foreach ($this->errors as $error) {
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
|
||||
public function firstOfAll(): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($this->errors as $field => $errors) {
|
||||
if (count($errors) > 0) {
|
||||
$result[$field] = $errors[0];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ValidationRuleNotFoundException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator\ValidationRules;
|
||||
|
||||
use Closure;
|
||||
|
||||
class Email implements ValidationRuleInterface
|
||||
{
|
||||
public function validate(string $field, array $input, Closure $fail): void
|
||||
{
|
||||
$email = $input[$field] ?? '';
|
||||
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$fail('Email is not valid');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator\ValidationRules;
|
||||
|
||||
use Closure;
|
||||
|
||||
class Required implements ValidationRuleInterface
|
||||
{
|
||||
public function validateRequired($value): bool
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_string($value) && trim($value) === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_countable($value) && count($value) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function validate(string $field, array $input, Closure $fail): void
|
||||
{
|
||||
$value = $input[$field] ?? null;
|
||||
|
||||
if ($this->validateRequired($value) === false) {
|
||||
$fail(':field is required');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator\ValidationRules;
|
||||
|
||||
use Closure;
|
||||
|
||||
interface ValidationRuleInterface
|
||||
{
|
||||
public function validate(string $field, array $input, Closure $fail): void;
|
||||
}
|
||||
@@ -2,23 +2,89 @@
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator;
|
||||
|
||||
class Validator
|
||||
{
|
||||
private $input;
|
||||
private $rules;
|
||||
use Openguru\OpenCartFramework\Validator\ValidationRules\ValidationRuleInterface;
|
||||
|
||||
public function __construct(array $input, array $rules)
|
||||
class Validator implements ValidatorInterface
|
||||
{
|
||||
private array $input;
|
||||
private array $rules;
|
||||
private ErrorBag $errors;
|
||||
private array $customMessages;
|
||||
private array $fieldNames;
|
||||
|
||||
public function __construct(array $validationRules = [], array $customMessages = [])
|
||||
{
|
||||
$this->validationRules = $validationRules;
|
||||
$this->customMessages = $customMessages;
|
||||
}
|
||||
|
||||
public function make(array $input, array $rules, array $fieldNames = []): Validator
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->rules = $rules;
|
||||
$this->errors = new ErrorBag();
|
||||
$this->fieldNames = $fieldNames;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function validate(): bool
|
||||
/**
|
||||
* @throws ValidationRuleNotFoundException
|
||||
*/
|
||||
private function validate(): void
|
||||
{
|
||||
foreach ($this->rules as $name => $rule) {
|
||||
$components = explode('|', $rule);
|
||||
foreach ($this->rules as $field => $rule) {
|
||||
$parts = $this->extractParts($rule);
|
||||
|
||||
foreach ($parts as $part) {
|
||||
$validationRule = $this->resolveRuleClass($part);
|
||||
|
||||
$validationRule->validate($field, $this->input, function ($message) use ($part, $field) {
|
||||
$this->errors->put($field, $this->formatMessage($message, $part, $field));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ValidationRuleNotFoundException
|
||||
*/
|
||||
public function fails(): bool
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
return $this->errors->count() > 0;
|
||||
}
|
||||
|
||||
private function extractParts($rule): array
|
||||
{
|
||||
return explode('|', $rule);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ValidationRuleNotFoundException
|
||||
*/
|
||||
private function resolveRuleClass($part): ValidationRuleInterface
|
||||
{
|
||||
$lazyClass = $this->validationRules[$part] ?? null;
|
||||
|
||||
if ($lazyClass === null) {
|
||||
throw new ValidationRuleNotFoundException('Unknown rule "' . $part);
|
||||
}
|
||||
|
||||
return true;
|
||||
return $lazyClass();
|
||||
}
|
||||
|
||||
public function getErrors(): ErrorBag
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
private function formatMessage(string $message, string $rule, string $field): string
|
||||
{
|
||||
$message = $this->customMessages[$rule] ?? $message;
|
||||
$field = $this->fieldNames[$field] ?? $field;
|
||||
|
||||
return str_replace(':field', $field, $message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator;
|
||||
|
||||
interface ValidatorInterface
|
||||
{
|
||||
public function make(array $input, array $rules, array $fieldNames = []): ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @throws ValidationRuleNotFoundException
|
||||
*/
|
||||
public function fails(): bool;
|
||||
|
||||
public function getErrors(): ErrorBag;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator;
|
||||
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
use Openguru\OpenCartFramework\Validator\ValidationRules\Email;
|
||||
use Openguru\OpenCartFramework\Validator\ValidationRules\Required;
|
||||
|
||||
class ValidatorServiceProvider extends ServiceProvider
|
||||
{
|
||||
protected function rules(): array
|
||||
{
|
||||
return [
|
||||
'required' => fn () => $this->container->get(Required::class),
|
||||
'email' => fn () => $this->container->get(Email::class),
|
||||
];
|
||||
}
|
||||
|
||||
public function register(): void
|
||||
{
|
||||
$this->container->bind(ValidatorInterface::class, function () {
|
||||
$langCode = $this->container->getConfigValue('', 'ru');
|
||||
$translationsFile = __DIR__ . "/translations/$langCode.php";
|
||||
|
||||
if (! file_exists($translationsFile)) {
|
||||
$translationsFile = __DIR__ . "/lang/en.php";
|
||||
}
|
||||
|
||||
return new Validator($this->rules(), require $translationsFile);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'required' => ':field обязательно для заполнения.',
|
||||
'email' => 'Неверный e-mail.',
|
||||
];
|
||||
@@ -10,6 +10,7 @@ use Openguru\OpenCartFramework\Router\RouteServiceProvider;
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
use Openguru\OpenCartFramework\Telegram\TelegramServiceProvider;
|
||||
use Openguru\OpenCartFramework\Telegram\TelegramValidateInitDataMiddleware;
|
||||
use Openguru\OpenCartFramework\Validator\ValidatorServiceProvider;
|
||||
|
||||
class ApplicationFactory
|
||||
{
|
||||
@@ -24,6 +25,7 @@ class ApplicationFactory
|
||||
RouteServiceProvider::class,
|
||||
AppServiceProvider::class,
|
||||
TelegramServiceProvider::class,
|
||||
ValidatorServiceProvider::class,
|
||||
])
|
||||
->withMiddlewares([
|
||||
TelegramValidateInitDataMiddleware::class,
|
||||
|
||||
@@ -3,12 +3,18 @@
|
||||
namespace App\Decorators;
|
||||
|
||||
use Cart\Cart;
|
||||
use Cart\Currency;
|
||||
use Config;
|
||||
use Loader;
|
||||
use Registry;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
* @property Loader $load
|
||||
* @property Cart $cart
|
||||
* @property Session $session
|
||||
* @property Currency $currency
|
||||
* @property Config $config
|
||||
* @property \ModelCatalogProduct $model_catalog_product
|
||||
*/
|
||||
class OcRegistryDecorator
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Rakit\Validation\ErrorBag;
|
||||
use Openguru\OpenCartFramework\Validator\ErrorBag;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
|
||||
@@ -9,16 +9,16 @@ use Exception;
|
||||
use Openguru\OpenCartFramework\Config\Settings;
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Http\Request;
|
||||
use Openguru\OpenCartFramework\Logger\Logger;
|
||||
use Openguru\OpenCartFramework\Logger\LoggerInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class ProductsHandler
|
||||
{
|
||||
private Settings $settings;
|
||||
private ProductsService $productsService;
|
||||
private Logger $logger;
|
||||
private LoggerInterface $logger;
|
||||
|
||||
public function __construct(Settings $settings, ProductsService $productsService, Logger $logger)
|
||||
public function __construct(Settings $settings, ProductsService $productsService, LoggerInterface $logger)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->productsService = $productsService;
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Decorators\OcRegistryDecorator;
|
||||
use App\Exceptions\OrderValidationFailedException;
|
||||
use Exception;
|
||||
use Openguru\OpenCartFramework\Config\Settings;
|
||||
use Openguru\OpenCartFramework\Logger\Logger;
|
||||
use Openguru\OpenCartFramework\Logger\LoggerInterface;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
use Openguru\OpenCartFramework\Telegram\TelegramService;
|
||||
use Rakit\Validation\Validator;
|
||||
use Openguru\OpenCartFramework\Validator\ValidationRuleNotFoundException;
|
||||
use Openguru\OpenCartFramework\Validator\ValidatorInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class OrderCreateService
|
||||
@@ -20,7 +23,8 @@ class OrderCreateService
|
||||
private OcRegistryDecorator $oc;
|
||||
private Settings $settings;
|
||||
private TelegramService $telegramService;
|
||||
private Logger $logger;
|
||||
private LoggerInterface $logger;
|
||||
private ValidatorInterface $validator;
|
||||
|
||||
public function __construct(
|
||||
ConnectionInterface $database,
|
||||
@@ -28,7 +32,8 @@ class OrderCreateService
|
||||
OcRegistryDecorator $registry,
|
||||
Settings $settings,
|
||||
TelegramService $telegramService,
|
||||
Logger $logger
|
||||
LoggerInterface $logger,
|
||||
ValidatorInterface $validator
|
||||
) {
|
||||
$this->database = $database;
|
||||
$this->cartService = $cartService;
|
||||
@@ -36,11 +41,16 @@ class OrderCreateService
|
||||
$this->settings = $settings;
|
||||
$this->telegramService = $telegramService;
|
||||
$this->logger = $logger;
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
public function create(array $data, array $meta = []): void
|
||||
{
|
||||
$this->validate($data);
|
||||
try {
|
||||
$this->validate($data);
|
||||
} catch (ValidationRuleNotFoundException $e) {
|
||||
throw new RuntimeException($e->getMessage());
|
||||
}
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$storeId = $this->settings->get('oc_store_id');
|
||||
@@ -170,23 +180,22 @@ class OrderCreateService
|
||||
$this->sendNotifications($orderData, $data['tgData']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ValidationRuleNotFoundException
|
||||
*/
|
||||
private function validate(array $data): void
|
||||
{
|
||||
$validator = new Validator();
|
||||
|
||||
$validation = $validator->make($data, [
|
||||
'firstName' => 'required',
|
||||
'lastName' => 'required',
|
||||
'email' => 'required|email',
|
||||
'phone' => 'required',
|
||||
'address' => 'required',
|
||||
'comment' => 'required',
|
||||
$v = $this->validator->make($data, $this->makeValidationRulesFromSettings(), [
|
||||
'firstName' => 'Имя',
|
||||
'lastName' => 'Фамилия',
|
||||
'email' => 'E-mail',
|
||||
'phone' => 'Номер телефона',
|
||||
'address' => 'Адрес доставки',
|
||||
'comment' => 'Комментарий',
|
||||
]);
|
||||
|
||||
$validation->validate();
|
||||
|
||||
if ($validation->fails()) {
|
||||
throw new OrderValidationFailedException($validation->errors());
|
||||
if ($v->fails()) {
|
||||
throw new OrderValidationFailedException($v->getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,4 +241,16 @@ class OrderCreateService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function makeValidationRulesFromSettings(): array
|
||||
{
|
||||
return [
|
||||
'firstName' => 'required',
|
||||
'lastName' => 'required',
|
||||
'email' => 'required|email',
|
||||
'phone' => 'required',
|
||||
'address' => 'required',
|
||||
'comment' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'config_timezone' => 'UTC',
|
||||
|
||||
'lang' => 'en-gb',
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Openguru\OpenCartFramework\Application;
|
||||
|
||||
class TestCase extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected Application $app;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$config = [];
|
||||
|
||||
$this->app = new Application($config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Validator;
|
||||
|
||||
use Openguru\OpenCartFramework\Validator\ErrorBag;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ErrorBagTest extends TestCase
|
||||
{
|
||||
public function testFirstOfAll(): void
|
||||
{
|
||||
$errorBag = new ErrorBag([
|
||||
'foo' => ['one', 'two'],
|
||||
'bar' => ['three', 'four'],
|
||||
]);
|
||||
|
||||
$expected = [
|
||||
'foo' => 'one',
|
||||
'bar' => 'three',
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $errorBag->firstOfAll());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Validator;
|
||||
|
||||
use Openguru\OpenCartFramework\Validator\ValidationRuleNotFoundException;
|
||||
use Openguru\OpenCartFramework\Validator\ValidationRules\Required;
|
||||
use Openguru\OpenCartFramework\Validator\Validator;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass Validator
|
||||
*/
|
||||
class ValidatorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Validator::fails()
|
||||
* @covers Validator::make()
|
||||
*/
|
||||
public function testValidateBasic(): void
|
||||
{
|
||||
$validator = new Validator();
|
||||
$this->assertFalse($validator->make([], [])->fails());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Validator::fails()
|
||||
*/
|
||||
public function testThrowExceptionIfRuleNotFound(): void
|
||||
{
|
||||
$validator = new Validator();
|
||||
$v = $validator->make([], [
|
||||
'field' => 'not_exists_rule',
|
||||
]);
|
||||
|
||||
$this->expectException(ValidationRuleNotFoundException::class);
|
||||
|
||||
$v->fails();
|
||||
}
|
||||
|
||||
public function testRequiredForNonExistentField(): void
|
||||
{
|
||||
$validator = new Validator([
|
||||
'required' => fn () => new Required(),
|
||||
]);
|
||||
|
||||
$v = $validator->make(['xyz' => 'abc'], ['foo' => 'required']);
|
||||
|
||||
$this->assertTrue($v->fails());
|
||||
$this->assertEquals(1, $v->getErrors()->count());
|
||||
$this->assertEquals(['foo is required'], $v->getErrors()->first());
|
||||
}
|
||||
|
||||
public function testRequiredForEmptyField(): void
|
||||
{
|
||||
$validator = new Validator([
|
||||
'required' => fn () => new Required(),
|
||||
]);
|
||||
|
||||
$v = $validator->make(['foo' => ''], ['foo' => 'required']);
|
||||
|
||||
$this->assertTrue($v->fails());
|
||||
$this->assertEquals(1, $v->getErrors()->count());
|
||||
$this->assertEquals(['foo is required'], $v->getErrors()->first());
|
||||
}
|
||||
|
||||
public function testRequiredForFalseValue(): void
|
||||
{
|
||||
$validator = new Validator([
|
||||
'required' => fn () => new Required(),
|
||||
]);
|
||||
|
||||
$v = $validator->make(['foo' => false], ['foo' => 'required']);
|
||||
|
||||
$this->assertFalse($v->fails());
|
||||
}
|
||||
|
||||
public function testRequiredForNullValue(): void
|
||||
{
|
||||
$validator = new Validator([
|
||||
'required' => fn () => new Required(),
|
||||
]);
|
||||
|
||||
$v = $validator->make(['foo' => null], ['foo' => 'required']);
|
||||
|
||||
$this->assertTrue($v->fails());
|
||||
$this->assertEquals(1, $v->getErrors()->count());
|
||||
$this->assertEquals(['foo is required'], $v->getErrors()->first());
|
||||
}
|
||||
|
||||
public function testRequiredForZero(): void
|
||||
{
|
||||
$validator = new Validator([
|
||||
'required' => fn () => new Required(),
|
||||
]);
|
||||
|
||||
$v = $validator->make(['foo' => 0], ['foo' => 'required']);
|
||||
|
||||
$this->assertFalse($v->fails());
|
||||
}
|
||||
|
||||
public function testRequiredForZeroString(): void
|
||||
{
|
||||
$validator = new Validator([
|
||||
'required' => fn () => new Required(),
|
||||
]);
|
||||
|
||||
$v = $validator->make(['foo' => "0"], ['foo' => 'required']);
|
||||
|
||||
$this->assertFalse($v->fails());
|
||||
}
|
||||
|
||||
public function testCustomValidationMessages(): void
|
||||
{
|
||||
$customMessages = [
|
||||
'required' => ':field is very required',
|
||||
];
|
||||
|
||||
$validator = new Validator([
|
||||
'required' => fn () => new Required(),
|
||||
], $customMessages);
|
||||
|
||||
$v = $validator->make(['foo' => ''], ['foo' => 'required']);
|
||||
|
||||
$this->assertTrue($v->fails());
|
||||
$this->assertEquals(1, $v->getErrors()->count());
|
||||
$this->assertEquals(['foo is very required'], $v->getErrors()->first());
|
||||
}
|
||||
|
||||
public function testCustomFieldNames(): void
|
||||
{
|
||||
$validator = new Validator([
|
||||
'required' => fn () => new Required(),
|
||||
]);
|
||||
|
||||
$v = $validator->make(['foo' => ''], [
|
||||
'foo' => 'required'
|
||||
], [
|
||||
'foo' => 'My Field'
|
||||
]);
|
||||
|
||||
$this->assertTrue($v->fails());
|
||||
$this->assertEquals(1, $v->getErrors()->count());
|
||||
$this->assertEquals(['My Field is required'], $v->getErrors()->first());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user