LOGIC Library

Questo sito rappresenta l'impegno di Logic nella condivisione delle esperienze acquisite nel lavoro quotidiano. L'obiettivo è creare una solida base di conoscenze e condividere le esperienze nello sviluppo software e nell'amministrazione dei sistemi.

Per maggiori informazioni su di noi, visitate logicsistemi.it.

Joomla! 2.5: aggiungere campi al profilo degli utenti

In questo post cerchiamo di spiegare come estendere le informazioni degli utenti di Joomla! utilizzando dei campi personalizzati, come ad esempio il cognome, l'organizzazione o altri.

La cattiva notizia è che avete bisogno di scrivere del codice PHP e creare un plugin. La buona notizia è che in Joomla! 2.5 questo compito è molto semplice e seguendo questo tutorial si può realizzare anche se le competenze di programmazione sono un po' limitate.

 

Il metodo più semplice

Se l'obiettivo è semplicemente quello di ampliare le informazioni degli utenti senza capire il funzionamento di Joomla! e come vengono memorizzate le informazioni aggiuntive, si può semplicemente seguire la guida che si trova sul sito ufficiale della documentazione di Joomla! e modificare nomi e tipologia dei campi in base alle vostre esigenze.

Nel seguito proviamo a spiegare il codice necessario per creare un plugin per il profilo degli utenti. La comprensione di questo meccanismo vi renderà capaci di estendere le funzionalità o creare componenti che, per altri scopi, leggono le informazioni memorizzate.

Il metodo errato

Uno degli errori più comuni è quello di modificare direttamente il codice sorgente di Joomla! per aggiungere le informazioni desiderate. Questo approccio è errato, in quanto al prossimo aggiornamento di Joomla! tutte le modifiche effettuate saranno sovrascritte.

Un altro modo sbagliato per eseguire questa operazione è quello di modificare il codice del plugin User - profile. Si tratta di un plugin, ma è pur sempre una parte di Joomla! core e si ricadrebbe nel problema precedente. Questo plugin è concepito come un esempio per creare un plugin personalizzato, oppure è possibile utilizzarlo senza modifiche se i campi che si necessitano sono già nella lista gestita dal plugin.

Sul web si possono trovare alcuni tutorial che consigliano di modificare la tabella degli utenti di Joomla! aggiungendo nuovi campi. Questo approccio era comune fino a Joomla! 1.5, ma, nelle nuove versioni, non è più considerato il metodo corretto di procedere. Nelle nuove versioni non avrete nemmeno bisogno di plugin aggiuntivi, come usermeta.  I concetti utilizzati dagli sviluppatori di Usermeta sono ora parte del core di Joomla!.

Cartelle e file

Iniziamo creando, sul nostro pc, una cartella per sviluppare il nostro plugin user profile personalizzato.

Ipotizzando di chiamare il plugin "testprofile", creiamo la seguente struttura di file e cartelle:

plg_user_testprofile
profiles
index.html
profile.xml
en-GB.plg_user_testprofile.ini
en-GB.plg_user_testprofile.sys.ini
index.html
testprofile.php
testprofile.xml

