Ho deciso di riscrivere in larga parte il codice dell’applicazione Gestione Fatture che avevo pubblicato in questo articolo, per renderla compatibile con la nuova versione di P4A (disponibile qui) (la 3.8.4) ed anche per correggere diversi bug che sono emersi nell’utilizzo.
Pur mantenendo tutte le caratteristiche della precedente versione, l’attuale non è compatibile con quella precedente per via di alcune modifiche sostanziali che ho dovuto apportare alla struttura del database.
Oltre a poter essere utile proprio per la gestione delle fatture delle ditte individuale e dei professionisti, credo che questo codice possa essere utile anche a tutti coloro che si avvicinano al framework P4A, in quanto all’interno ci sono diversi esempi di come risolvere la maggior parte dei problemi che si incontrano sviluppando con questo framework.
Alcune delle nuove caratteristiche sono:
Riscritto lo schema del database (non è più compatibile con la versione precedente)
Possibilità di inserire il saldo o il saldo parziale riscosso della fattura emessa per il controllo dei pagamenti
Nuova funzionalità per monitorare le fatture saldate interamente o parzialmente (conteggio dei soldi in cassa e dell’importo da riscuotere)
Nuova funzionalità per il filtraggio delle fatture
Possibilità di emettere note di credito
Nuova funzionalità per fatture ricorrenti
Corretto il codice della classe ezPDF (i file sono allegati nella dir. Libraries) per la compatibilità con PHP 5.3.x
Possibilità di inserire automaticamente la descrizione di prestazioni già inserite in fatture precedenti
A chi è rivolto:
Soggetti senza P.IVA che rilasciano la sola ritenuta di acconto
Soggetti con P.IVA iscritti alla Camera di Commercio (Ditte individuali)
Professionisti senza Cassa previdenziale autonoma
Professionisti con Cassa previdenziale autonoma
Per la mancanza di una gestione del magazzino è sconsigliata ai commercianti che hanno a che fare con un magazzino merce, inventario e via dicendo.
L’applicazione viene distribuita con licenza LGPL 3, in questo link potete trovare la traduzione non ufficiale in italiano.
Installazione:
Installare il framework p4a 3.8.4 (requisito obbligatorio)
Scompattare l’archivio “gestionefatture2.zip” all’interno della directory “p4a/applications”
Generare un database con il nome: “gestionefatture2” ed importare il dump SQL: “gestionefatture2.sql” che si trova all’interno della directory “_private”
Modificare il file “index.php” sostituendo nella riga di codice:
yourdbuser = l’utente MySQL con il quale accedere al vostro database
yourdbpassword = la password del suddetto utente.
Infine per accedere all’applicazione i parametri di login sono:
Username = admin
Password = admin
E’ importante mantenere nella directory “/libraries” i file di libreria di ezPdf che sono contenuti nel pacchetto, perché ho dovuto correggere alcune linee di codice (purtroppo ezPdf è stata abbandonata dal suo autore…) per renderla compatibile con PHP 5.3.x.
La applicazione richiede che sia installato il PHP5.3.x + MySQL 5.1.x o superiore.
Chi utilizza l’RDBMSMySQL in P4A avrà certamente notato che il framework produce in certi casi, delle tabelle il cui nome termina in ‘_seq’. Queste tabelle servono ad avere una compatibilità nella gestione di tutti gli RDBMS supportati (MySQL, PostgreSQL, SQLite, Oracle). PostgreSQL e Oracle, non hanno lo stesso tipo di gestione delle chiavi primarie con l’attributo ‘AUTOINCREMENT‘, rispetto a MySQL e SQLite. La soluzione adottata è di costruire, per ogni tabella con chiave primaria di tipo ‘AUTOINCREMENT’, delle tabelle accessorie che hanno un campo ‘id’ di tipo ‘AUTOINCREMENT’ e di riferirsi a quest’ultime per ottenre il ‘LAST INSERT ID‘. In questo modo viene ricalcato il comportamento delle chiavi primarie di tipo ‘SERIAL’ in PostgreSQL, e anche quelle di Oracle (leggermente diverse).
Prima di tutto una precisazione: questo articolo è riferito esclusivamente agli utenti MySQL. Se si pensa di utilizzare esclusivamente P4A Framework per la gestione dei dati del nostro database, sarebbe bene in fase di progettazione evitare di usare gli AUTOINCREMENT perché, come detto, non necessari. Nel caso in cui il framework venga utilizzato come ‘backoffice’ per la gestione di dati che vengono alimentati da un form di un sito web, oppure si abbia la necessità di utilizzare una struttura dati pre-esistente con tanto di chiavi primarie ‘AUTOINCREMENT’, potremmo prima o poi trovarci di fronte ad un problema di disallineamento dei valori fra la chiave primaria della tabella e l’id’ della tabella ‘_seq’ associata.
Immaginiamo di avere una tabella “test” con questi due campi:
+----+---------+
| id | name |
+----+---------+
con ‘id’ chiave primaria, P4A creerà automaticamente una tabella “test_id_seq” con una campo ‘id’ chiave primaria e ‘AUTOINCREMENT’, ed userà i valori forniti da quest’ultima sia per l’inserimento di nuovi record nella tabella “test“, che per altre operazioni sulla chiave primaria. Dunque utilizzando un programma esterno al framework per fare degli inserimenti e volendo mantenere allineate le tabelle principali e le tabelle “_seq” sarà necessario, per ogni “INSERT” nella tabella principale, fare altrettanto nella “_seq”! Anche utilizzando questo metodo, potrebbe verificarsi prima o poi il problema di un disallineamento, in questo caso ho pensato potesse utile scrivere un metodo della classe “P4A_DB_SOURCE” da utilizzare in extremis, per risistemare le cose.
Per maggiori informazioni sull’utilizzo degli ‘helper’ in P4A suggerisco questo link
Ecco il codice dell’helper, in pratica viene prelevato il valore massimo della chiave primaria ‘AUTOINCREMENT’ della tabella che funge da sorgente dati, quindi viene eliminata la tabella ‘_seq’ associata e successivamente ricostruita con il valore corretto.
Questo codice deve essere inserito in un file con il nome: “p4a_db_source_resync_seq.php” che deve essere posizionato nella directory “libraries” della nostra applicazione P4A.
Ecco infine un po’ di codice di esempio da aggiungere alla nostra ipotetica maschera di manutenzione del db:
class test extends P4A_Base_Mask
{publicfunction __construct(){
parent::__construct();// DB Source$this->build("p4a_db_source","source")->setTable("test")->setPk("id")->load();$this->setSource($this->source);// ....$this->build("p4a_button","btn_resync")->setLabel("resync")->implement("onclick",$this,"resync_seq_table");// ....}publicfunction resync_seq_table(){$res=$this->source->resync_seq();}// ....}
class test extends P4A_Base_Mask
{
public function __construct() {
parent::__construct(); // DB Source
$this->build("p4a_db_source", "source")
->setTable("test")
->setPk("id")
->load();
$this->setSource($this->source); // .... $this->build("p4a_button", "btn_resync")
->setLabel("resync")
->implement("onclick", $this, "resync_seq_table"); // ....
} public function resync_seq_table()
{
$res = $this->source->resync_seq();
} // ....
}
Conclusioni
Questo metodo dovrebbe essere usato con una certa cautela, e solo come procedura di emergenza. Non consiglio l’utilizzo se c’è la possibilità di accesso in scrittura alla tabella coinvolta da parte di altri utenti.
Questa applicazione web si basa sul framework PHP: P4A 3. Si tratta di una versione migliorata e corretta del codice già presentato in questo post. E’ un’applicazione completa per la gestione delle fatture, pensata soprattutto per chi eroga prestazioni, più che prodotti, in quanto non contempla una gestione del magazzino. Può essere utile per chi, come me, fa consulenze informatiche e realizza software, oppure per piccole aziende di autotrasporto che lavorano principalmente conto terzi o per artigiani e professionisti che non utilizzano un magazzino. Non può essere utilizzata però da coloro i quali sono iscritti ad un albo professionale, in quanto, da informazioni ricevute da un commercialista, mi risulta che il calcolo della ritenuta d’acconto e delle trattenute INPS sia leggermente differente.
Maschere:
Gestione azienda: in questa maschera è possibile definire la ragione sociale, i dati anagrafici e il logo dell’azienda, definire l’utente e la password e impostare il tipo di fatturazione: IVA fissa, IVA variabile, ritenuta d’acconto, contributo INPS (queste ultime due opzioni sono possibili solo con IVA fissa).
Gestione clienti: in questa maschera vengono immessi i dati anagrafici dei clienti.
Fatture: è la maschera principale per creare e modificare le fatture. E’ divisa in due parti selezionabili attraverso delle ‘linguette’ come per gli schedari. La sezione ‘fatture’ permette di inserire una nuova fattura vuota, indicando la data, il numero, il cliente e la tipologia di pagamento. E’ anche possibile indicare se la fattura è stata pagata attraverso un flag ed inserire eventuali note. Il numero viene suggerito automaticamente seguendo la progressione dell’anno in corso, è però possibile immetterlo manualmente, in questo caso esiste un controllo per evitare duplicati. La sezione ‘Dettaglio fattura’ serve per inserire la lista di prestazioni o prodotti da fatturare. E’ possibile raggruppare una lista attraverso il campo ‘sezione’. Gli altri campi da riempire sono la descrizione, la quantità il prezzo e l’IVA (se non si è scelta la modalità IVA fissa). In fondo alla maschera vengono riportati i valori del totale imponibile, totale IVA e totale fattura. (totale ritenuta d’acconto e contributo INPS, solo se lo si è attivato nella Gestione azienda). Attraverso il pulsante di stampa, viene generato un documento pdf stampabile con la fattura impaginata in una o più pagine (in questo caso numerate) e la dicitura del destinatario allineata con l’apertura delle buste a ‘finestra’ standard.
Lista fatture: attraverso questo report è possibile filtrare le fatture di un certo periodo, visualizzare e stampare su pdf l’elenco e i totali dell’imponibile, delle fatture e i totali di quelle pagate e quelle no.
Tipo pagamenti: E’ possibile inserire le varie modalità di pagamento (assegno, bonifico, riba ecc.)
Unità di misura: E’ possibile inserire le unità di misura (ore, pezzi, kg, ecc.)
Alcune note sull’utilizzo: Per aggiungere un nuovo record, è sempre necessario utilizzare il pulsante ‘Inserisci un nuovo elemento’, e una volta compilati i campi, premere il pulsante ‘Conferma e salva’. Nel caso di inserimento di una nuova fattura, dopo aver salvato e prima di inserire la lista delle prestazioni, è necessario selezionare con il puntatore (triangolino nero) la fattura appena creata. Per creare dei blocchi di prestazioni, inserire una dicitura nel campo ‘sezione’, in questo modo, i nuovi record creati con la stessa dicitura nel campo sezione, saranno raggruppati e ordinati alfabeticamente in fattura.
Installazione
Deve innazitutto essere installato il framework P4A versione 3.2.x (dettagli per il download e l’installazione). Poi è sufficiente scompattare l’archivio compresso nella direcory ‘applications’ che si trova sotto la directory ‘P4A’, caricare il dump .sql del database che si trova nella directory ‘_private’ in un server ‘MySQL’ e impostare i parametri per la connessione nel file ‘index.php’ (Nella maggioranza dei casi questo potrebbe non essere necessario). Chi utilizza linux, deve ricordarsi di dare i permessi di scrittura alla directory ‘uploads’ e alle sue subdirectories. Se il server web è installato localmente, per accedere all’applicazione digitare la url ‘http://localhost/p4a/applications/gestionefatture/’ Infine, volendo personalizzare l’aspetto grafico dell’applicazione, suggerisco questo articolo.
Il nome utente e la password per l’accesso iniziale sono: user = ‘utente’ e password = ‘utente’
Considerando che l’applicazione viene fornita gratuitamente, non garantisco nessun supporto ufficiale e non mi assumo alcuna responsabilità per eventuali anomalie di funzionamento. Sono comunque disponibile a correggere gli errori che mi segnalerete e a valutare eventuali upgrade, compatibilmente con il tempo richiesto.
Questo widget per il framework P4A è l’aggiornamento di quello descritto in questo post. L’aggiornamento deriva dal fatto che la nuova versione del codice originale per jQuery, presenta cambiamenti importanti e ha richiesto la riscrittura di una buona parte del widget. La versione del Countdown for jQuery attualmente installata è la 1.4.3.
Ho pensato di cogliere l’occasione per rendere un poco più interattivo il widget, facendo scattare un evento gestibile dall’utente attraverso un metodo personalizzato, allo scadere del contatempo. Inoltre, ho utilizzato l’integrazione di P4A con i18n, per impostare automaticamente la lingua per gli output delle etichette e il formato della data e dell’ora.
Questo è l’elenco dei metodi fino ad esso implementati:
Elenco dei metodi:
Nome
Tipo
Default
Note
setSince()
integer
"null"
Imposta la data e l’ora di avvio in formato UNIX timestamp
setUntil()
integer
"null"
Imposta la data e l’ora di stop in formato UNIX timestamp.
setDisplayFormat()
string
"dHMS"
‘Y’ anni, ‘O’ mesi, ‘W’ settimane, ‘D’ giorni, ‘H’ ore, ‘M’ minuti, ‘S’ secondi. I caratteri minuscoli impostano la visualizzazione opzionale
setCompactFormat()
string
"false"
Imposta il formato ridotto.
setDescription()
string
""
Imposta la descrizione del contatempo.
setServerTime()
string
null
Imposta l’offset per il fuso orario. Valori di esempio: ‘+1’, ‘+2’, ‘+3’, ‘-1’, ‘-2’, ‘-3’. etc.
setLayout()
string
''
Imposta un layout personalizzabile attraverso tag HTML e parametri per esprimere la data e l’ora. Le singole sezioni sono delimitate da %x…%x, dove x è ‘Y’ per definire gli anni, ‘O’ per i mesi, ‘W’ per le settimane, e ‘D’ per i giorni, ‘H’ per le ore, ‘M’ per i minuti, e ‘S’ per i secondi. All’interno di queste sezioni, è possibile utilizzare ‘%n’ per determinare il valore del periodo, ‘%nn’ per il valore con un minimo di due caratteri, e ‘%l’ per l’etichetta del periodo (in accordo con quanto impostato in setCompactFormat()).
setlocale()
string
'auto'
Imposta un valore per la regionalizzazione. Per default viene presa l’impostazione di P4A_LOCALE. In alternativa è possibile impostarla manualmente. Le traduzioni disponibili sono: Chinese – Simplified “zh-CN”, Chinese – Traditional “zh-TW”, Czech “cs”, Danish “da”, Dutch “nl”, French “fr”, German “de”, Hebrew “he”, Hungarian “hu”, Indonesian “id”, Italian “it”, Norwegian “nb”, Persian/Farsi “fa”, Polish “pl”, Portuguese/Brazilian “pt-BR”, Romanian “ro”, Russian “ru”, Slovak “sk”, Spanish “es”, Swedish “sv”, Turkish “tr”, Ukranian “uk”
setPauseResumeType()
string
null
Se impostato con i valori: “lap” o “pause” mostra un pulsante che ferma o riavvia il contatempo. “lap” ferma solo la visualizzazione, “pause” ferma anche il conteggio. Se null il pulsante non viene mostrato.
setPauseResumeLabels()
string
'pause,resume'
Imposta le etichette per il pulsante “Pause/resume”. I valori per l’azione toggle devono essere separati da una virgola.
onExpiry()
boolean
false
Imposta se deve scattare un evento allo scadere del countdown (funziona solo quando è impostato setUntil()).
setMessageOnExpire()
string
""
Imposta il testo del messaggio che viene visualizzato allo scadere del countdown.
messageOnExpire()
void
void
Se è impostato un messaggio, lo mostra e restituisce un handle per l’evento actionOnExpire. Questo metodo viene attivato quando onExpiry(true)
Ecco un po’ di codice di esempio per inserire il contatempo in una maschera e utilizzare l’evento actionOnExpire:
class test_countdown extends p4a_base_mask
{publicfunction __construct(){
parent::__construct();$this->setTitle("test Countdown");$this->build("P4A_jCountdown","countdown")->setStyleProperty("width","400px")->setStyleProperty("float","none")->setStyleProperty("margin","auto")->setDescription("test countdown")->countdown->setUntil(time()+11)->countdown->onExpiry(true)->countdown->setMessageOnExpire("Il tempo e' scaduto!");$this->countdown->implement('actionOnExpire',$this,'show');$this->frame->anchorCenter($this->countdown);}publicfunction show (){$this->info("Questa e' una prova!");//Enable code below for looping//$this->countdown->setUntil(time()+11);}}
class test_countdown extends p4a_base_mask
{
public function __construct()
{
parent::__construct();
$this->setTitle("test Countdown");
$this->build("P4A_jCountdown", "countdown")
->setStyleProperty("width","400px")
->setStyleProperty("float","none")
->setStyleProperty("margin","auto")
->setDescription("test countdown")
->countdown->setUntil(time()+11)
->countdown->onExpiry(true)
->countdown->setMessageOnExpire("Il tempo e' scaduto!");
$this->countdown->implement('actionOnExpire',$this,'show');
$this->frame->anchorCenter($this->countdown);
}
public function show ()
{
$this->info("Questa e' una prova!");
//Enable code below for looping
//$this->countdown->setUntil(time()+11);
}
}
Il pacchetto completo della maschera di esempio è scaricabile qui
Note:
L’impostazione di setLocale() non è in genere necessaria per il fatto che quando viene “costruito” il contatempo la regionalizzazione viene individuata automaticamente. Nel caso si volesse impostare questo parametro manualmente, si consiglia di non cambiarlo successivamente a run-time. Questo perché è stato scelto di caricare l’intero set di impostazioni per la regionalizzazione tramite codice javascript esterno, mediante files di libreria. Per questo metodo quindi, i cambiamenti a run-time generano codice non pulito, che sconsiglio, almeno fino a che non trovo il tempo di migliorare questa soluzione. Come nella precedente versione, è consigliabile aggiungere un secondo quando si utilizza:->setUntil() e decrementare di un secondo quando si utilizza ->setSince(time())per evitare una non perfetta sincronizzazione fra il tempo in cui viene mostrato il widget e lo scattare del conteggio. Infine è possibile rendere invisibile il widget, semplicemente con ->setVisible(false) e mantenere attivo il contatempo. Questo permette di utilizzare comunque l’handle per l’evento actionOnExpire anche senza visualizzare il widget.
Conclusioni:
Questi ultimi giorni sono stati davvero impietosi con il mio (già scarso) tempo libero, e non ho potuto sviluppare il codice come avrei voluto… spero di poterci dedicare ancora del tempo, perché mi sembra un progetto interessante e, spero utile a molti. Ci sono ancora alcune caratteristiche da integrare e miglioramenti da fare nel codice, spero nell’aiuto degli utenti! Nel frattempo cercherò anche di ampliare e migliorare la documentazione (già presente nel pacchetto).
Sulla personalizzazione dell’aspetto grafico delle maschere di P4A, esiste già questo interessante screencast di Fabrizio Balliano. Trovo interessante poter cambiare la grafica perché l’aspetto di default, sebbene gradevole e riposante, in alcuni casi, per esempio sugli schermi dei netbook appare un po’ troppo poco contrastato. Il tema alternativo proposto nello screencast è “Human” per Gnome, davvero molto bello! Il set di impostazioni per i colori e il set di icone vengono generati a partire da script PHP. Entrambi gli script sono disponibili in P4A Wiki nella sezione: “Theme customizations”, il requisito è di farli girare su una macchina Linux, che sia dotata del necessario software di conversione da SVG a PNG. Ho pensato di scrivere questo post, anche se in gran parte è una ripetizione dello screencast di Fabrizio, perché qualcuno si potrebbe trovare in difficoltà scoprendo al primo approccio che lo script che genera il set di icone, per funzionare correttamente, necessita di una particolare libreria.
Dunque, la situazione migliore è che possediamo una distro “Ubuntu“, quindi con installato il Desktop Gnome. Per prima cosa, ci dobbiamo accertare che sia installato il programma rsvg che fa parte della libreria librsvg. Se non è presente (in genere non lo è…), l’installazione è davvero molto semplice utilizzando apt-get:
sudo apt-get install librsvg2-2
invece, se volete perdere tempo e avete già installate tutte le librerie per il supporto alle manipolazioni dei formati SVG, potete installare il pacchetto manualmente. Queste librerie sono comunque necessarie: libxml2 e libxml2-dev
Adesso copiate le icone generate che saranno raggruppate nelle cartelle con il nome 16 e 32 nella directory human che si deve trovare all’interno di p4a/icons e aggiungete il seguente codice all’interno del file index.php della vostra applicazione P4A, prima della riga di codice: require_once dirname(__FILE__) . '/../../p4a.php'; e con le icone abbiamo finito.
define('P4A_ICONS_NAME','human');
define('P4A_ICONS_NAME', 'human');
In pratica lo script recupera le icone che servono a p4a e le copia, creando la struttura di directory necessaria, nella cartella /directory/che/volete. Se non sono disponibili nel formato richiesto, le genera dai modelli scalabili in SVG, oppure le cerca fra quelle del tema Gnome. Naturalmente, è sempre possibile aggiustare alcuni set a mano. Per esempio, ho notato che nella generazione del tema “Human”, l’icona “folder open”, risulta di colore grigio ed è piuttosto differente da “folder”, così l’ho sostituita con quella generata per il tema “Tangerine”.
Per quanto riguarda lo schema dei colori, dovete procurarvi lo script PHP: gtkrc2p4a.php per importare gli schemi Gnome gtkrc. Per generare il set di colori che armonizza le icone “Human”, digitate da linea di comando:
L’esecuzione genera il seguente set di impostazioni da copiare e incollare dentro index.php (sempre prima di: require_once dirname(__FILE__) . '/../../p4a.php';):
Sembra fatta, ma c’è ancora qualcosa di imperfetto. Se nella vostra applicazione è presente un “tab-panel” i bordi rimangono colorati dell’azzurro di default, e lo sfondo del bottoncino per il passaggio da un pannello all’altro, rimane azzurro chiaro. Così per essere pignoli rimane da modificare un poco il CSS in questo modo:
Create un file provacss.php con le seguenti istruzioni per il CSS (io l’ho messo nella directory libraries della mia applicazione):
E il gioco è fatto! In pratica, è possibile aggiungere un CSS dinamico che carica, mediante querystring, le costanti determinate dal tema adottato.
Ecco uno screeshot della mia applicazione per la gestione delle fatture “vestita” con Human-gnome:
Download
Per chi non avesse a disposizione un ambiente Linux (ma cosa aspetta a farlo?) metto a disposizione il set di icone Human che ho generato qui
Conclusioni
Una volta compreso il meccanismo, personalizzare p4a è piuttosto semplice. Mi sono divertito anche a creare un tema “Vista like”, tanto per non spiazzare troppo i clienti “allineati” a M$…
Riferimenti ed approfondimenti:
Screencast di Fabrizio Balliano: “Theme customizations in RC5”
P4A Wiki
Fabrizio Balliano ha scritto:
ottimo articolo come sempre, vedo però di risolvere il problema del tab pane perché va fixato :) 23.02.09 09:41 Fabrizio Balliano ha scritto:
Questo helper deriva naturalmente dalla funzione descritta nel precedente post.P4A mette a disposizione un widget chiamato P4A_DB_Navigator che si basa su archivi di tipo albero a liste di adiacenza e fornisce un output grafico della lista dei nodi, con un buon grado di interattività. Esiste, per esempio, un metodo che si chiama getPath() che restituisce in un array, il percorso dalla root al nodo fornito in input attraverso la chiave primaria. Purtroppo però, non esiste nessun metodo per estrarre l’insieme di nodi figli da un certo nodo parentale, così ho pensato di adottare la funzione presentata nel precedente post.
I parametri di input sono:
$navigator – l’oggetto da cui discende (implicito)
$id – l’identificativo del nodo da cui partire
$table – il nome della tabella che rappresenta l’albero
$pk – il nome della chiave primaria
$recursor – il nome del campo che identifica il nodo parentale
// File: P4A_db_navigator_getBranch.php
<?phpfunction P4A_db_navigator_getBranch ($navigator,$params){list($id,$table,$pk,$recursor)=$params;$arr= p4a_db::singleton()->getAll("SELECT * FROM $table");$pksArr=array();foreach($arras$rec){$pksArr[$rec[$pk]]=$rec[$recursor];}$branchIds=array($id);$i=0;while($i<count($branchIds)){$newKeys=array_keys($pksArr,$branchIds[$i]);if(!empty($newKeys)){foreach($newKeysas$newKey){array_push($branchIds,$newKey);}}++$i;}$res=array();foreach($arras$child){if(in_array($child[$pk],$branchIds)){$res[]=$child;}}return$res;}?>
// File: P4A_db_navigator_getBranch.php
<?php
function P4A_db_navigator_getBranch ($navigator, $params)
{
list($id, $table, $pk, $recursor) = $params;
$arr = p4a_db::singleton()->getAll("SELECT * FROM $table");
$pksArr = array();
foreach ($arr as $rec) {
$pksArr[$rec[$pk]]=$rec[$recursor];
}
$branchIds = array($id);
$i=0;
while ($i<count($branchIds)) {
$newKeys = array_keys($pksArr,$branchIds[$i]);
if (!empty($newKeys)) {
foreach ($newKeys as $newKey){
array_push($branchIds, $newKey);
}
}
++$i;
}
$res = array();
foreach ($arr as $child) {
if (in_array($child[$pk], $branchIds)) {
$res[] = $child;
}
}
return $res;
}
?>
Come esempio ho costruito una semplicissima maschera nella quale, ogni volta che viene selezionato un nodo, viene mostrato un messaggio con l’array dei nodi figli.
Questo sito Web utilizza i cookie in modo che possiamo fornirti la migliore esperienza utente possibile. Le informazioni sui cookie sono memorizzate nel tuo browser ed eseguono funzioni come riconoscerti quando ritorni sul nostro sito Web e aiutare il nostro team a capire quali sezioni del sito Web trovi più interessanti e utili.
This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.
Cookie strettamente necessari
I cookie necessari contribuiscono a rendere fruibile il sito web abilitandone funzionalità di base quali la navigazione sulle pagine e l'accesso alle aree protette del sito. Il sito web non è in grado di funzionare correttamente senza questi cookie.
Se disabiliti questo cookie, non saremo in grado di salvare le tue preferenze. Ciò significa che ogni volta che visiti questo sito web dovrai abilitare o disabilitare nuovamente i cookie.
Cookie di terze parti
Questo sito web utilizza Google Analytics per raccogliere informazioni anonime come il numero di visitatori del sito e le pagine più popolari.
Mantenere questo cookie abilitato ci aiuta a migliorare il nostro sito web.
This website uses Google Analytics to collect anonymous information such as the number of visitors to the site, and the most popular pages.
Keeping this cookie enabled helps us to improve our website.
Attiva i cookie strettamente necessari così da poter salvare le tue preferenze!