# Strategia di Migrazione a Symfony 7

Questo documento descrive il percorso di migrazione da Symfony 4.x a Symfony 7.x.
La migrazione deve essere **incrementale**: Symfony 4 → 5.4 → 6.4 → 7.x. Non e possibile saltare versioni major.

Ogni fase include prerequisiti, modifiche necessarie e criteri di validazione prima di procedere alla fase successiva.

---

## Panoramica delle Fasi

| Fase | Target | PHP Minimo | Effort Stimato |
|---|---|---|---|
| 0 | Preparazione (su Symfony 4.x) | 7.4 | Medio |
| 1 | Symfony 5.4 LTS | 7.2.5 (8.1 consigliato) | Alto |
| 2 | Symfony 6.4 LTS | 8.1 | Alto |
| 3 | Symfony 7.x | 8.2 | Medio |

**Raccomandazione**: Migrare sempre alle versioni LTS (5.4, 6.4) per avere supporto esteso. Poi passare a 7.x.

---

## Fase 0 — Preparazione (rimani su Symfony 4.x)

Questa fase e critica: risolvere tutti i deprecation warning PRIMA di cambiare versione. Symfony garantisce che il codice senza deprecation warning su versione N funziona su versione N+1.

### 0.1 Aggiornare PHP a 8.1+

Il Dockerfile attuale usa `php:7.4-fpm`. PHP 7.4 e EOL.

```dockerfile
# Dockerfile — cambiare da:
FROM php:7.4-fpm
# a:
FROM php:8.1-fpm
```

Aggiornare anche `composer.json`:
```json
"require": {
    "php": "^8.1"
}
```

**Verifica**: `php -v` e `composer validate --strict`.

### 0.2 Risolvere le vulnerabilita di sicurezza critiche

Prima di qualsiasi migrazione, correggere i problemi documentati nel README.md sezione "Problemi Critici":

1. SQL injection in SearchController e ConfiguratoreController
2. SSL verification disabilitata in OktaApiService
3. Validazione JWT assente
4. Accesso a superglobali (`$_GET`, `$_ENV`)

Questi problemi sono indipendenti dalla versione Symfony e vanno risolti immediatamente.

### 0.3 Eliminare la classe `Controller` deprecata

Tre controller estendono `Symfony\Bundle\FrameworkBundle\Controller\Controller`:

```php
// PRIMA (deprecato):
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MyController extends Controller

// DOPO:
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class MyController extends AbstractController
```

File da modificare:
- `src/Controller/MyPDFController.php`
- `src/Controller/WelcomeController.php`
- `src/Controller/HomeController.php`

**Attenzione**: `AbstractController` non espone il service locator. Verificare che non ci siano chiamate `$this->get('...')`. Se presenti, sostituirle con dependency injection.

### 0.4 Eliminare il service locator pattern

Sostituire tutte le chiamate `$this->get('nome_servizio')` con injection:

```php
// PRIMA:
$this->get('session')->set('key', 'value');
$this->get('security.token_storage')->setToken(null);

// DOPO (constructor injection):
public function __construct(
    private SessionInterface $session,
    private TokenStorageInterface $tokenStorage
) {}

public function someAction(): Response
{
    $this->session->set('key', 'value');
    $this->tokenStorage->setToken(null);
}
```

### 0.5 Completare la migrazione SwiftMailer → Symfony Mailer

SwiftMailer e stato rimosso in Symfony 6. Deve essere completamente sostituito PRIMA della migrazione.

1. Aggiornare `ReportService` per usare `Symfony\Component\Mailer\MailerInterface`
2. Rimuovere `symfony/swiftmailer-bundle` da `composer.json`
3. Eliminare `config/packages/swiftmailer.yaml`

```php
// PRIMA (SwiftMailer):
$message = (new \Swift_Message('Subject'))
    ->setFrom('from@example.com')
    ->setTo('to@example.com')
    ->setBody($body, 'text/html');
$mailer->send($message);

// DOPO (Symfony Mailer):
$email = (new Email())
    ->from('from@example.com')
    ->to('to@example.com')
    ->subject('Subject')
    ->html($body);
$mailer->send($email);
```

### 0.6 Rimuovere `sensio/framework-extra-bundle`

Questo bundle e deprecato. Le sue funzionalita sono integrate nel core di Symfony 5.4+.

