2013-05-23 12 views
8

Intoduction Problem:MongoDB Objektzuordnung (PHP)

Was ist die beste Praxis meines class T Objekt zu bauen, wenn ich es von einem MongoCursor::getNext() erhalten? Soweit es geht, Funktion eines MongoCursor kehrt mit einem array zurück. Ich möchte das Ergebnis von diesem Punkt als object vom Typ T verwenden.

Sollte ich einen eigenen Konstruktor für den Typ T schreiben, der eine array akzeptiert? Gibt es eine generische Lösung, zum Beispiel, wenn der Typ T extends G und G den Job als regulären Weg, rekursiv (für verschachtelte Dokumente).

Ich bin neu in MongoDB, und ich möchte meinen eigenen generischen Mapper mit einer netten Schnittstelle bauen.

Bounty:

  • , die die möglichen Ansätze, Muster sind und die würde das Konzept der MongoDB passen die aus der Sicht von PHP.
+0

Wenn Sie mehr darüber erklären, welche Art von Antwort Sie wollen, können wir Ihnen wahrscheinlich eine zur Verfügung stellen, ich meine kurz, es für Sie zu kodieren, was Sie wollen? – Sammaye

+0

Sie haben einen sehr konstruktiven und nützlichen Ansatz für mich, und ich habe bereits viel über Ihre Technik und Implementierung gelernt. Danke für das! Auch bin ich für jeden anderen Ansatz offen, der da draußen ist, ich bin bereit, es zu sehen, wenn es existiert. Ich versuche, alle Möglichkeiten und Muster dieses Problems zu erforschen. – Dyin

Antwort

3

Diese Antwort wurde umgeschrieben.

Die meisten Data Mapper arbeiten, indem sie ein Objekt pro Klasse oder "Modell" darstellen, normalerweise der geprägte Begriff. Wenn Sie mehrere Zugriffe durch ein einzelnes Objekt zulassen möchten (d. H. $model->find()), wird es normalerweise demediert, so dass die Methode nicht tatsächlich eine Instanz von sich selbst, sondern stattdessen die eines Arrays oder einer MongoCursor geladenen Klassen in den Raum zurückgibt.

Ein solches Paradigma ist normalerweise mit "Active Record" verbunden. Dies ist die Methode, die ORMs, ODMs und Frameworks verwenden, um mit Datenbanken auf die eine oder andere Weise zu kommunizieren, nicht nur für MongoDB, sondern auch für SQL und andere mögliche Datenbanken (Cassandra, CouchDB usw.).

Es sollte sofort bemerkt werden, dass obwohl aktive Aufzeichnung viel Macht gibt, sollte es nicht über die gesamte Anwendung ausgeblendet werden. Es gibt Zeiten, in denen die direkte Verwendung des Treibers vorteilhafter wäre. Die meisten ORMs, ODMs und Frameworks bieten die Möglichkeit, aus diesem Grund schnell und mühelos auf den Treiber zuzugreifen.

Es gibt, wie viele sagen würden, keinen leichten Mapper. Wenn Sie die zurückgegebenen Daten den Klassen zuordnen, werden Ende des Monats Ressourcen verbraucht. Der Vorteil dabei ist die Kraft, die Sie erhalten, wenn Sie Ihre Objekte manipulieren.

Active Record ist wirklich gut in der Lage, Ereignisse und Trigger innerhalb von PHP bereitzustellen.Ein gutes Beispiel ist das eines ORM ich für Yü gemacht: https://github.com/Sammaye/MongoYii es Haken für zur Verfügung stellen kann:

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

