mmofacts.com

"mappie": buhrmi's ORM in PHP

gepostet vor 14 Jahre, 10 Monate von buhrmi

Jaja als würde es nicht schon genug ORMs geben möchte ich demnächst mal meine eigene in die Menge werfen.

Bei uns auf der Arbeit darf man sich die Programmiersprache die man verwenden möchte leider noch nicht aussuchen. Und darum dieses Projekt. Es heißt mappie und soll alles was mich an doctrine stört abschaffen und wegrationalisieren. Und ein paar neue Features von PHP 5.3 abusen und vergewaltigen.

Hier gibt's schonmal ein kleines Tutorial zur Benutzung: http://wiki.github.com/buhrmi/mappie

Bin erstmal an Kritik oder evtl. Problemen der API interessiert, bzw. alles was nicht selbsterklärend ist (was eine gute API eben sein sollte). Nach einiger Zeit fallen einem Problemfälle ja immer seltener auf. Wenn ihr es gut findet dürft ihr das selbstverständlich auch schreiben :p

Ahjoa, was mich auch brennend interessieren würde sind API Vorschläge für joins und tabellenübergreifende queries.

gepostet vor 14 Jahre, 10 Monate von Redrick

ich nehme mir nie viel zeit um mich in all die "grossartigen" und "scheinbar unverzichtbaren" programmiersprachen , apis, frameworks oder was auch immer reinzulesen -  ich mag den "kranken" hype nicht, der oftmals um diese herum gemacht wird. Diesmal habe ich versucht, die Inhalte deiner URL durchzulesen und zu verstehen und rate mal was passiert ist.

Ab der Zeile mit

$family = $user->getFamily();
# SELECT * FROM family where (family_id = 1337)

war bei mir schluss mit intuitiv. Das grösste Problem dabei: viel Selbstfplege, wenig Hilfe für Einsteiger. Jeder normale Mensch dürfte sich fragen, woher dein Mappie die family_id 1337 her hat. Natürlich kann man es sich mit etwas Anstrengung denken dass diese vermutlich aus dem User-record stammt, aber ist es vertändlich erklärt? - NEIN! Dabei die Frage: wenn du schon mit Extensions der beiden erwähnten Tabellen arbeitest, dann stelle die auch bitte vor.

$users = $family->getAllUser();
# this code does not execute a query

alles fein, aber ist es intuitiv? grösste frage für mich und viele andere dürfte dabei sein: warum hier auf einmal  keine Query läuft. Grob abstrakt ist alles klar und dirgendwann, 4 verwirrende Beispiele später erbarmst du dich auch und sagst endlich : "Note that the query is only executed as soon as we start to iterate over the records". Aber ist es simpel und intuitiv?

Für wen? Für dich? Für mich? Für Milka-Kuh? Gerade  in dem DB-Thead von blackscorp,bei all dem Fachgequasel ist euch vermutlich garnicht aufgefallen, was das eigentliche Problem ist. Ein "Profi" ist oftmals zu sehr "Profi" um irgendwelchen Lösungen anderer "Profies" beachtung zu schenken und  alle anderen sind gerade auf vernünftige Dokumentation angewiesen, damit überhaupt Interesse zündet.

Andere irritieren/verwirren ist keine grosse Kunst, das kann jeder x-beliebige Textgenerator sicherlich besser und damit ersthaft angeben ist geradezu lächerlich ("alles was nicht selbsterklärend ist (was eine gute API eben sein sollte").

Doku-note: 5-

gepostet vor 14 Jahre, 10 Monate von buhrmi

OK OK. Der Wiki Text ist wirklich nicht als ernste SQL-Anfänger-Dokumentation gedacht und eher für jemanden formuliert, der von Propel, Doctrine, ActiveRecord o.Ä. kommt, diese Standard-ORM APIs bereits kennt, und einen Vergleich hat.

gepostet vor 14 Jahre, 10 Monate von Redrick

warum sql anfänger doc? ich hab die dreistigkeit zu behaupten, dass kein sql anfänger bin  und davon abgesehen, sollte doch in eigenem interesse sein möglichst viele leute anzusprechen. ich will nicht darüber urteilen ob dein ansatz gut oder schlecht ist, viel eher ist es die art die dinge anzupreisen ohne dass aussenstehende es durch die z.b. doku selbst einschätzen können

gepostet vor 14 Jahre, 10 Monate von buhrmi

Ja schon, aber dennoch ohne Kenntnisse anderer populärer Datenbank Frameworks. Die Kritik an schlechter / nicht vorhandenen Doku und Art des Anpreisens ist jedenfalls angekommen.

gepostet vor 14 Jahre, 10 Monate von Nuky

Wie kommst du auf die Idee uns was gratis anzubieten und dann nichtmal richtig zu dokumentieren. Nu hör mal.

