Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Ukrywanie metod modelu przed widokiem
Forum PHP.pl > Forum > PHP > Object-oriented programming
coolos
Witam,

mam pytanie w jaki sposób ukryć metody modelu przed widokiem? Chciałbym aby z poziomu akcji możliwe było wywołanie:

  1. $news->add_news($id);


lecz żeby niemozliwe było to w widoku. Chciałbym aby widok, pobierał dane tylko z getterów.

Pozdrawiam
Crozin
Prawdopodobnie powinieneś mieć dwa różne obiekty, każdy odpowiedzialny za jedno zadanie.
coolos
Cytat(Crozin @ 13.06.2012, 16:17:43 ) *
Prawdopodobnie powinieneś mieć dwa różne obiekty, każdy odpowiedzialny za jedno zadanie.


Tylko zdaje się że jeżeli 1 obiekt bedzie workiem danych (z setterami i getterami) a 2 samymi metodami (które modyfikują obiekt 1) to czy czasem nie będzie to antywozrzec projektowy "anemiczny model dziedziny"?
Orzeszekk
uzyj smarty jako widoku

albo jesli koniecznie chcesz miec wlasny framework php, to wysyłaj paczkę danych z kontrolera (tzw viewModel), do widoku, zamiast wysylac twoj domain model.

niech kontroler uruchomi domain model (logike biznesowa), pobierze z niego potrzebne dane, ulepi z niego viewmodel w postaci klasy lub tablicy asocjacyjnej i tą paczke wysle do widoku w celu jej wyswietlenia. W ten sposob bedziesz mial zapewnione ze widok będzie "głupi" tj nie bedzie zawieral logiki.

robienie viewModelu to dobry wzorzec, dzieki temu mozesz podmienic klasy logiki bez modyfikowania widoków. Nie wiem jak pehapowcy, w asp.net mvc to praktyka zalecana.
Crozin
@coolos: Prawdę powiedziawszy ciężko tutaj powiedzieć czy to będzie poprawne czy nie bo nie znamy Twojego przypadku, ale generalnie używanie DTO nie jest czymś złym. Jedyne co można z całą pewnością powiedzieć to to, że obiekt posiadający methody addNews() i, jak się domyślam, coś w stylu getRecentNews(), getNewsByAuthor() nie powinien w ogóle istnieć (powinny to być osobne obiekty).
Orzeszekk
to ze ograniczy mozliwosci umieszczania logiki w widoku

Cytat(Crozin @ 13.06.2012, 17:01:42 ) *
@coolos: Prawdę powiedziawszy ciężko tutaj powiedzieć czy to będzie poprawne czy nie bo nie znamy Twojego przypadku, ale generalnie używanie DTO nie jest czymś złym. Jedyne co można z całą pewnością powiedzieć to to, że obiekt posiadający methody addNews() i, jak się domyślam, coś w stylu getRecentNews(), getNewsByAuthor() nie powinien w ogóle istnieć (powinny to być osobne obiekty).


te 3 metody moga byc w obiekcie reprezentujacym tabele, natomiast to co leci do widoku powinno byc raczej obiektem reprezentujacym wiersz.
coolos
Cytat(Orzeszekk @ 13.06.2012, 16:57:41 ) *
uzyj smarty jako widoku


Szablon a Widok to różnica wink.gif.

  1. albo jesli koniecznie chcesz miec wlasny framework php, to wysyłaj paczkę danych z kontrolera (tzw viewModel), do widoku, zamiast wysylac twoj domain model.
  2.  
  3. niech kontroler uruchomi domain model (logike biznesowa), pobierze z niego potrzebne dane, ulepi z niego viewmodel w postaci klasy lub tablicy asocjacyjnej i tą paczke wysle do widoku w celu jej wyswietlenia. W ten sposob bedziesz mial zapewnione ze widok będzie "głupi" tj nie bedzie zawieral logiki.
  4.  
  5. robienie viewModelu to dobry wzorzec, dzieki temu mozesz podmienic klasy logiki bez modyfikowania widoków. Nie wiem jak pehapowcy, w asp.net mvc to praktyka zalecana.