Es sollte beachtet werden, dass, wenn es um Veranstaltungen wie beforeSave und afterSave kommt MongoDB nicht besitzt Trigger (https://jira.mongodb.org/browse/SERVER-124), so ist es sinnvoll, dass die Anwendung damit umgehen sollte. Zusätzlich zu dem offensichtlichen Grund für die Anwendung, dies zu handhaben, macht es auch eine viel bessere Handhabung der Speicherfunktionen, indem es in der Lage ist, Ihre nativen PHP-Funktionen aufzurufen, jedes gespeicherte Dokument zu manipulieren, bevor die Datenbank berührt wird.

Die meisten Data Mapper arbeiten mit der eigenen Klasse CRUD von PHP, um auch diese darzustellen. Zum Beispiel einen neuen Datensatz zu erstellen:

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

Dies ist ein recht guter Ansatz, da Sie eine „neue“ erstellen (https://github.com/Sammaye/MongoYii/blob/master/EMongoDocument.php#L46 zeigt, wie ich für einen neuen Datensatz in MongoYii vorbereiten) Klasse eine „neue“ Platte zu machen. Es passt ziemlich gut semantisch.

Auf die Update-Funktionen wird normalerweise über Lesefunktionen zugegriffen. Sie können ein Modell, von dem Sie nicht wissen, dass es existiert, nicht aktualisieren. Dies bringt uns auf den nächsten Schritt der Bestückung von Modellen.

Um mit dem Auffüllen eines Modells zu arbeiten, verpflichten sich verschiedene ORMs, ODMs und Frameworks zu verschiedenen Methoden. Zum Beispiel verwendet meine MongoYii-Erweiterung eine Factory-Methode namens model in jeder Klasse, um eine neue Instanz von sich zurückzuholen, so dass ich die dynamischen find und findOne und andere solche Methoden aufrufen kann.

Einige ORMs, ODMs und Frameworks stellen die Lesefunktionen als direkte static-Funktionen zur Verfügung, die sie selbst zu Factory-Methoden machen, während einige das Singleton-Muster verwenden, ich jedoch nicht (https://stackoverflow.com/a/4596323/383478).

Die meisten, wenn nicht alle, implementieren irgendeine Form des Cursors. Dies wird verwendet, um ein Vielfaches der Modelle zurückzugeben, und umschließt (normalerweise) die MongoCursor direkt, um die current()-Methode durch die Rückgabe eines vorbelegten Modells zu ersetzen.

Zum Beispiel ruft:

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

Würde ein EMongoCursor (in MongoYii) zurück, die würden dann sotre die Tatsache, dass die Klasse User verwendet wurde, um den Cursor und wenn wie genannt zu instanziiert:

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

Rufen Sie die current() Methode hier: https://github.com/Sammaye/MongoYii/blob/master/EMongoCursor.php#L102, die eine neue einzelne Instanz des Modells zurückgibt.

Es gibt einige ORMs, ODMs und Frameworks, die das Laden von Early-Arrays implementieren.Das bedeutet, dass sie das gesamte Ergebnis direkt als eine Reihe von Modellen in Ihren Arbeitsspeicher laden. Ich persönlich mag diesen Ansatz nicht, er ist verschwenderisch und verheißt nichts Gutes, wenn Sie für größere Updates Active Records verwenden müssen, weil Sie an Orten, an denen alte Datensätze hinzugefügt werden müssen, neue Funktionen hinzufügen.

Ein letztes Thema, bevor ich fortfahre, ist die schemalose Natur von MongoDB. Das Problem bei der Verwendung von PHP-Klassen mit MongoDB ist, dass Sie alle Funktionen von PHP, aber mit der variablen Natur von MongoDB haben wollen. Dies ist in SQL leicht zu überwinden, da es ein vordefiniertes Schema hat, das Sie einfach abfragen und Jobs erledigen. MongoDB hat jedoch keine solche Sache.

Dies macht die Schema-Handhabung in MongoDB ziemlich gefährlich. Die meisten ORMs, ODMs und Frameworks verlangen, dass Sie das Schema im Spot (d. H. Doctrine 2) vordefinieren, indem Sie private Variablen mit den Methoden get und set verwenden. In MongoYii, um mein Leben einfach und elegant zu machen, beschloss ich, MongoDBs schemaless Natur durch die Verwendung von Zaubern zu behalten, die (https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L26 ist mein __get und https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L47 ist mein __set), wenn das Eigentum wa in der Klasse unzugänglich wäre, wenn das Feld war eine interne _attributes Array und wenn nicht, dann einfach zurück null. Ebenso würde ich für die Einstellung eines Attributs nur die interne Variable _attributes setzen.

Wie für den Umgang mit, wie dieses Schema zuweisen ich jedoch bis zu dem Benutzer interne Zuordnung links, zu behandeln Eigenschaften von Formen Einstellung etc ich die Validierungsregeln (https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L236) eine Funktion namens getSafeAttributeNames() Aufruf, die eine Liste von Attributen zurückkehren die Validierungsregeln gegen sie hatten. Wenn sie keine Validierungsregeln hätten, würden diese Attribute, die im eingehenden $_POST oder $_GET Array existierten, nicht gesetzt werden. Dies ermöglichte eine Schema- und dennoch sichere Modellstruktur.

So haben wir behandelt, wie Sie tatsächlich das Stammdokument verwenden, fragen Sie auch, wie Data Mapper Subdokumente behandeln. Lehre 2 und viele andere bieten vollständige klassenbasierte Filialdokumente (http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/embedded-mapping.html), aber dies kann sehr einfallsreich sein. Stattdessen entschied ich, dass ich Hilfsfunktionen bereitstellen würde, die eine flexible Verwendung von Filialdokumenten ermöglichen würden, ohne sie eifrig in Modelle zu laden und so RAM zu verbrauchen. Im Grunde genommen habe ich sie verlassen, da sie einen Validator (https://github.com/Sammaye/MongoYii/blob/master/validators/ESubdocumentValidator.php) zur Validierung innerhalb von ihnen bieten. Natürlich erzeugt der Validator selbst. Wenn Sie also eine Regel im Validator haben, die den Validator erneut verwendet, um eine Überprüfung eines verschachtelten Filialdokuments zu veranlassen, würde es funktionieren.

Also ich denke,, die eine sehr grundlegende Diskussion von ORMs abgeschlossen, ODMs und Frameworks verwenden Data Mapper. Natürlich könnte ich wahrscheinlich einen ganzen Essay darüber schreiben, aber das ist eine gute Diskussion für die Minute, glaube ich.

+0

Wenn Sie den "MongoCursor" erweitern, dann den "EMongoCursor", warum "verlängert" er das nicht? Was ist '$ this-> partially' in' getNext() '? Was halten Sie von diesem Ansatz, wenn Sie "T" das Recht geben, tatsächlich mit der Datenbank zu kommunizieren, zum Beispiel: '$ t-> update()'? – Dyin

+0

@Dyin Ich würde Ihnen dringend empfehlen, das c-Objekt des MongoCursor nicht zu erweitern, es führt immer dazu, dass schlechte Dinge auf Ihrem Weg kommen. '$ this -> partially 'ist ein Fehler, dieser wird tatsächlich von meinem Yii ORM übernommen und modifiziert um eigenständig zu sein.Wie für "T" kommunizieren, ich tatsächlich implementieren aktiven Datensatz für Yii standardmäßig, wenn Sie es verstehen, hier ist die Codebasis: https://github.com/Sammaye/MongoYii und hier ist eine, die generischer ist: https : //github.com/Sammaye/mongoglue – Sammaye

+0

Könnten Sie bitte Ihre Antwort verbessern, indem Sie Anmerkungen zu den Entscheidungen dieses Designs und Ansatzes hinzufügen? Ist dies eine Lightweight-Version eines Data Mapper-Musters? Vielleicht wären mehr Anwendungsbeispiele hilfreich, um Ihren Ansatz besser zu verstehen. – Dyin