gepostet vor 14 Jahre, 10 Monate von Redrick

Original von buhrmi

Ja schon, aber dennoch ohne Kenntnisse anderer populärer Datenbank Frameworks.

das stimmt allerdings auch, aber stell dir mal vor, wie geil es doch wäre, wenn alle ORM-verweigerer auf einmal  deinen mappie nutzen würden, weil er so geil ist und total simpel erklärt ist und man sofort sieht, wie scheisse das programmierleben davor war. Dann könntest sogar blumen bekommen von heimlichen verehrern. Wenn das nicht die motivation ist!

gepostet vor 14 Jahre, 10 Monate von BlackScorp

also ich habe es mir mal angeschaut und irgendwie verstehe ich das so ganz. anscheinend werden querys ausgeführt ohne dass ich mysql_query etc schreiben muss. aber wie kann ich ihm sagen welche tabelle angesrochen werden soll? zb:

SQL:

$user = User::one(1);
# SELECT * FROM user where (user_id = 1)

 was wenn meine tabelle nicht user heist sondern accounts?

gepostet vor 14 Jahre, 10 Monate von buhrmi

Also wenn sich hier eine willige hübsche Schwarzhaarige oder Blonde offenbart die mir dann Blumen schickt, werde ich eine ORM-Agnostiker-geprüfte Dokumentation verfassen ;)

gepostet vor 14 Jahre, 10 Monate von buhrmi

Original von BlackScorp

 was wenn meine tabelle nicht user heist sondern accounts?

Hey. Das heißt "Convention over Configuration". Per Konvention muss die Klasse "User" auch in der Tabelle "user" gespeichert sein. Man kann für einzelne Klassen auch andere Tabellennamen konfigurieren, doch das steht da nicht.

gepostet vor 14 Jahre, 10 Monate von BlackScorp

achso dann muss ja erstmal alle klassen auf meine datenbank anpassen befor ich irgendwas aus db holen kann?

btw: eventuell ist mein DB Handler dingens(kann es nicht richtig zuordnen) einfacher für anfänger like me:

http://pastebin.com/m198e0d02

benutzung:

PHP:

require_once 'DataBase.class.php';
DataBase::connect('localhost','root','foo','bar'); // diese zeile kann man auch in config.php einfügen und in irgend einer
//datei includen die verbindung bleibt immer bestehen
$db = new DataBase();
$query = "SELECT * FROM user WHERE id=%d";
foreach($db->sql($query,1) as $row)
{
$id = $row['id'];
$username = $row['username'];
$email = $row['email'];
//etc...
}
// weiter sql befehle ausführen ohne neue instanz möglich
$query = "INSERT INTO user(username,password,email) VALUES('%s','%s','%s')";
if($db->sql($query,'testuser',md5('testpw'),'[email protected]')){
echo "Benutzer erfolgreich eingetragen";
}else{
echo "Benutzer konnte nicht eingetragen werden";
}

 MFG

gepostet vor 14 Jahre, 10 Monate von buhrmi

Jau, entweder das, oder man hält sich schon beim datenbank designen an die konventionen. aber das ist bei allen populären frameworks so

gepostet vor 14 Jahre, 10 Monate von Redrick

Original von buhrmi

Also wenn sich hier eine willige hübsche Schwarzhaarige oder Blonde offenbart die mir dann Blumen schickt, werde ich eine ORM-Agnostiker-geprüfte Dokumentation verfassen ;)

stehst du auf bestimmte blumen / farben / düfte?

gepostet vor 14 Jahre, 10 Monate von buhrmi

Ich bin ein Mann.

gepostet vor 14 Jahre, 10 Monate von knalli

Original von BlackScorp

also ich habe es mir mal angeschaut und irgendwie verstehe ich das so ganz. anscheinend werden querys ausgeführt ohne dass ich mysql_query etc schreiben muss. aber wie kann ich ihm sagen welche tabelle angesrochen werden soll? zb:

SQL:

$user = User::one(1);
# SELECT * FROM user where (user_id = 1)

 was wenn meine tabelle nicht user heist sondern accounts?

 Dann schreibe Account::one(1)?

CoC (Convention over Configuration) ist ein Bestandteil der RDF (Rapid Development Frameworks) und als solches zwar eingrenzend, dafür aber eben logisch und intuitiv nutzbar. Wenn nämlich klar ist, welche Tabelle in einer Assoziation als erstes kommt, wenn klar ist wie der Spaltenname heißt.. wird vieles einfacher.  Dabei Frage an buhrmi: Wieso heißt die Menge der Entität User folgerichtig nicht users, sondern nur user? Definierst du als per Standard im Singular?

