Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [ORM] Jak prawidłowo powiązać encje?, Klucze obce i nazewnictwo
WebCM
post 3.12.2013, 00:44:01
Post #1





Grupa: Zarejestrowani
Postów: 375
Pomógł: 20
Dołączył: 28.07.2006

Ostrzeżenie: (0%)
-----


Istnieją następujące tabele w bazie:

FILMY
- ID
- tytul

AKTORZY
- ID
- film (klucz obcy do FILMY.ID)
- imie

Załóżmy następujące klasy:
  1. class Film
  2. {
  3. public $id;
  4. public $tytul;
  5. }
  6. class Aktor
  7. {
  8. public $id;
  9. public $film; //niektóre ORM używają __get(), więc musi być private/protected
  10. public $imie;
  11. }

Chcę napisać kod zgodny z przyjętymi zasadami i jednocześnie czytelny. Powstają pytania:

1. Jak nazwać kolumny, które są kluczami obcymi?

Najłatwiej nazwać kolumnę film, ale nie wszystkie ORM sobie z tym poradzą ze względu na konflikt nazw.

  1. <?php
  2. $wartosc = $aktor->film->tytul;
  3.  
  4. // jeśli pole $film jest publiczne, wystąpi błąd, bo $film zawiera ID filmu
  5. // jeśli pole $film jest prywatne, otrzymamy tytuł filmu, jeśli ORM sobie poradzi
  6. ?>

2. Czy do klasy encji powinien trafić także ID powiązanego rekordu?

  1. class Aktor extends Encja
  2. {
  3. public $ID;
  4. public $filmid; //zakładając, że nazwa kolumny w bazie to filmid
  5. public $imie;
  6. private $film; //pole w zasadzie zbędne, to tylko informacja dla IDE
  7.  
  8. //Niektóre ORM-y wymagają zdefiniowania powiązań między encjami
  9. public function inicjuj()
  10. {
  11. $this->nalezyDo('filmid', Film::class, 'ID'); //pole filmid odwołuje się do ID encji Film
  12. }
  13.  
  14. //A także trzeba podać nazwę tabeli
  15. public function nazwaTabeli() { return 'AKTORZY'; }
  16. }

Zamiast funkcji można użyć także adnotacji lub pliku konfiguracyjnego. Przykład wyżej ma pole $filmid, ale do relacji odwołujemy się poprzez metodę magiczną __get(). Czy to zbyt nie komplikuje kodu? Może większość bibliotek ORM od razu pobiera powiązane encje n:1. Czy w powyższym przypadku po odwołaniu do $filmid (lub $film z poprzednich przykładów) powinniśmy otrzymać ID filmu czy obiekt klasy Film?

PS. Co myślicie o potworkach typu Film::find()?


--------------------
„Jesteśmy różni, pochodzimy z różnych stron Polski, mamy różne zainteresowania, ale łączy nas jeden cel. Cel ten to Ojczyna, dla której chcemy żyć i pracować.” Roman Dmowski
Go to the top of the page
+Quote Post
Crozin
post 3.12.2013, 09:00:33
Post #2





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


1. Zacznijmy od tego, że filmy i aktorzy tworza relację wiele-do-wielu, wiele-do-jednego.
2. O jaki konkretny ORM chodzi?
Go to the top of the page
+Quote Post
WebCM
post 4.12.2013, 14:32:04
Post #3





Grupa: Zarejestrowani
Postów: 375
Pomógł: 20
Dołączył: 28.07.2006

Ostrzeżenie: (0%)
-----


1. Masz napisane wiele-do-jednego (n:1).
2. O wszystkie - jak to jest w dobrze napisanych ORM - a konkretny przypadek to framework Phalcon.


--------------------
„Jesteśmy różni, pochodzimy z różnych stron Polski, mamy różne zainteresowania, ale łączy nas jeden cel. Cel ten to Ojczyna, dla której chcemy żyć i pracować.” Roman Dmowski
Go to the top of the page
+Quote Post
Crozin
post 4.12.2013, 15:16:55
Post #4





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Miało być: [...] tworzą relację wiele-do-wielu, NIE wiele-do-jednego..

Żeby było dobrze powinno być:
  1. class Film {
  2. private $id; // id
  3.  
  4. private $title; // string
  5.  
  6. private $actors; // array[Actor], czy jakaś obiektowa kolekcja, np. ArrayColection[Actor] z Doctrine
  7. }
  8.  
  9. class Actor {
  10. private $id;
  11.  
  12. private $firstName;
  13. private $lastName;
  14.  
  15. private $films; // ponownie, tablica/kolekcja jednak tym razem obiektów Film
  16. }
