Wpis 20. A będzie jeszcze milion.

Hey wszystkim!

Kilka dni zabierałem się do tego postu, bo niestety ale pewne problemy techniczne mnie powstrzymywały.

Dziś ostatni etap naszego skanu plików i wrzucania efektów do bazy danych. Na czym ten skan ma polegać możecie przeczytać w poprzednich wpisach [Standard nazewnictwa plików oraz przygotowanie do panelu CMS][Szukacz plików. Find’them’all!][KaperFileValidation and FlashMassages: „szukacz plików” nabiera rumieńców.].

Zabierając się do kolejnego etapu wpadłem na pomysł, aby przemodelować na początku główną tabelę w naszej bazie danych zawierającą nasze numery inwentarzowe zbiorów. Z uwagi na to, że każdy numer powinien być unikalny postanowiłem, że pozbędę się nic nie znaczącego „id” ustawionym na nim „Primary key”, i dodam ten klucz do kolumny inventory_number.

Mielibyśmy tu dość rzadki (ale spotykany) przeniesienia klucza głównego na kolumnę typu „string”. Poczytałem trochę o tym i wydaję mi się to w tym przypadku uzasadnione. Niestety, mój pomysł zaprowadził mnie w ślepy zaułek w dokumentacji Doctrine. Otóż Doctrine oczywiście potwierdza to, że mogę przenieść primary key na pole typu string, ale nie podaje żadnego przykładu jak poprawnie zrobić to w annotacjach.  Oczywiście mogłem również przeoczyć jakąś istotną informację, a przez to przeskakiwałem od jednego błędu do drugiego. W końcu udało mi się stworzyć taką tabelę o jakiej myślałem. Kluczem główny znalazł się na numerze_inwentarzowym, ale przy próbie zasypania tabeli danymi poprzez przygotowany DataFixture, znów musiałem przeskoczyć stos błędów. Uznałem, że na ten moment przy tym konkursowym deadlinie skorzystam ze standardowego sposobu i na spokojnie skorzystam z domyślnej kolumny „Id” z primary_key i auto_increment do niej dopisanej.

Postanowiłem również po raz otworzyć plik ArtifactRepository i dopisać do niego kilka przydatnych zapytań do bazy, aby program mógł podjąć odpowiednie działania względem znalezionych plików.

Po pierwsze, mając wyciągnięty numer inwentarzowy z pliku, chcemy sprawdzić czy podany numer już w bazie istnieje. Jeżeli nie to chcemy go dodać.
Po drugie, jeżeli dany numer już istnieje w bazie, to musimy sprawdzić czy nie próbujemy dodać, aby takiego samego pliku. W końcu zabytek ze zbioru może mieć wiele zdjęć, ale nie chcemy, aby dodawano takie same zdjęcia (przynajmniej z tym samym numerem fotograficznym i kategorią dla danego numeru inwentarzowego).

Prototyp sprawdzania pliki w bazie dla punktu pierwszego będzie wyglądał na razie tak:

Efektem wywołania funkcji importFiles() był u mnie następujący. Kilka numerów już w bazie istniało, kilka nowych plików zawierało nowe nazwy i program je wyłapał. Wszystko idzie dobrze.

Tu muszę się zastanowić jeszcze czy przekazywać w tej funkcji $entityManagera, czy może tworzyć jego instancję wewnątrz funkcji. Prawdopodobnie drugi sposób będzie lepszy, ale muszę jeszcze przemyśleć czy nie przemodelować tej funkcji tak, aby można było korzystać z różnych managerów do obsługi plików. Rozrysuję to jak Jacek Gmoch i będę wiedział. 😉

Teraz powinniśmy napisać funkcję do kroku drugiego. Który sprawdzi czy plik istnieje oraz w razie błędu powinien wyrzucić wyjątek zamiast treści „Wykryto błąd aplikacji”. 🙂

Zanim zajmiemy się zapisem tych informacji do bazy danych musimy jeszcze stworzyć w Doctrine właściwą relację między tabelami „Artifact” oraz „ArtifactFile”. Tu pojawi się swego rodzaju problem. Jeden zabytek może mieć wiele zdjęć, o tym już wspominałem, ale zdarzają się sytuację w których na jednym zdjęciu będzie wiele zabytków. Czy w takim razie powinniśmy stworzyć relację Many-To-Many? Zastanawiam się… W trakcie swojej muzealnej przygody kilkukrotnie natrafiałem na takie przypadki, ale jednocześnie pracowałem na tysiącach zdjęć. Wydaję mi się, że odsetek procentowy jest zbyt mały (ok 1-2% zdjęć), aby tworzyć relację many-to-many. Dodatkowo, tego typu zdjęcia zawierające kilka zabytków często nie stanowią głównej ewidencji zbioru. Najczęściej obok grupowych fotografii powstawały również oddzielne fotografie z poszczególnymi zabytkami osobno. Zamiast komplikować sprawę dla 2% fotografii, stworzymy oddzielną tabelę, która będzie przechowywała zdjęcia grup zabytków. Wydaje mi się, że tak będzie lepiej (przynajmniej na chwilę obecną). Zostajemy zatem przy opcji one-to-many. Jeden numer inwentarzowy może łączyć się z wieloma zdjęciami.

Piszemy…Shiiit.

