2013-05-23 16 views
8

Intoduction:MongoDB obiekt mapowanie (PHP) Problem

Jaka jest najlepsza praktyka budować mój class T obiektu, kiedy otrzyma on od MongoCursor::getNext()? O ile to działa, funkcja getNext() funkcji MongoCursor powraca z array. Chciałbym użyć wyniku z tego punktu jako object typu T.

Czy mogę napisać własny konstruktor dla typu T, który akceptuje numer array? Czy istnieje ogólne rozwiązanie tego problemu, na przykład gdy typ T extends G i G wykonuje zadanie jako zwykły sposób, rekurencyjnie (dla dokumentów zagnieżdżonych).

Jestem nowy w MongoDB i chciałbym stworzyć własny ogólny program odwzorowujący z ładnym interfejsem.

Bounty:

  • Jakie są możliwe podejścia, wzory i który pasuje do koncepcji MongoDB najbardziej z punktu widzenia PHP.
+0

Jeśli wyjaśnisz więcej o tym, jakiego rodzaju odpowiedzi chcesz, możemy prawdopodobnie zapewnić, to znaczy, że nie chcesz tego napisać, czego chcesz? – Sammaye

+0

Przedstawiono mi bardzo konstruktywne i użyteczne podejście, a ja już nauczyłem się wiele o waszej technice i wdrożeniu. Dziękuję za to! Ponadto, jestem otwarty na wszelkie inne podejście, które istnieje, jestem gotów to zobaczyć, jeśli istnieje. Próbuję zbadać wszystkie możliwości i wzorce tego problemu. – Dyin

Odpowiedz

3

Ta odpowiedź została przepisana.

Większość odwzorowań danych działa, reprezentując jeden obiekt na klasę lub "model" jest zwykle uformowanym terminem. Jeśli chcesz zezwolić na wiele akcesji za pośrednictwem pojedynczego obiektu (tj. $model->find()), jest on zwykle demagowany, aby metoda nie zwracała samej instancji, a zamiast niej tablicy MongoCursor żądnej ładowania klas w przestrzeń.

Taki paradygmat jest zwykle połączony z "Aktywnym zapisem". Jest to metoda, z której korzystają ORMy, ODM i frameworki w celu komunikacji z bazami danych w taki czy inny sposób, nie tylko w MongoDB, ale także w przypadku SQL i innych baz danych (Cassandra, CouchDB itp.).

Należy od razu zauważyć, że nawet jeśli aktywny rekord daje dużą moc, nie powinien być pokryty całą aplikacją. Są chwile, w których bezpośrednie korzystanie z sterownika byłoby bardziej korzystne. Większość ORMów, ODMów i frameworków zapewnia możliwość szybkiego i bezproblemowego dostępu bezpośrednio do sterownika z tego powodu.

Istnieje, jak można by rzec, brak mapera danych o niewielkiej wadze. Jeśli zamierzasz zamapować zwrócone dane na klasy, to zużyje zasoby, koniec. Zaletą tego jest moc, jaką otrzymujesz podczas manipulowania swoimi obiektami.

Rekord aktywny jest naprawdę dobry w dostarczaniu zdarzeń i wyzwalaczy z poziomu PHP.Dobrym przykładem jest ORM zrobiłem dla Yii: https://github.com/Sammaye/MongoYii może ona dostarczyć haki do:

  • afterConstruct
  • beforeFind
  • afterFind
  • beforeValidate
  • afterValidate
  • beforeSave
  • afterSave

