Benvenuti

Come creare un buon Model in Codeigniter

Come creare un buon Model in Codeigniter
Scritto da Martedì 8 Maggio 2012 in Articoli CodeIgniter
Letto 6,971 volte

Sviluppare con un framework MVC garantisce senza dubbio una maggiore riutilizzabilità e la robustezza del codice. In questo articolo ci soffermeremo sulla scrittura della parte model del paradigma MVC impiegando CodeIgniter. Questo modello non è specifico di CodeIgniter, ma una parte del codice lo sarà.

Modello CRUD

CRUD è un acronimo che sta per Create, Retrieve, Update e Delete. Questi sono i tipi più elementari di interazione che un codice può avere con una sorgente dati.
Alcuni esempi:

  • Create: Aggiunta di un account utente al tuo sito web
  • Retrieve: ottenere un elenco dei prodotti disponibili Aggiornamento
  • Update: della password di un utente o il nome di un prodotto
  • Delete: la rimozione di un account utente o di un prodotto

Quando si scrive un model in genere si inizia con la creazione di metodi CRUD per ognuno dei tipi logici di dati. Se ad esempio dovessimo scrive l’autenticazione dell’utente (login, logout, password dimenticata, attivazione degli account) sarà necessario un metodo per aggiungere, aggiornare e cancellare gli utenti e la possibilità di estrapolare le informazioni relative all’account per un singolo utente o per un gruppo di utenti.

Ad Esempio:

function AddUser()
function UpdateUser()
function DeleteUser()
function GetUsers()

La maggior parte delle interazioni che abbiamo con gli account utente possono essere gestiti da questi quattro metodi. Invece di creare un model “GetActiveUsers” ci basta creare un parametro in GetUsers che determina lo stato di utente come risposta, di seguito vedremo meglio la cosa.

Array di parametri

Tipicamente parametri per i metodi vengono inviati nel modo seguente:

function AddUser($insertData)
function UpdateUser($userId, $updateData)
function DeleteUser($userId)
function GetUsers($limit, $offset)

Naturalmente, (soprattutto per GetUsers) ci saranno sempre più parametri da aggiungere ai nostri metodi. Questo non solo rende molto difficile la lettura, ma può creare problemi nel caso in cui dovessimo tornare indietro e modificare il codice già scrittoo se dobbiamo variare un parametro sul metodo.
Per esempio:

function GetUsers($limit, $offset, $status)

Potremmo poi aver bisogno anche di una GetUser($userId) singolare, oltre al metodo GetUsers. Questo è un problema perché stiamo creando più versioni dello stesso metodo. Se cambiamo il modo in cui vogliamo informazioni da restituire poi avremmo bisogno di modificare il codice in due punti, i metodi GetUser e GetUsers.

Per superare questi problemi è consigliabile l’utilizzo di un array opzioni, in questo modo:

function AddUser($options = array())
function UpdateUser($options = array())
function DeleteUser($options = array())
function GetUsers($options = array())

Se prima era necessario usare GetUsers(5, 5, ‘active’) per avere la lista degli utentim adesso è possibile usare

