Vai al contenuto
Home / Blog /Tutorial / Sviluppare un'estensione per Maho con localdev

Sviluppare un'estensione per Maho con localdev

Trasforma la cartella localdev/ nel tuo cantiere: ogni pacchetto ha un repository git separato, viene symlinkato in vendor/ e i gate CI girano con un solo comando Harbor.

Read in English

Un’estensione Maho è un normale pacchetto Composer, ma svilupparla dentro lo store che la usa spinge di solito verso due strade pessime: lavorare direttamente nel vendor/, dove il prossimo composer update cancella le modifiche, oppure copiare i file avanti e indietro a mano. localdev/ chiude entrambe. Ogni pacchetto vive in una cartella sua, con un repository git separato dal root, e Composer lo symlinka dentro vendor/. Il codice che scrivi è già quello che lo store esegue, senza copie e senza reinstallare il progetto a ogni ritocco.

# senza localdev: lavori nel vendor e il prossimo update cancella le modifiche
vim vendor/acme/maho-example-shipping/Model/Shipping.php

# con localdev: lavori in localdev/, Composer lo symlinka in vendor/
vim localdev/maho-example-shipping/Model/Shipping.php

🔧 Nota di banco. Il cantiere è tuo: la cassetta degli attrezzi (localdev/) sta accanto al magazzino (vendor/), ma i due non si mescolano. Pialli, incolli e ricominci senza toccare la merce già in vendita sullo scaffale.

Cosa serve

  • Un progetto Maho con un ambiente funzionante. Nei nostri esempi usiamo Harbor, il launcher Docker Compose open source di MageMEGA, ispirato a Laravel Sail, descritto in Sviluppo locale di Maho con Harbor: se non lo conosci, parti da quell’articolo e poi torna qui.
  • Docker con il plugin Compose v2, perché ogni comando passa da Harbor.
  • Git, perché ogni pacchetto in localdev/ è un repository a sé, con il suo remote e la sua storia.

Quick start: dal pacchetto allo store

1. Dichiara il path repository

Dì a Composer che le cartelle di localdev/ sono una sorgente di pacchetti. Apri il composer.json del project root e aggiungi (o verifica) questo blocco:

{
    "repositories": [
        {
            "type": "path",
            "url": "./localdev/*",
            "options": {
                "symlink": true
            },
            "canonical": true
        }
    ]
}
  • type: "path" significa che la sorgente è una cartella locale, non Packagist.
  • url: "./localdev/*" tratta ogni sottocartella come un pacchetto.
  • symlink: true fa puntare vendor/<vendor>/<package> direttamente alla cartella in localdev/.
  • canonical: true fa vincere questa sorgente su Packagist per un pacchetto con lo stesso nome.

2. Metti il pacchetto in localdev/

mkdir -p localdev
git clone [email protected]:acme/maho-example-shipping.git localdev/maho-example-shipping

Se parti da zero, crea lo scheletro dal template empiricompany/module-template (fork di MahoCommerce/module-template) e inizializza il repository lì dentro. In entrambi i casi il pacchetto ha il suo .git, i suoi remote e la sua storia: il root non lo considera una sottocartella versionata.

3. Richiedilo in @dev

Un path repository non pubblica versioni taggate, quindi il pacchetto si risolve come versione di sviluppo. Installalo con il vincolo @dev:

./vendor/bin/harbor composer require acme/maho-example-shipping:@dev

In alternativa scrivi a mano la dipendenza e aggiorna solo quella:

"require": {
    "acme/maho-example-shipping": "@dev"
}
./vendor/bin/harbor composer update acme/maho-example-shipping

4. Installa le dipendenze del pacchetto ed esegui i gate

Il pacchetto ha un suo composer.json, con le proprie dipendenze di sviluppo e i propri script. Gestiscilo con --working-dir, senza entrare nella cartella:

# prima volta: installa le dipendenze di sviluppo dentro il pacchetto
./vendor/bin/harbor composer --working-dir=localdev/maho-example-shipping install

# tutti i gate del pacchetto (test, lint, cs, phpstan, rector) prima di pushare
./vendor/bin/harbor composer --working-dir=localdev/maho-example-shipping check