Do tego, każda z tych klas powinna mieć zestaw funkcji get/set/has/add/etc dla każdej z właściowości.
Go to the top of the page
+Quote Post
viking
post 4.12.2013, 16:40:56
Post #5





Grupa: Zarejestrowani
Postów: 6 378
Pomógł: 1116
Dołączył: 30.08.2006

Ostrzeżenie: (0%)
-----


Ale w sumie masz to dokładnie opisane w dokumentacji http://docs.phalconphp.com/en/latest/refer...-between-models więc jaki jest problem? Skoro już wykorzystujesz jakiś FW to w pierwszej kolejności postaraj się szukać rozwiązań dla niego specyficznych.


--------------------
Go to the top of the page
+Quote Post
WebCM
post 5.12.2013, 01:52:49
Post #6





Grupa: Zarejestrowani
Postów: 375
Pomógł: 20
Dołączył: 28.07.2006

Ostrzeżenie: (0%)
-----


W Doctrine i ORM-ach w Javie klucze obce są mapowane na obiekty:
  1. public class Aktor
  2. {
  3. private int ID;
  4. private String imie;
  5. private Film film; //uprośćmy, że aktor gra tylko w 1 filmie
  6. }
  7.  
  8. //Do ID filmu odwołujemy się tak
  9. aktor.getFilm().getID()
  10.  
  11. //Ostatecznie z publicznymi polami
  12. aktor.film.ID

Prawda, że proste? Twórcy Phalcona obrali inną ścieżkę. Czy właściwą? Pole film otrzyma ID powiązanego rekordu zamiast obiektu klasy Film. W przykładach nazwy tabel i klas są w liczbie mnogiej. Najlepiej pokażę do na przykładach:
  1. $aktor = Aktorzy::findFirst($id);
  2. $nazwa_filmu = $aktor->filmy->nazwa; //filmy - nazwa klasy
  3. $id_filmu = $aktor->film_id; //film_id - nazwa kolumny w tabeli
  4. $id_filmu = $aktor->film; //a jak sobie nazwiemy tak kolumnę
Nie trzeba żadnych adnotacji i plików konfiguracyjnych. Wystarczy tylko ustawić wirtualne klucze obce, bo tego Phalcon sam nie odczyta z bazy. Oczywiście wszystko możemy zmienić po swojemu, a nawet dodać aliasy dla nazw pól i relacji. Tu powstają pytania:

1. Czy w porządnym ORM potrzebujemy pól z ID powiązanych rekordów?
2. Czy z tego powodu zmieniać nazwy kolumn z "film" na "filmId" lub "film_id"?


--------------------
„Jesteśmy różni, pochodzimy z różnych stron Polski, mamy różne zainteresowania, ale łączy nas jeden cel. Cel ten to Ojczyna, dla której chcemy żyć i pracować.” Roman Dmowski
Go to the top of the page
+Quote Post
Crozin
post 5.12.2013, 08:10:50
Post #7





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Nie, nie potrzebujemy. Wręcz nie powinniśmy się zajmować tym jak powiązane są ze sobą obiekty w naszej hierarchii. Klucze obce to wewnętrzny mechanizm bazy danych, który nie powinien być odzwierciedlony w modelu obiektowym. Co innego ID pojedynczego obiektu - to już jest zwykła właściwość obiektu.

W Doctrine, które bardzo, bardzo mocno bazuje na JPA (Java) stosuje się model DataMapper oraz kieruje się zasadą, którą nazwałbym "pierwszeństwem modelu obiektowego, nad bazodanowym". IMHO jak do tej pory, najlepsze rozwiązanie jakie wymyślono w kwestii ORM-ów.
Go to the top of the page
+Quote Post
WebCM
post 7.12.2013, 14:10:50
Post #8





Grupa: Zarejestrowani
Postów: 375
Pomógł: 20
Dołączył: 28.07.2006

Ostrzeżenie: (0%)
-----


Phalcon jest podatny na SQL Injection w ograniczonym zakresie. Przykład:
  1. //localhost/kontroler/akcja/1=1
  2. public function akcjaAction($id)
  3. {
  4. $user = User::findFirst($id);
  5. }

Rozwiązania tego problemu:

1. Sprawdzać, czy $id zawiera cyfry - ctype_digit
2. Ręcznie ustawić ścieżki w klasie Router, aby parametr zawierał tylko cyfry
3. Napisać własne metody typu User::getById($id) i tam zadbać o bezpieczeństwo


--------------------
„Jesteśmy różni, pochodzimy z różnych stron Polski, mamy różne zainteresowania, ale łączy nas jeden cel. Cel ten to Ojczyna, dla której chcemy żyć i pracować.” Roman Dmowski
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 23.06.2025 - 01:30