Ecco una rapida spiegazione dei vari file:

  • testprofile.xml è il file manifest che contiene le istruzioni per l'installazione
  • testprofile.php è il nostro codice. E' in esso che implementiamo le funzionalità desiderate
  • i 2 file .ini sono i file per le traduzioni. Essi definiscono le conversioni tra le stringhe maiuscole utilizzate come etichette  e le scritte nelle varie lingue (abbiamo creato solamente le traduzioni per l'inglese). Il file .sys.ini file è utilizzato durante l'installazione. L'altro file è utilizzato dal nostro codice. Potete trovare qui informazioni aggiuntive sul funzionamento dell'internazionalizzazione.
  • profile.xml contiene le definizioni dei campi necessari. La sintassi di questo file è la stessa prevista per i file standard di definizione dei form utilizzati da Jooma!
  • i file index.html servono esclusivamente a evitare che venga elencato il contenuto delle cartelle in caso di accesso diretto tramite il browser

Il file manifest

Il contenuto di testprofile.xml è il seguente:

<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="user">
 <name>plg_user_testprofile</name>
  <author>Edy Incoletti</author>
  <authorEmail>edy.incoletti@logicsistemi.it</authorEmail>
  <authorUrl>http://library.logicsistemi.it</authorUrl>
  <creationDate>May 2012</creationDate>
  <version>1.0.0</version>
 <description>PLG_USER_TEXTPROFILE_XML_DESCRIPTION</description>
 
 <files>
    <filename plugin="testprofile">testprofile.php</filename>
    <filename>index.html</filename>
    <folder>profiles</folder>
 </files>
 
 <languages>
    <language tag="en-GB">en-GB.plg_user_testprofile.ini</language>
    <language tag="en-GB">en-GB.plg_user_testprofile.sys.ini</language>
 </languages>
</extension>

Il file inizia con il tag che definisce il tipo di estensione e che specifica la versione di Joomla! per cui è stato realizzato (2.5). Questo plugin verrà aggiunto al gruppo di plugin per gli utenti e quindi utilizzato per gestire gli eventi scatenati durante la loro gestione.

In seguito sono stati definiti acluni campi descrittivi e poi l'elenco di file e cartelle da copiare e le lingue da installare.

Rispetto al plug-in User profile abbiamo rimosso i parametri di configurazione. Questi sono utilizzati per attivare o disattivare i campi. Siccome stiamo realizzando un plugin fortemente personalizzato credo che questi requisiti possano essere definiti in fase di progettazione.

Definizione dei campi

Il file profile.xml definisce esclusivamente un campo aggiuntivo. Questo è solamente un esempio e ulteriori campi necessari possono essere aggiunti precisando il tipo corretto.

<?xml version="1.0" encoding="utf-8"?>
<form>
  <fields name="testprofile">
    <fieldset name="testprofile"
     label="PLG_USER_TESTPROFILE_SLIDER_LABEL">
     <field
        name="organization"
        type="text"
        id="organization"
        label="PLG_USER_TESTPROFILE_FIELD_ORGANIZATION_LABEL" />
    </fieldset>
  </fields>
</form>

Questo campo sarà mostrato in un riquadro (fieldset) separato nella pagina di registrazione degli utenti e nella gestione degli stessi.

Struttura del database

Joomla! memorizza le informazioni aggiuntive nella seguente tabella (la tabella fa parte del core di Joomla! e non deve essere creata):

CREATE TABLE #__user_profiles (
  user_id int(11) NOT NULL,
  profile_key varchar(100) NOT NULL,
  profile_value varchar(255) NOT NULL,
  ordering int(11) NOT NULL default '0',
  UNIQUE KEY idx_user_id_profile_key (user_id,profile_key)
);

I campi della tabella sono utilizzati per i seguenti scopi:

  • user_id è la chiave esterna verso la tabella degli utenti
  • profile_key è il nome dei nostri campi aggiuntivi. Per evitare conflitti tra plugin differenti è preferibile aggiungere, davanti al nome del campo, il nome del plugin. Nel nostro caso la chiave assumerà il valore testprofile.organization
  • profile_value è il campo che memorizza il valore inserito. Fate attenzione al fatto che questo campo è di tipo varchar e limitato a 255 caratteri. Questo significa che non sarà possibile utilizzare questo meccanismo per memorizzare informazioni che superino tali dimensioni, come ad esempio dei campi di tipo textarea
  • ordering è utilizzato per gli ordinamenti

Il codice

Il file testprofile.php contiene il codice necessario.

<?php 
defined('JPATH_BASE') or die;
 