Dobry Jezu. Gdzieś użyłem skrótu na auto-uzupełnianiu „use” i najwidoczniej mi źle przekształciło używane namespace’y. Mija pół godziny i szukam babola. Bardzo chciałem dzisiaj wstawić ten post, więc wstawiam go bez happy endu. Jak znajdę rozwiązanie to edytuje ten wpis i jedziemy dalej…

KaperFileValidation and FlashMassages: „szukacz plików” nabiera rumieńców.

Cześć!

Dzisiaj kolejna część tworzenia naszego uploadera plików, którego potrzebę powstania i funkcjonalność opisywałem we wcześniejszych wpisach (Szukacz plików, Przygotowanie do panelu CMS). Dzisiaj stworzyłem prosty validator nazwy plików. Jeżeli jego nazwa jest zgodna ze standardem KAPER to plik przechodzi dalej, jego nazwa zostaje rozbita na człony (wg. standardu), a następnie będziemy mogli wprowadzić ją do bazy danych i przenieść plik do folderu „shared” co oznacza, że został poprawnie zaimportowany do systemu. Jeżeli nazwa jest niepoprawna użytkownik (który próbował zaimportować pliki) ujrzy stosowny komunikat w formie Flash Message.

Po pierwsze zmieniłem nazwę folderu z którego będą importowane pliki z „shared” na „upload”. Uznałem, że nazwa „shared” wprowadzała w błąd. W końcu te pliki nie są udostępnione, tylko jeżeli znajdują się w tym folderze to dopiero zamierzamy je udostępnić.

W pliku konfiguracyjnym McvAdminBundle/Resources/config/services.yml utworzyłem dwa parametry:

Jeden określa ścieżkę do której będą trafiać będą pliki do importu do bazy danych. Następnie po poprawnej validacji i imporcie do bazy danych zostaną przeniesione do folderu „shared” skąd będą wyświetlane użytkownikowi. Domyślnie folder importu „upload” zamierzam ukryć tak, aby był on dostępny tylko dla zarządzających serwisem (którzy będą wgrywać ich większe ilości przez FTP).  Do wgrywania pojedynczych plików/lub ich niewielkiej ilości stworzymy formularz dodawania.

W poprzednim wpisie wykorzystaliśmy komponent Finder, aby przeszukiwał nam pliki znajdujące się w konkretnym folderze oraz wyświetlił ścieżki do tych plików. Teraz potrzebujemy klasy, która:

  1. Ze ścieżek wyciągnie tylko nazwy plików
  2. Przeprowadzi validację nazwy wg. standardu KAPER
  3. Po poprawnej validacji wyciągnie z nazwy numer_inventarzowy, numer_fotografii, znak_kategorii oraz rozszerzenie pliku.

Stworzyłem, więc klasę KaperFileValidation i umieściłem ją wewnątrz folderu Utils/Validation w naszym McvAdminBundle (może powinienem nazwać ją KaperFileValidator i umieścić w folderze Services?).

Jej postać prezentuje się tak:

To co od razu może nam się rzucić w oczy to trochę zbyt skromna validacja naszego pliku. Powinniśmy dodatkowo rozszerzyć sprawdzanie plików pod kontem rozszerzenia, formatu oraz czy nazwa oraz treść pliku nie zawiera złośliwego kodu. Na szczęście w nazwie pliku to byłoby trudne, ale myślę, że nie jest wcale niewykonalne.

Następnie zmodyfikowałem naszą klasę Findera, aby z otrzymanej ścieżki wyciągała nazwę pliku z rozszerzeniem oraz na każdym znalezionym pliku wykonywała wpisaną w KaperFileValidation funkcje validate.

Teraz wygląda ona tak:

Teraz możemy wyciągnąć poprawnie nazwane pliki i wyświetlić je w naszym panelu zarządzającym.

Nasz działający, acz straszliwie brzydki panel prezentuje się na razie w ten sposób.

Powyższy wers wykorzystałem, aby sprawdzić czy poprawnie zostały przesłane dane do szablonu. Poniżej scaliłem człony z rozbitej nazwy, aby wyświetlić jej pełną treść do użytkownika. (Myślę, że powinna do tego być jakaś miła funkcja).

W następnym odcinku dodamy już pliki do bazy. Będziemy mogli ruszyć dalej w nieznane. 😀

Za chwilę poniedziałek. A jak poniedziałek to

Do kolejnego!

 

Szukacz plików. Find’them’all!

Heyo!

Kontynuuję dzisiaj zabawę z odczytywaniem plików w udostępnionym folderze w naszej aplikacji. Jak napisałem wczoraj założeniem jest stworzenie skryptu, który odczyta z folderu nazwy plików dot. muzealiów i przygotuje z nich obiekty gotowe do wprowadzenia do bazy danych. Oczywiście pliki muszą spełniać wymogi standardu nazewnictwa plików KAPER o czym również wspominałem. Przystępujemy do pracy! 😀

Po pierwsze stworzyłem w naszym McvAdminBundle/Resources/config/services parametr „shared_dir”, który będzie przechowywał ścieżkę do folderu w którym znajdą się zbiory do wczytania.

Udostępnione pliki przechowuję u siebie wewnątrz katalogu shared, znajdującego się w katalogu /web, w głównym folderze naszej aplikacji. Dzięki temu parametrowi będziemy mogli się do niego odwołać w naszej klasie Szukacza (spokojnie! Nie nazwałem jej tak), która sporządzi listę plików oraz będzie nimi zarządzać na podstawie ścieżki do folderu, którą deklarujemy w parametrze.

