Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: Athlan, dodany: 09.03.2009 16:21, tagi: php, mvc

Powstało masę artykułów na temat MVC, temat staje się naprawdę oklepany. Postanowiłem zebrać wszystkie informacje w jedno miejsce i streścić je w jednym artykule uzupełniając go o informacje, które nabyłem z własnego doświadczenia oraz zwracając uwagę na najistotniejsze informacje.

Czym jest model

Model to jedna z warstw wzorca projektowego MVC, który odpowiada logikę biznesową, czyli pozyskiwanie oraz modelowanie danych pozyskanych ze źródła danych. Na samym wstępie brzmi to bardzo abstrakcyjnie. W myśl architektury MVC, dostęp do modelu powinien mieć tylko kontroler, a w żadnym wypadku widok. Dodatkowo model musi pobrać i modelować dane w taki sposób, aby można było go ewentualnie wymienić bez jakiejkolwiek ingerencji w kontroler, a co za tym idzie – widok. Niezależnie od tego, z jakiego źródła informacji korzysta (pliki tekstowe, bazy danych, pliki XML)  kontroler powinien otrzymać maksymalnie zbliżone dane podczas wymiany źródła informacji.

mvc-model

Model != baza danych

Często spotykam się z definicją modelu jako źródłem połączenia i wykonywania zapytań do serwera bazy danych. Otóż nie jest to prawdą. Według ideologii MVC model powinien być jedynie pośrednikiem między warstwą aplikacji przeznaczoną do połączenia do bazy danych, wykonywania zapytań itp., a kontrolerem. Dodatkowo powinien pomóc kontrolerowi w zbudowaniu zapytania do źródła informacji (pobranie danych na podstawie kryteriów), zmodelować je i zwrócić. Dlaczego model nie jest połączeniem do bazy danych? Jeżeli model potraktujemy jako pośrednika między kontrolerem a źródłem danych, ma on prawo wybrać dowolny sposób uzyskania żądanych informacji. Wcale nie oznacza to, że model musi używać baz danych, ale może użyć plików XML lub API udostępniane przez konkretny serwis (np. YouTube)

Wymienialność modeli i modelowanie danych

Modelowanie informacji jest to dostosowanie ich do użytku przez kontroler. Zazwyczaj jest to przekazywanie informacji w postaci tablic, wartości logicznych, liczb i ciągów znaków. Przykładem może być pobieranie informacji z bazy danych. Kontroler de facto nie wie skąd są pobierane dane, wie to tylko model, otrzymuje suche informacje. Jak rozumieć modelowanie danych przy projektowaniu aplikacji? Wyobraźmy sobie sytuację, że zmieniamy źródło informacji z bazy danych na pliki XML. W tym przypadku kontroler powinien otrzymać rekordy danych jako tablica o tych samych kluczach i tych samych typach danych, jak miało to miejsce przy używaniu bazy danych. Wymiana modelu odbywa się bez ingerowania w kontroler.

Przykłady modeli

Najpopularniejszym sposobem pozyskania informacji jest połączenie do bazy danych i pobieranie (reprezentowanie) ich na różnoraki sposób. Doskonale wyjaśnia to tekst znajdujący się w wikipedii:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Zyx, dodany: 07.03.2009 15:25, tagi: php

Niedawno postanowiłem przenieść na Doctrine jeden z projektów wykonanych w Zend Frameworku. Stanąłem wtedy przed problemem integracji tych dwóch narzędzi. Nie jest to specjalnie skomplikowane zadanie, ale może od nas wymagać napisania odrobiny dodatkowego kodu, zależnie od tego, czego w ZF używamy. W moim przypadku chodziło oczywiście o ORM oraz sesje. W tym wpisie pragnę krótko przedstawić, jak to wszystko zgrać ze sobą.

Autor wpisu: SongoQ, dodany: 07.03.2009 10:14, tagi: php, symfony

Szybkie serwisy, zoptymalizowane pod względem zużycia pamięci i ilości odwołań do bazy – czasami mogą być kluczowym elementem w powodzeniu naszego projektu. Chciałbym przedstawić jedną z takich możliwości, czyli użycie w Symfony widoków baz danych. Przykład można zastosować w bazach: PostgreSQL, MySQL, Oracle, itd. Najważniejszym elementem jest to, czy baza danych obsługuje widoki.

Dla przykładu użyję tabeli użytkownik i grupa.

schema.yml