Z pewnością efekt finalny zostałby osiągnięty przy takim podejściu. Z tym że tworzenie "viewModel" jak to nazwałeś to nic inego jak wspomniany post wyżej przezemnie antywzorzec projektowy "anemiczny model dziedziny". Przesyłanie tablic asocyjacyjnych również nie uważam za rozwiązanie, to że tworzy się jakieś obiekty i pobiera z nich dane w postaci tablic nie czyni aplikacji obiektowej (są to jedynie procedury poupychane w klasach).

Szukam jakiegoś innego sposobu na ukrycie metod z logiką biznesową przed widokiem.


Cytat(Crozin @ 13.06.2012, 17:01:42 ) *
@coolos: Prawdę powiedziawszy ciężko tutaj powiedzieć czy to będzie poprawne czy nie bo nie znamy Twojego przypadku, ale generalnie używanie DTO nie jest czymś złym. Jedyne co można z całą pewnością powiedzieć to to, że obiekt posiadający methody addNews() i, jak się domyślam, coś w stylu getRecentNews(), getNewsByAuthor() nie powinien w ogóle istnieć (powinny to być osobne obiekty).


Przynam szczerze że korzystałem jak do tej pory z DTO i było ok.

Miałem np. klase news_model oraz news_model_manager, manger manipulował danymi dodając i pobierając newsy jako obiekty news_model.

Z tym że ostatnio naczytałem się że ogólnie takie podejście nie jest ok, jeżeli chodzi o programowanie obiektowe i szukam innego sposobu.


Szukam jakiegoś pomysłu na realizacje modelu2 z tego artykułu.
Crozin
Cytat
[...] Z tym że ostatnio naczytałem się że ogólnie takie podejście nie jest ok, jeżeli chodzi o programowanie obiektowe i szukam innego sposobu.
Jakieś źródło tych "rewelacji"? Czy może dokładniej - co jest z tym nie tak.
coolos
Cytat(Crozin @ 13.06.2012, 17:41:02 ) *
Jakieś źródło tych "rewelacji"? Czy może dokładniej - co jest z tym nie tak.


Podam kilka źródeł wraz z cytowaniem:

artykuł 1

Cytat
Normalnie klasy mapujące tabele w bazie i wykonujące logikę to powinny być te same klasy, niestety w J2EE wymyślono jakieś DAO i anemiczne encje, które służą tylko jako worki na kartofle, ups... dane, a nie posiadają żadnych odpowiedzialności i logiki, stąd też często programiści J2EE mają problemy ze zrozumieniem literki M skrótu MVC.



artykuł 2

Cytat
Jednym z najczęstszych powodów powstawania anemicznych modeli domenowych jest sposób projektowania aplikacji w oparciu o wcześniej stworzony schemat bazy danych. To prowadzi to do tego, że model domenowy powstaje w skutek mapowania tabel do klas posiadających odzwierciedlone kolumny w postaci właściwości. Jedynym wyzwaniem dla niektórych osób może być modelowanie relacji, które w przypadku bazy danych są kluczami obcymi, zaś w przypadku obiektowego modelu powinny być relacjami do innych obiektów. Nie brakuje oczywiście przykładów, gdzie relacje w modelu domenowym tworzone są również w oparciu o klucze obce, co całkowicie zaprzecza obiektowemu programowaniu


artykuł 3

Cytat
The basic symptom of an Anemic Domain Model is that at first blush it looks like the real thing. There are objects, many named after the nouns in the domain space, and these objects are connected with the rich relationships and structure that true domain models have. The catch comes when you look at the behavior, and you realize that there is hardly any behavior on these objects, making them little more than bags of getters and setters. Indeed often these models come with design rules that say that you are not to put any domain logic in the the domain objects. Instead there are a set of service objects which capture all the domain logic. These services live on top of the domain model and use the domain model for data.
Crozin
Wątek zejdzie nam tutaj nieco na inny temat (reprezentacji bazy danych w aplikacji), ale mniejsza z tym... od razu zaznaczę, że wypowiadam się jedynie w kontekście tych trzech cytatów, nie całych artykułów.