Sprawdźmy najpierw czy nasz parametr dobrze obsługuję ścieżkę z parametru.

Wchodzimy w pierwszą lepszą akcję w kontrolerze McvAdminBundlue i wpisujemy:

Oto rezultat:

Wypisane zostały katalogi znajdujące się wewnątrz katalogu /web/shared. Dobrze. Wiedząc, że ścieżka wskazuje prawidłowy folder możemy przystąpić do dalszej części.

Nie będziemy wymyślali koła na nowo. Do prawidłowej obsługi plików wykorzystamy komponent Symfony – Finder. Pozwala on na szukanie, pobieranie nazw i podstawowe zarządzanie znajdowanymi plikami. Czyli dokładnie to do czego chcemy go użyć.

Dodajmy go do naszego projektu:

Teraz możemy go przetestować. Do moich folderów dodałem w różnych miejscach 3 pliki z różniącymi się nazwą i rozszerzeniem. Struktura katalogów wygląda tak:

Następnie wewnątrz naszego McvAdminBundle stworzyłem katalog Service, a w nim klasę CollectionFinder.php, której będzie spełniała rolę naszej wyszukiwarki plików. Na ten moment chcemy przetestować jej działanie i nauczyć się obsługi tego komponentu. Po kilku chwilach nasza klasa wygląda tak:

W konstruktorze klasy podamy nasz parametr wyciągnięty z service.yml i powinniśmy dostać wykaz plików (bez folderów), które znajdują się wewnątrz udostępnionego katalogu /shared. Czy tak się stało?

I po odpaleniu tej akcji dostajemy wykaz wyszukanych plików.

Wszystko działa jak należy. Teraz połączymy naszego Findera ze Standardem Kaper si zaczniemy pobierać poszczególne człony w nazwach plików (najprawdopodobniej przy pomocy jakiegoś wyrażenia regularnego) i przygotujemy ich metadane do wrzucenia do bazy danych.

Tymczasem do usłyszenia!

Standard nazewnictwa plików oraz przygotowanie do panelu CMS

Wielkie cześć po krótkiej przerwie!

Przepraszam za chwilową nieobecność, ale przez ostatni tydzień kopałem szpadlem i łopatą w ziemi Jaroszewskiej jako archeolog. Tak, taki mam wyuczony zawód, ale o tym opowiem innym razem. 😛

Czas nadgonić drobne zaległości, a trochę się ich nazbierało przez ten czas. Już za niecały miesiąc koniec konkursu, a tu tyle pracy. Nie pozwólmy jednak, żeby ten ogrom nas sparaliżował. Jak zjeść słonia? Kawałek po kawałku.

W ostatnim odcinku dotyczącym aplikacji stworzyłem mały diagram przedstawiający podstawowe zależności między klasami obiektu zabytek oraz danymi z bazy danych, które nadadzą stworzonemu obiektowi treść.

No dobrze, możemy stworzyć formularz dodawania numerów inwentarzowych i ich zdjęć i liczyć na to, że w jednostkach muzealnych znajdzie się kilka osób które tysiące rekordów będzie w ten sposób przepisywać/dodawać… To mało optymistyczna wersja naszej aplikacji. Dlatego podejdziemy do tego z innej strony. Pozwólmy, aby jednostka muzealna zamieściła swoje zbiory w naszej aplikacji (np. przez serwer ftp) i poprzez odpowiedni skrypt wyciągający nazwy z plików zaktualizowała obecną bazę swoich zbiorów (jeżeli jeszcze się w niej nie znajdują).

W tym celu posłużymy się Standardem Kaper, który wspomniałem w jednym z pierwszych postów konkursowych. O czym ten standard mówi?
Otóż, jak głosi jego treść:


Standard  przeznaczony  jest  do  opisu  plików  graficznych 2D dokumentujących   zbiory   muzeum.

(…)
Standard ma zapewnić realizację czterech opisanych poniżej funkcji.
Przede wszystkim ma umożliwić identyfikację odwzorowanego obiektu w pliku bez konieczności otwierania tego pliku.
Następnie, ma zapewnić możliwość maszynowego powiązania plików z rekordami ewidencyjnymi w systemach zarządzania bazami danych, czyli tak zwanej ewidencji elektronicznej. Spełnienie tych dwóch funkcji możliwe jest wyłącznie przy konsekwentnym stosowaniu z jednej strony unikalnych numerów identyfikacyjnych dla obiektów (np. w ewidencji muzealiów, rejestrach pomocniczych, księdze wpływu i innych)z drugiej natomiast ustandaryzowanej struktury nazw pliku w odniesieniu do wszystkich dokumentowanych zbiorów, które są zewidencjonowane w instytucji.
Trzecia funkcja nazwy pliku to klasyfikacja pliku poprzez wskazanie do jakiego zastosowania został wytworzony lub wtórnie zaklasyfikowany.
Ostatnia funkcja, związana z przenoszeniem danych, dotyczy możliwości masowej zmiany nazw przy zmianie w ramach migracji do nowego systemu wymagającego jakieś szczególnej formy nazewnictwa plików lub eksporcie do krajowego repozytorium.


Jak wygląda taka nazwa pliku? Żeby was nie zanudzać dokładnym opisem nazewniczym (o którym można poczytać w Standardzie Kaper) to za przykład posłuży nam taka oto nazwa pliku.