1. Rimuovere `sensio/framework-extra-bundle` da `composer.json`
2. Eliminare `config/packages/sensio_framework_extra.yaml`
3. Eliminare `config/packages/framework_extra.yaml`
4. Verificare che `@ParamConverter`, `@IsGranted`, `@Template` funzionino con gli attributi nativi

### 0.7 Sostituire `$this->getDoctrine()` (deprecato in 5.4)

```php
// PRIMA:
$em = $this->getDoctrine()->getManager();
$repo = $this->getDoctrine()->getRepository(User::class);

// DOPO:
public function __construct(
    private EntityManagerInterface $em,
    private UserRepository $userRepo
) {}
```

Questo interessa quasi tutti i controller.

### 0.8 Eseguire il deprecation detector

```bash
# Installa e configura il PHPUnit bridge per i deprecation warnings
SYMFONY_DEPRECATIONS_HELPER=max[direct]=0 ./vendor/bin/simple-phpunit

# Oppure usa il profiler web di Symfony (in dev) e controlla la toolbar
```

### 0.9 Aggiungere test per i percorsi critici

La copertura test attuale (~3%) rende la migrazione rischiosa. Aggiungere almeno:

- Test di login/logout (SecurityController)
- Test delle API principali
- Test dei servizi critici (OktaApiService, ReportService)
- Test smoke per ogni rotta protetta

**Criterio di uscita Fase 0**: Zero deprecation warning, tutti i test passano, PHP 8.1+.

---

## Fase 1 — Migrazione a Symfony 5.4 LTS

### 1.1 Aggiornare `composer.json`

```json
{
    "require": {
        "php": "^8.1",
        "symfony/framework-bundle": "^5.4",
        "symfony/security-bundle": "^5.4",
        "symfony/form": "^5.4",
        "symfony/mailer": "^5.4",
        "symfony/translation": "^5.4",
        "symfony/validator": "^5.4",
        "symfony/asset": "^5.4",
        "symfony/expression-language": "^5.4",
        "symfony/http-foundation": "^5.4",
        "symfony/security": "^5.4",
        "symfony/yaml": "^5.4",
        "symfony/flex": "^2.0",
        "doctrine/annotations": "^1.14",
        "doctrine/doctrine-bundle": "^2.7",
        "doctrine/orm": "^2.13"
    },
    "require-dev": {
        "symfony/browser-kit": "^5.4",
        "symfony/css-selector": "^5.4",
        "symfony/debug-bundle": "^5.4",
        "symfony/dotenv": "^5.4",
        "symfony/phpunit-bridge": "^6.0",
        "symfony/stopwatch": "^5.4",
        "symfony/twig-bundle": "^5.4",
        "symfony/var-dumper": "^5.4",
        "symfony/web-profiler-bundle": "^5.4"
    }
}
```

### 1.2 Aggiornare la configurazione Security

Il sistema di sicurezza e stato completamente riscritto in Symfony 5.3+.

```yaml
# config/packages/security.yaml
security:
    # PRIMA (deprecato):
    encoders:
        App\Entity\User: bcrypt

    # DOPO:
    password_hashers:
        App\Entity\User:
            algorithm: auto  # usa bcrypt o argon2 automaticamente

    # Firewall — aggiungere:
    firewalls:
        main:
            lazy: true  # sostituisce anonymous: true
            # ... resto della configurazione
```

### 1.3 Sostituire `IS_AUTHENTICATED_ANONYMOUSLY`

```yaml
# PRIMA:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }

# DOPO:
- { path: ^/login, roles: PUBLIC_ACCESS }
```

26 occorrenze da sostituire in `config/packages/security.yaml`.

### 1.4 Aggiornare l'entity User

`UserInterface` cambia in Symfony 5.3:

```php
// PRIMA:
class User implements UserInterface, \Serializable

// DOPO:
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;

class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    // Rimuovere serialize() e unserialize()
    // Aggiungere:
    public function getUserIdentifier(): string
    {
        return $this->username;
    }
}
```

### 1.5 Aggiornare i bundle di terze parti

Verificare la compatibilita di ogni bundle con Symfony 5.4:

| Bundle | Azione |
|---|---|
| `scheb/2fa-bundle` ^5 | Compatibile, verificare config |
| `lexik/jwt-authentication-bundle` ^2 | Aggiornare a ^3 |
| `friendsofsymfony/rest-bundle` ^2 | Aggiornare a ^3 |
| `friendsofsymfony/ckeditor-bundle` ^2 | Compatibile |
| `vich/uploader-bundle` ^1 | Aggiornare a ^2 |
| `endroid/qr-code-bundle` ^3 | Verificare compatibilita |
| `jmose/command-scheduler-bundle` ^2 | Verificare compatibilita |
| `mashape/unirest-php` ^3 | Sostituire con `symfony/http-client` |
| `roave/better-reflection` ^3 | Aggiornare a ^6 |