Mocno bym się spierał z tym co zostało tu przedstawione. Zarzucają, że obiekty domeny nie posiadają logiki co nie jest do końca prawdą. Wydaje mi się, że autorzy za bardzo wzięli sobie do serca podstawową definicję obiektówki*. Obiekty takie zawierają po prostu najbardziej elementarną logikę, która nie wymaga żadnych dodatkowych zależności czy skomplikowanego kodu. Czyli dla przykładowego obiektu News będą to metody pozwalające przyporządkować mu daną kategorię albo sprawdzić czy nie został on skasowany (gdzie skasowanie traktuje się np. jako niepustą wartość pola deletedAt). Innymi słowy proste metody, gdzie większość z nich mieści się w 5 - 15 linijkach kodu (nie mówię tutaj o klasycznych getterach/setterach).
Na samą myśl co by się stało z tym obiektem, gdyby wrzucić do niego realną, "ciężką" logikę słabo mi się robi. Ten nieszczęsny obiekt stałby się nagle odpowiedzialny na kilka, może nawet kilkanaście rzeczy na raz. Praca z takimi potworkami do przyjemnych nie należy, a gdy nagle trzeba dla jakiegoś fragmentu aplikacji zastosować inną logikę mamy niezły problem - bo właściwie jedyne co da się zrobić to dziedziczyć, czyli robić z potworka prawdziwe monstrum.

Dalej twierdzą, że takie obiekty niby są idealnym odzwierciedleniem bazy danych, co jest oczywiście bzdurą. Interfejs takich obiektów powinien być projektowany pod dobry model domeny, nie bazę danych (czy jakiekolwiek inne źródło danych). Przy późniejszym zapisie danych do źródła danych model obiektowy powinien zostać przetworzony na model relacyjny dla bazy danych - ale to już zadanie jakiegoś porządnego ORM-a, a nie samego obiektu domeny.

* Podstawowa definicja programowania obiektowego to połączenie struktury danych i funkcji operujących na niej w jeden logiczny obiekt, co stoi w sprzeczności z programowaniem proceduralnym, gdzie struktura danych i funkcje operujące na niej są kompletnie niezależne.
Orzeszekk
Cytat(coolos @ 13.06.2012, 17:23:21 ) *
Szablon a Widok to różnica wink.gif.


Panie złotousty,

Cytat
Z pewnością efekt finalny zostałby osiągnięty przy takim podejściu. Z tym że tworzenie "viewModel" jak to nazwałeś to nic inego jak wspomniany post wyżej przezemnie antywzorzec projektowy "anemiczny model dziedziny". Przesyłanie tablic asocyjacyjnych również nie uważam za rozwiązanie, to że tworzy się jakieś obiekty i pobiera z nich dane w postaci tablic nie czyni aplikacji obiektowej (są to jedynie procedury poupychane w klasach).

Szukam jakiegoś innego sposobu na ukrycie metod z logiką biznesową przed widokiem.


Więcej czasu poswiecasz na zastanawianie sie co jest "poprawna obiektowoscia" a co niepoprawna niz na faktyczne działania.
Skoro tak zalezy ci na poprawnosci skalowalnosci i rozszerzalnosci kodu dlaczego tworzysz wlasny framework zamiast wykorzystac jakis standard?

Szablon/Widok - a co za roznica? Oczywiscie widok moze byc klasą, moze w ogole nie zawierac kodu html, tylko wygenerowac wszystko z poziomu PHP, ale zycze ci zebys nie musial pracowac z projektami ktore dzialaja w ten sposob.. Miałem okazje przerabiajac pluginy do joomli.. boże broń przed tym.
takze jedyne podejscie poprawne przy MVC webowym to widok=template.

Zreszta ogolnie kazdy jak może ucieka od kodu w widokach, wiekszosc webowych technologii ma swoje silniki szablonów, czy to java, czy to php, czy to asp.net, w aplikacjach desktopowych czy na smartfony rowniez ludzie poszli po rozum do glowy i odeszli od tworzenia interfejsow w kodzie na rzecz xml-owych języków, przykład: android(XML), wp7 (XAML), wpf (XAML - wektorowy interfejs zastępujący winapi przy rysowaniu kontrolek)/silverlight, itd itp.


DTO czy ViewModel to swietna rzecz... jeśli ci pomogą to użyj ich.. ja ich uzywam i mi dobrze z nimi, chociaż w C# deklaracje klas są zwięzłe, bo mamy normalne propetries a nie te cuda z getPole, setPole. Więc mamy mniej pisaniny, klasa DTO wyglada zwiezle, taki twardo typowany widok jest znacznie czytelniejszy niz dynamiczny.
Bez DTO jest problem gdy chcesz w widoku wyswietlic cos co jest np obliczane na podstawie dwoch pól modelu. Bo nie ma tego wtedy gdzie wysłać. Tak samo, nie zawsze domain model odzwierciedla to co chcesz przesłać w formularzu bo czasem są potrzebne dodatkowe pola, i co wtedy? dodasz na siłę do bazy danych pole które zawsze będzie null? bez sensu.

