From 01b22f9c2da4c7c2ab41caba126df97fe68a7b78 Mon Sep 17 00:00:00 2001 From: Pier Paolo MAMMI Date: Wed, 22 Jul 2026 12:55:08 +0200 Subject: [PATCH] switch to php composer --- .agents/skills/php-common-library/SKILL.md | 2 +- .../skills/php-project-architecture/SKILL.md | 22 ++++----- .gitignore | 3 +- composer-dump-autoload.bat | 10 ++++ composer-install.bat | 10 ++++ composer.json | 13 +++++ composer.lock | 20 ++++++++ php/AGENTS.md | 8 ++-- php/common/ElixFormsComponent.php | 3 -- php/docker-compose.yml | 4 +- .../index.php | 3 +- .../search-contratti.php | 2 +- php/scelta-carriera/index.php | 2 +- scripts/composer-dump-autoload.ps1 | 2 + scripts/composer-install.ps1 | 2 + scripts/composer-run-command.ps1 | 47 +++++++++++++++++++ 16 files changed, 128 insertions(+), 25 deletions(-) create mode 100644 composer-dump-autoload.bat create mode 100644 composer-install.bat create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 scripts/composer-dump-autoload.ps1 create mode 100644 scripts/composer-install.ps1 create mode 100644 scripts/composer-run-command.ps1 diff --git a/.agents/skills/php-common-library/SKILL.md b/.agents/skills/php-common-library/SKILL.md index e386153..4a4708e 100644 --- a/.agents/skills/php-common-library/SKILL.md +++ b/.agents/skills/php-common-library/SKILL.md @@ -32,7 +32,7 @@ namespace ElixForms\Common; Le pagine importano con: ```php -require_once __DIR__ . '/../common/ElixFormsComponent.php'; +require_once __DIR__ . '/../../vendor/autoload.php'; use ElixForms\Common\ElixFormsComponent; ``` diff --git a/.agents/skills/php-project-architecture/SKILL.md b/.agents/skills/php-project-architecture/SKILL.md index 6e38cc6..a53a4dd 100644 --- a/.agents/skills/php-project-architecture/SKILL.md +++ b/.agents/skills/php-project-architecture/SKILL.md @@ -20,6 +20,8 @@ Questa struttura è l'equivalente PHP del monorepo React in `react/`. ``` elixforms-custom-pages/ +├── composer.json ← Configurazione Composer e autoload PSR-4 +├── vendor/ ← Autoloader generato (non versionato) ├── react/ ← Custom pages React (esistente) └── php/ ← Custom pages PHP ├── AGENTS.md ← Regole dell'agente PHP @@ -35,7 +37,7 @@ elixforms-custom-pages/ Ogni pagina (es. `scelta-carriera/`) è un file PHP autonomo che: -1. **Include la libreria `common/`** tramite `require_once` +1. **Carica l'autoloader Composer** tramite `vendor/autoload.php` 2. **Definisce una classe** che estende `ElixFormsComponent` 3. **Sovrascrive `createCustomFormFields()`** per i campi specifici 4. **Istanzia e renderizza** la pagina con `echo $page->render()` @@ -50,13 +52,10 @@ Il progetto usa **namespace PSR-4**: namespace ElixForms\Common; // Per le classi in common/ ``` -L'autoloading è gestito manualmente con `require_once` (non Composer): +L'autoloading PSR-4 è gestito da Composer: ```php -require_once __DIR__ . '/../common/ElixFormsComponent.php'; -// ElixFormsComponent.php include internamente: -// - QueryParamHelper.php -// - ElixFormsElement.php +require_once __DIR__ . '/../../vendor/autoload.php'; ``` ## Requisiti PHP @@ -108,7 +107,7 @@ Identica alla versione React: | **Linguaggio** | TypeScript/JSX | PHP 8.0+ | | **Rendering** | Client-side | Server-side | | **Build tool** | Vite (single bundle JS) | Nessuno (file serviti direttamente) | -| **Dipendenze** | npm (React, Vite, plugin) | Nessuna (PHP built-in) | +| **Dipendenze** | npm (React, Vite, plugin) | Composer (autoload PSR-4) | | **CSS loading** | `@import url()` + CSS injection plugin | `` tags | | **State management** | React state (`this.setState`) | Stateless (`$_GET`) | | **Deploy** | Upload del bundle `.js` | Upload dei file `.php` | @@ -116,9 +115,10 @@ Identica alla versione React: ## Deploy su Apache -1. Caricare la cartella `php/` sul server Apache -2. Configurazione Apache minima: +1. Eseguire `composer install --no-dev --optimize-autoloader` dalla root del repository +2. Caricare sul server le cartelle `php/` e `vendor/`, mantenendole allo stesso livello +3. Configurazione Apache minima: - `mod_php` o `php-fpm` abilitato - `DirectoryIndex index.php` (default Apache) -3. La pagina è accessibile via URL: `https://server/php/nome-pagina/` -4. elixForms reindirizza l'utente alla pagina passando i parametri via query string +4. La pagina è accessibile via URL: `https://server/php/nome-pagina/` +5. elixForms reindirizza l'utente alla pagina passando i parametri via query string diff --git a/.gitignore b/.gitignore index 105cb40..13f4e6d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ lerna-debug.log* # Dependency directories node_modules +vendor # Build generated files dist @@ -54,4 +55,4 @@ obj *.sw? # Configuration files -**/config.json \ No newline at end of file +**/config.json diff --git a/composer-dump-autoload.bat b/composer-dump-autoload.bat new file mode 100644 index 0000000..6731439 --- /dev/null +++ b/composer-dump-autoload.bat @@ -0,0 +1,10 @@ +@echo off +SETLOCAL EnableDelayedExpansion +echo %cmdcmdline% | findstr /i /c:"%~nx0" >NUL && set iscommandline=1 +echo %PSModulePath% | findstr /i /c:"%USERPROFILE%" >NUL && set ispowershell=1 +cd /D "%~dp0" + +@pwsh -NoProfile -ExecutionPolicy Bypass -Command .\scripts\composer-dump-autoload.ps1 + +IF DEFINED iscommandline IF NOT DEFINED ispowershell pause +ENDLOCAL diff --git a/composer-install.bat b/composer-install.bat new file mode 100644 index 0000000..9f7bf18 --- /dev/null +++ b/composer-install.bat @@ -0,0 +1,10 @@ +@echo off +SETLOCAL EnableDelayedExpansion +echo %cmdcmdline% | findstr /i /c:"%~nx0" >NUL && set iscommandline=1 +echo %PSModulePath% | findstr /i /c:"%USERPROFILE%" >NUL && set ispowershell=1 +cd /D "%~dp0" + +@pwsh -NoProfile -ExecutionPolicy Bypass -Command .\scripts\composer-install.ps1 + +IF DEFINED iscommandline IF NOT DEFINED ispowershell pause +ENDLOCAL diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..adc9318 --- /dev/null +++ b/composer.json @@ -0,0 +1,13 @@ +{ + "name": "elixforms-web-pages/pages", + "description": "Custom web pages PHP per elixForms", + "license": "proprietary", + "require": { + "php": ">=8.0" + }, + "autoload": { + "psr-4": { + "ElixForms\\Common\\": "php/common/" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..3f379b1 --- /dev/null +++ b/composer.lock @@ -0,0 +1,20 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "23a05b8814892947b8a622a763a2ace5", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=8.0" + }, + "platform-dev": {}, + "plugin-api-version": "2.9.0" +} diff --git a/php/AGENTS.md b/php/AGENTS.md index b34533d..42ba9c2 100644 --- a/php/AGENTS.md +++ b/php/AGENTS.md @@ -14,7 +14,8 @@ In caso di conflitti di ID (ad esempio con input `hidden`), applicare il suffiss 2. **Namespace PSR-4**: - Tutte le classi nella libreria comune usano il namespace `ElixForms\Common;`. - - Il caricamento è manuale tramite `require_once __DIR__ . '/../common/ElixFormsComponent.php';`. + - L'autoload PSR-4 è gestito da Composer tramite `vendor/autoload.php`. + - Gli entry point includono `require_once __DIR__ . '/../../vendor/autoload.php';`; le classi comuni non devono includersi manualmente tra loro. 3. **Rendering Server-Side**: - I file PHP generano direttamente l'HTML server-side usando il design system Bootstrap Italia di UniPR. @@ -24,12 +25,13 @@ In caso di conflitti di ID (ad esempio con input `hidden`), applicare il suffiss - I checkbox inviano il proprio stato serializzato come stringa separata da virgole tramite un input hidden (gestito client-side da uno script JS automatico). ## Deploy e Server Locale -- **Deploy**: Le cartelle vengono caricate direttamente su web server Apache. +- **Dipendenze**: dalla root del repository eseguire `composer install --optimize-autoloader` oppure `composer-install.bat`. +- **Deploy**: Eseguire `composer install --no-dev --optimize-autoloader` e caricare sul server sia `php/` sia `vendor/`, mantenendole allo stesso livello. - **Server locale**: - **PHP CLI**: Avviare il server dalla cartella `php/` tramite `php -S localhost:8080` (le pagine saranno raggiungibili su `http://localhost:8080//`). - **Docker**: Dalla root del repository, eseguire: ```bash - docker run --rm -p 8080:8080 -v "${PWD}/php:/app" -w /app php:8.2-cli php -S 0.0.0.0:8080 + docker run --rm -p 8080:8080 -v "${PWD}:/app" -w /app/php php:8.2-cli php -S 0.0.0.0:8080 ``` ## Skill PHP Correlate diff --git a/php/common/ElixFormsComponent.php b/php/common/ElixFormsComponent.php index cb29d61..f48ed23 100644 --- a/php/common/ElixFormsComponent.php +++ b/php/common/ElixFormsComponent.php @@ -4,9 +4,6 @@ declare(strict_types=1); namespace ElixForms\Common; -require_once __DIR__ . '/QueryParamHelper.php'; -require_once __DIR__ . '/ElixFormsElement.php'; - /** * Classe astratta base per le custom page PHP di elixForms. * Equivalente PHP di ElixFormsComponentAbstract.tsx nel progetto React. diff --git a/php/docker-compose.yml b/php/docker-compose.yml index 6b3021c..b5ff245 100644 --- a/php/docker-compose.yml +++ b/php/docker-compose.yml @@ -6,13 +6,13 @@ services: context: . dockerfile: ../.docker/php/Dockerfile container_name: elixforms-www - working_dir: /app + working_dir: /app/php extra_hosts: - "host.docker.internal:host-gateway" ports: - "8080:8000" volumes: - - .:/app + - ..:/app - ../.docker/php/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini #environment: # XDEBUG_MODE: debug diff --git a/php/recupero-proposta-cct-da-contratti/index.php b/php/recupero-proposta-cct-da-contratti/index.php index 955e070..be2e637 100644 --- a/php/recupero-proposta-cct-da-contratti/index.php +++ b/php/recupero-proposta-cct-da-contratti/index.php @@ -2,8 +2,7 @@ declare(strict_types=1); -require_once __DIR__ . '/../common/ElixFormsComponent.php'; -require_once __DIR__ . '/../common/QueryParamHelper.php'; +require_once __DIR__ . '/../../vendor/autoload.php'; use ElixForms\Common\ElixFormsComponent; use ElixForms\Common\QueryParamHelper; diff --git a/php/recupero-proposta-cct-da-contratti/search-contratti.php b/php/recupero-proposta-cct-da-contratti/search-contratti.php index c292ec3..145b11b 100644 --- a/php/recupero-proposta-cct-da-contratti/search-contratti.php +++ b/php/recupero-proposta-cct-da-contratti/search-contratti.php @@ -4,7 +4,7 @@ declare(strict_types=1); header('Content-Type: application/json; charset=utf-8'); -require_once __DIR__ . '/../common/HttpClient.php'; +require_once __DIR__ . '/../../vendor/autoload.php'; use ElixForms\Common\HttpClient; diff --git a/php/scelta-carriera/index.php b/php/scelta-carriera/index.php index 80bccca..0641d10 100644 --- a/php/scelta-carriera/index.php +++ b/php/scelta-carriera/index.php @@ -2,7 +2,7 @@ declare(strict_types=1); -require_once __DIR__ . '/../common/ElixFormsComponent.php'; +require_once __DIR__ . '/../../vendor/autoload.php'; use ElixForms\Common\ElixFormsComponent; diff --git a/scripts/composer-dump-autoload.ps1 b/scripts/composer-dump-autoload.ps1 new file mode 100644 index 0000000..0dd5311 --- /dev/null +++ b/scripts/composer-dump-autoload.ps1 @@ -0,0 +1,2 @@ +$ErrorActionPreference = 'Stop' +& (Join-Path $PSScriptRoot 'composer-run-command.ps1') -Command dump-autoload -Arguments @('--optimize') diff --git a/scripts/composer-install.ps1 b/scripts/composer-install.ps1 new file mode 100644 index 0000000..e1bdd1e --- /dev/null +++ b/scripts/composer-install.ps1 @@ -0,0 +1,2 @@ +$ErrorActionPreference = 'Stop' +& (Join-Path $PSScriptRoot 'composer-run-command.ps1') -Command install -Arguments @('--optimize-autoloader') diff --git a/scripts/composer-run-command.ps1 b/scripts/composer-run-command.ps1 new file mode 100644 index 0000000..db0c5b2 --- /dev/null +++ b/scripts/composer-run-command.ps1 @@ -0,0 +1,47 @@ +param( + [Parameter(Mandatory)][string]$Command, + [string[]]$Arguments = @() +) + +$ErrorActionPreference = 'Stop' +$root = (Resolve-Path (Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) '..')).Path + +$useDockerComposer = $false +$dockerRoot = $null + +if (-not (Get-Command composer -ErrorAction SilentlyContinue)) { + Write-Host "Composer non trovato localmente. Verifico se Docker è disponibile..." + if (-not (Get-Command docker -ErrorAction SilentlyContinue)) { + throw "Composer non trovato e Docker mancante! Installa Composer o Docker prima di continuare." + } + + $dockerRoot = $root -replace '\\', '/' + if ($dockerRoot -match '^([A-Za-z]):') { + $dockerRoot = "/$($Matches[1].ToLower())$($dockerRoot.Substring(2))" + } + + Write-Host "Docker trovato. Verifico Composer tramite container..." + docker run --rm -v "$($dockerRoot):/app" -w /app composer:2 composer --version 2>&1 + if ($LASTEXITCODE -ne 0) { + throw "Docker presente, ma Composer non riesce ad avviarsi tramite container. Installa Composer localmente o verifica Docker." + } + + $useDockerComposer = $true +} + +Push-Location $root +try { + if ($useDockerComposer) { + docker run --rm -v "$($dockerRoot):/app" -w /app composer:2 composer $Command @Arguments + } + else { + composer $Command @Arguments + } + + if ($LASTEXITCODE -ne 0) { + throw "Composer ha restituito il codice di uscita $LASTEXITCODE." + } +} +finally { + Pop-Location +}