« powrót

Podejście obiektowe w tworzeniu aplikacji web

Opublikowano: 2009-07-28 , wyświetlono: 13264

Wstęp

Tekst ten ma na celu przedstawićenie pewnego sposobu podejścia do tworzenia aplikacji web z wykorzystaniem języka Perl i bazy danych MySql. Może być też przykładem praktycznego wykorzystania obiektowości w Perl'u. Całość tekstu oparta będzie na tworzeniu rozwiązania konkretnego, prostego problemu.

Zadanie:

Stworzyć małą aplikację, która ma wyświetlić cennik produktów w przeglądarce internetowej. Produkt będzie posiadał charaktryzował się czterema cechami:

id - unikalny identyfikator
kod - kod produktu
nazwa - nazwa produktu
cena - cena

Dane o produktach będą przechowywane będą w bazie MySql o nazwie test_oop w tabeli produkt.

Analiza problemu wskazuje, że potrzebne będą następujące klasy:

- klasa reprezentująca produkt
- klasa dostępu do bazy danych
- klasa odpowiadająca za odczyt produktów z tabeli
- klasa realizująca wyświetlanie cennika jako strony html

Pierwszym i najprostszym zadaniem będzie implementacja klasy produkt. Jej zadaniem będzie tylko reprezentacja atrybutów produktów.


package  Produkt;

sub  new
{
    my  $self  =  {};

    $self->10  =  0;
    $self->{kod}  =  "";
    $self->{nazwa}  =  "";
    $self->{cena}  =  0.0;

    bless  ($self);
    return  $self;
}

return  1; 

Następnym krokiem będzie stworzenie klasy do łączności z bazą danych MySql. Klasa będzie miała za zadanie nawiązać łączność z bazą oraz w wypadku powodzenia zwracać uchwyt do połączenia.
W związku z tym klasa zawierać będzie tylko konstruktor, w którym przekazane zostaną parametry połaczenia, czyli nazwa hosta, nazwa użytkownika, hasło, itp. Potrzebna będzie też metoda, która dokona połączenia i zwróci uchwyt do bazy danych, by wykorzystać go w klasach dostępu do konkretnych tabel. Poniżej implementacja klasy Database.


package  Database;

#  zmienna  przechowujaca  uchwyt  do  polaczenia
my  $connection;
my  $dbName;
my  $dbUser;
my  $dbPass;
my  $dbHost;
my  $dbPort;

sub  new
{
    my  $class  =  shift;
    my  $self  =  {};

    $dbName  =  shift;
    $dbUser  =  shift;
    $dbPass  =  shift;
    $dbHost  =  shift;
    $dbPort  =  shift;

    if  (!$dbPort)
    {
        $dbPort  =  3306;
    }

    if  (!$dbHost)
    {
        $dbHost  =  "localhost";
    }

    bless  ($self,  $class);
    return  $self;
}

#  polaczenie  z  baza  danych
#----------------------------------------------------------
sub  Connect
{
    my  $self  =  shift;

    $connection  =  DBI->connect("DBI:mysql:$dbName:$dbHost:$dbPort",
        $dbUser,  $dbPass)
        ||  return  undef;

    return  $connection;
} 

Mając klasę do nawiązania połączenia z bazą danych można rozpocząć projektowanie klasy dostępu do tabeli produkt, którą nazwiemy DbProdukt. Ma ona umożliwiać dodawanie, aktualizację oraz usunięcie wiersza na podstawie obiektu produkt. Operacje te powinny być łatwe w użyciu i czytelne w kodzie aplikacji. Konieczna też będzie metoda, która pozwala na przekazanie połączenia do bazy danych do tworzonej klasy.


#  utworzenie  obiektu  polaczenia  z  baza
my  $db  =  new  Database("test_oop",  "user",  "pass",  "host",  "port");
my  $conn  =  $db->Connect();

#  utworzenie  obiektu  produkt
my  $produkt  =  new  Produkt();

#  i  ustawienie  dla  niego  atrybutow
$produkt->10  =  0;
$produkt->{kod}  =  "0001";
$produkt->{nazwa}  =  "nasz  produkt";
$produkt->{cena}  =  10.50;

#  utworzeni  obiektu  dostepu  do  tabeli  produkt
my  $dbProdukt  =  new  DbProdukt($conn);

#  dodanie  takich  samych  kilku  wierszy
$dbProdukt->Insert($produkt);  #  nadane  id  =  1
$dbProdukt->Insert($produkt);  #  nadane  id  =  2
$dbProdukt->Insert($produkt);  #  nadane  id  =  3
$dbProdukt->Insert($produkt);  #  nadane  id  =  4 

Poniewaz pole id ma atrybut AUTOINCREMENT i jest to unikalny klucz, metody aktualizacji i usuwania powinny to wykorzystywac.