Należy zauważyć, że jeśli chodzi o wydarzenia, takie jak beforeSave i afterSave MongoDB nie posiada wyzwalaczy (https://jira.mongodb.org/browse/SERVER-124), więc ma to sens, że aplikacja powinna zająć. Oprócz oczywistego powodu, dla którego aplikacja radzi sobie z tym zadaniem, znacznie lepiej radzi sobie z funkcjami składowania, ponieważ może wywoływać twoje natywne funkcje PHP, aby manipulować każdym dokumentem zapisanym przed dotknięciem bazy danych.

Większość odwzorowań danych działa przy użyciu własnej klasy CRUD w PHP, aby reprezentować ich również. Na przykład, aby utworzyć nowy rekord:

$d=new User(); 
$d->username='sammaye'; 
$d->save(); 

Jest to dość dobre podejście skoro stworzyć „nowe” (https://github.com/Sammaye/MongoYii/blob/master/EMongoDocument.php#L46 pokazuje, jak przygotować się do nowego rekordu w MongoYii) klasę, aby „nowy” rekord. Jest to rodzaj dość ładnie semantycznie.

Funkcje aktualizacji są zwykle dostępne poprzez funkcje odczytu, nie można aktualizować modelu, o którym nie wiesz. Prowadzi nas to do kolejnego etapu zapełniania modeli.

Aby obsłużyć zapełnianie modelu różnych ORMów, ODM i frameworki zatwierdzają różne metody. Na przykład moje rozszerzenie MongoYii używa fabrycznej metody o nazwie model w każdej klasie, aby przywrócić nową instancję samego siebie, dzięki czemu mogę nazwać dynamiczne find i findOne i inne podobne metody.

Niektóre ORMy, ODM i frameworki udostępniają funkcje odczytu jako bezpośrednie funkcje static, czyniąc je własnymi metodami fabrycznymi, podczas gdy niektóre używają wzorca singleton, jednak nie wybrałem (https://stackoverflow.com/a/4596323/383478).

Większość, jeśli nie wszystkie, zaimplementować jakąś formę kursora. Służy do zwracania wielokrotności modeli i bezpośrednio owija (zwykle) MongoCursor, aby zastąpić metodę current(), zwracając wstępnie wypełniony model.

Na przykład wywołanie:

User::model()->find(); 

zwróci EMongoCursor (w MongoYii), które następnie sotre fakt, że klasa User został użyty do wystąpienia kursor i po nazwie jak:

foreach(User::model() as $k=>$v){ 
    var_dump($v); 
} 

Wywołanie metody current() tutaj: https://github.com/Sammaye/MongoYii/blob/master/EMongoCursor.php#L102 zwrócenie nowej pojedynczej instancji modelu.

Istnieje kilka ORMów, ODMów i frameworków, które implementują szybkie ładowanie macierzy.Oznacza to, że po prostu załadują cały wynik prosto do pamięci RAM jako zestaw modeli. Osobiście nie podoba mi się to podejście, jest marnotrawstwem, a także nie wróży dobrze, gdy trzeba użyć rekordu aktywnego w przypadku większych aktualizacji z powodu dodania nowych funkcji w miejscach, które wymagają dodania do starych rekordów.

Jednym z ostatnich tematów, zanim przejdę dalej, jest bezzasadna natura MongoDB. Problem z używaniem klas PHP w MongoDB polega na tym, że chcesz mieć wszystkie funkcje PHP, ale ze zmienną naturą MongoDB. Łatwo to przekroczyć w SQL, ponieważ ma predefiniowany schemat, po prostu zapytanie o to i wykonane zadania; jednak MongoDB nie ma czegoś takiego.

To sprawia, że ​​obsługa schematów w MongoDB jest dość niebezpieczna. Większość ORM, ODM i frameworków wymaga wcześniejszego zdefiniowania schematu w miejscu (to jest Doctrine 2) przy użyciu zmiennych private przy pomocy metod get i set. W MongoYii, aby moje życie stało się łatwe i eleganckie, postanowiłem zachować naturę bezochronną MongoDB za pomocą magii, która wykrywa (https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L26 jest moją __get i https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L47 jest moją __set), jeśli właściwość była niedostępna w klasie, jeśli pole było w polu wewnętrzna tablica _attributes, a jeśli nie, to po prostu zwróć null. Podobnie, dla ustawienia atrybutu ustawiłbym po prostu zmienną intrernal _attributes.

Co do czynienia z jak przypisać ten schemat zostawiłem zadanie wewnętrznego września użytkownikowi jednak do czynienia z ustawienie właściwości z form itp użyłem zasady walidacji (https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L236) wywołanie funkcji o nazwie getSafeAttributeNames() która zwraca listę atrybutów który miał zasady walidacji przeciwko nim. Jeśli nie mają reguł sprawdzania poprawności, te atrybuty, które istniały w przychodzącej tablicy $_POST lub $_GET, nie zostaną ustawione. Dało to możliwość stworzenia schematu, a jednocześnie bezpiecznej struktury modelu.

Tak więc omówiliśmy, jak właściwie używać dokumentu głównego, a także zapytać, w jaki sposób program odwzorowujący dane obsługuje pod-dokumenty. Doctrine 2 i wiele innych udostępnia dokumenty subdomenowe oparte na pełnej klasy (http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/embedded-mapping.html), ale może to być niezwykle zaradne. Zamiast tego zdecydowałem, że udostępnię funkcje pomocnicze, które pozwolą na elastyczne wykorzystanie poddokumentów bez chęci załadowania ich do modeli i tak pochłaniającej pamięci RAM. Zasadniczo to, co zrobiłem, to pozostawić je, ponieważ zapewniają walidację (https://github.com/Sammaye/MongoYii/blob/master/validators/ESubdocumentValidator.php) do sprawdzania poprawności wewnątrz nich. Oczywiście walidator sam się odradza, więc jeśli miałbyś regułę w walidatorze, która używałaby walidatora ponownie do wydania walidacji zagnieżdżonego poddokumentu, to działałoby.

Więc myślę, że, która kończy bardzo podstawową dyskusję na temat ORM-ów, ODM-ów i frameworków, używają maperów danych. Oczywiście prawdopodobnie mógłbym napisać cały esej na ten temat, ale jest to wystarczająco dobra dyskusja na minutę, w którą wierzę.

+0

Jeśli rozszerzasz 'MongoCursor', niż' EMongoCursor', dlaczego 'nie rozszerzasz' go? Co to jest '$ this-> partial' w' getNext() '? Co sądzisz o tym podejściu, kiedy dajesz prawo do "T" do rzeczywistej komunikacji z bazą danych, na przykład: '$ t-> update()'? – Dyin

+0

@Dyin Zaleca się, aby nie rozszerzać obiektu c MongoCursor, zawsze powoduje to, że złe rzeczy pojawiają się na twojej drodze. '$ this-> partial' jest błędem, w rzeczywistości jest on pobierany z mojego Yii ORM i zmodyfikowany tak, aby był niezależny.Jeśli chodzi o komunikację 'T', domyślnie implementuję aktywny rekord Yii, jeśli rozumiesz, to jest baza kodu: https://github.com/Sammaye/MongoYii i tutaj jest bardziej ogólna: https : //github.com/Sammaye/mongoglue – Sammaye

+0

Czy możesz poprawić odpowiedzi, dodając uwagi dotyczące decyzji dotyczących tego projektu i podejścia? Czy jest to lekka wersja wzorca Mapowania Danych? Może więcej przykładów użycia byłoby miło, aby lepiej zrozumieć twoje podejście. – Dyin