Ich weiß nicht wie buhrmi es hält, bei anderen Frameworks lässt sich alles umkonfigurieren. Vorteil: Man kann das vorhandene Schema nutzen. Nachteil: Die Wartbarkeit explodiert.

 Für wen? Für dich? Für mich? Für Milka-Kuh? Gerade  in dem DB-Thead von blackscorp,bei all dem Fachgequasel ist euch vermutlich garnicht aufgefallen, was das eigentliche Problem ist. Ein "Profi" ist oftmals zu sehr "Profi" um irgendwelchen Lösungen anderer "Profies" beachtung zu schenken und  alle anderen sind gerade auf vernünftige Dokumentation angewiesen, damit überhaupt Interesse zündet.

Ich verstehe und teile dein grundsätzlichen Ansatz, dass die Dokumentation ausführlicher sein und mehr ins Detail gehen sollte. Allerdings halte ich es fatal, einen SQL-Newbie an einen ORM ranzulassen. Nein sorry, etwas Verständnis muss da sein! Man braucht evtl. nicht das Fachwissen über alle Arten des Joins, GroupBy & Co. Aber man sollte einigermaßen wissen, wie die relationale Algebra dahinter in etwa aussieht. Ansonsten sieht man sich in ein paar Wochen wieder: Warum ist meine Applikation so langsam, wenn ich mit findAll()+loop arbeite?

gepostet vor 14 Jahre, 10 Monate von buhrmi

Original von knalli

Dabei Frage an buhrmi: Wieso heißt die Menge der Entität User folgerichtig nicht users, sondern nur user? Definierst du als per Standard im Singular?

Jep.

z.B. in Propel beispielsweise treten so tolle sachen auf wie getNews (eine) getNewses (mehrere) ... Daher bei mir getNews und getAllNews

gepostet vor 14 Jahre, 10 Monate von knalli

Original von buhrmi

Original von knalli

Dabei Frage an buhrmi: Wieso heißt die Menge der Entität User folgerichtig nicht users, sondern nur user? Definierst du als per Standard im Singular?

Jep.

z.B. in Propel beispielsweise treten so tolle sachen auf wie getNews (eine) getNewses (mehrere) ... Daher bei mir getNews und getAllNews

Das ist für mich aber keine Sache der Technik, oder  irgendeines (verkackten) Frameworks. Sondern eine Sache der Logik im Datenmodell. RoR/CakePHP/Groovy zeigen, dass die Pluralizer wohl funktionieren. Und für unbekannte Sonderfälle muss eben Hand angelegt werden, wobei "News" wohl ein bekannter sein würde. Meine Meinung, ganz klar :)

gepostet vor 14 Jahre, 10 Monate von buhrmi

In diesem Fall ist es eine Sache der Technik. Da alles konfigurationsfrei funktionieren soll. Der ORM kann z.B. nicht wissen ob getUsers() mehrer user sind oder eine Klasse namens "Users" ist. Probleme gibts dann wenn jemand seine Klasse "Alluser" nennt aber wayne ^^

gepostet vor 14 Jahre, 10 Monate von knalli

Eben deswegen erwähnte ich ja als Beispiel Rails und Co. Im unkonfigurierten Zustand _ist_ getUsers() also immer eine Mehrzahl von User. Was ja auch logisch ist. Alluser und Allusers.

Die Klasse Alluser ist auch kein Problem: Weil ich verstehe das so: allUser => all User, aber allAlluser => all Alluser, und AllUser ist mal was ganz anderes. Sonst ist das nicht sehr flexibel.

Ich wollte damit eigentlich nur den Unterschied aufzeigen, der eben zwischen diesem und den anderen Frameworks besteht. Und derzeit sehe ich auch nicht den Vorteil..

gepostet vor 14 Jahre, 10 Monate von buhrmi

Es geht technisch nicht. Der ORM kennt seine Klassen nicht. Rails dagegen schon.

Ein Aufruf von $user->getEmails() wäre zweideutig. Entweder es wird eine Klasse namens "Emails" gemeint, oder mehrere Instanzen der Klasse namens "Email". Wohingegen das Risiko der Zweideutigkeit bei der Variante $user->getAllEmail() vermindert wäre, da die Warscheinlichkeit dass eine Klasse mit "All[Großbuchstabe]" anfängt niedriger ist als dass eine auf "s" endet.

gepostet vor 14 Jahre, 10 Monate von knalli

Naja, wenn du streng CoC nimmst, dann ist das schon eindeutig. $user->getEmails() wären dann alle hasMany: Email-Objekte. Eine Klasse Emails könnte ja gar nicht existieren, weil die Konvention vorschriebe, dass es im Singular vorhanden sein muss*.