class plgUserTestprofile extends JPlugin
{
    function onContentPrepareData($context, $data)
    {
        // Check we are manipulating a valid form.
        if (!in_array($context, array('com_users.profile','com_users.registration','com_users.user','com_admin.profile'))){
            return true;
        }
 
        $userId = isset($data->id) ? $data->id : 0;
 
        // Load the profile data from the database.
        $db = &JFactory::getDbo();
        $db->setQuery(
            'SELECT profile_key, profile_value FROM #__user_profiles' .
            ' WHERE user_id = '.(int) $userId .
            ' AND profile_key LIKE \'testprofile.%\'' .
            ' ORDER BY ordering'
        );
        $results = $db->loadRowList();
 
        // Check for a database error.
        if ($db->getErrorNum()) {
            $this->_subject->setError($db->getErrorMsg());
            return false;
        }
 
        // Merge the profile data.
        $data->testprofile = array();
        foreach ($results as $v) {
            $k = str_replace('testprofile.', '', $v[0]);
            $data->testprofile[$k] = $v[1];
        }
 
        return true;
    }
 
    function onContentPrepareForm($form, $data)
    {
        // Load user_profile plugin language
        $lang = JFactory::getLanguage();
        $lang->load('plg_user_testprofile', JPATH_ADMINISTRATOR);
 
        if (!($form instanceof JForm)) {
            $this->_subject->setError('JERROR_NOT_A_FORM');
            return false;
        }
        // Check we are manipulating a valid form.
        if (!in_array($form->getName(), array('com_users.profile', 'com_users.registration','com_users.user','com_admin.profile'))) {
            return true;
        }

        // Add the profile fields to the form.
        JForm::addFormPath(dirname(__FILE__).'/profiles');
        $form->loadFile('profile', false);
    }
 
    function onUserAfterSave($data, $isNew, $result, $error)
    {
        $userId    = JArrayHelper::getValue($data, 'id', 0, 'int');
 
        if ($userId && $result && isset($data['testprofile']) && (count($data['testprofile'])))
        {
            try
            {
                $db = &JFactory::getDbo();
                $db->setQuery('DELETE FROM #__user_profiles WHERE user_id = '.$userId.' AND profile_key LIKE \'testprofile.%\'');
                if (!$db->query()) {
                    throw new Exception($db->getErrorMsg());
                }
 
                $tuples = array();
                $order    = 1;
                foreach ($data['testprofile'] as $k => $v) {
                    $tuples[] = '('.$userId.', '.$db->quote('testprofile.'.$k).', '.$db->quote($v).', '.$order++.')';
                }
 
                $db->setQuery('INSERT INTO #__user_profiles VALUES '.implode(', ', $tuples));
                if (!$db->query()) {
                    throw new Exception($db->getErrorMsg());
                }
            }
            catch (JException $e) {
                $this->_subject->setError($e->getMessage());
                return false;
            }
        }
 
        return true;
    }
 
    function onUserAfterDelete($user, $success, $msg)
    {
        if (!$success) {
            return false;
        }
 
        $userId    = JArrayHelper::getValue($user, 'id', 0, 'int');
 
        if ($userId)
        {
            try
            {
                $db = JFactory::getDbo();
                $db->setQuery(
                    'DELETE FROM #__user_profiles WHERE user_id = '.$userId .
                    " AND profile_key LIKE 'testprofile.%'"
                );
 
                if (!$db->query()) {
                    throw new Exception($db->getErrorMsg());
                }
            }
            catch (JException $e)
            {
                $this->_subject->setError($e->getMessage());
                return false;
            }
        }
 
        return true;
    }
 
}
?>

Il metodo onContentPrepareData è invocato dal metodo loadFormData del model "profile" nel componente com_admin. Il metodo onContentPrepareData si limita a creare una nuova sezione nell'oggetto $data. Questa sezione sarà utilizzata per completare il form utente con le informazioni memorizzate nel database. Per una migliore comprensione del meccanismo con cui funzionanto model e form in Joomla è opportuno consultare la documentazione specifica e dare un'occhiata al codice del componente com_admin.