### 1.6 Aggiornare Symfony Flex

```bash
composer require symfony/flex:^2
```

**Criterio di uscita Fase 1**: Applicazione funzionante su Symfony 5.4, zero deprecation warning 5.4, tutti i test passano.

---

## Fase 2 — Migrazione a Symfony 6.4 LTS

### 2.1 PHP 8.1 obbligatorio

Symfony 6 richiede PHP 8.1+. Se non gia fatto nella Fase 0, aggiornare ora.

### 2.2 Migrare da Annotations a PHP Attributes

Symfony 6.x favorisce i PHP Attributes nativi (PHP 8.0+). Doctrine annotations restano supportate ma sono deprecate.

```php
// PRIMA (annotations):
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 * @ORM\Table(name="user")
 */
class User
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", unique=true)
     */
    private $username;
}

// DOPO (PHP 8 attributes):
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: 'user')]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private int $id;

    #[ORM\Column(type: 'string', unique: true)]
    private string $username;
}
```

Stesso discorso per le rotte:

```php
// PRIMA:
/**
 * @Route("/login", name="security_login")
 */
public function login(): Response

// DOPO:
#[Route('/login', name: 'security_login')]
public function login(): Response
```

**Strumento consigliato**: `rector/rector` con il set `Symfony64` per automatizzare le conversioni.

```bash
composer require --dev rector/rector
# Configurare rector.php con i set appropriati
vendor/bin/rector process src/
```

### 2.3 Aggiornare `composer.json` a Symfony 6.4

```json
{
    "require": {
        "php": "^8.1",
        "symfony/framework-bundle": "^6.4",
        // ... tutti i pacchetti symfony a ^6.4
    }
}
```

### 2.4 Rimuovere `doctrine/annotations`

```bash
composer remove doctrine/annotations
```

Tutte le entity, controller e configurazioni devono usare PHP attributes a questo punto.

### 2.5 Aggiornare Doctrine

```json
{
    "require": {
        "doctrine/orm": "^3.0",
        "doctrine/doctrine-bundle": "^2.11",
        "doctrine/doctrine-migrations-bundle": "^3.3"
    }
}
```

**Criterio di uscita Fase 2**: Applicazione su Symfony 6.4, PHP attributes ovunque, zero deprecation warning, test passano.

---

## Fase 3 — Migrazione a Symfony 7.x

### 3.1 PHP 8.2 obbligatorio

Symfony 7 richiede PHP 8.2+.

### 3.2 Aggiornare `composer.json`

```json
{
    "require": {
        "php": "^8.2",
        "symfony/framework-bundle": "^7.0",
        // ... tutti i pacchetti symfony a ^7.0
    }
}
```

### 3.3 Cambiamenti principali Symfony 7

Symfony 7 rimuove tutto cio che era deprecato in Symfony 6.4. Se la Fase 2 e stata completata correttamente (zero deprecation warning), questa fase dovrebbe essere relativamente semplice.

Principali rimozioni:
- `AbstractController::getDoctrine()` (gia rimosso in Fase 0)
- `UserInterface::getPassword()` senza `PasswordAuthenticatedUserInterface` (gia migrato in Fase 1)
- Annotations support rimosso (gia migrato in Fase 2)
- Vecchio sistema di sicurezza rimosso (gia migrato in Fase 1)

### 3.4 Aggiornare il Dockerfile

```dockerfile
FROM php:8.2-fpm
# oppure php:8.3-fpm per la versione piu recente

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
```

### 3.5 Aggiornare CI/CD

Sostituire `.travis.yml` con GitHub Actions:

```yaml
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  tests:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php: ['8.2', '8.3']
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: intl, pdo_mysql, gd, zip, imagick
      - run: composer install --no-progress
      - run: vendor/bin/phpunit
      - run: vendor/bin/php-cs-fixer fix --dry-run --diff
      - run: php bin/console lint:yaml config
      - run: php bin/console lint:twig templates
```

**Criterio di uscita Fase 3**: Applicazione su Symfony 7.x, PHP 8.2+, CI moderna, tutti i test passano.

