sabato 21 gennaio 2012

Programmazione Android: I menù - Costruire una web application (terza parte)

Una piccola premessa: smartphone e tablet gestiscono i menù che vedremo in modo differente. Mentre i tablet mostrano i pulsanti del menù nella barra di titolo (TitleBar, quella eliminata dal tema FullScreen nel post precedente), gli smartphone esigono la pressione di un determinato tasto del telefono per mostrare a video il menù (per ovvie ragioni di spazio). Ovviamente se vogliamo mostrare su un tablet il menù, dovremo eliminare l'impostazione del tema "Fullscreen".
Ricordando i post precedenti, Android sfrutta perfettamente il modello MVC: la prima cosa da fare, quindi, è creare il layout del nostro menù personalizzato. Per fare ciò, per prima cosa bisogna creare una cartella "menu" sottocartella di "res". Selezionare la cartella appena creata e premere "Ctrl + N" oppure fare click con il pulsante destro e scegliere New->Other. Scegliere a questo punto Android XML File e cliccare su Next.

Nella schermata successiva dare un nome al file, ad esempio menubar.xml e fare click su "Finish". Eclipse a questo punto apre automaticamente l'editor per l'xml appena creato, riconoscendo che andrà a specificare la struttura di un menù. Basterà cliccare su "Add" e poi scegliere "Item" per aggiungere un elemento al menù. Ovviamente bisogna specificare:
  • Id: @+id/item_exit
    Tutti gli id iniziano per @+id/ e sono seguiti dal nome identificativo, in questo caso item_exit
  • Title e Title Condensed: Esci
    Sono il titolo e il titolo breve del menù, in questo caso "Esci"
  • Icon: @drawable/ic_exit
    L'icona associata al bottone. Android cercherà l'icona ic_exit.png sotto le cartelle res/drawable-*
Per il momento basta questa semplice configurazione. Ovviamente si dovrà spiegare ad Android quando e soprattutto in quale attività (Activity) questo menù dovrà essere mostrato. Per fare ciò, apriamo il file sorgente dell'attività principale (per chi non si ricordasse il primo post sull'argomento, il nome è webappActivity.java) e aggiungiamo questa funzione:
@Override
 public boolean onCreateOptionsMenu(Menu menu) {
     MenuInflater inflater = getMenuInflater();
     inflater.inflate(R.menu.menubar, menu);
     return true;
 }
Il codice crea un menù sulla base del file xml specificato (menubar, sotto la cartella menu). Adesso bisogna associare un determinato comportamento alla pressione dei vari bottoni del menù creato. Anche qui, un semplice override con un codice che discrimina l'id del pulsante premuto:
@Override
 public boolean onOptionsItemSelected(MenuItem item) {
     switch (item.getItemId()) {
         case R.id.item_exit:
          finish();
             return true;
         default:
             return super.onOptionsItemSelected(item);
     }
 }
La funzione finish() chiede ad Android di "terminare" l'attività corrente; se quest'ultima è quella principale, il sistema tornerà al menù principale (la home). In realtà, Android ha una gestione dei processi e della loro terminazione tutta sua, quindi anche se l'applicazione non viene mostrata a schermo, può essere che sia ancora in memoria.
Ed ora il risultato finale:
Questo è un esempio con un solo bottone nel menù; ovviamente basta ripetere le semplici operazioni precedenti per aggiungerne ad oltranza. Con una piccola restrizione: Android non mostra più di 6 bottoni. Tutti quelli che oltrepassano questa soglia vengono raccolti un un bottone magico "Altro".

martedì 17 gennaio 2012

Programmazione Android: Costruire una web application (seconda parte) - jQuery Mobile

In questa seconda parte incontriamo jQuery Mobile, una versione del famoso framework appositamente creata per gestire e mostrare contenuti per dispositivi quali smartphone e tablet. E' possibile analizzarne il comportamento accedendo alla demo disponibile, che mostra tutti i componenti utili per realizzare una splendida web application. Ovviamente la cosa più semplice è scaricare l'intero framework, caricarlo sul sito che farà da base per l'applicazione web, studiarsi il sorgente html + javascript della demo e modificarlo a piacimento; vediamo però a grandi linee quale sia la struttura:
Header
<!DOCTYPE html> 
<html> 
 <head> 
 <title>My Page</title> 
 <meta name="viewport" content="width=device-width, initial-scale=1"> 
 <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css" />
 <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
 <script src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js"></script>