Il metodo onContentPrepareForm completa la definizione del form aggiungendo le informazioni che trova nel file profile.xml.  I nuovi campi sono aggiunti alla pagina del profilo utente in un riquadro separato e sono riempiti con i valori recuperati tramite onContentPrepareData. Questo metodo si occupa anche di caricare i file di traduzione.

La funzione onUserAfterSave è chiamata dopo il salvataggio dei dati, sia per gli inserimenti che per le modifiche. Questa funzione elimina tutti i record presenti nella tabella #__user_profiles che riguardano le informazioni dell'utente gestite dal nostro plugin. Esse sono individuate, olre che tramite il campo user_id, dal fatto che i nomi della chiave iniziano sempre con testprofile. Dopo questa operazione i nuovi valori sono salvati con delle query di INSERT.

La funzione onUserAfterDelete si limita, semplicemente, a rimuovere le informazioni dell'utente nel caso venga cancellato. I record sono eliminati basandosi sul campo user_id.

Tutti i metodi hanno del codice aggiuntivo per il controllo degli errori e per garantire una maggiore sicurezza del codice.

Nel caso si desideri impostare dei campi come obbligatori è possibile aggiungere delle linee come la seguente alla fine del metodo oncontentPrepareForm:

$form->setFieldAttribute('organization', 'required', 'required', 'testprofile');

File per le traduzioni

Questo è il contenuto del file en-GB.plg_user_testprofile.sys.ini:

PLG_USER_TESTPROFILE="User - Test Profile"
PLG_USER_TESTPROFILE_XML_DESCRIPTION="User Test Profile Plug-in"

Sono le stringhe utilizzate nel file manifest. Esse vengono utilizzate durante la registrazione del componente.

E questo è il contenuto del file en-GB.plg_user_testprofile.ini:

PLG_USER_TESTPROFILE="User - Test Profile"
PLG_USER_TESTPROFILE_XML_DESCRIPTION="User Test Profile Plug-in"
PLG_USER_TESTPROFILE_SLIDER_LABEL="User Test Profile"
PLG_USER_TESTPROFILE_FIELD_ORGANIZATION_LABEL="Organization"

Sono presenti le traduzioni precedenti (questa volta per la normale operatività) e le etichette per il fieldset e per il campo aggiunto.

Installazione e test

Per creare il pacchetto di installazione è sufficiente comprimere la cartella plg_user_testprofile come file zip. È anche possibile utilizzare il pacchetto che potete scaricare da questo link.

Installate il pacchetto utilizzando l'Extension Manager e poi attivate il plugin utilizzando l'apposita gestione.

Dopo queste operazioni, troverete un nuovo riquadro nelle seguenti pagine:

  • Gestione degli utenti in amministrazione
  • Modulo di registrazione per gli utenti
  • Pagina di dettaglio dell'utente

Questo è tutto per ora.

Commenti   

 
#1 Beppe 2013-07-14 21:48
E' tutto perfetto solamente che rendendo dei campi obbligatori (correttamente visibili con *) nella form, anche se non vengono compilati, la registrazione va a buon fine ugualmente.
Se apro la pagina della registrazione, e clicco su Registrati senza inserire nessun dato, vengono segnati in rosso (come essenziali) solamente i campi obbligatori di joomla ma non i miei che ho impostato come dalla tua guida!!.
Se hai una soluzione, fammi sapere, continuo a fare test e sbatterci la testa.
Saluti.
Beppe.
Citazione
 
 
#2 Beppe 2013-07-14 22:10
MMM ho scoperto che il problema si presenta solo con le drop-down... Perchè con le scelte singole tipo testo funziona corretamente.
Riusciresti a trovare l'inghippo ???


