Permet d'analyser des projets php d'un point de vue semantique : - Bon nom de variable , de fonction , de classe ; - Vérification de la langue -...
  • PHP 97.1%
  • Twig 2%
  • JavaScript 0.4%
  • Shell 0.3%
  • Dockerfile 0.2%
Find a file
Nora 78e6dd29c7
All checks were successful
Symfony / symfony-tests (push) Successful in 1m30s
Release / release (push) Successful in 1m26s
Merge pull request 'fix/Cleaning' (#134) from fix/Cleaning into develop
Reviewed-on: #134
2026-06-07 17:45:00 +00:00
.claude cleanig 2026-05-25 18:55:35 +02:00
.forgejo/workflows update PHP VERSION 2026-06-02 18:02:34 +02:00
.idea to try branch revie 2026-06-06 17:20:31 +02:00
assets update PHP VERSION 2026-06-02 18:02:34 +02:00
bin init symfony 2026-05-08 14:18:44 +02:00
config ongoing 2026-06-07 18:17:07 +02:00
docker/db Init docker 2026-05-08 13:50:38 +02:00
frankenphp add git 2026-05-30 20:41:04 +02:00
migrations cleaning some bugs 2026-05-22 15:46:28 +02:00
public init symfony 2026-05-08 14:18:44 +02:00
scripts ongoing cleaning 2026-05-10 14:03:40 +02:00
src ongoing 2026-06-07 18:17:07 +02:00
templates add badge to find source prompt 2026-06-05 11:08:56 +02:00
tests ongoing 2026-06-07 18:17:07 +02:00
translations tralansate 2026-06-04 11:55:12 +02:00
.dockerignore Init docker 2026-05-08 13:50:38 +02:00
.editorconfig init symfony 2026-05-08 14:18:44 +02:00
.env ongoing 2026-06-07 18:17:07 +02:00
.env.test hexagonal 2026-05-08 16:04:08 +02:00
.gitignore fix bug 2026-05-26 10:43:40 +02:00
.mcp.json add mcp 2026-05-23 00:34:21 +02:00
Caddyfile Init docker 2026-05-08 13:50:38 +02:00
CLAUDE.md ongoing 2026-06-07 18:17:07 +02:00
compose.override.yaml add method pattern rename 2026-05-12 16:39:55 +02:00
compose.yaml Add doctrine entity mapping 2026-05-08 17:49:39 +02:00
composer.json update PHP VERSION 2026-06-02 18:02:34 +02:00
composer.lock to try branch revie 2026-06-06 17:20:31 +02:00
dc create docker script 2026-05-28 00:25:16 +02:00
Dockerfile update PHP VERSION 2026-06-02 18:02:34 +02:00
exec-bin-console some renaming 2026-06-04 17:53:02 +02:00
exec-test-coverage some cleaning 2026-06-05 18:16:42 +02:00
importmap.php step 06 2026-05-25 13:53:27 +02:00
mago.toml updat mago 2026-06-02 17:59:24 +02:00
package.xml add messenger asynchro 2026-05-09 17:31:27 +02:00
phpstan.dist.neon update phpstan level to 10 2026-05-23 19:19:34 +02:00
phpunit.dist.xml on going symfony 2026-05-08 14:23:46 +02:00
README.md update readme 2026-06-06 11:51:18 +02:00
report.xml fix reveiws 2026-05-08 18:16:28 +02:00
symfony.lock step 06 2026-05-25 13:53:27 +02:00

PhpLocalReviewer

PhpLocalReviewer est un outil d'analyse sémantique de code PHP piloté par l'IA (LLM via Ollama). Il ne se contente pas de vérifier la syntaxe : il analyse le sens et l'architecture du code (principes SOLID, clarté des noms, pertinence des tests).

Toutes les analyses s'exécutent en local — le code source ne quitte jamais la machine.


Prérequis

  • Docker & Docker Compose : l'application (FrankenPHP) et la base (MySQL) sont conteneurisées.
  • Ollama : pour faire tourner les modèles d'IA en local. Télécharger Ollama
  • Git : pour cloner le projet.
  • PHP 8.5+ (optionnel) : utile uniquement pour lancer mago ou composer hors Docker.

Le script ./dc

Docker Compose ne lit que .env par défaut — il ignore .env.local, qui est pourtant la convention Symfony pour les surcharges locales.

Le script ./dc à la racine passe automatiquement les deux fichiers :

./dc up -d          # = docker compose --env-file .env [--env-file .env.local] up -d
./dc exec php ...   # idem pour exec, run, down, etc.

Toujours utiliser ./dc à la place de docker compose afin que .env.local soit pris en compte à l'interpolation du compose.


Installation rapide

  1. Cloner le projet et démarrer Docker.

  2. Télécharger un modèle Ollama :

    ollama pull ministral-3:14b
    
  3. Créer un .env.local à la racine :

    OLLAMA_BASE_URL=http://host.docker.internal:11434
    EXTERNAL_PROJECTS_PATH=/chemin/vers/votre/projet
    

    Sur Linux, Ollama doit écouter sur toutes les interfaces ou utiliser l'IP de docker0.

  4. Démarrer les services :

    ./dc up -d
    

    Le schéma de base est initialisé automatiquement au démarrage.

  5. Vérifier l'accès : https://localhost


Analyser des projets externes

Définissez EXTERNAL_PROJECTS_PATH dans .env.local, puis relancez ./dc up -d. Toutes les analyses ciblent exclusivement ce dossier (monté dans le conteneur à /app/external-projects).


Revues de code (CLI)

Chaque commande analyse un fichier ou un répertoire selon un principe SOLID ou une dimension qualité.

Commande Principe Description
app:review:syntaxe Syntaxe & Nommage Clarté des noms, conventions, cohérence linguistique
app:review:srp SRP Responsabilité unique
app:review:ocp OCP Ouvert/fermé
app:review:liskov LSP Substitution de Liskov
app:review:isp ISP Ségrégation des interfaces
app:review:dip DIP Inversion des dépendances
app:review:tu Tests Unitaires Qualité et couverture des tests
app:review:all Tous Lance toutes les revues ci-dessus en chaîne
app:review:branch Tous (filtré) Revue limitée aux .php modifiés sur la branche courante vs develop

Lancer une analyse :

# Tout external-projects (aucun argument)
./dc exec php bin/console app:review:srp

# Sous-dossier ou fichier (chemin relatif à external-projects)
./dc exec php bin/console app:review:srp src
./dc exec php bin/console app:review:srp src/Service/Foo.php

Options communes des commandes mono-type :

Option Description
--format=console|json Format de sortie (défaut console)
--fail-on=N Retourne un code non-zéro si total d'erreurs >= N (0 = désactivé)
--no-cache Ignore le cache SHA-1 en lecture (le nouveau rapport est tout de même persisté)

Options de app:review:branch :

Option Description
--types=srp,ocp,… Sous-ensemble des types à exécuter (défaut : tous)
--with-tests Inclure aussi les fichiers de tests (défaut : exclus)

Toutes les analyses sont persistées en base. Si le fichier n'a pas changé depuis la dernière analyse (même hash SHA-1 + même empreinte prompts/modèle), le rapport en cache est retourné sans appel LLM.

Attention TU : si vous ne modifiez que le fichier de test, le SHA-1 du code source reste identique et l'analyse n'est pas relancée.

Stratégie multi-appels (sub-prompts)

Toutes les revues (Syntaxe, TU et SOLID) effectuent 3 appels LLM séquentiels, chacun ciblé sur un angle précis. Les critères retournés sont fusionnés dans un unique rapport.

Type Sub-prompt 1 Sub-prompt 2 Sub-prompt 3
Syntaxe Clarté du nommage Conventions du langage Cohérence de la documentation
TU Présence & mapping Branches & cas limites Isolation & qualité
SRP Densité des méthodes publiques Cohésion interne Couplage des responsabilités
OCP Fermeture aux modifications Ouverture aux extensions Patterns de conception
LISKOV Compatibilité des signatures Invariants Polymorphisme
ISP Interfaces larges Implémentations vides Injection excessive
DIP Abstractions au constructeur Instanciation dans les méthodes Séparation des couches

Les fichiers de prompt se trouvent dans config/prompts/<type>/01_*.md, 02_*.md, 03_*.md. Ils sont découverts automatiquement par convention — aucune variable d'environnement par prompt n'est nécessaire.

Contexte de revue enrichi

Avant chaque appel LLM, le système construit un ReviewContext enrichi par fichier. L'enrichissement est piloté par AnalysisType::enrichments() (qui renvoie un ContextEnrichmentFlags), ce qui évite de charger les données inutiles selon le type :

Donnée Source Activée par
Interfaces implémentées (source) PHP-Parser + grep Toutes les revues
Classe parente (source) PHP-Parser + grep Toutes les revues
Callers (fichiers qui utilisent la classe) grep -rl SOLID uniquement
Diff git (git diff HEAD) git diff SOLID uniquement
Fichier de test associé (*Test.php) Convention de nommage TU uniquement

Pour la revue TU, si aucun fichier de test n'est trouvé, un rapport d'erreur est retourné immédiatement sans appel LLM.

Filtres de fichiers par type

app:review:branch (et le runner batch) applique un filtre par AnalysisType avant l'appel LLM :

Type Filtre Effet
SYNTAX AllPhpFilesFilter Tous les .php lisibles
SRP/OCP/LISKOV/ISP/DIP ConcreteClassFileFilter Classes concrètes uniquement (pas les interfaces, traits, enums)
TU NonTestFileFilter Fichiers de code source (exclut les *Test.php)

Initialisation de branche (CLI)

La commande app:init:branch crée interactivement une branche git typée depuis develop, avec génération optionnelle d'un document de spec.

./dc exec php bin/console app:init:branch [--spec] [--no-llm] [--base=develop]
Option Description
--spec Génère un document de spécification pour la branche
--no-llm Avec --spec : utilise un template statique au lieu du LLM
--base=<branche> Branche de base (défaut : develop)

Types disponibles : feature, fix, hotfix, chore

Le wizard demande le type, la référence de ticket (optionnelle) et une description courte qui devient le slug. Avec --spec, deux questions supplémentaires (contexte et critères d'acceptance) permettent de générer un document de spec.

Le fichier produit est écrit dans external-projects/docs/specs/<YYYY-MM-DD>-<branch-name>.md.


Analyse de projet (init:context)

La commande app:init:context analyse le projet présent dans external-projects/ et génère brain/storm.md à sa racine — un document de synthèse architectural produit par un pipeline LLM multi-étapes.

./dc exec php bin/console app:init:context

Le fichier généré (brain/storm.md) est non versionné : c'est un artefact de travail à relire avant tout commit.


Serveur MCP

PhpLocalReviewer expose un serveur MCP (Model Context Protocol) utilisable par Claude Code ou tout client compatible. Il est configuré dans .mcp.json à la racine du projet.

Les conteneurs doivent être démarrés (./dc up -d) avant utilisation.

Démarrage automatique (via .mcp.json) :

{
  "mcpServers": {
    "php-local-reviewer": {
      "type": "stdio",
      "command": "docker",
      "args": ["compose", "exec", "-T", "php", "bin/console", "mcp:server:start"]
    }
  }
}

Outils MCP exposés (un par AnalysisType, plus utilitaires) :

Outil Description
syntax-review Analyse syntaxe & nommage
srp-review Analyse SRP
ocp-review Analyse OCP
liskov-review Analyse LSP
isp-review Analyse ISP
dip-review Analyse DIP
tu-review Qualité des tests
get-analysis-report Récupère le dernier rapport stocké pour un fichier
bash-exec Exécute une commande de la liste autorisée (ALLOWED_BASH_COMMANDS)
ollama-chat Chat direct avec Ollama (modèle + prompt + system)

Les handlers de revue sont enregistrés automatiquement à la compilation par ReviewHandlerCompilerPass (une instance de McpReviewHandler par AnalysisType). Le nom de l'outil est dérivé de la valeur de l'enum : strtolower($type->value) . '-review'.


Qualité du code

Le projet utilise Mago pour le lint, le format, l'analyse statique et le guard architectural.

# Vérification complète
./dc exec php scripts/mago-check.sh

# Sortie détaillée
./dc exec php scripts/mago-check.sh true

Les règles de dépendance entre couches (Domain → Application → Infrastructure) sont définies dans mago.toml.


Tests

# Tous les tests
./dc exec php scripts/run-tests.sh

# Un fichier précis
./dc exec php vendor/bin/phpunit tests/Unit/Infrastructure/Adapter/Serialization/AnalysisReportDeserializerTest.php

# Tests d'intégration uniquement
./dc exec php vendor/bin/phpunit tests/Integration/

Les tests d'intégration (tests/Integration/) exercent les commandes de bout en bout, sans appel réseau. La partie LLM est remplacée par un stub et la base de données par SQLite en mémoire.

Problème : Unable to create the "cache" directory

Symptôme lors de l'exécution des tests hors de Docker :

RuntimeException: Unable to create the "cache" directory (…/var/cache/test).

Cause : var/ a été créé par Docker (root) et n'est pas accessible en écriture par l'utilisateur local.

Solution — corriger les permissions via Docker :

./dc run --rm php chown -R $(id -u):$(id -g) .

Interface d'administration

Accédez à https://localhost/admin pour consulter les rapports d'analyse, les KPI et les métriques.


Architecture

Le projet suit une architecture hexagonale stricte, vérifiée par mago guard en CI.

Couche Dépendances autorisées
Domain PHP natif + Psl uniquement
Application Domain + Symfony + PSR + PhpParser
Infrastructure Domain + Application + tout le reste

Composants principaux

src/Domain/

  • Entity/AnalysisReport — agrégat principal (critères, statut, fileHash, type)
  • Entity/LLMConfig / LLMConfigInterface, LLMParameters, LLMMetric — configuration LLM
  • Enum/AnalysisTypeSYNTAX, TU, SRP, OCP, LISKOV, ISP, DIP ; expose enrichments() qui pilote l'enrichissement de contexte
  • Enum/AnalysisStatusPENDING, SUCCESS, FAILURE, …
  • Enum/CacheModeREAD (défaut) ou BYPASS (--no-cache)
  • Enum/BranchTypefeature, fix, hotfix, chore
  • Enum/BranchSpecGeneratorKindLLM ou TEMPLATE
  • Constants/CharConstants, Constants/ProjectConstants, Constants/BranchConstantes, Constants/ReviewLabels, Constants/TextLines — constantes partagées
  • ValueObject/ReviewContext — contexte enrichi (filename, sourceCode, runName, callbacks lazy, cacheMode, cacheFingerprint, fileHash calculé)
  • ValueObject/ContextEnrichmentFlags — quels enrichissements charger pour un type
  • ValueObject/BranchName — nom de branche typé (type + ticket + slug)
  • ValueObject/Criterion, ValueObject/Problem — value objects pour les findings
  • Review/ReviewStrategyInterface + AbstractMultiCallReviewStrategy, MultiCallReviewStrategy, TuReviewStrategy, ReviewStrategyContext
  • Provider/ — ports persistance/FS (AnalysisReportProvider, ProjectFileSystemProvider/Lister/Writer, CodeReviewerProvider, CacheFingerprintProviderInterface)
  • Stats/DashboardStats, Stats/DashboardStatsProviderInterface, Stats/RunFilter, Stats/RunFilterKind, Stats/RunNameListerInterface

src/Application/

  • UseCase/Review/CodeReviewOrchestratorContext — cache SHA-1+fingerprint, délègue à la stratégie résolue, persiste
  • UseCase/Review/FileReviewRunner — itère les fichiers, construit le contexte, dispatche vers un FileReviewCollectorInterface
  • UseCase/Review/ReviewBatchRunner — orchestre plusieurs AnalysisType sur un même set de fichiers en appliquant les filtres par type
  • UseCase/Review/RunAllSummary — agrégation des compteurs (success/error/skipped) pour app:review:all/branch
  • UseCase/Branch/CreateBranchOrchestratorContext — création interactive d'une branche typée + spec optionnelle
  • UseCase/InitContext/InitContextOrchestratorContext — pipeline LLM multi-étapes → brain/storm.md
  • Port/ — interfaces ports (BashCommandRunnerInterface, BranchChangedFilesProviderInterface, FileDiffProviderInterface, FileFilterProviderInterface, FileReviewCollectorInterface, GitBranchManagerInterface, InheritanceResolverInterface, CallerLocatorInterface, TestFileResolverInterface, OllamaChatAdapterInterface, ProjectStructureAnalyzerInterface, ReviewContextBuilderInterface, RunNameProviderInterface, ShellTokenizerInterface, etc.)
  • DTO/CreateBranchInput, DTO/BranchSpecInput
  • Service/BranchSpecGeneratorSelector — sélectionne LLM ou TEMPLATE selon BranchSpecGeneratorKind
  • Service/Prompt/TemplateRenderer — rendu de templates {{placeholder}}
  • Service/InitContext/InitPromptGraphValidator — valide les dépendances du DAG de prompts init-context

src/Infrastructure/

  • Adapter/LLM/AiCodeReviewer — implémente CodeReviewerProvider ; orchestre OllamaInvoker, ReportAssembler, ReviewerErrorHandler
  • Adapter/LLM/OllamaInvoker (+ OllamaMessageBagFactory, LLMOptionsBuilder, HttpClientPlatformExceptionClassifier) — couche d'appel Ollama
  • Adapter/LLM/ReviewPromptBuilder — assemble le prompt depuis un ReviewContext
  • Adapter/LLM/OllamaChatAdapter — chat Ollama simple (implémente OllamaChatAdapterInterface)
  • Adapter/Serialization/AnalysisReportDeserializer, MetricReportDeserializer, ManualAnalysisReportMapper, AliasResolver
  • Adapter/Persistence/Doctrine/DoctrineAnalysisReportRepository — implémentation de AnalysisReportProvider
  • Adapter/Persistence/Doctrine/DoctrineDashboardStatsProvider + helpers Stats/ (ByTypeBreakdownBuilder, DailyTrendBuilder, RunFilterClauseBuilder, StatusBreakdownClassifier)
  • Adapter/Persistence/Doctrine/DoctrineRunNameLister — liste les runName existants pour les filtres dashboard
  • Adapter/Persistence/Doctrine/Type/CriteriaType, Type/CriterionHydrator — type Doctrine custom pour les critères
  • Adapter/FileSystem/SymfonyProjectFileSystem — implémente ProjectFileSystemProvider/Lister/Writer
  • Adapter/Bash/ShellBashCommandRunner, ShellTokenizer
  • Bridge/Symfony/Command/AbstractReviewCommand — base des commandes mono-type (options --format, --fail-on, --no-cache)
  • Bridge/Symfony/Command/ReviewCommand — implémentation générique enregistrée 7 fois (une par AnalysisType)
  • Bridge/Symfony/Command/ReviewAllTypeCommand (app:review:all) — enchaîne tous les types
  • Bridge/Symfony/Command/ReviewBranchCommand (app:review:branch) — revue limitée aux fichiers modifiés vs develop
  • Bridge/Symfony/Command/InitBranchCommand (app:init:branch)
  • Bridge/Symfony/Command/InitContextCommand (app:init:context)
  • Bridge/Symfony/Command/StartMcpServerCommand (mcp:server:start) — démarre le serveur MCP
  • Bridge/Symfony/Command/{Console,Json,Composite,}FileReviewCollector — collecteurs de résultats
  • Bridge/Symfony/Command/CommandFailure — helper de sortie d'erreur uniforme
  • Bridge/Symfony/Mcp/McpReviewHandler — handler générique enregistré par compiler pass (un service par AnalysisType)
  • Bridge/Symfony/Mcp/McpReportHandler, McpBashCommandHandler, McpOllamaChatHandler, McpFileReviewCollector
  • Bridge/Symfony/DependencyInjection/ReviewHandlerCompilerPass — crée et câble une instance de McpReviewHandler par AnalysisType
  • Bridge/Symfony/SummaryTableRenderer — tableau récap pour app:review:all / branch
  • Bridge/Symfony/Controller/Admin/ — EasyAdmin CRUD (AnalysisReportCrudController, LLMMetricCrudController, DashboardController)
  • Bridge/Symfony/Controller/HomeController, DashboardController
  • Bridge/Symfony/Twig/Components/KpiCard, RecentAnalysesTable
  • Bridge/Symfony/Form/RunFilterType, Bridge/Symfony/Chart/DashboardChartFactory
  • Service/Prompt/PromptLoader (+ PromptFileLister, LoadedPrompt) — charge config/prompts/<principe>/*.md
  • Service/Prompt/InitPromptLoader — charge les prompts init-context avec ordre de dépendances
  • Service/Review/ReviewStrategyFactorycreateMultiCall(principe, type) / createTu(principe)
  • Service/Review/ReviewContextBuilder — orchestre l'enrichissement (lazy : interfaces, parent, callers, diff, test)
  • Service/Review/ReviewStrategyFingerprintProvider — empreinte du couple (modèle + prompts) injectée dans ReviewContext::$cacheFingerprint ; toute évolution invalide le cache
  • Service/Review/TimestampRunNameProvider — génère le runName (horodatage + suffixe aléatoire) partagé par tous les fichiers d'un run
  • Service/FileSystem/AnalysisFileResolver + FileReviewPipeline — résolution et lecture des .php
  • Service/FileSystem/{AllPhpFiles,ConcreteClass,NonTest}FileFilter + AnalysisTypeFileFilterContext — filtres par AnalysisType
  • Service/Git/GitFileDiffProvider, GitBranchManager, GitBranchChangedFilesProvider
  • Service/PhpAnalysis/PhpInheritanceResolver, PhpSymbolFileLocator, ProjectStructureAnalyzer (+ Builder/, Parser/)
  • Service/Project/GrepCallerLocator, UnitTestFileResolver, ProjectRootResolver
  • Service/BranchSpec/LlmBranchSpecGenerator, TemplateBranchSpecGenerator, ProjectDirBranchSpecWriter (écrit dans external-projects/docs/specs/)
  • Service/InitContext/ClassItemFormatter
  • Service/Stats/RunFilterResolver
  • Service/Json/ExtractorJson, ReparatorJson — nettoyage de la sortie LLM

Ajouter un nouveau type de revue

  1. Ajouter un case à Domain/Enum/AnalysisType (et son cas dans enrichments())
  2. Créer les sub-prompts config/prompts/<type>/01_*.md, 02_*.md, 03_*.md
  3. Enregistrer app.review_strategy.<name> dans services.yaml (via ReviewStrategyFactory) et l'ajouter à la map de ReviewStrategyContext
  4. Enregistrer app.review_command.<name> dans services.yaml (la ReviewCommand générique)
  5. Ajouter une entrée au AnalysisTypeFileFilterContext (filtre par type)
  6. Rien à faire pour MCP : ReviewHandlerCompilerPass crée automatiquement un McpReviewHandler pour chaque case d'AnalysisType

Variables d'environnement

Variable Description Valeur par défaut
DATABASE_URL DSN MySQL mysql://app:!ChangeMe!@database:3306/app
OLLAMA_BASE_URL URL de l'API Ollama http://localhost:11434
OLLAMA_MODEL Modèle Ollama partagé par toutes les stratégies de revue ministral-3:14b
EXTERNAL_PROJECTS_PATH Chemin hôte monté dans /app/external-projects (vide)
ALLOWED_BASH_COMMANDS Commandes bash autorisées par le serveur MCP ls,cat,grep,find
LLM_SEED Seed fixe optionnelle (sortie déterministe) (vide)
TOKEN_PRICE_PER_1M Prix par million de tokens (affichage dashboard) 1

Les sub-prompts ne sont pas configurés via env — ils sont découverts par convention dans config/prompts/<type>/*.md.


Stack technique

  • PHP 8.5+ avec property hooks
  • FrankenPHP — serveur d'application
  • Symfony 8 avec Symfony AI Bundle
  • EasyAdmin 5 — interface d'administration
  • Doctrine ORM avec mappings XML (config/orm/domain/)
  • Mago — lint, format, analyse statique et guard architectural
  • Ollama — inférence LLM locale