GetUsers(array(‘limit’ => 5, ‘offset’ => 5, ‘status’ => ‘active’);

I parametri passati in un array possono essere inviati in qualsiasi ordine o possono anche essere completamente omessi. Questo permette di aggiungere e rimuovere parametri senza aggiornare le parti di codice che fanno uso di questo metodo.

Utility

Al fine di creare metodi adeguatamente robusti abbiamo bisogno di implementare alcune piccole fuznionalità comuni. Vale a dire, la capacità di stabilire quali sono i campi richiesti e quali valori hanno di default. Ad esempio, un campo richiesto quando si aggiunge un utente potrebbe essere la mail. Per questo creiamo il metodo ‘required’.

/**
* _required method returns false if the $data array does not contain all of the keys assigned by the $required array.
*
* @param array $required
* @param array $data
* @return bool
*/
function _required($required, $data)
{
    foreach($required as $field) if(!isset($data[$field])) return false;
    return true;
}

Questa utility nel nostro ‘AddUser’ potrebbe essere utilizzato così:

/**
* AddUser method creates a record in the users table.
*
* Option: Values
* --------------
* userEmail            (required)
* userPassword
* userName
* userStatus        active(default), inactive, deleted
*
* @param array $options
*/
function AddUser($options = array())
{
    // required values
    if(!$this->_required(array('userEmail'), $options)) return false;

    // At this point we know that the key 'userEmail' exists in the $options array.
}

Adesso il metodo ‘AddUser’ restituirà false se il campo ‘userEmail’ non è stato inviato con la matrice dei parametri.

Nel blocco PHPDoc abbiamo stabilito che lo stato di default per i nuovi utenti è ‘attivo’. Naturalmente, se volessimo creare un utente inattivo dovremmo essere in grado di passare il parametro ‘stato_utente’ con il valore inattivo. Tuttavia, siamo non ne abbiamo voglia 🙂 e preferiamo non dover dichiarare esplicitamente ‘attivo’.

Il metodo di ‘default’:

/**
* _default method combines the options array with a set of defaults giving the values in the options array priority.
*
* @param array $defaults
* @param array $options
* @return array
*/
function _default($defaults, $options)
{
    return array_merge($defaults, $options);
}

Fatto, questo metodo consiste di un singolo comando. La creazine di un nuovo metodo può essere utile per aggiungere funzionalità extra senza dover poi cambiare ogni singolo metodo che ne prevede l’uso.

Torniamo a noi ed implementiamo il metodo ‘default’ in ‘AddUser’:

/**
* AddUser method creates a record in the users table.
*
* Option: Values
* --------------
* userEmail            (required)
* userPassword
* userName
* userStatus        active(default), inactive, deleted
*
* @param array $options
*/
function AddUser($options = array())
{
    // required values
    if(!$this->_required(array('userEmail'), $options)) return false;

    // default values
    $options = $this->_default(array('userStatus' => 'active'), $options);
}

A questo punto sappiamo che il campo ‘userEmail’ esiste nell’array $option e se nessun campo ‘userStatus’ è stato definito tra i parametri di chiamata del metodo, ne verrà creato uno con valore ‘.

Questi metodi rendono il codice più robusto, ed hanno come scotto solo l’aggiunta di poche righe per ciascun metodo.

Gestione Record

Molti database (MySQL, Oracle, Microsoft SQL, PostgreSQL, ecc) utilizzano differenti costrutti SQL. Proprie variazioni della sintassi SQL ‘ufficiale’ e tutti lavorano un po diversamente gli uni dagli altri. CodeIgniter ci mette a disposizione delle librerie che astraggono questo problema. Questo ci permette in altre parole, eseguire query su qualsiasi database supportato dalla nostra libreria.

Un’esempio di come potremmo integrare il gestore del DB di codeIgniter nel nostro esempio:

/**
* AddUser method creates a record in the users table.
*
* Option: Values
* --------------
* userEmail            (required)
* userPassword
* userName
* userStatus        active(default), inactive, deleted
*
* @param array $options
*/
function AddUser($options = array())
{
    // required values
    if(!$this->_required(array('userEmail'), $options)) return false;

    // default values
    $options = $this->_default(array('userStatus' => 'active'), $options);

    // qualification (make sure that we're not allowing the site to insert data that it shouldn't)
    $qualificationArray = array('userEmail', 'userName', 'userStatus');
    foreach($qualificationArray as $qualifier)
    {
        if(isset($options[$qualifier])) $this->db->set($qualifier, $options[$qualifier]);
    }

    // MD5 the password if it is set
    if(isset($options['userPassword'])) $this->db->set('userPassword', md5($options['userPassword']));

    // Execute the query
    $this->db->insert('users');

    // Return the ID of the inserted row, or false if the row could not be inserted
    return $this->db->insert_id();
}

/**
* UpdateUser method alters a record in the users table.
*
* Option: Values
* --------------
* userId            the ID of the user record that will be updated
* userEmail
* userPassword
* userName
* userStatus        active(default), inactive, deleted
*
* @param array $options
* @return int affected_rows()
*/
function UpdateUser($options = array())
{
    // required values
    if(!$this->_required(array('userId'), $options)) return false;

    // qualification (make sure that we're not allowing the site to update data that it shouldn't)
    $qualificationArray = array('userEmail', 'userName', 'userStatus');
    foreach($qualificationArray as $qualifier)
    {
        if(isset($options[$qualifier])) $this->db->set($qualifier, $options[$qualifier]);
    }

    $this->db->where('userId', $options['userId']);

    // MD5 the password if it is set
    if(isset($options['userPassword'])) $this->db->set('userPassword', md5($options['userPassword']));

    // Execute the query
    $this->db->update('users');

    // Return the number of rows updated, or false if the row could not be inserted
    return $this->db->affected_rows();
}

/**
* GetUsers method returns an array of qualified user record objects
*
* Option: Values
* --------------
* userId
* userEmail
* userStatus
* limit                limits the number of returned records
* offset                how many records to bypass before returning a record (limit required)
* sortBy                determines which column the sort takes place
* sortDirection        (asc, desc) sort ascending or descending (sortBy required)
*
* Returns (array of objects)
* --------------------------
* userId
* userEmail
* userName
* userStatus
*
* @param array $options
* @return array result()
*/
function GetUsers($options = array())
{
    // default values
    $options = $this->_default(array('sortDirection' => 'asc'), $options);

    // Add where clauses to query
    $qualificationArray = array('userId', 'userEmail', 'userStatus');
    foreach($qualificationArray as $qualifier)
    {
        if(isset($options[$qualifier])) $this->db->where($qualifier, $options[$qualifier]);
    }

    // If limit / offset are declared (usually for pagination) then we need to take them into account
    if(isset($options['limit']) && isset($options['offset'])) $this->db->limit($options['limit'], $options['offset']);
    else if(isset($options['limit'])) $this->db->limit($options['limit']);

    // sort
    if(isset($options['sortBy'])) $this->db->order_by($options['sortBy'], $options['sortDirection']);

    $query = $this->db->get('users');
    if($query->num_rows() == 0) return false;

    if(isset($options['userId']) && isset($options['userEmail']))
    {
        // If we know that we're returning a singular record, then let's just return the object
        return $query->row(0);
    }
    else
    {
        // If we could be returning any number of records then we'll need to do so as an array of objects
        return $query->result();
    }
}

/**
* DeleteUser method removes a record from the users table
*
* @param array $options
*/
function DeleteUser($options = array())
{
    // required values
    if(!$this->_required(array('userId'), $options)) return false;

    $this->db->where('userId', $options['userId']);
    $this->db->delete('users');
}

Questo è un’esempio di come possiamo usare questi metodi per interagire con il nostro database.

Aggiungere un utente

$userId = $this->user_model->AddUser($_POST);

if($userId)
    echo "The user you have created has been added successfully with ID #" . $userId;
else
    echo "There was an error adding your user.";

Aggiornare il suo profilo

if($this->user_model->UpdateUser(array('userId' => 3, 'userName' => 'Shawn', 'userEmail' => 'not telling')))
    // The user has been successfully updated
else
    // The user was not updated

Autenticare l’utente

$user = $this->user_model->GetUsers(array('userEmail' => $userEmail, 'userPassword' => md5($userPassword), 'userStatus' => 'active'));
if($user)
    // Log the user in
else
    // Sorry, your user / password combination isn't correct.

Recuperare l’elenco degli utenti

$users = $this->user_model->GetUsers(array('userStatus' => 'active')); 
if($users) { 
    echo "Active Users "; 
    foreach($users as $user) { 
        echo $user->userName . " "; 
    } 
} else { 
    echo "There are no active users."; 
}

Cancellare un’utente

$this->user_model->DeleteUser(array('userId' => $userId));

Naturalmente CodeIgniter permette l’accesso a più database contemporaneamente anche di diversa natura, garantendo sempre quell’astrazione che permette l’esecuzione delle query in questo semplice modo.

This Post Has 2 Comments

  1. Alex says:

    Ciao, ottimo tutorial!

    Volevo segnalarti che nel codice che proponi sono saltati tutti i caratteri “>”, che sono stati trasformati nel relativo codice “>”. Questo rende difficile la lettura del codice, soprattutto per chi è alle prime armi.

    • Giuseppe Quaranta says:

      Ciao Alex,
      grazie mille per il complimento e per la segnalazione.
      Ho aggiornato il plugin di visualizzazione che ha resettato alcuni parametri di configurazione.

      Ora è ok.

      Ciao,
      Giuseppe

Leave A Reply