* Natürlich jetzt unter der Konvention, wie Rails und Co das machen (oben bereits beschrieben). CakePHP nutzt ein ähnliches Verfahren und sucht auch erst zur Laufzeit nach den Klassen (und meckert zurecht, wenn sie nicht da sind).

gepostet vor 14 Jahre, 10 Monate von buhrmi

Noch ein Beispiel für Scopes hinzugefügt.

Es folgt STI und Joins, und dann kommt der Source online und würde mich über ein paar Mitschreiber oder Ausprobierer freuen ;)

gepostet vor 14 Jahre, 10 Monate von buhrmi

STI ist fertig. Doku update. Comments, Lob, Kritik plx. Versinke hier in innerem Selbstlob

gepostet vor 14 Jahre, 10 Monate von Fobby

Ich find's sehr interessant, mach mal weiter ... ;)

Dass die Doku nicht idotproof ist, find ich nicht schlimm. In dem frühen Stadium geht es wohl eher um die Idee, Funktionalität und das Vermitteln warum mappie so f*cking cool ist. Ich werd auf jeden Fall weiter verfolgen, was du daraus machst :)

gepostet vor 14 Jahre, 10 Monate von Bloodredangel

Mir gefällt es soweit ganz gut. :) Aber ich kenn mich bei anderen ORM auch nicht aus in wie weit die gut optimieren / lazy sind. Ich hab zwar sogut wie garnicht mit Closures gearbeitet, aber find die schon sehr schick. Und deine Syntax ist wirklich nahe dran angelegt (zumindest das was ich bei Martin Fowler als Ruby-Beispiele gesehen habe).

gepostet vor 14 Jahre, 10 Monate von buhrmi

Thx ;-)

Der erste Ansatz für Join Queries und einer schicken API ging in die Hose und wurde mir auch von der Programmierung zu komplex/fragil. Ist schwieriger als gedacht.

Mein Ziel wäre etwas einfaches wie z.b.

User::all()->includeAll('group')->include('group.owner'), wobei "owner" wieder der Klasse user angehört. Ist mir jedoch zu spät aufgefallen dass so etwas ohne Konfiguration nicht möglich ist. Wird also wahrscheinlich etwas wie User::all('group.visible', true)->includeAllGroup()->includeUser('group.owner'), oder so ähnlich.

gepostet vor 14 Jahre, 10 Monate von Fobby

Eine Konfiguration schreibt man einmal. Queries hingegen gibt es viele - wäre es da nicht sinnvoller, dem Anwender etwas mehr Konfigurationsaufwand aufzubürden und im Gegenzug übersichtlichere Queries zu ermöglichen?

Nur so ein Gedanke.

gepostet vor 14 Jahre, 10 Monate von knalli

Der Sinn und Witz an der Sache ist ja, keine/kaum Queries zu schreiben!

gepostet vor 14 Jahre, 10 Monate von Fobby

Entschuldige, mit Query meinte ich den Vorgang, auf Daten zuzugreifen also z.B. User::all()->includeAll('group')->include('group.owner')

Und der Fokus sollte meines Erachtens einfach darauf liegen, dass jener Part möglichst kurz, prägnant und vor allem lesbar ist.

gepostet vor 14 Jahre, 10 Monate von buhrmi

Original von Fobby

Eine Konfiguration schreibt man einmal

Waah neeee.... Dann würde das Projekt an sich gar keinen Sinn machen, da eines der Hauptziele komplette Konfigurationsfreiheit ist.

Mit jedem neuen Feature, jeder futzelkleinen Änderung an der Datenbank passt man üblicherweise auch die Konfiguration, die Klassen, das Schema, whatever an. Alles davon soll weg, auch die noch so kleine Konfiguration. Wenn ich nun doch mit Konfigurationen anfangen würde, dann liegt das Gedankenmodell "ach, ich habe eh schon eine Konfiguration, pack ich die anderen Funktionen auch noch da rein" recht nahe und schwupps ist man wieder bei etwas was man nicht leiden kann.

gepostet vor 14 Jahre, 10 Monate von Bloodredangel

Ich denke aber auch nicht das beides geht. Also möglichst kurze Anfragen und gleichzeitig keine Konfiguration. Oder ist dir die Kürze nicht zwingend so wichtig?

Falls du beides unter einen Hut bekommen solltest: Umso besser. *g*

gepostet vor 14 Jahre, 10 Monate von buhrmi

Mein Dickschädel mag sich einfach nicht so recht um automatische joins, bzw. eine effiziente hydration mehrfacher joins herumbiegen. Da warte ich im Moment noch auf einen inneren Geistesblitz.

In der Zwischenzeit gibts daher ein anderes lecker feature und zwar multiple edits :o Unten ein kleines Kapitel in der Doku http://wiki.github.com/buhrmi/mappie

Auf diese Diskussion antworten