--working-dir punta Composer alla cartella del pacchetto, mentre harbor va sempre lanciato dalla root del progetto. check è l’alias definito nel composer.json del pacchetto: li dentro ci sono tutti i controlli che il repository esegue in CI.

5. Applica il modulo allo store

./vendor/bin/harbor composer update     # root: aggancia e aggiorna il pacchetto
./vendor/bin/harbor maho migrate        # esegue gli installer del modulo
./vendor/bin/harbor maho cache:flush

Lo store ora vede l’estensione. migrate applica schema e dati dichiarati dal modulo; cache:flush è obbligatorio dopo aver rinominato blocchi, handle di layout o alias di configurazione.

🔧 Nota di banco. Tra il banco e la vetrina c’è un composer update dalla root che collega il pacchetto allo store. È il momento in cui la panchina di lavoro si affaccia sulla bottega: da qui in poi ogni saldatura in localdev/ è già visibile, senza ricopiare niente.

Come funziona

Il punto centrale è che vendor/<vendor>/<package> non è una copia del pacchetto: è un link.

ls -l vendor/acme/maho-example-shipping
# lrwxrwxrwx ... vendor/acme/maho-example-shipping -> ../../localdev/maho-example-shipping

Da qui tre conseguenze pratiche:

  • Modifica e vedi subito. Il bootstrap di Maho carica le classi dal percorso dentro vendor/, che è il link: una modifica in localdev/ è già in esecuzione, senza reinstallare niente.
  • Repository separato. localdev/ raccoglie repository a sé, mentre il root resta il tuo progetto. Puoi versionare, ramificare e pushare il pacchetto senza toccare lo store, e viceversa.
  • Nessun inquinamento del vendor. Non lavori mai dentro vendor/ e non rischi di perdere le modifiche a ogni aggiornamento.

La parola @dev non è un vezzo: serve perché un path repository non espone versioni taggate. Il pacchetto si risolve come dev e le sue modifiche vengono rilette a ogni composer update.

Lavoro quotidiano

Modificare il codice del modulo. Lavora direttamente in localdev/<package>: PHP, etc/config.xml, layout, template e codice sotto app/code/ sono letti live dal symlink. Dopo un cambio di nome a blocchi, alias o handle di layout, svuota la cache:

./vendor/bin/harbor maho cache:flush

Eseguire i gate del pacchetto. Sono gli stessi comandi del passo 4, e la sequenza giusta prima di pushare è install la prima volta, poi check:

./vendor/bin/harbor composer --working-dir=localdev/maho-example-shipping check

Evita harbor composer exec --working-dir: fallisce con chdir(): No such file or directory. Lancia il binario da uno script o direttamente.

Reinstradare lo store sul pacchetto. Dopo aver aggiunto o rinominato un pacchetto, o dopo aver cambiato i suoi asset:

./vendor/bin/harbor composer update

Verificare il risultato.

./vendor/bin/harbor maho migrate
./vendor/bin/harbor maho db:query "SELECT * FROM core_resource WHERE code LIKE '%example%'"
./vendor/bin/harbor maho cache:flush

Se il pacchetto spedisce comandi CLI, compaiono nella lista di Maho:

./vendor/bin/harbor maho list | grep example

L’eccezione: gli asset pubblicati in public/

Tutto quanto sopra vale per il codice PHP e per i file risolti live dal symlink. Gli asset sono l’eccezione. Il maho-composer-plugin copia le cartelle public/, skin/ e js/ di ogni modulo installato dentro l’albero public/ del progetto: qui non c’è nessun symlink, è una copia vera e propria.

Conseguenze:

  • Modificare un file sotto localdev/<package>/public/ non si propaga da solo. Rilancia composer update dalla root (basta il solo pacchetto) per ripubblicarlo.
  • La pubblicazione copia soltanto, non elimina: se rinomini una cartella di asset, la vecchia copia resta in public/ e va rimossa a mano.
# un file cambiato sotto public/ del pacchetto non è attivo finché non ripubblichi
./vendor/bin/harbor composer update acme/maho-example-shipping

