tekwork/framework

Mini framework PHP MVC avec routing avancé

Installs: 14

Dependents: 1

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/tekwork/framework

v0.6.0 2025-10-13 13:36 UTC

This package is auto-updated.

Last update: 2026-01-13 14:09:17 UTC


README

Packagist Version Packagist Downloads PHP Version License

Mini framework PHP MVC avec système de routing avancé, extrait de TekNotes.

⚠️ Note: Ceci est un projet d'apprentissage personnel. Il est fonctionnel mais n'a pas été audité pour une utilisation en production critique.

📋 Table des matières

✨ Caractéristiques

  • Architecture MVC légère et flexible
  • Routing dynamique avec paramètres et regex
  • Gestion des erreurs avec pages personnalisables (mode DEBUG/PRODUCTION)
  • Configuration par environnement (dev/staging/prod)
  • PSR-4 Autoloading via Composer
  • Controller/View pattern avec injection de dépendances
  • Patterns de sécurité prédéfinis pour validation
  • Aucune dépendance externe (PHP pur)

🚀 Installation

Démarrage rapide (recommandé)

La manière la plus rapide de démarrer avec Tekwork :

composer create-project tekwork/skeleton mon-projet
cd mon-projet

Projet prêt à l'emploi ! Structure complète, config auto-générée, exemples fonctionnels inclus.

👉 Voir tekwork/skeleton sur GitHub

Installation manuelle du framework seul

Si vous préférez construire votre structure vous-même :

Prérequis

  • PHP >= 8.0
  • Composer
  • Serveur web (Apache/Nginx) ou Laragon

Étapes

# 1. Installer via Composer
composer require tekwork/framework

# 2. Créer votre structure
mkdir -p app/Controllers app/views public

# 3. Créer le fichier de configuration
cp vendor/tekwork/framework/config.example.php config.php

# 4. Éditer config.php selon votre environnement
nano config.php

# 5. Configurer votre serveur web (voir ci-dessous)

Configuration serveur web

Nginx

