Compare commits
7 Commits
5e68f7dd64
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d97114915 | |||
| ece0147b3a | |||
| d133898383 | |||
| 9f8c2b1959 | |||
| 404e2089eb | |||
| 58c9b298db | |||
| 72415949e3 |
@@ -41,6 +41,10 @@ ContainerFactory::build(Environment $env, Config $config, string $basePath): Con
|
|||||||
|
|
||||||
- Autowiring включён всегда
|
- Autowiring включён всегда
|
||||||
- В prod: `$builder->enableCompilation($basePath . '/var/cache/prod/')`
|
- В prod: `$builder->enableCompilation($basePath . '/var/cache/prod/')`
|
||||||
|
- Автоматически регистрирует `Config::class`, `Environment::class` и `LoggerInterface::class`
|
||||||
|
в контейнере — любой класс может получить их через DI без ручного биндинга в `services.php`
|
||||||
|
- `LoggerInterface` по умолчанию резолвится в `CompositeLogger([StdoutLogger])`;
|
||||||
|
если задан `log.file` — добавляется `FileLogger`
|
||||||
- Загружает `$basePath/config/routes.php` (если есть) — файл возвращает `RouteDefinition[]`,
|
- Загружает `$basePath/config/routes.php` (если есть) — файл возвращает `RouteDefinition[]`,
|
||||||
фреймворк автоматически создаёт `Router` и регистрирует его в контейнере
|
фреймворк автоматически создаёт `Router` и регистрирует его в контейнере
|
||||||
- Загружает `$basePath/config/services.php` (если есть) — файл возвращает
|
- Загружает `$basePath/config/services.php` (если есть) — файл возвращает
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ final class JwtService
|
|||||||
$signer = new Sha256();
|
$signer = new Sha256();
|
||||||
$key = InMemory::plainText($secret);
|
$key = InMemory::plainText($secret);
|
||||||
|
|
||||||
$this->jwtConfig = Configuration::forSymmetricSigner($signer, $key);
|
$jwtConfig = Configuration::forSymmetricSigner($signer, $key);
|
||||||
$this->jwtConfig->setValidationConstraints(
|
$this->jwtConfig = $jwtConfig->withValidationConstraints(
|
||||||
new SignedWith($signer, $key),
|
new SignedWith($signer, $key),
|
||||||
new StrictValidAt(new class implements ClockInterface {
|
new StrictValidAt(new class implements ClockInterface {
|
||||||
public function now(): DateTimeImmutable
|
public function now(): DateTimeImmutable
|
||||||
@@ -45,6 +45,7 @@ final class JwtService
|
|||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable();
|
||||||
$token = $this->jwtConfig->builder()
|
$token = $this->jwtConfig->builder()
|
||||||
->issuedAt($now)
|
->issuedAt($now)
|
||||||
|
->canOnlyBeUsedAfter($now)
|
||||||
->expiresAt($now->modify("+{$this->accessTtl} seconds"))
|
->expiresAt($now->modify("+{$this->accessTtl} seconds"))
|
||||||
->relatedTo($userId)
|
->relatedTo($userId)
|
||||||
->getToken($this->jwtConfig->signer(), $this->jwtConfig->signingKey());
|
->getToken($this->jwtConfig->signer(), $this->jwtConfig->signingKey());
|
||||||
|
|||||||
@@ -13,13 +13,30 @@ final class ConsoleApplication
|
|||||||
|
|
||||||
public function run(array $argv): int
|
public function run(array $argv): int
|
||||||
{
|
{
|
||||||
$commandStr = $argv[1] ?? null;
|
if (!isset($argv[1]) || $argv[1] === 'help') {
|
||||||
|
|
||||||
if ($commandStr === null || $commandStr === 'help') {
|
|
||||||
$this->printHelp($argv[2] ?? null);
|
$this->printHelp($argv[2] ?? null);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split argv (after script name) into positional command tokens and option tokens.
|
||||||
|
// Positional tokens form the command string matched against command signatures
|
||||||
|
// (e.g. "users:create admin"). Tokens from the first "--" onwards are options.
|
||||||
|
$positional = [];
|
||||||
|
$optionTokens = [];
|
||||||
|
$inOptions = false;
|
||||||
|
for ($i = 1, $n = count($argv); $i < $n; $i++) {
|
||||||
|
$tok = $argv[$i];
|
||||||
|
if (!$inOptions && str_starts_with($tok, '--')) {
|
||||||
|
$inOptions = true;
|
||||||
|
}
|
||||||
|
if ($inOptions) {
|
||||||
|
$optionTokens[] = $tok;
|
||||||
|
} else {
|
||||||
|
$positional[] = $tok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$commandStr = implode(' ', $positional);
|
||||||
$match = $this->router->match($commandStr);
|
$match = $this->router->match($commandStr);
|
||||||
|
|
||||||
if (!$match->found) {
|
if (!$match->found) {
|
||||||
@@ -31,7 +48,7 @@ final class ConsoleApplication
|
|||||||
$input = ConsoleInput::parse(
|
$input = ConsoleInput::parse(
|
||||||
$commandStr,
|
$commandStr,
|
||||||
$match->pathParams,
|
$match->pathParams,
|
||||||
array_slice($argv, 2),
|
$optionTokens,
|
||||||
$match->definition->options,
|
$match->definition->options,
|
||||||
);
|
);
|
||||||
$output = new ConsoleOutput();
|
$output = new ConsoleOutput();
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ namespace Pronchev\Pinecore;
|
|||||||
use DI\Container;
|
use DI\Container;
|
||||||
use DI\ContainerBuilder;
|
use DI\ContainerBuilder;
|
||||||
use Pronchev\Pinecore\Http\Router;
|
use Pronchev\Pinecore\Http\Router;
|
||||||
|
use Pronchev\Pinecore\Log\CompositeLogger;
|
||||||
|
use Pronchev\Pinecore\Log\FileLogger;
|
||||||
|
use Pronchev\Pinecore\Log\StdoutLogger;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class ContainerFactory
|
class ContainerFactory
|
||||||
{
|
{
|
||||||
@@ -20,7 +24,19 @@ class ContainerFactory
|
|||||||
$builder->enableCompilation($cacheDir);
|
$builder->enableCompilation($cacheDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
$builder->useAutowiring(true);
|
$builder->useAttributes(true);
|
||||||
|
|
||||||
|
$builder->addDefinitions([
|
||||||
|
Config::class => $config,
|
||||||
|
Environment::class => $env,
|
||||||
|
LoggerInterface::class => function ($c) use ($config) {
|
||||||
|
$loggers = [$c->get(StdoutLogger::class)];
|
||||||
|
if ($config->get('log.file')) {
|
||||||
|
$loggers[] = $c->get(FileLogger::class);
|
||||||
|
}
|
||||||
|
return new CompositeLogger($loggers);
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
$routesFile = $basePath . '/config/routes.php';
|
$routesFile = $basePath . '/config/routes.php';
|
||||||
if (file_exists($routesFile)) {
|
if (file_exists($routesFile)) {
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ final class MongoHydrator
|
|||||||
$propName = $field->property->getName();
|
$propName = $field->property->getName();
|
||||||
$value = $doc[$key] ?? null;
|
$value = $doc[$key] ?? null;
|
||||||
|
|
||||||
if ($value instanceof \MongoDB\Model\BSONArray) {
|
$value = $this->normalizeBson($value);
|
||||||
$value = $value->getArrayCopy();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($field->isEmbedded && $value !== null) {
|
if ($field->isEmbedded && $value !== null) {
|
||||||
$value = $this->hydrate($field->embeddedClass, $this->toArray($value));
|
$value = $this->hydrate($field->embeddedClass, $this->toArray($value));
|
||||||
@@ -72,6 +70,19 @@ final class MongoHydrator
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function normalizeBson(mixed $value): mixed
|
||||||
|
{
|
||||||
|
if ($value instanceof \MongoDB\Model\BSONArray) {
|
||||||
|
return array_map($this->normalizeBson(...), $value->getArrayCopy());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value instanceof BSONDocument) {
|
||||||
|
return array_map($this->normalizeBson(...), iterator_to_array($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
private function toArray(array|BSONDocument $doc): array
|
private function toArray(array|BSONDocument $doc): array
|
||||||
{
|
{
|
||||||
if ($doc instanceof BSONDocument) {
|
if ($doc instanceof BSONDocument) {
|
||||||
|
|||||||
Reference in New Issue
Block a user