---

## Strumenti Utili per la Migrazione

### Rector (refactoring automatizzato)

```bash
composer require --dev rector/rector

# rector.php
use Rector\Config\RectorConfig;
use Rector\Symfony\Set\SymfonySetList;
use Rector\Doctrine\Set\DoctrineSetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src'])
    ->withSets([
        SymfonySetList::SYMFONY_54,
        SymfonySetList::SYMFONY_64,
        DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
    ]);
```

```bash
# Anteprima delle modifiche (dry-run):
vendor/bin/rector process src/ --dry-run

# Applicare le modifiche:
vendor/bin/rector process src/
```

### Symfony Deprecation Detector

```bash
# In phpunit.xml.dist, assicurarsi che SYMFONY_DEPRECATIONS_HELPER sia configurato
# Poi eseguire i test per vedere tutti i deprecation warning
SYMFONY_DEPRECATIONS_HELPER=max[direct]=0 vendor/bin/simple-phpunit
```

### PHPStan (analisi statica)

```bash
composer require --dev phpstan/phpstan phpstan/phpstan-symfony
vendor/bin/phpstan analyse src/ --level=5
```

---

## Checklist Riepilogativa

### Fase 0 (su Symfony 4.x)
> Stato live in `UPGRADE_PROGRESS.md`.
- [x] Aggiornare PHP a 8.1+ (composer.json `^8.1` + platform 8.1.0, Dockerfile `php:8.1-fpm`; lock da rigenerare in Fase 1)
- [x] Correggere SQL injection (Search, Configuratore, Check, Counters; Converter/C4rgoUtils già a posto)
- [x] Abilitare SSL verification in OktaApiService (env-configurabile `OKTA_SSL_VERIFY`, default `true`)
- [ ] Aggiungere validazione JWT in OktaApiService (rimandato: serve `firebase/php-jwt` + JWKS)
- [~] Sostituire `$_GET`, `$_ENV` con DI e Request (OktaApiService fatto; ~15 file rimanenti)
- [x] Sostituire `Controller` con `AbstractController`
- [x] Eliminare `$this->get('...')` (service locator)
- [x] Completare migrazione SwiftMailer → Symfony Mailer (verificato completo)
- [x] Rimuovere `sensio/framework-extra-bundle` (@Method→@Route, @Security ridondanti rimosse, bundle deregistrato + tolto da composer.json; lock da rigenerare in Fase 1)
- [x] Sostituire `$this->getDoctrine()` con DI (58 file, zero usi attivi)
- [~] Aggiungere test per percorsi critici (rimossi i test demo skeleton, aggiunto smoke test DB-independent; i test di rotta richiedono un DB MariaDB di test)
- [~] Zero deprecation warning su Symfony 4.x (compile-time pulito; restano deprecation di terze parti FOSRest/property-access risolte aggiornando i bundle in Fase 1, + User `Serializable` in Fase 1.4)

### Fase 1 (Symfony 5.4)
- [ ] Aggiornare tutti i pacchetti Symfony a ^5.4
- [ ] `encoders` → `password_hashers`
- [ ] `IS_AUTHENTICATED_ANONYMOUSLY` → `PUBLIC_ACCESS`
- [ ] `UserInterface` → + `PasswordAuthenticatedUserInterface`
- [ ] Aggiungere `getUserIdentifier()`, rimuovere `serialize()`/`unserialize()`
- [ ] Aggiornare bundle terze parti
- [ ] Sostituire `mashape/unirest-php` con `symfony/http-client`
- [ ] Aggiornare Symfony Flex a ^2
- [ ] Zero deprecation warning su Symfony 5.4

### Fase 2 (Symfony 6.4)
- [ ] PHP 8.1+ confermato
- [ ] Migrare annotations → PHP attributes (entity, controller, validation)
- [ ] Aggiornare Doctrine ORM a ^3
- [ ] Rimuovere `doctrine/annotations`
- [ ] Aggiornare tutti i pacchetti Symfony a ^6.4
- [ ] Zero deprecation warning su Symfony 6.4

### Fase 3 (Symfony 7.x)
- [ ] Aggiornare PHP a 8.2+
- [ ] Aggiornare tutti i pacchetti Symfony a ^7.0
- [ ] Aggiornare Dockerfile
- [ ] Migrare CI da Travis a GitHub Actions
- [ ] Tutti i test passano
- [ ] Deploy in staging e test completo