server {
    listen 80;
    server_name monsite.local;
    root /chemin/vers/projet/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Apache (.htaccess dans /public)

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

⚙️ Configuration

Le fichier config.php (à la racine) gère les environnements :

<?php
return [
    // Mode debug
    // true  = Affichage détaillé des erreurs (développement)
    // false = Pages d'erreur personnalisées (production)
    'debug' => true,

    // Chemin vers les vues d'erreur personnalisées
    'error_views_path' => path_it(ROOT, 'app', 'views', 'errors'),

    // Chemin du fichier de logs
    'log_path' => path_it(ROOT, 'log', 'app_errors.log'),
];

Important :

  • config.php est dans .gitignore (jamais versionné)
  • config.example.php sert de modèle
  • Chaque environnement a sa propre configuration

📖 Utilisation

Structure du projet

projet/
├── src/                    # Framework core (ne pas modifier)
│   ├── Router.php
│   ├── Road.php
│   ├── Dispatcher.php
│   ├── Controller.php
│   ├── View.php
│   ├── ErrorHandler.php
│   └── ...
├── app/                    # Votre application
│   ├── bootstrap.php       # Définition des routes
│   ├── Controllers/        # Vos contrôleurs
│   └── views/              # Vos templates
│       └── errors/         # Pages d'erreur personnalisées (404.php, 500.php)
├── public/                 # Point d'entrée web
│   └── index.php
├── config.php              # Configuration (non versionné)
└── config.example.php      # Template de config

1. Définir des routes

Dans app/bootstrap.php :

use Tekwork\Router;
use Tekwork\Road;
use Tekwork\Dispatcher;
use Tekwork\Request;
use Tekwork\SecurityPatterns;

$router = new Router();

// Route simple (page d'accueil)
$router->add(
    new Road('', 'App\Controllers@HomeController:index', 'home')
);

// Route avec paramètre
$router->add(
    (new Road('article/{:slug}', 'App\Controllers@ArticleController:show', 'article.show'))
        ->rule('slug', SecurityPatterns::SLUG)
);

// Route avec wildcard (multi-segments)
$router->add(
    (new Road('docs/{:*path}', 'App\Controllers@DocsController:show', 'docs.show'))
        ->rule('path', SecurityPatterns::SAFE_PATH)
);

// Route avec valeurs par défaut
$router->add(
    (new Road('blog/{:page}', 'App\Controllers@BlogController:index', 'blog'))
        ->rule('page', '[0-9]+')
        ->default('page', '1')
);

// Dispatching
$request = new Request();
$dispatcher = new Dispatcher($router);
$dispatcher->dispatch($request->get_uri());

⚠️ Important: Les URIs ne commencent PAS par / :

  • Page d'accueil : '' (chaîne vide)
  • Autres routes : 'about', 'user/{:id}'

2. Créer un contrôleur

Dans app/Controllers/ArticleController.php :

<?php
namespace App\Controllers;

use Tekwork\Controller;
use Tekwork\View;

class ArticleController extends Controller
{
    public function show(): void
    {
        // Accès aux paramètres de route
        $slug = $this->params['slug'] ?? null;

        // Créer une vue avec chemin absolu
        $view = new View(path_it(ROOT, 'app', 'views', 'article.php'));

        // Injecter des variables
        $view->add_vars([
            'title' => 'Mon Article',
            'slug' => $slug,
            'content' => 'Lorem ipsum...'
        ]);

        // Rendu avec layout
        $layout = path_it(ROOT, 'app', 'views', 'layout.php');
        echo $this->render($layout, $view);
    }
}

3. Créer une vue

Dans app/views/article.php :

<article>
    <h1><?= htmlspecialchars($title) ?></h1>
    <p><?= htmlspecialchars($content) ?></p>
</article>

4. Créer un layout

Dans app/views/layout.php :

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>Mon Site</title>
</head>
<body>
    <header>
        <nav><!-- Menu --></nav>
    </header>
    <main>
        <?= $content ?> <!-- Contenu de la vue injectée -->
    </main>
    <footer>
        <p>&copy; 2025</p>
    </footer>
</body>
</html>

5. Pages d'erreur personnalisées

Créez app/views/errors/404.php et 500.php :

<!DOCTYPE html>
<html lang="fr">
<head>
    <title>404 - Page non trouvée</title>
</head>
<body>
    <h1>Page non trouvée</h1>
    <a href="/">Retour à l'accueil</a>
</body>
</html>

Hiérarchie de recherche des vues d'erreur :

  1. app/views/errors/{code}.php (ex: 404.php, 500.php)
  2. app/views/errors/error.php (vue générique)
  3. Vue par défaut intégrée au framework

🛡️ Sécurité

Bonnes pratiques

  • Toujours échapper les sorties HTML : htmlspecialchars($var)
  • Utiliser les SecurityPatterns pour valider les paramètres de route
  • Mettre debug = false en production dans config.php
  • Ne JAMAIS versionner config.php (déjà dans .gitignore)
  • ⚠️ CSRF protection : pas encore implémentée (à faire manuellement)
  • ⚠️ Validation des inputs utilisateur : à implémenter dans vos contrôleurs

SecurityPatterns disponibles

use Tekwork\SecurityPatterns;

SecurityPatterns::SAFE_PATH       // [a-zA-Z0-9_\-\/]+
SecurityPatterns::SAFE_FILENAME   // [a-zA-Z0-9_\-]+
SecurityPatterns::ALPHA_NUM       // [a-zA-Z0-9]+
SecurityPatterns::SLUG            // [a-zA-Z0-9\-]+

Reporter une vulnérabilité

Si vous découvrez une faille de sécurité, merci de la signaler de manière responsable via les Issues GitHub (en privé si possible).

📚 Documentation

Fonctions helpers

// Dump formaté pour debug
dump($variable);

// Construction de chemins multi-OS
path_it('app', 'views', 'home.php'); // app/views/home.php (ou app\views\home.php sur Windows)

Objet Request

$request = new Request();

// URI courante (sans slash initial)
$request->get_uri(); // "article/mon-slug"

// Segment par position (commence à 1)
$request->get_param(1); // "article"
$request->get_param(2); // "mon-slug"

// URLs
$request->get_base_url();  // "https://monsite.com"
$request->get_full_url();  // "https://monsite.com/article/mon-slug"
$request->get_host();      // "monsite.com" ou "monsite.com:8080"

Génération d'URLs

$router->url('article.show', ['slug' => 'mon-article']);
// Retourne : "article/mon-article"

Format des contrôleurs

Format : Namespace@Classe:methode

Exemples :

  • App\Controllers@HomeController:indexApp\Controllers\HomeController::index()
  • Admin@UserController:editAdmin\UserController::edit()

Le framework cherchera automatiquement :

  • Tekwork\ → dans /src/
  • Autre namespace → dans /{namespace_lowercase}/

🗺️ Roadmap

✅ Implémenté

  • Architecture MVC
  • Routing avancé avec paramètres dynamiques
  • ErrorHandler avec mode DEBUG/PRODUCTION
  • Configuration par environnement
  • Gestion des exceptions typées (NotFoundException)

🔮 Améliorations futures

  • Middleware support (before/after)
  • Session management sécurisée
  • CSRF protection
  • Database abstraction layer (PDO wrapper)
  • Template engine (Twig/Blade)
  • Logging system avancé
  • CLI commands support
  • Unit tests (PHPUnit)
  • Validation des inputs utilisateur
  • Rate limiting

🤝 Contribution

Les contributions sont les bienvenues ! N'hésitez pas à :

  1. Fork le projet
  2. Créer une branche (git checkout -b feature/amelioration)
  3. Commit vos changements (git commit -m 'Add: nouvelle feature')
  4. Push vers la branche (git push origin feature/amelioration)
  5. Ouvrir une Pull Request

📝 Notes

  • Ce framework est un projet d'apprentissage extrait de TekNotes
  • Il privilégie la simplicité et la compréhensibilité à la sur-architecture
  • Parfait pour petits/moyens projets ou pour apprendre les concepts MVC
  • Pour des projets critiques, préférez Laravel, Symfony ou Slim

🎓 Crédits

  • Extrait et adapté depuis TekNotes (système de documentation technique)
  • Développé avec l'assistance de Claude AI (Anthropic)
  • Auteur : Florian

📄 Licence

Ce projet est sous licence MIT. Voir le fichier LICENSE pour plus de détails.

Philosophie : Minimaliste mais extensible. 🚀