Questo vale per skin, JavaScript e qualsiasi asset che il modulo spedisce. Per i temi c’è un percorso dedicato, che evita di ripubblicare a mano a ogni build.

Temi: copiare indietro con --pack

Quando il pacchetto è un tema, la build degli asset segue un flusso suo, perché gli stessi file vanno sviluppati nella copia pubblicata e poi riportati nel repository. Il pacchetto tema riregistra il comando core dev:frontend:theme:build e aggiunge l’opzione --pack, che copia i file dal progetto al pacchetto (con prune) dopo la build. Viene dal repository utility empiricompany/maho-theme-kit.

# lavora sugli asset nella copia pubblicata del progetto
./vendor/bin/harbor maho dev:frontend:theme:build --theme <pkg>/<theme> --watch

# oppure ricostruisci e riporta nel pacchetto a ogni modifica
./vendor/bin/harbor maho dev:frontend:theme:build --theme <pkg>/<theme> --watch --pack

# build minificata, prima di committare
./vendor/bin/harbor maho dev:frontend:theme:build --theme <pkg>/<theme> --pack

L’ordine conta: composer install/update sovrascrive le copie degli asset nel progetto, quindi lancia build --pack prima di Composer, oppure non lanciare Composer mentre hai modifiche non ancora riportate nel pacchetto. --pack salta i pacchetti installati come copia in vendor/ (una dist, non un checkout di sviluppo): lì riportare i file sarebbe inutile.

🔧 Nota di banco. Il tema è il mobile che monti sulla vetrina: lo ceselli nella copia installata e, quando è finito, --pack lo riporta nello stampo. Per i moduli normali non serve un attrezzo ad hoc: basta un composer update che rimetta in vetrina gli asset cambiati.

Gate e rilascio

Prima di pushare, la sequenza completa dentro il pacchetto:

./vendor/bin/harbor composer --working-dir=localdev/maho-example-shipping install
./vendor/bin/harbor composer --working-dir=localdev/maho-example-shipping check

check esegue gli script dichiarati nel composer.json del pacchetto: tipicamente test, lint, cs (php-cs-fixer), phpstan e rector. Gli stessi controlli girano in GitHub Actions insieme a composer validate --strict, ai controlli di sintassi e al gate sulle line ending. Quando sono verdi:

git -C localdev/maho-example-shipping add -A
git -C localdev/maho-example-shipping commit -m "Add example shipping extension"
git -C localdev/maho-example-shipping push

Un tag di versione avvia la release quando il pacchetto ha il workflow dedicato. I gate provano stile e tipi, non il comportamento: dopo il push, prova a mano il flusso nello store (checkout, area clienti, admin) prima di considerarlo pronto.

🔧 Ultima nota di banco. Il banco è in ordine, gli attrezzi al loro posto e la vetrina è a un composer update di distanza. Da qui puoi pubblicare il modulo, aprirne un altro accanto e tenere tutto separato nello stesso cantiere. Buon lavoro!

Troubleshooting

Sintomo Controlla
Composer non vede il pacchetto il blocco repositories con url: "./localdev/*" nel root, poi composer update
Il pacchetto installato non è un symlink options.symlink: true e che non ci sia una copia precedente in vendor/
Le modifiche PHP non si vedono cache:flush; per i rename di blocchi e alias la cache di layout/config serve ancora XML vecchio
Un asset cambiato non si aggiorna ripubblica con composer update dalla root: è una copia, non un symlink
Resta una cartella asset orfana la pubblicazione non elimina: rimuovila a mano da public/
harbor composer exec --working-dir fallisce non usarlo: lancia il binario tramite uno script
I gate passano ma lo store si rompe i gate non provano il comportamento: test manuale del flusso

Nota di redazione.Testo preparato con l'aiuto dell'AI e verificato sulla fonte prima della pubblicazione. Può contenere errori: se ne trovi uno, segnalalo.Leggi il Manifesto

Il tuo negozio vende ancora?

Raccontaci da dove parti: ti rispondiamo con una prima valutazione, senza impegno.

Chiedi l'analisi del negozio