</head> 
Fino a qui niente di particolare: in sostanza il caricamento delle librerie necessarie al funzionamento di jQuery Mobile. Da notare però la parola chiave "viewport" all'interno di un meta tag, fondamentale per l'impostazione delle dimensioni dello schermo per il risultato finale html.

Body
<body> 

<div data-role="page">

 <div data-role="header">
  <h1>My Title</h1>
 </div><!-- /header -->

 <div data-role="content"> 
  <p>Hello world</p>  
 </div><!-- /content -->

</div><!-- /page -->

</body>
</html>
Da questa parte di codice si comprende come una pagina sia indicata come una div con attributo "data-role" impostato su "page". La barra di navigazione in alto a sua volta avrà ruolo "header", mentre il contenuto vero e proprio della pagina avrà ruolo "content".

L'idea di base è quella di mostrare un sito (o una sezione di sito) appositamente sviluppato con jQuery Mobile all'interno dell'applicazione Android; all'utente sarà quindi invisibile se questa parte sia sviluppata con il framework Android o con il più immediato e graficamente appagante html, css e javascript. Ovviamente, riprendendo il codice del post precedente, è sufficiente modificare la pagina alla quale l'oggetto webView si deve connettere:
webView1.loadUrl("http://code.jquery.com/mobile/latest/demos/");
Ho chiaramente usato l'url del demo per semplicità; andrà sostituito con la parte del sito mobile che avrete destinato ad Android (ad esempio, www.example.com/android).
Per terminare questa parte, mostro un piccolo accorgimento grafico: se si prova ad eseguire l'applicazione android creata in precedenza si nota una fastidiosa barra in alto, con il nome dell'applicazione. Questa barra può essere migliorata graficamente (e lo mostrerò nei post successivi) oppure, più facilmente, può essere nascosta. Per fare quest'ultima operazione è sufficiente aprire il file manifest AndroidManifest.xml e creare, all'interno del tag activity principale, l'attributo "android:theme", impostandolo ad un determinato valore. Vediamo il risultato:
<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="net.stefanobianchini.webapp"  
    android:versionCode="1"  
    android:versionName="1.0" >  
  
    <uses-sdk android:minSdkVersion="10" />  
    <uses-permission android:name="android.permission.INTERNET"/>  
    <application  
        android:icon="@drawable/ic_webapp"  
        android:label="@string/app_name" >  
        <activity  
            android:name=".webappActivity"  
            android:label="@string/app_name" 
            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
    </application>  
  
</manifest>
Questa direttiva chiederà ad Android di mostrare l'applicazione a tutto schermo, senza la fastidiosa TitleBar. In figura il risultato finale, visualizzato dentro l'emulatore:

lunedì 16 gennaio 2012

Programmazione Android: Costruire una web application (prima parte)

Grazie al regalo di Natale di mia moglie (un tablet Acer Iconia Tab A500), ultimamente mi sono interessato alla programmazione di applicazioni Android. questo è il primo di una serie di post in cui affronterò l'ambiente android ed in particolare lo sviluppo di applicazioni Web per android, un misto tra applicazioni android ed applicazioni Web. Tralascio volutamente tutta la parte relativa alla preparazione dell'ambiente di sviluppo, ampiamente disponibile via web; l'unica cosa a cui accenno è che è necessario fornirsi di:

Preparato l'ambiente, Eclipse è ora in grado di gestire al meglio i progetti Android. Per iniziare un nuovo progetto, File ->New->Project e selezioniamo Android Project.
Quindi diamo un nome al progetto (ad esempio, webapp) e selezioniamo la versione dell'sdk di riferimento. I tablet in commercio attualmente sono equipaggiati della versione 3.2 (Honeycomb), ma molti telefoni hanno ancora la versione 2.3, ragion per cui io scelgo di sviluppare con una versione meno recente, come si vede in figura.
Successivamente verrà chiesto il package, è norma utilizzare tre parole separate dal punto ".", ad esempio net.stefanobianchini.applicazioneweb. Lo scheletro del progetto è quindi pronto.