propel:

  groups:
    id:              { type: integer, required: true, primaryKey: true, autoincrement: true }
    owner_id:        { type: integer, foreignTable: users, foreignReference: id, index: true }
    last_user_id:    { type: integer, foreignTable: users, foreignReference: id, index: true }
    name:            { type: varchar, size: 80, index: true }
    routing_name:    { type: varchar, size: 80, index: true, uniq: true }
    description:     { type: varchar, size: 400 }
    created_at:      { type: timestamp }
    user_count:      { type: integer, index: true }
    position_rank:   { type: integer }

  users:
    id:              { type: integer, required: true, primaryKey: true, autoincrement: true }
    login:           { type: varchar, size: 15, index: true, uniq: true }
    password:        { type: varchar, size: 255 }
    name:            { type: varchar, size: 255 }
    created_at:      { type: timestamp }
    updated_at:      { type: timestamp }
    last_login_at:   { type: timestamp }
    last_request_at: { type: timestamp }
    group_id:        { type: integer, foreignTable: groups, foreignReference: id, index: true }

Załóżmy, że mamy template w którym pokazujemy 20 grup według ilości użytkowników, w której wyświetlamy: nazwę grupy wraz z linkiem do profilu grupy, właściciela grupy, ostatniego dodanego użytkownika do tej grupy i ilość użytkowników w grupie. Stosując klasyczne wykorzystanie modelów Propela, dostaniemy modele grup z zależnymi 2 modelami użytkowników – właściciel i ostatnio dodany użytkownik. Od razu widać że większość danych jest zbędna, a co z tym idzie wykorzystanie pamięci będzie większe i czas zwracania danych z bazy będzie dłuższy.

Definiowanie widoku (views) w schema

Aby rozdzielić pliki w którym są definicje tabel i widoki, warto utworzyć osobny plik w którym zapiszemy naszą definicje widoku.

config/views_schema.yml

propel:
  groups_view:
    _attributes:              { skipSQL: true, readOnly: true }
    id:                       { type: integer }
    name:                     { type: varchar }
    routing_name:             { type: varchar }
    user_count:               { type: integer }
    owner_name:               { type: varchar }
    last_user:                { type: varchar }

Kolejnym krokiem jest przygotowanie SQL z definicją naszego vidoku. Dobrym rozwiązaniem jest by każdy widok umieszczać w osobnym pliku i dodawać do sqldb.map, w celu zbudowania widoku z automatu (nie musimy już ręcznie wywoływać SQL).

Tworzymy plik sql

data/sql/views/groups_view.sql

CREATE OR REPLACE VIEW groups_view AS
  SELECT groups.id,
         groups.name ,
         groups.routing_name,
         groups.user_count,
         owner.login AS owner_name,
         last.login AS last_user
    FROM groups
    JOIN users owner ON owner.id = groups.owner_id
    JOIN users last ON last.id = groups.ast_user_id;

Dodajemy widok do sqldb.map

Edytujemy plik sqldb.map i dodajemy nową pozycję

data/sql/sdldb.map

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Athlan, dodany: 06.03.2009 14:58, tagi: php.pl

Dziś otwarty został sklep.php.pl, którego mały engine miałem okazję pisać. Póki co można w nim nabyć kubek-termos programatora o szczelnym, plastikowym zamknięciu zapobiegającym rozlewaniu się zawartości:

  • Pojemność 400 ml.
  • Nadaje się do spożywania napojów zimnych i gorących.
  • Utrzymuje temperaturę wiele godzin.
  • Dostosowany dla osób prawo i lewo ręcznych.

Cena z przesyłką wynosi 40zł. Mam nadzieję, że z biegiem czasu asortyment znacznie się powiększy. Warto wspomnieć, że z każdym złożonym zamówieniem zasilasz pulę pieniężną przeznaczoną na nagrody w konkursach o 5 zł.

Autor wpisu: Zyx, dodany: 04.03.2009 11:19, tagi: php

Kiedy podczas prac natkniemy się na problem zbyt skomplikowany, by wymyślać własne rozwiązanie, musimy skorzystać z gotowych projektów. Niestety, najtrudniejsza część to znalezienie czegoś odpowiedniego. Google nie zawsze bywa pomocny, gdyż często trzeba mniej więcej wiedzieć, czego się szuka, a wiele wartościowych projektów może zostać przytłoczonych przez odnośniki reklamowe oraz wypozycjonowane, które z tym, czego szukamy, nie mają nic wspólnego. Dlatego postanowiłem w tym wpisie zebrać zbiór różnych przydatnych aplikacji i bibliotek napisanych w PHP oraz dla PHP.