mg-in-201_img23151_e.jpg

Możemy w tej nazwie wyróżnić 4 bloki oddzielone znakami podkreślenia oraz rozszerzeniem pliku po kropce.

  1. mg-in-201 to nazwa obiektu występującego pod podanym numerem inwentarzowym w jednostce muzealnej. Numer jest unikalny. Jeżeli mamy do czynienia z większą grupą zabytków do podanego numeru dodajemy znak myślnika oraz kolejne cyfry oznaczające kolejne części grupy obiektów np. mg-in-201-1, mg-in-201-2 itd.
  2. Kolejnym członem w nazwie jest numer zdjęcia dodany przez aparat, który dany obraz wytworzył, dzięki temu unikniemy sytuacji, że wystąpią dwa pliki o tej samej nazwie.
  3. Trzeci człon stanowi pojedyncza litera określająca charakter zdjęcia zgodnie ze Standardem wyróżniamy 5 typów: konserwacja, archiwum, publikacja, ewidencja, reportaż. Stąd powstał nasz akronim KAPER.
  4. Czwartym jest rozszerzenie naszego pliku.

Mając tak nazwaną bazę naszych zbiorów możemy stworzyć system który wyciągnie z masy plików jej numery inwentarzowe/nazwy inwentarzowe oraz doda je do naszej bazy danych.

W tym celu stworzyłem w naszym Museum Collection Viewer nowy bundle, który będzie odpowiadał za część administracyjną aplikacji. Używając konsoli:

nadałem mu nazwę McvAdminBundle oraz utworzyłem prosty szablon w którym użytkownik z odpowiednimi uprawnieniami będzie mógł zarządzać zbiorami. Na ten moment nie będę opisywał sposobu na stworzenie systemu logowania, bo po pierwsze są dziesiątki opisanych sposobów jak to zrobić, a po drugie w tej chwili nie jest to potrzebne i chcę się skupić na czymś co może być charakterystyczne dla tej aplikacji tzn. odciążenie administratorów od niepotrzebnej pracy ;).

Z uwagi na to, że nie czuję się dobrze we front-end’zie posiłkuję się tym co daje mi Bootstrap.

Na ten moment nie wygląda to zachwycająco, ale najpierw MVP, a potem SHL (mój akronim od słów „SUPER HIPER LOOK„) 😉

Ten post ma już trochę słów, więc skrypt przedstawię w kolejnym odcinku. Do usłyszenia!

 

 

Wirtualna rzeczywistość to nic. Tworzenie wirtualnej rzeczywistości będąc w wirtualnej rzeczywistości to jest czad.

Cześć!

Dzisiejszy post sponsoruje cudowne uczucia wdzięczności dla wielkich umysłów tego świata za to, że dzięki ich pracy możemy wejść do światów, które widzieliśmy do tej pory w filmach Sci-Fi.

Pamiętacie Mysz (Mouse) z Matrixa? Chłopak tworzył programy w których bohaterowie Matrixa mogli ćwiczyć przed wejściem do świata maszyn.  Zapisał się również w naszej pamięci jako konstruktor „Czerwonej Pani” z którą chciał umówić głównego bohatera.

Można powiedzieć, że reprezentował on standardowe/konserwatywne* podejście do programowania. Program powstawał w całości przed komputerem, poza aplikacją i kiedy był gotowy prawdopodobnie testował go na Morpheuszu.

Upraszczając historię można powiedzieć, że programiści niskopoziomowi tworzyli oprogramowanie/programy/języki programowania wysokopoziomowe na bazie której kolejni programiści tworzyli oprogramowanie dostępne dla ludzi i ich biznesu. A co jeżeli jesteśmy w momencie przejściowym do trzeciego poziomu. Programowanie wewnątrz-poziomowe! Tak to nazwałem. Ha! Może się przyjmie.

Oczywiście zaraz ktoś powie „phi” to nic nowego. Istnieją przecież programy dzięki którym programujemy już wewnątrz programu np. platformy do nauki programowania. Jak działa taki Scratch/AppInventor itp. Ja traktuję to jako programowanie pre-wewnątrz-poziomowe, dlatego bo sami znajdujemy się poza systemem. Granica my – system/komputer jest wyraźnie nakreślona.

Dobra, dobra… Do czego zmierzasz Hubercie. Co to znaczy standardowe, a już tym bardziej, co to znaczy konserwatywne podejście do programowania. HA!

Przykład. Przykład. Na przykładzie najlepiej pokazać co nim nie jest, albo lepiej co… Co będzie tym nowym podejściem.

Doświadczenie wirtualnej rzeczywistości jest niezwykłym uczuciem, tworzenie jej również, ale Unity oraz Unreal Engine wspięły się o krok wyżej i umożliwiły zarządzanie naszym projektem będąc
„wewnątrz” naszego projektu. Wewnątrz projektu mamy dostęp do naszych bibliotek, modeli i funkcji z których korzystamy w naturalny sposób podczas programowania.

Bez tego ujęcia, w momencie błędu lub czegoś co nam się nie podoba w projekcie musieliśmy ściągnąć headset i dłubać w naszym projekcie. A tu? Patrzymy na swoją rękę. Zatrzymujemy czas (przechodzimy w tryb developerski) i dodajemy do naszego świata co nam się podoba lub zmieniamy atrybuty jakiejś metody! Beng!