L'icona
Una applicazione che si rispetti ha bisogno di un'icona giusta. Cercate un'icona 72x72 pixel in formato png che più rappresenta la vostra applicazione e posizionatela sotto res/drawable-hdpi (qui una spiegazione sulle directory delle risorse grafiche), chiamandola ad esempio ic_webapp.png. A questo punto si apre il file AndroidManifest.xml e nella sezione application->application attributes->icon impostare @drawable/ic_webapp. Questa configurazione chiederà ad android di utilizzare l'immagine che avete scelto come icona nel menù principale, una volta che l'applicazione sarà installata. La modifica è simile anche se si sceglie di modificare direttamente l'xml anziché utilizzare il wizard dell'ADT.

I permessi
Fondamentale per lo sviluppo Android è la corretta gestione dei permessi. Una applicazione ha bisogno di permessi particolari, infatti, per collegarsi ad internet, usare il GPS, la fotocamera eccetera. Il consenso al rilascio di questi permessi viene effettuato al momento dell'installazione da parte dell'utente. Ma dobbiamo spiegare ad Android di quali permessi ha bisogno la nostra applicazione! Nel nostro caso, solo dei permessi della navigazione internet. Apriamo quindi il manifest (AndroidManifest.xml) e cerchiamo la parte "Permission": cliccando su "Add" si selezione "Uses Permission" e poi "Android.Permission.Internet". Tutto qua, niente di trascendentale.

Vediamo quindi il risultato xml di queste modifiche:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.stefanobianchini.webapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:icon="@drawable/ic_webapp"
        android:label="@string/app_name" >
        <activity
            android:name=".webappActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Come si vede dall'xml, il nome che sarà visualizzato nel menù di android che identificherà l'applicazione è un valore chiamato app_name all'interno delle risorse stringa del progetto. Le risorse stringa sono simili alle risorse grafiche (drawable), è praticamente un file xml con coppie di nomi - valori. Se apriamo il file res->values->strings.xml possiamo modificare il valore della stringa app_name, in modo da personalizzarla:

Il Layout
Android predilige il modello MVC, quindi il layout sarà separato dalla parte del funzionamento dell'applicazione. E cosa meglio di XML per disegnare i vari componenti grafici dell'applicazione? Ovviamente si può anche sfruttare l'editor visuale di Eclipse che dà una bella mano. La parte grafica si trova sotto res->layout e poiché Eclipse già crea nel progetto base una impaginazione "Hello World", basterà modificare il file main.xml già presente. Nel nostro caso è molto, molto semplice: eliminiamo la textview esistente ed andiamo ad inserire un componente magico, chiamato WebView (sotto la linguetta Composite).
Un'occhiata al risultato xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <WebView
        android:id="@+id/webView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
Come si vede dalla figura, Eclipse ha chiamato il componente appena inserito "webView1". Ovviamente il nome può essere cambiato.

Il codice sorgente
Ora che tutto è pronto, diamo una occhiata al comportamento che l'applicazione deve adottare. Apriamo il file creato automaticamente webappActivity.java (ovviamente, se il progetto si chiama pincopallino il file che eclipse creerà automaticamente sarà nominato pincopallinoActivity.java). Iniziamo dalla base: appena l'applicazione viene lanciata, viene eseguito un metodo standard chiamato onCreate() dell'attività scelta per essere la principale (ossia quella eseguita per prima). Questo metodo viene reimplementato (override) e possiamo inserire dentro tutte le istruzioni utili al funzionamento base dell'applicazione, non prima però di aver definito una variabile pubblica relativa all'oggetto webview:
public WebView webView1;
/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //istruzione che imposta il layout main.xml
        setContentView(R.layout.main);      
        //ottengo l'oggetto webview
        webView1 = (WebView) findViewById(R.id.webView1);
        //Attivo il supporto javascript
        webView1.getSettings().setJavaScriptEnabled(true);
        //Carico la pagina desiderata
        webView1.loadUrl("http://www.stefanobianchini.net");
    }