Padł argument ze DTO/ViewModel to nic tylko worek getterów i setterów. I tak jest w istocie, dopóki viewModele zostały napisane pod konkretny model. Gdy okazuje sie ze trzeba zmienic model na inny, czasami na taki którego nie mozemy zmodyfikowac bo np stworzyl go inny dzial firmy i dostarczyl go w takiej a nie innej postaci, takie proxy pomiedzy danymi a widokiem sie bardzo przydaje. Autor po prostu byc moze zajmuje sie zbyt prostymi rzeczami i dlatego nie widzi dla nich zastosowania, i kloci sie o 20 zazwyczaj automatycznie wygenerowanych linijek kodu.

Duzo ludzi zastanawia sie nawet czy gettery/settery są potrzebne, tak im żal tyłek sciska ze muszą naklepac troche "niepotrzebnych" linijek. Albo machnąć jakąś factory.

mam w starszych projektach niektore modele po 2,5 tys linijek kodu, ktorych nijak nie idzie podzielic bo trzeba by bylo przeryć pol projektu. a naprawde wolalbym zeby tam byly dto

Tak ogólnie wg mnie wszelkie wywody nad poprawną obiektowością PHP wydają mi się głupie. Przygadał kocioł garnkowi. Jeśli chcesz osiągać orgazmy przy refaktoryzacji to wybitnie wybrałeś nie tą technologie.
Burdel w kodzie, bałagan i syf jest wg mnie wpisany w historie i specyfikę php. Pisz, w miare czytelnie, niech ci dziala i nie trac czasu na takie zastanawianie się smile.gif

ps. jakiego ORM uzywasz?
coolos
Cytat(Orzeszekk @ 13.06.2012, 19:13:25 ) *
ps. jakiego ORM uzywasz?


Autorskiego, napisanego na potrzeby własne.

Nie twierdzę że to w jaki sposób piszesz aplikacje jest złe, każdy ma swój sposób na tworzenie systemu. Jedni piszą kod spaghetti, inni walą spaghetti w klasy a jeszcze inni pisza aplikację obiektowo. Najgorsze co może być to usiąść i stwierdzic że to w jaki sposób piszę aplikacje jest najlepszym sposbem i po co mi inne skoro to działa. Wydaje mi się że jeżeli chodzi o programowanie trzeba cały czas myśleć by dążyć do samodoskonalenia.

Bynajmniej nie uważam się za dobrego programiste, dopiero się ucze i szukam ciekawych rozwiązań.


@Crozin

Dzięki za opinię. Mam też pytanie, jak byś widział model w odnisieniu do tego artykułu i cytatu dotyczącego zmodyfikowanego MVC.

Cytat
Różnica w tym podejściu jest taka, że Model nie komunikuje się w żaden sposób z Widokiem, natomiast Widok w trybie read-only pobiera dane z Modelu.


Mi tutaj do głowy przychodzi tylko DTO.
Crozin
Przeczytałem ten artykuł (pomijając dwie ostatnie sekcje) i generalnie poprawnie opisuje on MVC i jego modyfikację, która właściwie zdominowała PHP. O fragment z DAO czy umiejscowieniem JSF jako przykładu implementacji MVC Model 2 już się nie czepiam. Swoją drogą pierwszy raz spotykam się z taką nazwą, "MVC z pasywnym widokiem" jest chyba bardziej popularne przynajmniej w środowisku JEE/PHP.

W zmodyfikowanej wersji, gdzie wygenerowane dane są przekazywane z kontrolera do widoku nie ma innej opcji jak DTO. Przekazane dane są już w pełni przetworzone i oczekują wyłącznie na zostanie wyświetlonymi. Jedyne operacje jakie powinny na być na nich wykonane to te związane z logiką widoku.
Orzeszekk
Cytat(coolos @ 13.06.2012, 19:59:24 ) *
Autorskiego, napisanego na potrzeby własne.

Nie twierdzę że to w jaki sposób piszesz aplikacje jest złe, każdy ma swój sposób na tworzenie systemu. Jedni piszą kod spaghetti, inni walą spaghetti w klasy a jeszcze inni pisza aplikację obiektowo.