#  aktualizacji  ostatnio  dodanego  wiersza
$produkt->10  =  4;
$produkt->{kod}  =  "0004";
$produkt->{nazwa}  =  "zaktualizowana  nazwa";
$produkt->{cena}  =  12.30;

$dbProdukt->Update($produkt) 

Ten sam sposób zostanie wykorzystany do usunięcia wiersza z tabeli.


#  usuniecia  wiersza  o  id  =  2
$produkt->10  =  2;
$dbProdukt->Delete($produkt) 

Jak do tej pory zastosowanie stworzonych klas jest bardzo proste i czytelne i implementacja nie powinna nastręczaj dużych trudności. Teraz pora na nieco trudniejsze zadanie. Niezbędny jest sposób czytania danych z wiersza tabeli, który utrzymany będzie w duchu dotychczasowych konstrukcji.

Można by spróbować w tradycyjny sposób, czyli:


$rs  =  $conn->execute("SELECT  *  FROM  produkt");
while  ($row  =  $rs->fetchrow_hashref)
{
    $produkt->10  =  $row->10;
    $produkt->{kod}  =  $row->{kod};
    $produkt->{nazwa}  =  $row->{nazwa};
    $produkt->{cena}  =  $row->{cena};
} 

lecz nie wygląda to zbyt elegancko. Użyteczne byłoby pozbycie się zmiennych $rs i $row,
by ukryć funkcje z pakietu DBI. Spróbujmy w ten sposób:


$dbProdukt->CreateQuery();
while  ($produkt  =  $dbProdukt->GetRow())
{
    print  $produkt->{nazwa}  .  "\n";
}

Wygląda to zdecydowanie lepiej. Przydało by się jeszcze przy tworzeniu zapytania uwzględnienie przynajmniej klauzu WHERE i ORDER BY by mieć większy wpływ na otrzymywane wyniki.


#  zapytanie  SQL:  SELECT  *  FROM  produkt  WHERE  id  >  1  ORDER  BY  nazwa
$dbProdukt->CreateQuery("id  >  1",  "nazwa");

#  gdy  GetRow()  zwróci  undef  to  znak,  że  odczytano  wszystkie  wiersze
while  ($produkt  =  $dbProdukt->GetRow())
{
    print  $produkt->{nazwa}  .  "\n";
} 

Taki dostęp do wierszy tabeli powinien już nas zadowolić.

Pozostała teraz część wizualna aplikacji, czyli zaprojektowanie klasy, która będzie odpowiadać za prezentację cennika. W tym momencie można przdstawić już zarys całej aplikacji.


use  DBI;
use  Cgi;

use  Database;
use  Produkt;
use  HtmlProdukt;

$cgi  =  new  Cgi();

my  $db  =  new  Database("test_oop",  "root",  "");
my  $conn  =  $db->Connect();

$html  =  new  HtmlProdukt($conn,  $cgi);
$html->Head();
$html->PriceList();
$html->Foot();

exit; 

Klasa HtmlProdukt będzie odpowiadać za odczyt parametrów przekazywanych w formularzach, czytanie danych z bazy i wyświetlanie wyników. W kodzie powyżej można zauważyć, że do klasy HtmlProdukt przekazane zaostało połączenie do bazy danych oraz obiekt CGI by można było operować na zmiennych przekazywanych z formularzy www.
Poniżej przedstawiona jest implementacja konstruktora.


package  HtmlProdukt;

my  $connDb;
my  $queryCgi;

sub  new
{
    my  $class  =  shift;
    my  $self  =  {};

    $connDb  =  shift;
    $queryCgi  =  shift;

    bless  ($self,  $class);
    return  $self;
} 

Główną metodą klasy jest PriceList(), która ma wyświetlić nasz cennik. Sposób wyświetlania będzie bardzo surowy, lecz wystarczający dla celow przykładu.


sub  PriceList
{
    $self  =  shift;

    my  $produkt  =  new  Produkt();
    my  $dbProdukt  =  new  DbProdukt($connDb);

    print  "\n";

    $dbProdukt->CreateQuery(undef,  "nazwa");
    while  ($produkt  =  $dbProdukt->GetRow())
    {
        print  $produkt->{kod}  .  "    ";
        print  $produkt->{nazwa}  .  "    ";
        print  $produkt->{cena}  .  "\n";
    }

    print  "\n";
} 

I to już wszystko. Zadanie zostało wykonane.
Mam nadzieję, że ten sposób podejścia do pisania aplikecji web z wykorzystaniem Perl'a i MySql'a spowoduję większą czytelność i łatwiejsze modyfikowanie pisanych aplikacji.

Całość kodu źródowego dostępna jest w sekcji Download.

Data: 24-04-2004


Komentarze: