refactor solution to PHP through AI
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
---
|
||||
name: elixforms-php-common-library
|
||||
description: >
|
||||
Documentazione della libreria condivisa PHP common/ del progetto elixForms.
|
||||
Descrive la classe base ElixFormsComponent, i metodi factory per i campi form,
|
||||
ElixFormsElement per il layout, QueryParamHelper per i query parameter,
|
||||
e il pattern di ereditarietà per creare pagine custom.
|
||||
Attiva questa skill quando lavori sui componenti PHP condivisi, crei nuovi tipi di campo,
|
||||
modifichi la classe base, o integri con la piattaforma elixForms in PHP.
|
||||
---
|
||||
|
||||
# Libreria Common PHP elixForms
|
||||
|
||||
## Panoramica
|
||||
|
||||
La cartella `php/common/` contiene la libreria condivisa PHP usata da tutte le pagine custom PHP. È basata su **Bootstrap Italia + HTML nativo** e implementa un sistema di form con campi dinamici, analogo alla libreria React in `react/common/`.
|
||||
|
||||
## Architettura delle Classi
|
||||
|
||||
```
|
||||
ElixFormsComponent (classe astratta, PHP 8.0+)
|
||||
└── SceltaCarrieraPage (classe concreta, in scelta-carriera/index.php)
|
||||
└── [AltrePageCustom] (classi concrete nelle sotto-cartelle)
|
||||
```
|
||||
|
||||
### Namespace
|
||||
|
||||
Tutte le classi usano il namespace PSR-4:
|
||||
```php
|
||||
namespace ElixForms\Common;
|
||||
```
|
||||
|
||||
Le pagine importano con:
|
||||
```php
|
||||
require_once __DIR__ . '/../common/ElixFormsComponent.php';
|
||||
use ElixForms\Common\ElixFormsComponent;
|
||||
```
|
||||
|
||||
## File della Libreria
|
||||
|
||||
### `ElixFormsComponent.php` (Classe Base Astratta)
|
||||
|
||||
Equivalente di `ElixFormsComponentAbstract.tsx` in React.
|
||||
|
||||
#### Proprietà
|
||||
|
||||
```php
|
||||
protected array $properties; // Equivalente di IElixFormsComponentProperties
|
||||
```
|
||||
|
||||
Chiavi supportate in `$properties`:
|
||||
| Chiave | Tipo | Obbligatorio | Descrizione |
|
||||
|---|---|---|---|
|
||||
| `moduleName` | string | Sì | Nome del modulo nel breadcrumb |
|
||||
| `cardTitle` | string | Sì | Titolo della card principale |
|
||||
| `userDisplayName` | string | No | Nome utente nell'header |
|
||||
| `headerTitle` | string | No | Titolo sotto il breadcrumb |
|
||||
| `headerHeroImageSrc` | string | No | URL immagine hero |
|
||||
| `cardDescription` | string | No | Descrizione nella card |
|
||||
| `alertInfoTitle` | string | No | Titolo alert informativo |
|
||||
| `alertInfoMessage` | string | No | Messaggio alert informativo |
|
||||
| `instructionsTitle` | string | No | Titolo istruzioni |
|
||||
| `instructionsMessage` | string | No | Messaggio istruzioni |
|
||||
| `submitText` | string | No | Testo bottone submit (default: 'INVIA') |
|
||||
| `additionalFieldsJson` | string | No | JSON schema per campi dinamici |
|
||||
| `isDarkTheme` | bool | No | Tema scuro (riservato per uso futuro) |
|
||||
|
||||
#### Metodi Factory (Campi Form)
|
||||
|
||||
| Metodo | Tipo Campo | HTML Output |
|
||||
|---|---|---|
|
||||
| `createTextInput($name, $label, $required)` | Testo | `<input type="text">` |
|
||||
| `createTextAreaInput($name, $label, $required)` | Textarea | `<textarea>` |
|
||||
| `createNumberInput($name, $label, $required)` | Numerico | `<input type="number">` |
|
||||
| `createBooleanInput($name, $label, $required)` | Booleano (Sì/No) | Radio buttons |
|
||||
| `createRadioInput($name, $label, $options, $required)` | Radio | Radio buttons |
|
||||
| `createCheckboxInput($name, $label, $options)` | Checkbox multipli | Checkboxes + hidden |
|
||||
| `createDropdownInput($name, $label, $options, $required)` | Dropdown | `<select>` |
|
||||
| `createHiddenInput($name)` | Nascosto | `<input type="hidden">` |
|
||||
|
||||
#### Metodi Estensibili (Override)
|
||||
|
||||
```php
|
||||
// Campi custom del form — OBBLIGATORIO sovrascrivere
|
||||
protected function createCustomFormFields(): string { return ''; }
|
||||
|
||||
// Contenuto extra prima del form
|
||||
protected function renderExtraContentPre(): string { return ''; }
|
||||
|
||||
// Contenuto extra dopo il form
|
||||
protected function renderExtraContentPost(): string { return ''; }
|
||||
```
|
||||
|
||||
#### Metodo Principale
|
||||
|
||||
```php
|
||||
public function render(): string
|
||||
```
|
||||
|
||||
Genera l'HTML **completo** della pagina (`<!DOCTYPE html>` ... `</html>`), includendo:
|
||||
- `<head>` con CSS Bootstrap Italia e design system UniPR
|
||||
- Header con logo UniPR e nome utente
|
||||
- Breadcrumb
|
||||
- Card con alert, istruzioni, form e campi
|
||||
- Footer "powered by elixForms"
|
||||
- Script JS per checkbox
|
||||
|
||||
### `ElixFormsElement.php` (Wrapper Layout)
|
||||
|
||||
Genera il layout a due colonne per ogni campo form:
|
||||
|
||||
```php
|
||||
$element = new ElixFormsElement($labelHtml, $inputHtml, $separator);
|
||||
echo $element->render();
|
||||
```
|
||||
|
||||
Output HTML:
|
||||
```html
|
||||
<div class="row mb-3 align-items-start">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="text-md-end pe-md-3 mt-2">{label}</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-8">
|
||||
{input}
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### `QueryParamHelper.php` (Utility Query String)
|
||||
|
||||
Classe statica per leggere parametri dalla query string `$_GET`:
|
||||
|
||||
```php
|
||||
QueryParamHelper::getCheckedFromQuery('COL0006'); // int[] (checkbox, valori separati da virgola)
|
||||
QueryParamHelper::getOptionFromQuery('COL0015'); // ?int (radio/dropdown)
|
||||
QueryParamHelper::getBooleanFromQuery('COL0004'); // ?bool (boolean)
|
||||
QueryParamHelper::getDecodedTextFromQuery('COL0002'); // ?string (testo URL-decoded)
|
||||
```
|
||||
|
||||
### `HttpClient.php` (Utility Richieste HTTP REST)
|
||||
|
||||
Classe orientata agli oggetti per effettuare chiamate HTTP server-to-server sicure verso Web Service esterni (es. endpoint contratti):
|
||||
|
||||
```php
|
||||
use ElixForms\Common\HttpClient;
|
||||
|
||||
$client = new HttpClient([
|
||||
'X-Api-Key' => 'chiave-api-custom',
|
||||
'Accept' => 'application/json'
|
||||
]);
|
||||
$client->setBasicAuth('username', 'password');
|
||||
$client->setTimeout(10); // timeout in secondi
|
||||
|
||||
// Richiesta GET
|
||||
$response = $client->get('http://api-endpoint/cerca', [
|
||||
'parametro1' => 'valore1'
|
||||
]);
|
||||
```
|
||||
|
||||
**Best Practices gestite da HttpClient:**
|
||||
- **Timeout**: Gestione dei timeout di connessione ed esecuzione per evitare blocchi infiniti del server Apache.
|
||||
- **Sicurezza delle credenziali**: Permette di eseguire chiamate server-side mantenendo chiavi API e password nascoste al browser del client.
|
||||
- **Error Handling**: Se il server remoto restituisce codici HTTP diversi da 20x (es. 404, 500), solleva una `RuntimeException` contenente il codice di stato generico senza includere nel messaggio d'errore l'eventuale payload della risposta (es. tag HTML dell'errore di Apache) per motivi di sicurezza ed integrità del JSON finale.
|
||||
|
||||
## Differenze rispetto alla versione React
|
||||
|
||||
| Aspetto | React | PHP |
|
||||
|---|---|---|
|
||||
| **Rendering** | Client-side (JSX → DOM) | Server-side (PHP → HTML) |
|
||||
| **State** | `this.state` + `this.setState()` | Valori da `$_GET` (stateless) |
|
||||
| **Checkbox sync** | React state + hidden input | JS client-side + hidden input |
|
||||
| **Build** | Vite → single bundle JS | Nessuna build necessaria |
|
||||
| **CSS** | Iniettato nel JS | `<link>` tags nell'HTML |
|
||||
| **Output** | Singolo file `.js` | File `.php` serviti da Apache |
|
||||
|
||||
## Parametri Obbligatori elixForms
|
||||
|
||||
Gestiti automaticamente come hidden inputs dalla classe base:
|
||||
- `RWE2_MODULE_ID`, `RWE2_REQUEST_ID`
|
||||
- `custom-workflow-back-url`, `custom-workflow-generic-id`
|
||||
- `custom-workflow-current-tabrel-genid`, `custom-workflow-source-field`
|
||||
- `crc`, `MODULE_TESTMODE_KEY`, `ELANG`
|
||||
|
||||
## Note Importanti
|
||||
|
||||
- Il form fa POST a `https://procedure.unipr.it/rwe2/ComeBackToElixAndSave`
|
||||
- L'encoding charset è `ISO-8859-1` per compatibilità con il backend
|
||||
- Gli ID dei campi form **non devono mai essere manipolati** (vedi AGENTS.md)
|
||||
- L'ID dell'hidden input dei checkbox e dei mandatory fields ha suffisso `_hidden`
|
||||
- I checkbox usano un attributo `data-param` e uno script JS per sincronizzare il valore con l'hidden input
|
||||
@@ -0,0 +1,258 @@
|
||||
---
|
||||
name: elixforms-php-create-new-page
|
||||
description: >
|
||||
Guida step-by-step per creare una nuova pagina custom PHP nel progetto elixForms.
|
||||
Copre la struttura dei file, l'importazione della libreria common,
|
||||
le convenzioni di naming, e la configurazione per il deploy su Apache.
|
||||
Attiva questa skill quando devi creare una nuova pagina PHP,
|
||||
duplicare una pagina esistente, o scaffoldare un nuovo micro-progetto PHP nel monorepo.
|
||||
---
|
||||
|
||||
# Creare una Nuova Pagina PHP elixForms Custom
|
||||
|
||||
## Prerequisiti
|
||||
|
||||
- PHP 8.0+ installato
|
||||
- Web server Apache configurato per servire la cartella `php/`
|
||||
|
||||
## Step 1: Creare la Cartella della Pagina
|
||||
|
||||
```powershell
|
||||
cd php
|
||||
mkdir <nome-pagina>
|
||||
```
|
||||
|
||||
Il nome della cartella deve essere in **kebab-case** (es. `scelta-carriera`, `recupero-proposta`).
|
||||
|
||||
## Step 2: Creare il File index.php
|
||||
|
||||
Creare `php/<nome-pagina>/index.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../common/ElixFormsComponent.php';
|
||||
|
||||
use ElixForms\Common\ElixFormsComponent;
|
||||
|
||||
/**
|
||||
* Pagina custom "<NomePagina>" per elixForms.
|
||||
*/
|
||||
class NomePaginaPage extends ElixFormsComponent
|
||||
{
|
||||
protected function createCustomFormFields(): string
|
||||
{
|
||||
$html = '';
|
||||
|
||||
// Aggiungi qui i campi del form usando i metodi factory:
|
||||
// $html .= $this->createTextInput('COL0001', 'Campo Testo', true);
|
||||
// $html .= $this->createDropdownInput('COL0002', 'Scelta', [...options], true);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
// Opzionale: contenuto extra prima del form
|
||||
// protected function renderExtraContentPre(): string { return ''; }
|
||||
|
||||
// Opzionale: contenuto extra dopo il form
|
||||
// protected function renderExtraContentPost(): string { return ''; }
|
||||
}
|
||||
|
||||
// Entry point
|
||||
$page = new NomePaginaPage([
|
||||
'moduleName' => 'Nome Modulo',
|
||||
'cardTitle' => 'Titolo Pagina',
|
||||
'cardDescription' => 'Descrizione della pagina.',
|
||||
'userDisplayName' => '', // Verrà popolato da elixForms
|
||||
'headerTitle' => '',
|
||||
'headerHeroImageSrc' => '',
|
||||
'alertInfoTitle' => '',
|
||||
'alertInfoMessage' => '',
|
||||
'instructionsTitle' => '',
|
||||
'instructionsMessage' => '',
|
||||
'submitText' => 'INVIA',
|
||||
]);
|
||||
|
||||
echo $page->render();
|
||||
```
|
||||
|
||||
## Step 3: Definire i Campi Custom
|
||||
|
||||
Sovrascrivere `createCustomFormFields()` con i campi necessari:
|
||||
|
||||
```php
|
||||
protected function createCustomFormFields(): string
|
||||
{
|
||||
$html = '';
|
||||
|
||||
// Dropdown
|
||||
$html .= $this->createDropdownInput('COL0015', 'Scelta', [
|
||||
['value' => 0, 'label' => 'Opzione A'],
|
||||
['value' => 1, 'label' => 'Opzione B'],
|
||||
['value' => 2, 'label' => 'Opzione C'],
|
||||
], true);
|
||||
|
||||
// Testo
|
||||
$html .= $this->createTextInput('COL0002', 'Nome', true);
|
||||
|
||||
// Textarea
|
||||
$html .= $this->createTextAreaInput('COL0003', 'Note', false);
|
||||
|
||||
// Booleano (Sì/No)
|
||||
$html .= $this->createBooleanInput('COL0004', 'Conferma', true);
|
||||
|
||||
// Radio
|
||||
$html .= $this->createRadioInput('COL0005', 'Preferenza', [
|
||||
['value' => 1, 'label' => 'Prima scelta'],
|
||||
['value' => 2, 'label' => 'Seconda scelta'],
|
||||
], true);
|
||||
|
||||
// Checkbox
|
||||
$html .= $this->createCheckboxInput('COL0006', 'Opzioni Multiple', [
|
||||
['value' => 1, 'label' => 'Opzione 1'],
|
||||
['value' => 2, 'label' => 'Opzione 2'],
|
||||
]);
|
||||
|
||||
// Numerico
|
||||
$html .= $this->createNumberInput('COL0007', 'Quantità', true);
|
||||
|
||||
return $html;
|
||||
}
|
||||
```
|
||||
|
||||
## Step 4: Opzionale — Aggiungere File di Configurazione
|
||||
|
||||
Per pagine complesse, creare un file `config.json` nella cartella della pagina:
|
||||
|
||||
```json
|
||||
{
|
||||
"component": {
|
||||
"moduleName": "Nome Modulo",
|
||||
"cardTitle": "Titolo",
|
||||
"cardDescription": "Descrizione",
|
||||
"submitText": "CONFERMA"
|
||||
},
|
||||
"elixForms": {
|
||||
"inputs": {
|
||||
"codiceFiscale": "COL0009"
|
||||
},
|
||||
"outputs": {
|
||||
"campo1": "COL0001",
|
||||
"campo2": "COL0002"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Caricare nel PHP:
|
||||
```php
|
||||
$config = json_decode(file_get_contents(__DIR__ . '/config.json'), true);
|
||||
|
||||
$page = new NomePaginaPage($config['component']);
|
||||
echo $page->render();
|
||||
```
|
||||
|
||||
## Step 4.1: Pagine Interattive e Chiamate Asincrone (AJAX)
|
||||
|
||||
Se la pagina richiede autocompletamento o interattività (es. ricerca contratti):
|
||||
|
||||
### 1. Proxy Script PHP Locale
|
||||
Per non esporre credenziali sensibili (API Key, Basic Auth) al client, creare sempre uno script proxy locale (es. `search-contratti.php`) che:
|
||||
- Riceve i dati dal client.
|
||||
- Esegue la chiamata protetta tramite `HttpClient`.
|
||||
- Valida con `json_decode` che la risposta sia JSON valido prima di inviarla.
|
||||
- Risponde con `500` e un JSON d'errore pulito in caso di eccezioni.
|
||||
|
||||
### 2. Risoluzione Percorso URL in JavaScript
|
||||
Il server integrato PHP non esegue il redirect automatico per aggiungere lo slash alla fine delle cartelle. In JavaScript, calcolare sempre la base directory dinamica per supportare URL sia con che senza slash finale o con `index.php` esplicito:
|
||||
```javascript
|
||||
var baseDir = window.location.pathname;
|
||||
if (!baseDir.endsWith('/') && !baseDir.endsWith('.php')) {
|
||||
baseDir += '/';
|
||||
}
|
||||
var lastSlash = baseDir.lastIndexOf('/');
|
||||
var dir = baseDir.substring(0, lastSlash + 1);
|
||||
|
||||
var url = dir + 'search-contratti.php?term=' + encodeURIComponent(term);
|
||||
```
|
||||
|
||||
### 3. Parsing Sicuro degli Errori HTTP (Fetch)
|
||||
Non eseguire direttamente `response.json()` su risposte d'errore (500/404) o non-JSON per evitare il crash `Unexpected token '<'`. Utilizzare la tecnica del `response.text()`:
|
||||
```javascript
|
||||
fetch(url)
|
||||
.then(function(response) {
|
||||
return response.text().then(function(text) {
|
||||
var data = null;
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
} catch (e) {
|
||||
// Risposta non JSON (es. HTML d'errore del server)
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
var errMsg = (data && data.message) ? data.message :
|
||||
(data && data.error) ? data.error :
|
||||
('Errore API: ' + response.status + ' ' + response.statusText);
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
|
||||
if (data === null) {
|
||||
throw new Error('Risposta del server non in formato JSON.');
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
})
|
||||
```
|
||||
## Step 5: Testing Locale
|
||||
|
||||
Per testare le pagine localmente, è necessario avviare il server web dalla cartella radice `php/` (in modo che la cartella `common/` sia accessibile correttamente):
|
||||
|
||||
### Opzione 1: PHP CLI Server locale
|
||||
```powershell
|
||||
cd php
|
||||
php -S localhost:8080
|
||||
```
|
||||
Aprire nel browser:
|
||||
```
|
||||
http://localhost:8080/<nome-pagina>/?RWE2_MODULE_ID=123&RWE2_REQUEST_ID=456&COL0002=test&COL0015=3
|
||||
```
|
||||
|
||||
### Opzione 2: 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
|
||||
```
|
||||
Aprire nel browser:
|
||||
```
|
||||
http://localhost:8080/<nome-pagina>/?RWE2_MODULE_ID=123&RWE2_REQUEST_ID=456&COL0002=test&COL0015=3
|
||||
```
|
||||
|
||||
## Step 6: Deploy su Apache
|
||||
|
||||
1. Caricare la cartella `php/` (o la singola cartella della pagina) sul server Apache
|
||||
2. Assicurarsi che Apache abbia `mod_php` o `php-fpm` configurato
|
||||
3. La pagina sarà accessibile via URL diretto (es. `https://server.example.com/php/nome-pagina/`)
|
||||
4. elixForms reindirizza l'utente alla pagina passando i parametri in query string
|
||||
|
||||
## Struttura Finale
|
||||
|
||||
```
|
||||
php/<nome-pagina>/
|
||||
├── index.php ← Entry point e classe pagina
|
||||
└── config.json ← Opzionale: configurazione separata
|
||||
```
|
||||
|
||||
## Checklist Nuova Pagina PHP
|
||||
|
||||
- [ ] Cartella creata in `php/<nome-pagina>/`
|
||||
- [ ] `index.php` con `declare(strict_types=1)` e namespace
|
||||
- [ ] Classe che estende `ElixFormsComponent`
|
||||
- [ ] `createCustomFormFields()` sovrascritta con i campi corretti
|
||||
- [ ] Proprietà di configurazione impostate correttamente
|
||||
- [ ] `require_once __DIR__ . '/../common/ElixFormsComponent.php'`
|
||||
- [ ] Test locale con `php -S` o Docker
|
||||
- [ ] Verifica che i campi form producano l'HTML corretto
|
||||
- [ ] Verifica che i parametri obbligatori vengano letti da `$_GET`
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
name: elixforms-php-project-architecture
|
||||
description: >
|
||||
Architettura e struttura della parte PHP del progetto elixForms Custom Pages.
|
||||
Descrive la cartella php/, la libreria common condivisa, il pattern delle pagine,
|
||||
le convenzioni di naming, e il deploy su Apache.
|
||||
Attiva questa skill quando lavori sulla parte PHP del progetto,
|
||||
crei nuove pagine PHP, modifichi l'architettura, o devi capire come è organizzato il codice PHP.
|
||||
---
|
||||
|
||||
# Architettura PHP del Progetto elixForms Custom Pages
|
||||
|
||||
## Panoramica
|
||||
|
||||
La cartella `php/` contiene le custom page elixForms realizzate in **PHP 8.0+ puro** (nessun framework). Ogni pagina è un file PHP autonomo che include la libreria `common/` e produce HTML server-side con **Bootstrap Italia**.
|
||||
|
||||
Questa struttura è l'equivalente PHP del monorepo React in `react/`.
|
||||
|
||||
## Struttura del Workspace
|
||||
|
||||
```
|
||||
elixforms-custom-pages/
|
||||
├── react/ ← Custom pages React (esistente)
|
||||
└── php/ ← Custom pages PHP
|
||||
├── AGENTS.md ← Regole dell'agente PHP
|
||||
├── common/ ← Libreria condivisa PHP
|
||||
│ ├── ElixFormsComponent.php ← Classe base astratta
|
||||
│ ├── ElixFormsElement.php ← Wrapper layout label+input
|
||||
│ └── QueryParamHelper.php ← Utility query string
|
||||
└── scelta-carriera/ ← Esempio di pagina custom
|
||||
└── index.php ← Entry point (classe + rendering)
|
||||
```
|
||||
|
||||
## Pattern Architetturale: Singolo File PHP per Pagina
|
||||
|
||||
Ogni pagina (es. `scelta-carriera/`) è un file PHP autonomo che:
|
||||
|
||||
1. **Include la libreria `common/`** tramite `require_once`
|
||||
2. **Definisce una classe** che estende `ElixFormsComponent`
|
||||
3. **Sovrascrive `createCustomFormFields()`** per i campi specifici
|
||||
4. **Istanzia e renderizza** la pagina con `echo $page->render()`
|
||||
5. **Genera HTML completo** (dalla `<!DOCTYPE html>` al `</html>`)
|
||||
6. **Non richiede build** — servito direttamente da Apache
|
||||
|
||||
## Namespace e Autoloading
|
||||
|
||||
Il progetto usa **namespace PSR-4**:
|
||||
|
||||
```php
|
||||
namespace ElixForms\Common; // Per le classi in common/
|
||||
```
|
||||
|
||||
L'autoloading è gestito manualmente con `require_once` (non Composer):
|
||||
|
||||
```php
|
||||
require_once __DIR__ . '/../common/ElixFormsComponent.php';
|
||||
// ElixFormsComponent.php include internamente:
|
||||
// - QueryParamHelper.php
|
||||
// - ElixFormsElement.php
|
||||
```
|
||||
|
||||
## Requisiti PHP
|
||||
|
||||
- **Versione minima**: PHP 8.0+
|
||||
- **Funzionalità usate**:
|
||||
- `declare(strict_types=1)` — strict typing
|
||||
- Typed properties (`protected array $properties`)
|
||||
- `match` expression (nel renderField)
|
||||
- Named arguments
|
||||
- Union types (`int|null`, `string|null`)
|
||||
- Arrow functions (`fn() =>`)
|
||||
|
||||
## CSS Strategy
|
||||
|
||||
Le pagine PHP usano `<link>` tags per caricare i CSS (non bundle JS):
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Titillium+Web:wght@300;400;600;700&display=swap">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-italia@2.18.2/dist/css/bootstrap-italia.min.css">
|
||||
<link rel="stylesheet" href="https://console-unipr.elixforms.it/rwe2/css/design-bs/util.css">
|
||||
<link rel="stylesheet" href="https://console-unipr.elixforms.it/rwe2/css/themes/blu-italia.css">
|
||||
```
|
||||
|
||||
> **Nota**: Stessi CSS del progetto React, ma caricati via `<link>` anziché `@import url()` nel JS bundle.
|
||||
|
||||
## Integrazione con elixForms
|
||||
|
||||
Identica alla versione React:
|
||||
|
||||
1. **Query parameters**: Parametri obbligatori passati nell'URL da elixForms
|
||||
2. **Form POST**: Il form fa submit a `https://procedure.unipr.it/rwe2/ComeBackToElixAndSave`
|
||||
3. **Hidden inputs**: I parametri query vengono inseriti come campi hidden nel form
|
||||
4. **Encoding**: `accept-charset="ISO-8859-1"` per compatibilità con il backend
|
||||
|
||||
## Convenzioni di Naming
|
||||
|
||||
- **Cartelle pagina**: kebab-case (es. `scelta-carriera`)
|
||||
- **File entry point**: sempre `index.php`
|
||||
- **Classi PHP**: PascalCase con suffisso `Page` (es. `SceltaCarrieraPage`)
|
||||
- **Namespace**: `ElixForms\Common` per la libreria condivisa
|
||||
- **Configurazione**: opzionale `config.json` nella cartella della pagina
|
||||
|
||||
## Differenze con il Progetto React
|
||||
|
||||
| Aspetto | React (`react/`) | PHP (`php/`) |
|
||||
|---|---|---|
|
||||
| **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) |
|
||||
| **CSS loading** | `@import url()` + CSS injection plugin | `<link>` tags |
|
||||
| **State management** | React state (`this.setState`) | Stateless (`$_GET`) |
|
||||
| **Deploy** | Upload del bundle `.js` | Upload dei file `.php` |
|
||||
| **Dev server** | `npm run dev` (Vite HMR) | `php -S` / Docker |
|
||||
|
||||
## Deploy su Apache
|
||||
|
||||
1. Caricare la cartella `php/` sul server Apache
|
||||
2. 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
|
||||
Reference in New Issue
Block a user