E la prima funzione di base è pronta: ora però vogliamo che, navigando tra le pagine, la pressione del pulsante indietro del sistema android permetta di navigare nella cronologia anziché tornare al menù principale. Questo può essere fatto attraverso un override semplice:
@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView1.canGoBack()) {
         webView1.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
Bene. L'applicazione ha già la sua funzionalità di base, come si comprende se viene eseguito il progetto da Eclipse nell'emulatore. Se però si carica l'applicazione su un device, aprendo e chiudendo l'applicazione si possono avere dei problemi: questo perché l'applicazione, quando si torna al menù principale del sistema, viene messa in pausa automaticamente dall'OS Android. Per risolvere questo problema bastano poche righe di codice:
public void onResume() {
       super.onResume();
       if (webView1 != null) {
        webView1.resumeTimers();
       }
     }

    public void onPause() {
       super.onPause();
       if (webView1 != null) {
        webView1.pauseTimers();
       }
     }

Ora l'applicazione è funzionante. Nei futuri post spiegherò come utilizzare un framework per lo sviluppo di applicazioni web mobile (jquery mobile), ossia simulare una applicazione vera e propria via internet. Inoltre verranno integrate piccole migliorie all'applicazione base mostrata in questo post, come ad esempio un pulsante esci, un pulsante home, una finestra di caricamento e magia delle magie, un ponte che collega javascript al codice java della nostra applicazione android, ovvero come eseguire comandi java dal una pagina web per android. Questo ovviamente apre vasti scenari (utlizzo della fotocamera, GPS eccetera). Ovviamente con i permessi opportuni :-)

martedì 13 dicembre 2011

FullCalendar - un calendario jQuery con agenda e drag & drop

Per un piccolo gestionale medico ultimamente mi è capitato sotto mano FullCalendar, un ottimo calendario jQuery "full-size" altamente configurabile. Già dalla home page di questo progetto emergono i punti forti del plugin: eventi di tutto il giorno o schedulati, drag & drop degli eventi, viste per mese, per settimana e vista giornaliera. Il progetto è molto ben documentato, quindi per un utilizzo base rimando ogni spiegazione al sito.
Voglio pubblicare però la configurazione che ho utilizzato, cercando di mostrarne le potenzialità:
$('#calendar_strutture').fullCalendar({
   header: {
    left: 'prev,next today',
    center: 'title',
    right: 'month' //,agendaWeek,agendaDay
   },
   firstHour: 6,
   firstDay: 1,
   allDaySlot : false,
   timeFormat: 'HH:mm',
   monthNames:['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno','Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'],
   monthNamesShort: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'],
   dayNames: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
   dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
   buttonText: {
    prev:     ' &#9668 ',  // left triangle
    next:     ' &#9658 ',  // right triangle
    prevYear: ' &lt;&lt; ', // <<
    nextYear: ' &lt;&lt; ', // >>
    today:    'Oggi',
    month:    'Mese',
    week:     'Settimana',
    day:      'Giorno'
   },
   columnFormat: {
    month: 'ddd',    // Mon
    week: 'd/M ddd', // Mon 9/7
    day: 'dddd d/M'  // Monday 9/7
   },
   editable: true,
   
   events: {
    url: 'lista_calendario_strutture.php',
    cache: true,
    //color: 'purple',   // a non-ajax option
          textColor: 'white' // a non-ajax option
   },
   lazyFetching: false,
     
   eventClick: function(calEvent) {
    if(confirm("Elimino dal calendario la disponibilita' della struttura per il giorno selezionato?")) {
     $.ajax({
       url: "interventi.php?section=calendario_strutture&action=delete",
       type: 'POST',
       data: {
      struttura: calEvent.title,
      data: calEvent.start.getTime()
       },
       success: function(msg){
      //alert(msg); //debug
      $('#calendar_strutture').fullCalendar('removeEvents',calEvent.id); 
       },
       error: function() {
      revertFunc();
       }
     });
    }
   },
   
   eventMouseover: function(calEvent) {
    $(this).find('.fc-event-title').html('<img src="template/default/admin/assets/images/delete.png" /> '+calEvent.title);
   },
   
   eventMouseout: function(calEvent) {
    $(this).find('.fc-event-title').html(calEvent.title);  
   },
   
   eventDrop: function(calEvent,dayDelta,minuteDelta,allDay,revertFunc) {
    //Qui ajax per spostamento evento
    $.ajax({
      url: "interventi.php?section=calendario_strutture&action=move",
      type: 'POST',
      data: {
     struttura: calEvent.title,
     movimento: dayDelta,
     nuova_data: calEvent.start.getTime()
               },
      success: function(msg){
     //alert(msg);
      },
      error: function() {
     revertFunc();
      }
    });
   },
   droppable: true,
   drop: function(date, allDay) { // this function is called when something is dropped
   
    // retrieve the dropped element's stored Event Object
    var originalEventObject = $(this).data('eventObject');
    
    // we need to copy it, so that multiple events don't have a reference to the same object
    var copiedEventObject = $.extend({}, originalEventObject);
    
    var today = new Date();
    
    // assign it the date that was reported
    copiedEventObject.id = today.getTime();
    copiedEventObject.start = date;
    copiedEventObject.allDay = allDay;
    
    //alert(copiedEventObject.title + ' ' + copiedEventObject.start.getTime());
    
    //Qui ajax per inserimento disponibilita in calendario struttura
    $.ajax({
      url: "interventi.php?section=calendario_strutture&action=insert",
      type: 'POST',
      data: {
     struttura: copiedEventObject.title,
     data: copiedEventObject.start.getTime()
               },
      success: function(msg){
     //alert(msg); //debug
     // render the event on the calendar
     $('#calendar_strutture').fullCalendar('renderEvent', copiedEventObject, false);
      }
    });
    
   }
   
  });