size="1">
-
18 - 25
26 - 32
33 - 40
Oltre 40
Citazione
 
 
#3 Beppe 2013-07-14 22:44
Trovato!!!!
Neanche sulla documentazione di joomla l'ho trovato!!!
in tutti i forum dicevano di mettere default="" ma non funziona.
Io ho risolto così
<field name="Sesso" type="list" id="Sesso" label="PLG_USER _TESTPROFILE_FI ELD_SESSO_LABEL " size="1">
<option value=""></option>
<option value="Maschio">Maschio</option>
<option value="Femmina">Femmina</option>
</field>


Magari ti può tornare utile pure a te o aggiungerlo alla tua fantastica guida.
Ciao grazie
Citazione
 
 
#4 vittorio 2013-07-17 11:07
come lo correggo ? grazie in anticipo.

Strict Standards: Only variables should be assigned by reference in D:\Xampp\htdocs \J25\plugins\us er\testprofile\ testprofile.php on line 16
Citazione
 
 
#5 Edy Incoletti 2013-07-17 15:12
Citazione vittorio:
Strict Standards: Only variables should be assigned by reference in D:\Xampp\htdocs\J25\plugins\user\testprofile\testprofile.php on line 16

Modifica le impostazioni del tuo file php.ini affinché segnalino solamente gli errori.
Citazione
 
 
#6 MarcoJ 2013-09-15 19:47
Ciao,
grazie del materiale utilissimo.
Ho fatto come hai detto, con solo la complicazione ho usato sia la funzione "onuserbeforesa ve" che "onuseraftersav e", perchè devo interfacciarmi ad un AS400.
Sembra difficile, ma in realtà funziona tutto come un orologio: inserisco i dati, li passo ad AS, confronto i dati, accetto o rifiuto la registrazione in base a quanto letto.
Solo un piccolo problema, che non riesco a risolvere: quando la mia registrazione termina con successo, mi ritorna sempre una pagina bianca, senza il classico messaggio "Il tuo account è stato creato...", mentre quando c'è un errore mi ripropone la form vuota per la registrazione, senza nessun messaggio.
Insomma funziona, ma ho perso i messaggi.
Agendo sulle due funzioni e mettendo lì dei messaggi, questi non vengono visualizzati (credo perchè la pagina viene rinfrescata e quindi la cosa dei messaggi persa).
Sai darmi qualche dritta ?
Grazie mille
Citazione
 
 
#7 Edy Incoletti 2013-09-23 08:30
Citazione MarcoJ:
Solo un piccolo problema, che non riesco a risolvere: quando la mia registrazione termina con successo, mi ritorna sempre una pagina bianca, senza il classico messaggio "Il tuo account è stato creato...", mentre quando c'è un errore mi ripropone la form vuota per la registrazione, senza nessun messaggio.
Insomma funziona, ma ho perso i messaggi.

Sembra più un problema del template che del plugin. Hai provato con il template standard di Joomla!?
Citazione
 
 
#8 Antonio 2013-09-24 22:39
Ciao, grazie per il materiale utilissimo. Se volessi rendere visibili i dati inseriti nella tabella del backend come potrei fare?
Grazie mille
Citazione
 
 
#9 biosan75 2014-03-25 12:26
Citazione MarcoJ:
Ciao,
grazie del materiale utilissimo.
Ho fatto come hai detto, con solo la complicazione ho usato sia la funzione "onuserbeforesave" che "onuseraftersave", perchè devo interfacciarmi ad un AS400.


Ciao MarcoJ, ho letto che ti interfacci con AS400. Visto che interessa anche a me, sapresti indirizzarmi verso qualche guida per interfacciare AS400 e Joomla!?

Ciao
Citazione
 
 
#10 Lorenzo 2014-07-22 16:54
Guida utilissima, in un ora sono riuscito a fare quasi tutto quello che mi serviva tranne che....

Vorrei creare form diversi che contengono campi diversi, ad esempio dovrei creare un form di registrazione per Privato ed uno per Azienda.

Grazie per l'articolo :-)
Citazione