Cytat(wikipedia)
Odkrywanie kwadratowego koła (ang. Reinventing the square wheel) Rozwiązywanie problemu w zły sposób, podczas gdy istnieją skuteczne i sprawdzone rozwiązania. Na przykład tworzenie własnego systemu bazodanowego, zamiast wykorzystania istniejących darmowych rozwiązań, z dużym prawdopodobieństwem lepszych niż sami jesteśmy w stanie stworzyć.


i nie, nie wale spagetti w klasy tongue.gif

mvc z pasywnym widokiem sprawia duzo mniej problemów. ASP.NET MVC 2/3/4 rowniez uzywa tego wzorca.

za to bron boze przed mvc rodem z joomli, to juz chyba lepszy kod pisany ciurkiem
coolos
Cytat
Odkrywanie kwadratowego koła (ang. Reinventing the square wheel) Rozwiązywanie problemu w zły sposób, podczas gdy istnieją skuteczne i sprawdzone rozwiązania. Na przykład tworzenie własnego systemu bazodanowego, zamiast wykorzystania istniejących darmowych rozwiązań, z dużym prawdopodobieństwem lepszych niż sami jesteśmy w stanie stworzyć.


Słusznie, lecz z drugiej strony gdyby ktoś, kiedyś nie myślał szerzej, to do tej pory ujeźdżalibyśmy konie zamiast wsiadać do wygodnego autka smile.gif
Mephistofeles
Z takim podejściem każdy producent samochodów tworzyłby od nowa własny silnik, wymyślał własny skład paliwa, projektował wygląd od zera. Do niczego byśmy nie doszli.
Stosujmy sprawdzone rozwiązania i poprawiajmy je/twórzmy nowe wtedy, kiedy to konieczne.
Tworzenie czegoś od zera się nie sprawdza - nowe systemy operacyjne są oparte na starych, silniki gier wywodzą się z kilku początkowych...
!*!
Mephistofeles - nie zaczynaj znowu.
Orzeszekk
Cytat(coolos @ 13.06.2012, 22:47:53 ) *
Słusznie, lecz z drugiej strony gdyby ktoś, kiedyś nie myślał szerzej, to do tej pory ujeźdżalibyśmy konie zamiast wsiadać do wygodnego autka smile.gif


gdyby kazdy inzynier tworzyl swoje rozwiazania od zera, to nie pisał byś tego co teraz piszesz w php, tylko wlasnie konstruowalbys wlasny mikroprocesor, by napisac na niego wlasnego assemblera by w tym assemblerze napisac kompilator C w ktorym bys napisal parser php i baze danych dla twojego uC, i w nim zrobilbys strone.

napisal bys gre 3d w assemblerze?
nie sądze...

ktos napisal w assemblerze kompilator C, ktos w C napisal translator C++ do C (duniec, nazwiska nie pamietam), ktos w tym napisal silnik graficzny/fizyczny/maszyne wirtualna w ktorej silniki powstaly a ty korzystajac z tych silnikow tworzysz gre, i to jest juz do ogarniecia.

nie da sie tworzyc wszystkiego od zera, chodzi o to by ogarnac to co juz jest, i przerobic to /rozszerzyc/ napisac wlasne ale inspirujac sie tym i nie powielajac bledow poprzedników, stąd pochodzi postęp.

gwarantuje ci ze zrobienie czegos w dobrym frameworku usunie twoje watpliwosci, gdzie kontroler, gdzie widok, jak przeslac dane z widoku do modelu bo to sa smieszne, nieistotne problemy.. konwencja frameworka to narzuci. A jak juz sobie w nim posiedzisz i bedziesz uwazal go za slaby, to wtedy napiszesz wlasny niepowielajacy ich błędów. ale raczej juz wtedy nie bedziesz chcial pisac wlasnego.

chcialbys aby kazde urzadzenie elektryczne mialo inna wtyczke? czy wolisz jak jest normalna wtyczka, na napiecie 230, albo interfejs usb ktorym podlaczysz niemal wszystko do wszystkiego, czy wolisz jak kazde ma inna wtyczke? bo wspolny framework jest wlasnie taka wtyczka spajajaca rozne rozwiazania roznych ludzi. Zrozumiesz jak ktos da ci czyjs kod do rozwijania, wtedy odkryjesz ze "własny framework" w 99% przypadkow podoba sie tylko jego autorowi, i tylko on w nim cos potrafi zrobic.
Skoro tak ciezko namowic ludzi do nauczenia sie chocby tego symfony, wolą pisac wlasne to pomysl jest jak ciezko jest kogos namowic by nauczyl sie czyjegos autorskiego frameworka ktorego pewnie wiecej nigdy poza tym zleceniem nigdy nie zobaczy.

