Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
35b0379
beta test
Flytachi Jul 21, 2026
ea15c2f
file moving, delete crashed functional and base docs
Flytachi Jul 21, 2026
081be25
New Engine Process (betta test)
Flytachi Jul 22, 2026
4497ba3
New Engine Process (betta test)
Flytachi Jul 22, 2026
214b5da
New Engine Process (betta test)
Flytachi Jul 22, 2026
a4ec7e8
New Engine Process (betta test)
Flytachi Jul 22, 2026
0b885a2
New Engine Process (betta test)
Flytachi Jul 23, 2026
b49831e
New Engine Process (betta test)
Flytachi Jul 23, 2026
dad310e
New Engine Process (betta test)
Flytachi Jul 23, 2026
d1d89db
New Engine Process (betta test)
Flytachi Jul 23, 2026
9cea916
New Engine Process (betta test)
Flytachi Jul 23, 2026
0a81ef8
Process (betta test)
Flytachi Jul 23, 2026
df6516b
Process fix
Flytachi Jul 23, 2026
0d11747
крн
Flytachi Jul 24, 2026
4a0308c
Schedule beta test
Flytachi Jul 25, 2026
ea62313
Schedule beta test
Flytachi Jul 25, 2026
48fa942
Schedule beta test
Flytachi Jul 26, 2026
1a1720f
Schedule beta test
Flytachi Jul 26, 2026
1df66e1
Schedule beta test
Flytachi Jul 26, 2026
0a8204c
rebuild beta test
Flytachi Jul 26, 2026
000e880
rebuild - hot relod
Flytachi Jul 26, 2026
d8a3514
крн
Flytachi Jul 27, 2026
082c297
test - new dep
Flytachi Jul 27, 2026
eaab540
starter
Flytachi Jul 28, 2026
ec523fc
starter
Flytachi Jul 28, 2026
6f03f54
starter
Flytachi Jul 28, 2026
f2bcea0
starter
Flytachi Jul 28, 2026
bfc3f3e
starter
Flytachi Jul 28, 2026
5742312
starter
Flytachi Jul 29, 2026
8b20fd0
starter
Flytachi Jul 29, 2026
ffbb9ba
docker
Flytachi Jul 31, 2026
72b93e2
docker
Flytachi Jul 31, 2026
f275cd2
docker
Flytachi Jul 31, 2026
b771002
docker dev
Flytachi Jul 31, 2026
d488b90
pool
Flytachi Jul 31, 2026
c692fb3
pool
Flytachi Jul 31, 2026
e6ca022
pool
Flytachi Aug 1, 2026
7e6bab7
pool
Flytachi Aug 1, 2026
418060c
pool
Flytachi Aug 1, 2026
0917c12
pool
Flytachi Aug 1, 2026
aca4f47
pool
Flytachi Aug 1, 2026
3ecf762
new ressource
Flytachi Aug 1, 2026
98de60d
tests
Flytachi Aug 1, 2026
e4ae56c
tests
Flytachi Aug 1, 2026
f22a88b
tests
Flytachi Aug 1, 2026
ebb230b
tests
Flytachi Aug 1, 2026
bad8470
pool fix - grace-down final
Flytachi Aug 1, 2026
33a807f
zz
Flytachi Aug 1, 2026
9836c2d
sqlite
Flytachi Aug 1, 2026
42049da
full redisign
Flytachi Aug 2, 2026
9fa8833
full redisign
Flytachi Aug 3, 2026
a406599
di - fixes
Flytachi Aug 3, 2026
198358b
di - fixes
Flytachi Aug 3, 2026
6adfa28
env
Flytachi Aug 4, 2026
e518f7d
env
Flytachi Aug 4, 2026
4197df1
env
Flytachi Aug 4, 2026
3affd0d
env
Flytachi Aug 4, 2026
b6bce55
env
Flytachi Aug 4, 2026
02b8df9
context req
Flytachi Aug 4, 2026
0e08960
memory and ppa
Flytachi Aug 5, 2026
c30dba1
timeout control
Flytachi Aug 5, 2026
93ce502
timeout control
Flytachi Aug 5, 2026
7875e07
timeout control
Flytachi Aug 5, 2026
0bcc89b
timeout control
Flytachi Aug 5, 2026
a99bd99
timeout control
Flytachi Aug 5, 2026
a0ef188
timeout control
Flytachi Aug 5, 2026
9d624d3
timeout control
Flytachi Aug 5, 2026
ee7f93f
profile
Flytachi Aug 5, 2026
cc7a4e5
profile
Flytachi Aug 6, 2026
9a54567
profile
Flytachi Aug 6, 2026
0f1a6e0
profile
Flytachi Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
203 changes: 203 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,206 @@
[![Latest Version on Packagist](https://img.shields.io/packagist/v/flytachi/winter-kernel.svg)](https://packagist.org/packages/flytachi/winter-kernel)
[![PHP Version Require](https://img.shields.io/packagist/php-v/flytachi/winter-kernel.svg?style=flat-square)](https://packagist.org/packages/flytachi/winter-kernel)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)

The kernel of the Winter framework — a PHP 8.4 library that turns a directory of
classes into a running application. It carries the HTTP layer, dependency injection,
the database layer (PPA), managed processes and daemons, scheduling, and the console.

It is a **library, not a skeleton**: there is nothing to scaffold and no directory tree
to create. You add it to a project, write one class that says what the application
contains, and run it.

---

## Requirements

| | |
|---|---|
| PHP | **8.4+** |
| Extensions | `pcntl`, `posix`, `fileinfo` (required) · `swoole` (for the HTTP server, coroutines and connection pooling) · `pdo` for a database |

Everything else is pulled by composer.

---

## Install

```bash
composer require flytachi/winter-kernel
```

## The whole application: two files

**`bootstrap.php`** — loads the autoloader and declares what the application contains:

```php
<?php
declare(strict_types=1);

use Flytachi\Winter\Kernel\App\Attribute\EnableWeb;
use Flytachi\Winter\Kernel\WinterApplication;

require __DIR__ . '/vendor/autoload.php';

#[EnableWeb]
final class Application extends WinterApplication
{
public static function main(array $argv): never
{
parent::run($argv);
}
}
```

**`call`** — the single entry point (make it executable with `chmod +x call`):

```php
#!/usr/bin/env php
<?php
chdir(__DIR__);
require './bootstrap.php';
Application::main($argv);
```

That is a working project. No `.env`, no directories — the kernel creates what it needs,
when it needs it.

```bash
php call # console: the command list
php call run # bring the application up
php call run dev # same, restarting on file changes
```

Add a controller anywhere under the project and it is found by the scan:

```php
use Flytachi\Winter\Kernel\Route\Annotation\GetMapping;
use Flytachi\Winter\Kernel\Http\Stereotype\Controller;

final class PingController extends Controller
{
#[GetMapping('/ping')]
public function ping(): array
{
return ['pong' => true];
}
}
```

---

## What the application contains — `#[Enable*]`

The attributes on the application class are the manifest. Each one adds a component;
declare none and the boot fails rather than starting an application that does nothing.

| Attribute | Effect |
|---|---|
| `#[EnableWeb]` | the Swoole HTTP server |
| `#[EnableActuator]` | `/actuator` diagnostics (health, info, metrics, mappings) |
| `#[EnableScheduler]` | runs `#[Scheduled]` methods on their triggers |
| `#[EnableProcess(Foo::class)]` | a managed worker beside the server |
| `#[EnableDaemon(Bar::class)]` | a supervised fleet of workers beside the server |
| `#[EnableAsync]` | proxies `#[Async]` methods so they run off the request |
| `#[Import('vendor/pkg', '/prefix')]` | mounts a plugin package under a URL prefix |

Everything else is configured by ordinary classes the scan finds — there are no
configuration hooks to override:

```php
#[Configuration] / #[Bean] // DI factories
WebConfigurer // host, port, Swoole tuning, CORS, static files
LoggingConfigurer // extra log channels
```

---

## Project layout

Only two directories are conventional, and both are optional:

```
resources/
static/ web assets — served by Swoole when enabled (see WebConfigurer)
views/ view files — ResponseView's default root
storage/
logs/ cache/ runnable/ created on demand, never committed
```

There is no `public/`: that belongs to the FPM document-root model, and the server here
decides for itself what it serves. Static files are opt-in:

```php
final class WebConfig extends WebConfigurerAdapter
{
public function configureServer(ServerSettings $server, ApplicationArguments $args): void
{
$server->port(8000)
->staticPath('resources/static'); // resources/static/app.css → /app.css
}
}
```

## Configuration

`.env` is optional; every variable has a working default.

| Variable | Default | Meaning |
|---|---|---|
| `DEBUG` | `false` | verbose errors and a full rescan on every boot |
| `LOG_LEVEL` | *(empty — logging off)* | `debug`…`emergency` |
| `LOG_OUTPUT` | `auto` → stdout | `stdout`, `stderr`, `file`, `syslog`, `null` |
| `LOG_FILE` | `storage/logs/<channel>.log` | absolute path when `LOG_OUTPUT=file` |
| `SERVER_WORKERS` | Swoole default | worker count |
| `WINTER_KEY` | *(none)* | signs payloads handed to background processes |
| `PPA_POOL_TELEMETRY` | `5` | seconds between pool-stat publishes; `0` disables |

---

## Console

```bash
php call # command list
php call run [dev] # serve
php call make -c UserController # scaffold a class
php call daemon <dot.Class> start [-d] | stop | status
php call process <dot.Class> start [-d] | stop | status
php call db ping | migrate | sql | pool
php call schedule start [-d] | stop | status
php call cfg completion -i # shell completion
```

Class names use dot notation: `main.process.Emails` → `Main\Process\Emails`.

---

## Runtimes

The kernel runs the same application two ways:

- **Swoole** — one long-lived server process; coroutines, connection pooling and static
files handled in C. This is the primary target.
- **CLI / plain processes** — the console, and processes or daemons started on their own.

FPM is not served by the kernel itself; it is moving to a separate `winter-fpm` project.

---

## Documentation

- [`docs/starter/00-quickstart.md`](docs/starter/00-quickstart.md) — from an empty
directory to a served request, then to a background worker.
- [`docs/`](docs) — the reference for each subsystem (routing, request binding,
responses, PPA, processes and daemons, scheduling, console, configuration).

## Development

```bash
vendor/bin/phpunit # the default suite
vendor/bin/phpunit --group integration # real forks, signals and servers
vendor/bin/phpcs # PSR-12
```

## License

MIT — see [LICENSE](LICENSE).
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,25 @@
"autoload": {
"psr-4": {
"Flytachi\\Winter\\Console\\": "console/",
"Flytachi\\Winter\\K2\\": "src/"
"Flytachi\\Winter\\Kernel\\": "src/"
},
"files": [
"function/dependencies.php"
]
},
"autoload-dev": {
"psr-4": {
"Flytachi\\Winter\\K2\\Tests\\": "tests"
"Flytachi\\Winter\\Kernel\\Tests\\": "tests"
}
},
"bin": ["wKernelRunner"],
"require": {
"php": ">=8.4",
"flytachi/winter-di": "^1.0",
"flytachi/winter-di": "^2.0",
"flytachi/winter-base": "^3.0",
"flytachi/winter-logger": "^1.0",
"flytachi/winter-thread": "^3.0",
"flytachi/winter-cdo": "^3.0",
"flytachi/winter-cdo": "^4.0",
"flytachi/winter-cache": "^1.0",
"flytachi/file-store": "^2.0",
"vlucas/phpdotenv": "^5.6",
Expand Down
49 changes: 14 additions & 35 deletions console/Command/Cfg.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
namespace Flytachi\Winter\Console\Command;

use Flytachi\Winter\Console\Inc\Cmd;
use Flytachi\Winter\K2\Kernel;
use Flytachi\Winter\Kernel\Kernel;

class Cfg extends Cmd
final class Cfg extends Cmd
{
public static string $title = "manage project configuration, environment and keys";
private string $templatePath;
Expand Down Expand Up @@ -200,37 +200,18 @@ private function envShow(): void

private function dockerArg(): void
{
$runtime = array_key_exists('swoole', $this->args['options']) ? 'swoole' : 'fpm';

// Single unified template: one stable Dockerfile + docker/ (fpm, swoole,
// dependencies.sh) + compose. The runtime is selected by the RUNTIME
// build arg, not by which files are copied.
// Flat Swoole template: Dockerfile + docker-compose.yml + docker/
// (entrypoint.sh, php-opcache.ini, dependencies/*.sh). dev vs prod is the
// DEV var in compose; DB drivers / extensions are the dependencies/ scripts.
multiCopy($this->templatePath . '/Docker', Kernel::$pathRoot);
$this->setComposeRuntime($runtime);

self::printBadge('runtime', $runtime, 34, 36);
self::printBadge('docker/', 'CREATED', 34, 32);
self::printBadge('docker/dependencies.sh', 'CREATED', 34, 32);
self::printBadge('docker/dependencies/', 'CREATED', 34, 32);
self::printBadge('.dockerignore', 'CREATED', 34, 32);
self::printBadge('docker-compose.yml', 'CREATED', 34, 32);
self::printBadge('Dockerfile', 'CREATED', 34, 32);
self::printInfo("Switch runtime anytime: set RUNTIME (fpm|swoole) in docker-compose.yml");
self::printInfo("Add extensions/cron: edit docker/dependencies.sh");
}

/**
* Pin the default RUNTIME build arg in the freshly scaffolded compose file.
* The template ships `RUNTIME: fpm`; on `--swoole` we flip it to swoole so
* `docker compose build` picks the requested runtime out of the box.
*/
private function setComposeRuntime(string $runtime): void
{
$compose = Kernel::$pathRoot . '/docker-compose.yml';
if (is_file($compose)) {
$content = file_get_contents($compose);
$content = preg_replace('/(RUNTIME:\s*)(?:fpm|swoole)/', '${1}' . $runtime, $content, 1);
file_put_contents($compose, $content);
}
self::printInfo("Run: docker compose up (dev, hot-reload) | DEV=false docker compose up (prod)");
self::printInfo("DB drivers / extensions: keep or remove docker/dependencies/*.sh");
}

private function completionArg(): void
Expand Down Expand Up @@ -356,11 +337,11 @@ public static function help(): void

// docker
self::printLabel("docker — scaffold Docker files", $cl);
self::print("--fpm default runtime = PHP-FPM + Nginx (default)", $cl);
self::print("--swoole default runtime = Swoole HTTP server", $cl);
self::print(" one stable Dockerfile serves both; switch via", $cl);
self::print(" RUNTIME in docker-compose.yml. Extra packages,", $cl);
self::print(" redis/pgsql/mysql, cron → docker/dependencies.sh", $cl);
self::print("Swoole image. dev vs prod = DEV in docker-compose.yml:", $cl);
self::print(" docker compose up dev (hot-reload, opcache off)", $cl);
self::print(" DEV=false docker compose up prod (opcache on, no watcher)", $cl);
self::print("DB drivers / extensions / cron → docker/dependencies/*.sh", $cl);
self::print(" (keep or remove; bcmath, pgsql, mysql, redis shipped)", $cl);
self::printLabel("docker — scaffold Docker files", $cl);

// examples
Expand All @@ -372,9 +353,7 @@ public static function help(): void
self::printInfo("call cfg env -i");
self::printInfo("call cfg env -s");
self::printInfo("call cfg env -s --file");
self::printInfo("call cfg docker (fpm mode, default)");
self::printInfo("call cfg docker --fpm (explicit fpm mode)");
self::printInfo("call cfg docker --swoole (swoole mode)");
self::printInfo("call cfg docker (scaffold Docker files)");
self::printInfo("call cfg completion (print scripts to stdout)");
self::printInfo("call cfg completion -i (install: ~/.zsh/completions/_call or ~/.bash_completion.d/call)");
self::printInfo("call cfg completion -if (force update installed file)");
Expand Down
Loading
Loading