Autor wpisu: Diabl0, dodany: 03.03.2009 11:52, tagi: zend_framework, php

Po ostatniej aktualizacji ZF do 1.7.6 w jednym z projektów pojawił się nowy “nieplanowany” wyjątek:

Warning: Exception caught by form: Requested scripts may not include parent directory traversal (”../”, “..\” notation)

Cały wyjątek wygląda następująco:

Warning: Exception caught by form: Requested scripts may not include parent directory traversal ("../", "..\" notation) Stack Trace:
#0 C:\HTDOCS\projekt\library\Zend\View\Abstract.php(816): Zend_View_Abstract->_script('../forms/AddApp...')
#1 C:\HTDOCS\projekt\library\Zend\View\Helper\Partial.php(103): Zend_View_Abstract->render('../forms/AddApp...')
#2 [internal function]: Zend_View_Helper_Partial->partial('../forms/AddApp...', Array)
#3 C:\HTDOCS\projekt\library\Zend\View\Abstract.php(329): call_user_func_array(Array, Array)
#4 [internal function]: Zend_View_Abstract->__call('partial', Array)
#5 C:\HTDOCS\projekt\library\Zend\Form\Decorator\ViewScript.php(130): Zend_View->partial('../forms/AddApp...', Array)
#6 C:\HTDOCS\projekt\library\Zend\Form.php(2595): Zend_Form_Decorator_ViewScript->render('')
#7 C:\HTDOCS\projekt\library\Zend\Form.php(2610): Zend_Form->render()
#8 C:\HTDOCS\projekt\application\cytologia\views\scripts\doctor\addapplication.phtml(6): Zend_Form->__toString()
#9 C:\HTDOCS\projekt\library in C:\HTDOCS\projekt\library\Zend\Form.php on line 2615

Po dokładniejszych oględzinach okazało się że problem tkwi w używaniu względnych ścieżek i “wychodzenia” ponad katalog (więcej: ZF-5748) w widokach. Z jednej strony miło że ktoś dba o nasze bezpieczeństwo, ale z drugiej strony po raz kolejny sprawia to problemy przy migracji istniejących projektów (IMHO zmiany wpływające na kompatabilność w obrębie jednej gałęzi są niedopuszczalne).

Na szczęście zostało to szybko zauważone i dodano możliwość wyłączenia tego sprawdzania.

r14063: ZF-5748: Added ability to override LFI protection as needed Documented fix in new “Zend_View Migration” chapter

Przykładowy kod dla Zend_Layout inicjalizowanego w bootstrapie:

$view = Zend_Layout::getMvcInstance ()->getView ();
$view->setLfiProtection ( false );    // override LFI protection

Inne przykłady za manualem:

// Disabling via constructor
$view = new Zend_View(array('lfiProtectionOn' => false));

// Disabling via exlicit method call:
$view = new Zend_View();
$view->setLfiProtection(false);

Related posts

Autor wpisu: SongoQ, dodany: 02.03.2009 10:13, tagi: sql, symfony, php

Lazy load (wzorzec projektowy) – w przypadku Propela oznaczenie atrybutu modelu lazyLoad powoduje, że zostanie on zwrócony w momencie jego jawnego wywołania. Wykorzystuje się to w przypadku jeśli nie potrzebujemy danego atrybutu (z powodu jego rozmiaru) lub chcemy wykorzystać w późniejszym etapie (w widoku). Najczęściej stosuje się to do typów text (longvarchar), blob, clob.

Definicja w schema.yml

schema.yml

documents:
  id:         { type: integer, required: true, primaryKey: true, autoincrement: true }
  created_at: { type: timestamp }
  name:       { type: varchar, size: 100 }
  content:    { type: longvarchar, lazyLoad: true }

Pobieramy obiekt documents, atrybut content ma ustawionym lazyLoad, zostaje on pominięty w zapytaniu SQL. Jeśli wywołamy metodę ->getContent(), zostanie wykonane dodatkowe zapytanie i pole zostanie zwrócone. Lazy load można wykorzystać w celu zoptymalizowania obiektów Propela, jednak trzeba pamiętać że w momencie żądania zwrócenia atrybutu zostanie wykonane dodatkowe zapytanie do bazy danych.

Related Posts

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.