ironflow-framework/framework
最新稳定版本:v0.1.5
Composer 安装命令:
composer require ironflow-framework/framework
包简介
IronFlow — PHP 8.2+ HMVC Framework Core
README 文档
README
ironflow-framework/framework
Le cœur d'IronFlow — conteneur DI, routeur, ORM, modules HMVC, CLI.
Installation · Architecture modulaire · Injection de dépendances · Routing · ORM · CLI · Contribuer
Ce dépôt contient le noyau du framework. Il n'est pas destiné à être cloné directement pour démarrer un projet — utilise ironflow/skeleton pour ça. Ce README documente l'architecture interne, les API publiques et les conventions à respecter pour y contribuer.
Installation
Via le skeleton (recommandé) :
composer create-project ironflow/skeleton mon-app
Ou comme dépendance directe dans un projet existant :
composer require ironflow/framework
Prérequis : PHP 8.2+, Composer 2+, extensions pdo, mbstring, json.
Architecture modulaire
IronFlow organise le code en modules HMVC isolés avec dépendances déclaratives — inspiré de NestJS, porté en PHP idiomatique.
#[Module(
name: 'blog',
imports: ['auth'], // modules dont celui-ci dépend
providers: [PostService::class], // services internes
exports: [PostService::class], // API publique exposée aux autres modules
)]
class BlogModule extends BaseModule {}
Règles d'isolation
- Un provider est privé par défaut : inaccessible hors du module, sauf s'il est listé dans
exports. - Un module ne peut consommer que les providers exportés de ses dépendances déclarées dans
imports. - Les violations sont détectées au démarrage, pas à l'exécution.
Graphe de dépendances
Au boot, IronFlow construit un graphe orienté de tous les modules, valide l'absence de cycles (tri topologique) et détermine l'ordre d'initialisation. Inspecte-le :
php forge module:graph # affichage ASCII php forge module:graph --check # retourne une erreur en cas de cycle (utile en CI)
Scaffolding d'un module
php forge make:module Blog php forge make:controller PostController --module=Blog --resource php forge make:model Post --module=Blog --migration --factory
Injection de dépendances
Le conteneur résout les dépendances par réflexion sur les type hints. Aucune configuration manuelle nécessaire pour les cas courants.
#[Injectable] class PostService { public function __construct( private readonly PostRepository $posts, private readonly EventBus $events, #[Inject('config.app.name')] private readonly string $appName, ) {} }
Ce que supporte le conteneur
| Fonctionnalité | Exemple |
|---|---|
| Auto-résolution par type hint | PostRepository $posts |
| Injection de scalaires nommés | #[Inject('config.mail.from')] |
| Injection dans les méthodes de contrôleurs | public function show(Post $post, Request $request) |
| Singletons et liaisons explicites | $container->bind(MailerInterface::class, SmtpMailer::class) |
| Providers de module | définis dans providers: [...] de #[Module] |
Liaison manuelle
// Dans un ServiceProvider ou un Module::register() $this->container->bind(CacheInterface::class, RedisCache::class); $this->container->singleton(Config::class, fn() => new Config(base_path('config')));
Routing
Routes basiques
Router::get('/posts/{id}', [PostController::class, 'show']) ->name('posts.show') ->middleware('auth') ->where('id', '[0-9]+'); Router::post('/posts', [PostController::class, 'store']) ->middleware(['auth', 'throttle:10,1']);
Groupes et ressources
Router::group(['prefix' => '/api/v1', 'middleware' => ['throttle:60']], function () { Router::resource('posts', Api\PostController::class); // 7 routes RESTful Router::resource('comments', Api\CommentController::class)->only(['index', 'store']); });
Routes nommées dans les templates
<a href="{{ route('posts.show', {id: post.id}) }}">Lire</a>
Inspection
php forge route:list # +---------+----------------------------+------------------+-----------+ # | Method | URI | Name | Middleware| # +---------+----------------------------+------------------+-----------+ # | GET | /posts/{id} | posts.show | auth | # | POST | /posts | posts.store | auth,thro…| # …
ORM
Active Record sur doctrine/dbal. Pas de QueryBuilder exposé directement — passe par les modèles et les scopes.
Modèle de base
class Post extends Model { protected string $table = 'posts'; protected array $casts = [ 'published_at' => 'datetime', 'status' => PostStatus::class, // enum PHP 8.1+ 'metadata' => 'json', ]; protected array $fillable = ['title', 'body', 'author_id']; use SoftDeletes; }
Requêtes
// Eager loading anti N+1 $posts = Post::with('author', 'comments') ->withCount('comments') ->published() // scope ->latest() ->paginate(15); // Scope personnalisé public function scopePublished(QueryBuilder $query): QueryBuilder { return $query->where('status', PostStatus::Published) ->where('published_at', '<=', now()); }
Relations supportées
| Relation | Méthode |
|---|---|
| Un-à-plusieurs | hasMany(Comment::class) |
| Plusieurs-à-plusieurs avec pivot | belongsToMany(Tag::class)->withPivot('weight') |
| À travers | hasManyThrough(Comment::class, Post::class) |
| Inverse | belongsTo(User::class) |
Migrations
Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('body'); $table->enum('status', ['draft', 'published'])->default('draft'); $table->timestamp('published_at')->nullable(); $table->foreignId('author_id')->constrained('users'); $table->softDeletes(); $table->timestamps(); });
php forge migrate php forge migrate --rollback php forge migrate --fresh --seed
Événements de modèle
Post::creating(fn(Post $post) => $post->slug = Str::slug($post->title)); Post::deleted(fn(Post $post) => Cache::forget("post:{$post->id}"));
Middlewares
Deux styles au choix — cohérence garantie dans les deux cas.
Style oignon (recommandé) :
class AuthMiddleware { public function handle(Request $request, Closure $next): Response { if (!$request->session()->has('user')) { return redirect()->route('login'); } return $next($request); } }
Style Django (hooks) :
class LogMiddleware { public function processRequest(Request $request): ?Response { /* ... */ } public function processResponse(Request $request, Response $response): Response { /* ... */ } }
Middlewares globaux définis dans config/http.php, alias par route enregistrés dans le router.
Bus d'événements
Découplage inter-modules sans import direct.
// Dans BlogModule : émet $this->events->dispatch(new PostPublished($post)); // Dans NewsletterModule : écoute — sans importer BlogModule #[EventListener] class SendNewsletterOnPublish { public function handle(PostPublished $event): void { $this->mailer->queue(new NewPostEmail($event->post)); } }
L'abonnement est auto-détecté via #[EventListener] à condition que le module soit dans le graphe de dépendances.
Templates Twig
Namespaces par module :
{# modules/Blog/templates/posts/index.html.twig #} {% extends '@app/layouts/main.html.twig' %} {% block content %} {% for post in posts %} <a href="{{ route('posts.show', {id: post.id}) }}">{{ post.title }}</a> <span>{{ post.published_at | time_ago }}</span> {% endfor %} {{ paginator(posts) }} {% endblock %}
Fonctions et filtres disponibles
| Catégorie | Exemples |
|---|---|
| Routing | route('name', params), current_route() |
| Assets | asset('app.css') — cache-busting automatique |
| Formulaires | csrf_field(), old('field'), errors('field') |
| Filtres | time_ago, markdown, slug, money, truncate |
| Auth | auth_user(), is_auth() |
CLI Forge
php forge list # toutes les commandes disponibles php forge make:module <Name> # scaffolde un module complet php forge make:controller <Name> [opts] # --module, --resource, --api php forge make:model <Name> [opts] # --module, --migration, --factory php forge make:middleware <Name> php forge make:command <Name> php forge migrate [--fresh] [--seed] [--rollback] php forge db:seed [--class=] php forge route:list php forge module:graph [--check] php forge down [--message=] [--retry=] # mode maintenance php forge up php forge serve [--host=] [--port=]
Commandes personnalisées
#[Command(signature: 'blog:seed {count=10} {--fresh}', description: 'Seed blog posts')] class SeedBlogCommand extends BaseCommand { public function handle(): int { $count = (int) $this->argument('count'); // ... $this->info("$count posts créés."); return self::SUCCESS; } }
Ce qui est sur étagère vs fait maison
| Délégué à | Construit par IronFlow |
|---|---|
symfony/http-foundation — HTTP bas niveau |
Conteneur DI avec attributs PHP 8 |
symfony/console — fondation CLI |
Système de modules + graphe de dépendances |
twig/twig — moteur de templates |
Routeur fluide avec route naming |
doctrine/dbal — couche SQL |
ORM Active Record, migrations, factories |
monolog/monolog — logging |
Middlewares, bus d'événements |
firebase/php-jwt — tokens JWT |
Extension Twig, scaffolding CLI complet |
vlucas/phpdotenv — variables d'env |
Auth session + JWT, validation, CSRF |
Chaque composant externe est wrappé derrière nos propres interfaces dans Ironflow\Ironflow\. Ton code n'importe jamais Symfony\Component\HttpFoundation\Request — seulement Ironflow\Ironflow\Http\Request.
Roadmap
- Conteneur DI avec attributs, résolution par réflexion
- Architecture modulaire HMVC avec graphe de dépendances
- Routeur fluide — groupes, ressources, named routes, contraintes
- ORM Active Record — relations, eager loading, scopes, soft deletes
- Migrations et Schema builder
- CLI forge avec scaffolding complet
- Auth session + JWT
- Validation
- CSRF, middlewares globaux et par-route
- Bus d'événements découplé
- Extension Twig maison + view composers
- Cache — facade unifiée, drivers file/redis
- File d'attente de jobs (queue)
- WebSockets / diffusion temps réel
- Documentation complète avec recettes
Contribuer
git clone https://github.com/ironflow-framework/framework git clone https://github.com/ironflow-framework/skeleton cd skeleton composer install # le framework est lié en repository path (symlink local) php forge serve
# Lancer les tests vendor/bin/phpunit # Avec couverture vendor/bin/phpunit --coverage-html coverage/
Conventions :
- PSR-12, typages stricts (
declare(strict_types=1)dans tous les fichiers) - Chaque feature → test unitaire + test d'intégration
- Pas de breaking change en patch, dépréciation avant suppression en minor
- Issues marquées
good first issuepour débuter
- Fork du dépôt concerné
git checkout -b feature/ma-feature- Tests au vert (
vendor/bin/phpunit) - Pull Request vers
mainavec description des changements
Chaque framework est une théorie du bon code.
IronFlow parie sur la modularité explicite, les attributs PHP 8, et le respect de tes conventions à toi.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 4
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-10