Uczucie jest bardzo fajne. Gdyby jeszcze sposób poruszania był łatwiejszy! Moglibyśmy biec i dostawiać sobie pod naszymi nogami schody i poruszać się po przestrzeni naszego świata(a właściwie naszego RAMU). Oczywiście jest jeden minus. Przynajmniej taki który mnie dotyczy, jak komuś lekko drżą ręce to zarządzanie niektórymi suwakami/opcjami jest kłopotliwe. Myszką dziabniemy to w trymiga. Smuteczek. Potrzebny jest dokładniejszy kontroler (odporny na wstrząsy), albo jakiś inny patent. Oczywiście ludzie z dłońmi chirurga to nie dotyczy. Farciarze.

Właśnie to jest dla mnie takim programowaniem wewnątrz poziomowym. Jesteśmy odizolowani od świata rzeczywistego, wchodzimy do świata projektu i możemy nim zarządzać (na razie), a w przyszłości programować, tworzyć, rozwijać. Wyobrażacie sobie debbuging przyszłości ? 😀 Poruszasz się jak Neo w Matriksie z bronią Colt-Debugger która sprawdza wam jak zachowuje się obiekt wewnątrz świata.

Chciałbym Wam pokazać jakiś przykład od siebie, ale muszę to najpierw nagrać,  i dodatkowo stworzyć coś co nie będzie nudne.

A… jakby ktoś nie widział to polecam również :Uncanny Valley.

On pokazuje niebezpieczeństwa VR. Oglądajcie do końca :P.

Do kolejnego odcinka!

Bzdury Pan pleciesz, ale na bzdurach się nauczysz.

Cześć!

Późnym niedzielnym wieczorem czas napisać coś o pracach nad tworzonym portalem.

O czym będzie dzisiejszy post? Ho ho! Czytelniku Drogi, o błądzeniu będzie. Myślę, że ten post będzie o błądzeniu.

Człowiek naczyta się dokumentacji, poradników, książek, ludzi na forach i przejrzy kilka losowo wybranych projektów na githubie i podejmuje próbę zastosowania tego do swojego projektu. I się boi…

A boi się, że zabiera się do czegoś niewłaściwie, boi się że nie wszystko dobrze zrozumiał, boi się, że coś namiesza i będzie przepisywał na nowo to co stworzył. Jestem dokładnie w tym momencie. Mógłbym poświęcić więcej czasu na czytanie, albo na zaczepienie kogoś bardziej doświadczonego i zadania mu dziesiątków pytań dotyczących tego czy dobrze przemyślałem moją aplikację, ale zamiast truć komuś tyłek moimi wątpliwościami postanowiłem najpierw sam popełnić kilka błędów. 😉

Mój plan jest prosty:

  1. Stworzyć za pomocą Doctrine tabelę zabytku oraz kilka tabel wchodzących z nią w relacje.
  2. Stworzyć klasę, która będzie łączyła informacje dot. zabytku i która będzie w stanie stworzyć obiekt klasy zawierający te wszystkie informacje.
  3. Stworzyć usługę, która będzie wykorzystywała obiekt klasy zabytku i będzie w stanie nim zarządzać.
  4. Zarejestrować usługę w menadżerze usług i liczyć na to, że działa.

Na szybko popełniłem taki diagram. Ohyda! Ale moja, moja własna 😀

Niebieskie pola oznaczają poszczególne tabele w bazie danych, wyjątek stanowi Klasa Zabytek, która nie ma swojego miejsca w bazie danych, a jest rodzajem łącznika wszystkich informacji dot. zabytku. Wszystkie poboczne tabele wychodzą z tabeli „Zabytek Numer Inwentarzowy”, bo id tej tabeli służyć będzie do łączenia różnych informacji z uwagi na to, że numer inwentarzowy jest numerem unikalnym dla każdego zabytku (nadaje go jednostka muzealna i wpisuje do księgi inwentarzowej). W dymkach przy niebieskich polach oznaczyłem relację jaką ma dana tabela względem tabeli z numerem inwentarzowym.

Na czerwono zaznaczyłem usługę, której stworzenie mi się marzy. Marzy mi się jej działanie. Marzy mi się, że bez problemu ją po stworzeniu zarejestruje w ServiceManagerze i wszystko będzie jak należy. 😉 I have a dream!

Problem w tym, że 100% nie jestem pewny czy dobrze rozumuję, ale nic tak nie rozwieje wątpliwości jak kilka komentarzy z waszej strony. Polecam następujące szablony komentarzy:

  1. „Co za gówno, usuń swój internet, dodatkowo myślę, że powinieneś zmienić $to i $to…”
  2. „Oł mejn, co za żal, pomiędzy $tym i $tym dodaj $to i $to”
  3. „Chyba upadłeś na głowę, ja bym skupił się na $tym”

Wykorzystanie jednego z nich na pewno przyczyni się nie tylko do poprawy mojej aplikacji, ale również pozwoli pośmiać się zaglądającym tu czytelnikom.

Nie czekając na was rozpocząłem pisanie.