$('#external-events div.external-event').each(function() {

 // create an Event Object (http://arshaw.com/fullcalendar/docs/event_data/Event_Object/)
 // it doesn't need to have a start or end
 var eventObject = {
  title: $.trim($(this).text()), // use the element's text as the event title
  backgroundColor: $(this).css('background-color')
 };
 
 // store the Event Object in the DOM element so we can get to it later
 $(this).data('eventObject', eventObject);
 
 // make the event draggable using jQuery UI
 $(this).draggable({
  zIndex: 999,
  revert: true,      // will cause the event to go back to its
  revertDuration: 0  //  original position after the drag
 });
 
});

Questa prima parte, che deve essere contenuta nella parte relativa a $(document).ready(...), specifica il comportamento del calendario, in particolare:
  1. deve poter gestire, tramite chiamate ajax, lo spostamento degli eventi (eventDrop), che in questo caso particolare, sono "disponibilità" delle sale operatorie in determinate strutture ospedaliere
  2. deve gestire l'eliminazione delle disponibilità, mediante click del mouse (eventClick) sull'evento stesso (notare che quando il mouse si trova sopra l'evento viene mostrata una icona "cestino")
  3. deve gestire la creazione delle disponibilità mediante il trascinamento dall'elenco strutture sulla sinistra al calendario (drop), date una occhiata allo screenshot per capire di cosa sto parlando
  4. La parte finale del codice jQuery è relativa al punto 3, fa capire al motore javascript che i
    sulla sinistra deve gestirli come "draggable" e creare un oggetto evento (Event Object) in modo da poterlo poi gestire in FullCalendar.
Di seguito il codice html utilizzato (elenco strutture + calendario):
<div id='wrap' style="width:100%;margin: 0 auto;"> 
                 <div id='external-events' style="float: left;width: 150px;padding: 0 10px;border: 1px solid #ccc;background: #eee;text-align: left;margin-right:20px;">
                  <h4>Elenco Strutture</h4>
                                    <div class='external-event' style="background-color:#0099FF">Struttura Ospedaliera 1</div>
                                    <div class='external-event' style="background-color:#996699">Struttura Ospedaliera 2</div>

                                    </div>
                 <div id='calendar_strutture' style="width: 900px;float:left;"></div>
                 <div style='clear:both'></div>
              </div>
            </div>
Il risultato finale!

mercoledì 31 agosto 2011

familyFinance.NET - sorgente - gestire le finanze familiari con C#

Vi propongo un software semplice semplice da me sviluppato per testare il funzionamento del C# con la tecnologia Sqlite.
Prendetelo così com'è, con i suoi bug e i suoi difetti (vuole essere semplicemente un test). I sorgenti sono scaricabili direttamente dal mio sito: http://www.stefanobianchini.net/familyfinance.net/familyfinance.net.zip
Tra le caratteristiche:
  • Sviluppato in C# (Framework 2.0)
  • Database Sqlite
  • Gestione movimenti (entrate, uscite) con data, note, descrizione, categoria (testuali)
  • Gestione saldo iniziale e opzioni basilari
  • Grafico a torta entrate / uscite
Alcuni screenshots:

martedì 2 agosto 2011

C# - un file browser personalizzato, riutilizzabile!

In questi giorni mi sono dedicato allo sviluppo di un piccolo componente (uno user control, utilizzando la terminologia .NET) che si occupa di fare da "file browser", ossia di navigare tra cartelle e file, effettuando le operazioni più comuni (apertura, nuova cartella, eliminazione, spostamento mediante drag & drop ecc.).
Ne è uscita fuori una libreria DLL riutilizzabile, scaricabile a questo indirizzo:
Ora vediamo come importare questo componente, contenuto nella libreria DLL, all'interno di un progetto C#:
  1. per prima cosa cliccare con il tasto destro sulla casella degli strumenti (quella con i componenti più comuni) e selezionare "Scegli elementi";
  2. cliccare su "Sfoglia" e selezionare la libreria dll. Abilitare il componente (chiamato in questo caso filebrowser) tramite il check a sinistra dello stesso;
  3. trascinare infine il componente dalla casella degli strumenti al form nel quale si intende avvalersi dei suoi servigi;
  4. impostare la proprietà che specifica la cartella da cui partire come radice (nell'esempio, il disco c:\)
    fileBrowser1._ROOT = @"c:\";
    
Spero che questo mio lavoro sia utile anche ad altri :-)
Qui potete vedere il risultato finale:

lunedì 1 agosto 2011

Php: una comoda libreria per interagire con MySql

Pubblico una comoda libreria da utilizzarsi per interagire con un database MySql. Fa parte del codice di Opencart che, come al solito, si rivela per me fonte di ottimo codice Php. Nella realtà sarebbe un driver, ossia un codice specifico per DBMS; Opencart in realtà usa una classe wrapper (chiamata db.php) non interessandosi dell'implementazione. A seconda del DBMS utilizzato, viene incluso un driver oppure un altro (ad esempio, MySql.php oppure Mssql.php e così via).
Dopo questa precisazione, diamo una occhiata al codice:
<?php
final class MySQL {
 private $connection;

 public function __construct($hostname, $username, $password, $database) {
  if (!$this->connection = mysql_connect($hostname, $username, $password)) {
   exit('Error: Could not make a database connection using ' . $username . '@' . $hostname);
  }

  if (!mysql_select_db($database, $this->connection)) {
   exit('Error: Could not connect to database ' . $database);
  }

  mysql_query("SET NAMES 'utf8'", $this->connection);
  mysql_query("SET CHARACTER SET utf8", $this->connection);
  mysql_query("SET CHARACTER_SET_CONNECTION=utf8", $this->connection);
  mysql_query("SET SQL_MODE = ''", $this->connection);
 }

 public function query($sql) {
  $resource = mysql_query($sql, $this->connection);

  if ($resource) {
   if (is_resource($resource)) {
    $i = 0;
     
    $data = array();

    while ($result = mysql_fetch_assoc($resource)) {
     $data[$i] = $result;
      
     $i++;
    }

    mysql_free_result($resource);

    $query = new stdClass();
    $query->row = isset($data[0]) ? $data[0] : array();
    $query->rows = $data;
    $query->num_rows = $i;

    unset($data);

    return $query;
   } else {
    return TRUE;
   }
  } else {
   exit('Error: ' . mysql_error($this->connection) . '<br />Error No: ' . mysql_errno($this->connection) . '<br />' . $sql);
  }
 }

 public function escape($value) {
  return mysql_real_escape_string($value, $this->connection);
 }

 public function countAffected() {
  return mysql_affected_rows($this->connection);
 }

 public function getLastId() {
  return mysql_insert_id($this->connection);
 }

 public function __destruct() {
  mysql_close($this->connection);
 }
}
?>
Notate il costruttore (che si occupa di creare la connessione) ma soprattutto il distruttore (__destruct) che avrà il compito di chiudere la connessione (cosa che, diciamolo, viene spesso dimenticata).
L'utilizzo di questa classe è semplice e immediato:
//creo l'oggetto con i parametri desiderati 
$db = new MySql("localhost","user","password","test_db");
//ottengo il risultato della query
$result = $db->query("SELECT * FROM users");
//se il numero di righe è maggiore di zero
if($result->num_rows) { 
//Ciclo nelle righe del risultato stampando il campo "name"
   foreach ($result->rows as $user_row) {
      echo $user_row['name'];
   }
}