Development

Documentation/pl_PL/book/1.0/08-Inside-the-Model-Layer

You must first sign up to be able to contribute.

Version 3 (modified by Artur.Kotyrba, 10 years ago)
Zmiana wielkości liter w tytule

Oryginalny tekst: http://www.symfony-project.com/book/trunk/08-Inside-the-Model-Layer [EN]

Wersja robocza

Rozdział 8 - Wewnątrz Warstwy Modelu

Do tej pory, rozdziały omawiały takie aspekty jak tworzenie stron, obsługę żądań i odpowiedzi. Jednak większość logiki biznesowej aplikacji internetowej opiera się na modelu danych. W symfony model danych domyślnie korzysta z warstwy mapowania obiektowo-relacyjnego(ORM) zapewnianą przez projekt Propel (http://propel.phpdb.org). Tak więc, w aplikacjach pisanych przy użyciu Symfony dostęp do danych zapisanych w bazie danych i ich modyfikacja odbywa się poprzez obiekty - prawie nigdy nie operujesz bezpośrednio na bazie danych, co pozwala na zachowanie wysokiego poziomu abstrakcji i przenośności.

W tym rozdziale zostanie wytłumaczone w jaki sposób można stworzyć model danych oraz zostaną pokazane sposoby operowania na danych przy użyciu Propel'a. Zostanie również zademonstrowana integracja Propel'a z symfony.

Dlaczego używać ORM i warstwy abstrakcji bazodanowej?

Bazy danych są relacyjne, a PHP 5 i Symfony są zorientowane obiektowo. Aby efektywnie korzystać z baz danych w środowisku obiektowym potrzebne jest odwzorowanie logiki relacyjnej na obiekty. Jak wyjaśniono w Rozdziale 1. to odwzorowanie nazywamy mapowaniem obiektowo-relacyjnym(ORM). Pozwala ono na korzystanie z obiektów, które umożliwiają operowanie na danych i przechowywanie w nich reguł biznesowych związanych z danymi.

Główną zaletą warstwy ORM jest wysoka zdatność obiektów do wielokrotnego użycia, pozwalająca na wywoływanie metod obiektu danych z różnych części aplikacji, a nawet z obrębu innej. Warstwa ORM dokonuje enkapsulacji logiki związanej z danymi – przykładem może być wyliczenie oceny użytkownika forum w oparciu o ilość postów i ich popularność. W momencie, gdy potrzebujemy wyświetlić ocenę użytkownika, wywołujemy po prostu metodę obiektu danych i nie musimy się martwić o szczegóły wyliczenia tejże oceny. Jeśli w przyszłości sposób wyliczania ocen zmieni się, wystarczy wtedy jedynie zmienić metodę odpowiedzialną za wyliczanie oceny w obiekcie danych, pozostawiając resztę aplikacji nietkniętą.

Używanie obiektów zamiast rekordów a klas zamiast tabel ma jeszcze inną zaletę. Pozwala na dodanie nowych akcesorów do klas modelu danych, które niekoniecznie są bezpośrednio odwzorowywane w bazie danych. Dla przykładu, jeśli mamy tabelę nazwaną Client(klient) z dwoma polami first_name(imię) i last_name(nazwisko), możemy zechcieć pobrać jednocześnie imię i nazwisko ( Name ). W podejściu zorientowanym obiektowo jest to bardzo proste. Wystarczy dodać nową metodę do klasy Client - tak jak na Listingu 8-1. Z punktu widzenia aplikacji nie ma różnicy między atrybutami FirstName, LastName i Name klasy Client, a jedynie sama klasa modelu danych może stwierdzić czy dany jej atrybut odpowiada polu w tabeli, czy też nie.

Listing 8-1 - Akcesor klasy modelu maskujący strukturę tabeli w bazie danych

[php]
public function getName()
{
    return $this->getFirstName().' '.$this->getLastName();
}

Wszystkie powtarzające się funkcję dostępu do danych i logiki związanej z danymi mogą być także trzymane w klasach modelu danych. Przypuśćmy, że mamy klasę ShoppingCart ( KoszykZakupów ), która przechowuje informacje o wybranych produktach (jako obiekty klasy Item). Do policzenia całkowitej ceny za koszyk zakupów, napiszemy metodę dokonującą enkapsulacji obliczeń, taką jak na Listingu 8-2.

Listing 8-2 - Akcesor klasy modelu maskujący logikę związaną z danymi

[php]
public function getTotal()
{
  $total = 0;
  foreach ($this->getItems() as $item)
  {
    $total += $item->getPrice() * $item->getQuantity();
  }

  return $total;
}

Jednym z punktów wartych zastanowienia podczas budowy procedur dostępu do danych, jest fakt, że bazy danych używają różnych wariantów(dialektów) języka SQL. Normalnie, zmiana systemu zarządzania bazą danych (SZBD) wymaga przepisania części zapytań, które zostały zaprojektowane pod poprzedni system. Jeśli natomiast do budowania zapytań użyjemy składni niezależnej od konkretnej implementacji bazy danych i wykorzystuamy zewnętrzną bibliotekę tworzącą z nich odpowiednie zapytania SQL'owe, możemy zmienić system bazodanowy bez najmniejszego problemu. Jest to główne zadanie warstwy abstrakcji bazodanowej - zmusza cię ona do użycia określonej składni, natomiast sama dostosowuje ją do konkretnej implementacji bazy danych i optymalizuje zapytania.

Kolejną z zalet warstwy abstrakcji bazodanowej jest przenośność pisanego kodu, umożliwiająca zmianę dostawcy bazy danych nawet po rozpoczęciu projektu. Załóżmy, że musisz napisać szybko prototyp aplikacji, jednakże klient nie zdecydował się, który system bazodanowy, będzie najbardziej odpowiadał jego potrzebom. Możesz zacząć budować aplikację używając SQLite, a kiedy klient się ostatecznie zdecyduje - zmienić ją na MySQL, PostgreSQL albo Oracle. Wystarczy modyfikacja jednej linii w pliku konfiguracyjnym i aplikacja będzie działać na innym systemie bazodanowym.

Symfony używa Propela jako biblioteki ORM, a Propel używa wewnętrznie Creole jako warstwy abstrakcji bazodanowej. Obie te biblioteki, rozwijanę przez Propel team, zostały w wysokim stopniu zintegrowane z symfony i możesz je postrzegać jako część frameworka. Ich składnia i konwencje, opisane w tym rozdziale, zostały zaadaptowane do symfony, tak więc różnią się w bardzo niewielkim stopniu od tych używanych w symfony.

NOTE W ramach jednego projektu symfony, wszystkie aplikacje dzielą jeden model danych. Model jest częścią wspólną dla całego projektu, a podział na aplikacje powinien zależeć przede wszystkim od reguł biznesowych. Jest to powodem, dla którego model jest niezależny od aplikacji i jest przechowywany w podkatalogu lib/model katalogu głównego projektu.

Symfony's Database Schema

Przykład schematu bazy danych

Podstawowa składnia schematów bazy danych

Klasy Modelu

Klasy bazowe i rozszerzające

Klasy Object i Peer

Dostęp do danych

Pobieranie wartości z kolumny

Pobieranie powiązanych rekordów

Zapisywanie i usuwanie danych

Pobieranie rekordów po kluczu głównym

Pobieranie obiektów z pomocą klasy Criteria

Używanie bezpośrednio kodu SQL

Użycie specjalnych kolumn daty

Połączenie z bazą danych

Rozszerzanie modelu

Przesłanianie istniejących metod

Użycie Model Behaviors

Rozszerzona składnia schematów

Atrybuty

Szczegóły kolumn

Klucze obce

Indeksy

Puste kolumny

Tabele I18n

Poza schema.yml: schema.xml

Nie twórz modelu dwukrotnie

Budowanie struktury bazy danych oparte o istniejący schemat

Generowanie modelu danych YAML z istniejącej bazy danych

Podsumowanie