Stworzyłem na obecną chwilę podane tabelę z nr_inwentarzowym (artifact) oraz tabelę z jej opisem (artifact_description) w której zawarłem 14 kolumn poza jej indexem głównym. Pytanie które mi się nasunęło zaraz na początku to to czy nie powinienem podzielić tej tabeli na kilka mniejszych np. tabele z opisem, tabele z danymi metrycznymi, tabele dot. technik wykonania, czy materiałów z jakich został stworzony zabytek. Co do tych dwóch ostatnich to myślę, że będzie to dobrym pomysłem. W końcu zabytek może posiadać wiele technik wykonania oraz być zbudowany z różnych materiałów.

Dodatkowo, zaimportowałem do naszego kochanego Symfony DataFixtures i wypełniłem dla testu naszą bazę jakimiś danymi, żeby zobaczyć jak to się trzyma.

 

Teraz powinienem stworzyć klasę, która połączy informację z bazy i na podstawie której, stworzymy obiekt zabytku.

Czas popełnić kilka nowych błędów! Hurra!

Trzymajcie się!

 

Myślenie obiektowe w programowaniu wg. Matta Weisfelda

Cześć!

Skończyłem dzisiaj czytać „Myślenie obiektowe w programowaniu” Matta Weisfelda (wydanie IV) i pomyślałem, że może warto napisać posta dot. tego czy warto posiłkować się czytaniem książek o tematyce programistycznej, kiedy w internecie mamy tysiące stron dot. programowania w tym również programowania obiektowego. Oczywiście nie będę was trzymał w niepewności i nie odkryję niczego nowego: tak warto. Głównie dlatego, że w internecie mamy kawałki kodu który możemy wykorzystać, ale rzadko ktoś rozpisze się na tyle, aby uchwycić problem od strony teoretycznej.

Na pewno mogę tę pozycję śmiało polecić osobom początkującym w tej tematyce, albo tym które dopiero chcą zapoznać się z tematem. Myślę, że osoby doświadczone mogą się szybko znudzić.

Książka posiłkuje się elementami kodu z języka Java, ale jestem pewny, że będzie zrozumiała dla każdego (ja nigdy nie miałem do czynienia z programowaniem w Javie, a nie miałem żadnych problemów ze zrozumieniem kodu). Co więcej, powiem śmiało, że gdybym przeczytał tę książkę dwa miesiące wcześniej to możliwe, że przeszedłbym do dalszego etapu rozmowy kwalifikacyjnej w której brałem udział. Ale nie ma tego złego. Powiedzmy zatem kilka słów o samej pozycji.

Spis treści dostępny jest pod tym linkiem, więc nie będę go omawiał.

Matt Weisfeld skupią się przede wszystkim w przekazywaniu sposobu myślenia programisty obiektowego. W książce liczącej ponad 300 stron większe fragmenty kodu znajdują się na co 15-20 stronie. O wiele częściej pojawiają się drobne fragmenty, które mają zobrazować przedstawianą myśl. Oprócz informacji dot. podstawowych pojęć takich jak agregacja-asocjacja, interfejs, konstruktor itp., które bez problemu możemy znaleźć w internecie w kilkanaście sekund, autor duży nacisk kładzie na tak zwane „best practices”, czyli właściwym wykorzystaniu możliwości płynących z programowania obiektowego w celu bardziej wiarygodnego opisu rzeczywistości oraz tego, aby tworzony kod był przenośny i łatwy w konserwacji. Doskonale to współgra z tworzoną przeze mnie, na potrzeby konkursu, przeglądarką zbiorów w Symfony3. A Symfony bardzo lubi gdy moduły (bundle) są przenośne i mogą być wykorzystywane poza swoim „matczynym” projektem. 🙂

Każdy rozdział ma bardzo podobną budowę, którą można przybliżyć w kilku krokach:

  1. Definicja tematu rozdziału. Typowy książkowy dokumentacyjny opis.
  2. Rysunek/Graf/Diagram. Próba wizualizacji problemu poruszanego w rozdziale. Zaczynamy łapać.
  3. Przykład problemu z życia. Jest to odpowiedź na pytanie czemu lepiej podejść do problemu w sposób obiektowy.
  4. Rysunek2/Graf2/Diagram2. Kolejna wizualizacja naszego problemu z dorysowanym rozwiązaniem. W tym miejscu nasze wątpliwości (jeśli je mieliśmy) zostają rozwiązane.
  5. Podsumowanie, kawałek większego kodu, zwrócenie uwagi na inne problemy.

I tak rozdział po rozdziale.

Myślenie obiektowe w programowaniu czyta się bardzo przyjemnie. Można powiedzieć, że jest to lekka literatura do pociągu lub jesienno-zimowe wieczory ;). Podobnie jak jest to w przypadku książek Myśl jak programista Antona Spraul czy Pragmatyczny programista Andrew Hunta i Davida Thomasa. Lekko, jasno i przyjemnie. Te dwie wymienione pozycje również polecam, ale nie dotyczą one programowania obiektowego.

Dodatkowo, Matt poświęca również kilka rozdziałów na opis narzędzi pomocnych dla programujących obiektowo tj. diagramach UML, formatach XML, JSON, a także technice zdalnego wywoływania procedur RPC.

Minusy?

Jeżeli chodzi o to czego mi w tej pozycji zabrakło to myślę, że będzie to bardziej rozbudowany rozdziału ze wzorcami projektowymi. W obecnej formie zajmuje około 20 stron i czuć wielki niedosyt. Rozumiem jednak, że nie jest to pozycja o wzorcach projektowych tylko o ogólnym sposobie myślenia w programowaniu obiektowym. Będę musiał poszukać innej pozycji w tym temacie.