Co do tej innowacyjnosci:

Microsoft zerwal ze wsteczna kompatybilnoscia, wypuszczajac windows phone 7. Chyba caly core systemu zostal napisany od nowa, nie bazujac na komponentach z windowsa mobile 6.5. Windows mobile byl swojego czasu lepszy niz android 1.0, android poszedl mocno do przodu. microsoft wzial sie za pisanie windowsa phone 7 od zera, co prawda system jest swietnie zoptymalizowany, ale widac ze bardzo brakowalo im czasu na to, w pierwszej wersji systemu nie zdazyli nawet dodac kopiowania i wklejania. tylko ze microsoft to jest mocny gracz ktory jest w stanie przezyc 2 lata biedy i nie zdechnąć, zrobią sobie tego wp8 i zbiorą kupony, natomiast normalny program raczej musi byc rozwijany na bazie istniejacych rozwiazan.
ich jest stac zeby zaplacic producentom nawigacji aby zrobili np nawigacje na wp7 specjalnie bo przeciez portowanie z C++ na C# szlo bardzo ciezko i wszytsko musialo byc napisane od zera, po łebkach.
Ale tobie ciezko bedzie zrobic tak zeby namowic ludzi zeby pisali pluginy do twojej architektury. po to sa jakies standardy. i mali gracze je raczej stosuja.
irmidjusz
Cytat(coolos @ 13.06.2012, 16:07:59 ) *
mam pytanie w jaki sposób ukryć metody modelu przed widokiem? Chciałbym aby z poziomu akcji możliwe było wywołanie:
$news->add_news($id);
lecz żeby niemozliwe było to w widoku. Chciałbym aby widok, pobierał dane tylko z getterów.


Skoro tak bardzo chcesz - to wzorzec Proxy Twoim przyjacielem.

A inny sposób - używaj tylko getterów na obiektach modeli przekazanych do widoków tongue.gif I po sprawie... wink.gif

---------------------------------------------------------------------------------------------------------------------------

Cytat
Normalnie klasy mapujące tabele w bazie i wykonujące logikę to powinny być te same klasy


Bzdura.

------------------------------------------------------------------

Popieram, co napisali Crozin i Orzeszekk - dobrze piszą. Jakby tu były plusiki, to bym im kliknął smile.gif

-------------------------------------------------------------------

Cytat(Orzeszekk)
Zrozumiesz jak ktos da ci czyjs kod do rozwijania, wtedy odkryjesz ze "własny framework" w 99% przypadkow podoba sie tylko jego autorowi


TAK! TAK! TAK! TAK! TAAAAAAAK!

Orzeszekk
Cytat(irmidjusz @ 14.06.2012, 02:41:52 ) *
TAK! TAK! TAK! TAK! TAAAAAAAK!



No bo taka prawda, prawdopodobnie kazdy z nas sie wkurza na roznice miedzy przegladarkami i ich javascriptami ktore dopiero nakładka (czyli proxy...) jQuery pozwoliło rozwiązać w sposób łatwy i przyjemny. A to taka sama sytuacja jak z wlasnymi frameworkami PHP.
A wystarczyłoby gdyby twórcy przegladarek dali sobie na wstrzymanie ze swoimi "innowacyjnymi" pomysłami które w gruncie rzeczy w przypadku htmla 4 i css2 oraz javascriptow ktore powstaly zanim pojawil sie html5, polegały często na nadawaniu innych nazw tym samym funkcjom i zmiennym (IE tutaj góruje, chocby głupie eventArgs eventu keypressed... numer klawisza mozna odczytac w kazdej przegladarce w inny sposócool.gif.

Oczywiscie to co jest z html5 to juz co innego ponieważ standard się jeszcze nie wyklarował, a i twórcy przeglądarek dogaduja sie miedzy sobą by interfejsy tego co dodają z html5 poza specyfikacją były kompatybilne. Ktoś wyciągnął nauczkę z tej lekcji smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.