Spokojnych świąt!

 

Poprawki w Mordorze. Raport z postępu prac.

Heyo!

Dzisiaj poprawiałem kilka rzeczy, które nie do końca się udały przy dodawaniu skryptów przez assetica. Miałem drobny problem, bo wyglądało na to, że pomimo tego, że w źródle strony występował mój plik .js z jQuery, Bootstrapem oraz Panzoom to i tak konsola pokazywała błąd $ is not defined, co oznaczało, że wgrano biblioteki niepoprawnie. Na tę chwilę przeniosłem je na początek skryptu do pliku layout i już ładują się poprawnie.

Muszę tylko porozdzielać poszczególne elementy Jumbotron Bootstrap Theme, aby były łatwe w modyfikacji tj. menu, header, widok główny, stopka i jakiś pasek boczny. Nie przewiduję tu większych problemów.

Chciałbym w dzisiejszym wpisie napisać coś ciekawego, ale z uwagi na to, że od ostatnich wpisów minęły trzy dni (a jutro wyjeżdżam na dłuższy urlop świąteczny) to chcę chociaż w drobny sposób usprawnić tworzoną aplikację i podzielić się z wami postępami prac.

 

 

Widok jest niemal bliźniaczo podobny do tego co robiłem wykorzystując Zend Framework 3. Wtyczka Panzoom już działa. Możemy powiększać i pomniejszać zdjęcie kółkiem myszy oraz poruszać zdjęciem w obszarze roboczym, którego kolor zmieniłem na czerń, aby nie dezorientował użytkowników (powiększanie poprzez scrollowanie jest dostępne tylko w obszarze roboczym zdjęcia). Chcę jednak oddzielić funkcjonalność portalu, od funkcjonalności przeglądanych fotografii. Na ten moment myślę o wywoływaniu takiej funkcji poprzez wyświetlanie pełnoekranowego okna z dodatkowymi funkcjami – podobnie jak w The Metropolitan Museum of Art.

 

Sposób działania galerii w The Metropolitan Museum of Art.

 

Czas wysłać te drobne zmiany na githuba. Ja wciskam push, a wam życzę Spokojnych Świąt!

You have my Bootstrap, and my Jquery, AND MY PANZOOM!

Cześć!

W dzisiejszym wpisie utworzymy katalog Resources w naszym bundlu „McvBundle”, w którym będziemy przechowywać widoki do naszego modułu. Nie chcielibyśmy, żeby ktoś wyciągając moduł McvBundle odkrył, że nie skopiował widoków z jakiegoś miejsca w naszej aplikacji, o którym nie miał pojęcia. Niech wszystko co dotyczy modułu będzie na swoim miejscu. 🙂

Po tym jak utworzyliśmy katalog Resources, stworzyłem również katalog views, następnie katalog mcv (w którym znajdą się widoki poszczególnych akcji).

No dobrze, ale jak je teraz wykorzystywać w naszej aplikacji. Z folderu głównego app/Resources wywołujemy widoki poprzez:

Po tym jak przenieśliśmy nasze widoki wewnątrz bundla McvBundle ta metoda już nie zadziała. Rozwiązanie? Musimy po prostu wykorzystać ogólny schemat [BundleName:short_name:twig_view] i dodać go do naszej metody renderującej widok:

Zrobione.

Dodatkowo doinstalujemy sobie Bootstrapa i jQuery oraz wtyczkę Panzoom, która pomoże nam w wyświetlaniu zbiorów.
Instalacja? Nic prostszego.

W przypadku jquery nie zauważyłem komendy, która można w bliźniaczy sposób wywołać, więc dodałem wpis do composer.json

Następnie:

I Jquery zainstalowane.

Panzoom nie posiada możliwości ściągnięcia przez composera, więc musimy dodać go ręcznie wprost z githuba.

Panzoom korzysta z jquery, więc umieszczamy go w folderze vendor/components/ zaraz obok jquery. Tak dla porządku. 🙂

Jeżeli zerkniemy do „Best practices” przeczytamy, że powinniśmy trzymać wszystkie nasze pliki .js .css .media w katalogu /web. No dobrze, ale composer zainstalował je w folderze /vendor, gdzie czekają na użycie wraz z innymi bibliotekami. Nierozsądnie byłoby uruchamiać je po stronie klienta wprost z tego folderu. Z pomocą przychodzi nam Assetic (albo Grunt).

W Symfony3 nie jest on domyślnie zainstalowany, ale to żaden problem:

Powinniśmy również dodać go do pliku app/KernelApp.php pomiędzy innymi bundlami.

Dzięki Assetic’owi na naszą komendę wszystkie używane pliki .js, media, .cssy zostaną zgrane do folderu /web, gdzie będą dostępne od strony klienta.
No dobrze, ale skąd program będzie wiedział skąd je pobrać?

Do tego celu potrzebujemy skonfigurować ścieżki w pliku .yml {domyślnie config.yml}.

Pomiędzy parametrami twig: i doctrine: dodałem następujące wersy.

Dzięki nim w naszych widokach będziemy mogli zaznaczać, że potrzebujemy użyć konkretnych bibliotek:

Pozostaje nam już tylko wykorzystać assetica, aby przegrał poszczególne pliki.

W konsoli wpisujemy:

Sprawdzamy, co się stało w naszym folderze /web …

Miodzik 🙂 Potrzebne pliki zostały dodane do projektu.

Teraz trzeba tylko skonfigurować wtyczkę panzoom, aby działała poprawnie.

Jak widać trochę zabawy z tym było. Ale teraz będziemy mogli korzystać z tego do woli.

Już 2:00. Czas na drzemkę.

Do kolejnego odcinka!

 

Entities, Repositories – z chaosu wyłonił się „Zabytek”

Cześć wszystkim!

Czas opisać kolejne postępy w tworzeniu aplikacji. Oczywiście o ile nie zakaszlę się na śmierć podczas pisania tego posta. Wiosenne powietrze mi służy.

<atak_kaszlu>

Stworzyłem nowego bundla o nazwie „McvBundle” (MuseumCollectionBundle) w którym będę przechowywał wszystkie akcje, kontrolery, repozytoria oraz widoki potrzebne do prezentowania zbiorów. System zarządzania treścią oraz system uwierzytelniania zamierzam oddzielić tak, aby można było przenieść tylko mojego bundla i zaszczepić go w swoim systemie, bez konieczności wielki zmian w projekcie i dostosowywaniu go do innego środowiska. Best practices! Zobaczymy jak mi to wyjdzie.

Przez chwilę zastanawiałem się jak nazwać encję główną zabytku i co w niej zawrzeć. Na pewno chciałem uniknąć stosowania formy „object” – już sobie wyobrażam jaki by to spowodowało zamęt. „Monument” oraz „relic” również odrzuciłem. Zostaje „antique” oraz „artifact”. Zdecydowałem się na „artifact”. Nie wiem czy dobrze wybrałem, ale o ile będę konsekwentny w nazewnictwie to nie będzie miało to większego znaczenia. Przyjmijmy zatem, że za każdym razem jeżeli w aplikacji zobaczymy takie byty jak ArtifactController, ArtifactRepository, ArtifactFactory to będziemy wiedzieli, że podana klasa związana jest z obsługą „zabytku”. Jak pisałem już wcześniej, w moim modelu zabytek będzie bytem abstrakcyjnym z którego będą dziedziczyć kolejne kategorie zabytku. Zabytek sam w sobie nie istnieje, coś nim jest, ale każdy zabytek posiada swój numer inwentarzowy wpisany do księgi inwentarzowej w muzeum.

Wykorzystując symfony/console zaczynamy pisać.

Za to lubię Symfony. Nie dość, że dokumentacja jest napisana w przyjemny sposób to jeszcze co chwila pojawiają się przykłady, abyś broń Boże nie zbłądził. I do tego jest fajna konsola, która również zadba o to, abyś trzymał się pewnej konwencji (tak jak na załączonym obrazku).

Nadałem jej nazwę McvBundle:Artifact <enter>

Typ: String 100 znaków. Nie spotkałem się z dłuższymi numerami inwentarzowymi niż ten.

Czy pole ma być unikalne? Tak. Potrzebujemy numeru inwentarzowego, który będzie unikalny dla wszystkich zabytków. Widziałem już kilka przypadków w których występowało kilka takich samych numerów inwentarzowych, ale to pomyłka instytucji. Przed wprowadzeniem do programu takie przypadki powinny zostać uporządkowane np. poprzez dodanie jakiego sufixa do numeru.

Problemem mogą być również zbiory zabytków wpisane pod jeden numer inwentarzowy. Takie przypadki również występują. Ale podobnie jak z podwójnym numerem, jest to według mnie problem który powinien zostać rozwiązany przed próbą dodania takiego zbioru do systemu. Np. Zabytek pod numerem CS-IN-201, który w rzeczywistości jest zbiorem kilku przedmiotów można wpisać jako „CS-IN-201-{kolejny-numer-przedmiotu}. Dzięki temu będziemy mogli wyciągnąć z bazy wszystkie elementy tego zbioru wyszukując według wzorca %CS-IN-201% i zwrócone rekordy pokazać jako wspólny wzór. Ale w jaki sposób oznaczyć, że dany zabytek jest częścią większej kolekcji? Czy jest to konieczne na tym etapie? Trudno mi teraz na to odpowiedzieć. Możliwe jest stworzenie kolejnej kolumny przechowującej wartość boolean -kolekcja {true/false}, ale nie jestem do tego przekonany na tym etapie.

Zastanawiałem się również czy dodać na tym etapie wartość zabytku. W końcu każdy zabytek posiada jakąś oszacowaną wartość. Niestety z tym również wiążą się problemy. Która wartość przechowywać. W muzeach przechowuje się cenę nabycia danego zabytku, aktualną wartość zabytku itp. Możliwe jest otrzymanie zabytku w darze, który będzie bardzo cenny. Na obecną chwilę myślę, że lepiej będzie przechowywać takie informacje w innej tabeli związanej z informacjami o zabytku.

Stworzyliśmy na ten moment dość ubogą encję, ale od której wszystko się zaczęło.

Dodatkowo zostały wygenerowane również settery i gettery naszej encji. Miodzik. Oraz plik ArtifactRepository mieszczący się w katalogu McvBundle/Repository.

Teraz pozostaje nam już tylko:

Utworzona została baza danych. 🙂

A teraz przystępuję do pisania kolejnego posta. Przez tę chorobę mam zaległości. 😉

Heyo!