Es gibt viele Code-Styling Presets die man einfach in PHPStorm einstellen kann, wie PSR-2 für PHP. Für JavaScript gibt es da wenige und z.B. Prettier wird auch erstmal via NPM installiert.
Dann kann das Problem kommen, dass man Node nicht unter Windows laufen lässt sondern in WSL. Aber da hat PHPStorm zum Glück eine eine fertige Framework-Integration für.
Damit kann Prettier auch für die normale Reformatierung von PHPStorm mit JS-Dateien ausgewählt werden.
Ich hab cJSv2 jetzt soweit erweitert, dass man nun sich einfach in verschiedene Services in seine Controller injecten lassen kann (und ist dann unter seinem Namen oder einem Alias dort direkt aufrufbar). Jeder Service ist Singleton, so dass jeder Controller auf die selbe Instance des Services zugreift.
An sich wird damit die cjsGetController Methode, mit der sich Controller untereinander mit ihren Namen konnten, überflüssig und man kann einfach asynchrone/reactive Lösungen basteln.
Hier erst einmal ein kleines synchrones Event-System:
Nach vielen vielen Monden habe ich es am Ende doch mal fertig gebracht mein altes Zeiterfassung-Projekt bei Github hoch zu laden. Wobei das komplizierteste noch war das Framework "hübsch" zu machen. Das Modul ist jetzt auch mehrsprachig.
Frameworks gelten ganz ganz oft als etwas sehr kompliziertes und mächtiges Werkzeug, das nur von wenigen auserwählten entwickelt und designed wird. Wenn ein Framework etwas nicht kann wird es meistens so hingenommen und darauf gehofft, dass es vielleicht doch noch irgendwann mal eingebaut wird. Meistens würde man sich nie trauen, sich dabei einzubringen oder einzumischen.
Man selbst ist ja einfacher "Anwender" und wie die eigenen Anwender, die das eigene Programm nutzen, das wieder das Framework nutzt, sollte man sich nicht die Dinge einmischen, von denen man keine Ahnung hat.
Ich habe über die Jahre doch ein paar Frameworks gebaut. Gute, schlechte, noch schlechtere und auch welche, die durch die allgemeine Frameworks ersetzt wurden. Auch mal ein Bugfix für ein vorhandenes Framework war dabei.
Wichtig ist dabei, dass man sich klar wird, dass Frameworks im Kern meistens alles andere als hoch komplex sind. Das würde schon dem
Zweck des Frameworks widersprechen, das ja für möglichst viele Anwendungszwecke funktionieren soll. Der Core ist meistens sehr einfach und klar strukturiert. Komplexität kommt meistens über Zusatzfunkionen rein, die wieder rum nur die Kernfunktionen bedienen. Wenn diese Kernfunktionen gemischt werden und kann es am Anfang sehr unübersichtlich erscheinen, weil teilweise nicht ganz klar ist, was wofür da ist.
Bei React mit Hooks kann selbst das Mischen von useState und useEffect teilweise kompliziert sein, weil aus der Sicht des Entwicklers vielleicht, von diesen Funktionen was anderes Erwartet wird, als im Framework-Kern damit wirklich erreicht wird.
Frameworks machen keine Zauberrei aber dafür sehr viel Referenz-Verwaltung. Meiner Erfahrung nach beschäftigt man sich im Framework-Kern zu 75% allein damit Instanzen und Referenzen zu erzeugen und zu verwalten.
Um das ganze etwas zu verdeutlichen habe ich mich einmal hingesetzt und in unter einer Stunde (hatte ich mir auch so vorgegeben) ein kleines Framework gebaut, das useState und useEffect reimplementiert und zeigt, wie man das Verhalten dieser Funktionen nutzt, aber auch, welche Funktion für das Framework wirklich dahinter steckt. Weil am Ende kommt man zu meist immer zu selben Strukturen, die bei allen Frameworks immer nur etwas anders benannt und implementiert sind.
Irgendwann fängt man an aus seinem großen Framework einzelne kleine Module heraus lösen zu wollen. Die will man dann als Composer-Requirements wieder einbinden. Zum Glück geht das sehr einfach, indem man einfach ein Repository zu seiner composer.json hinzufügt:
Was man in Java teilweise mit Javassist gemacht hat und man für die Erkennung von Änderungen an Object-Values in JavaScript dringend braucht sind Proxy-Objekte.
Das geht zum Glück an sich ganz einfach.
<html>
<head>
<script type="text/javascript">
var x = {value: ""};
Die Überarbeitung meines CMS-Frameworks läuft gut. Optional gibt es auch schon ein parallax-scrolling Modul, das Subpages direkt unter der eigentlichen Page mit Parallax-Effekt rendern kann.
Seiten erstellen, bearbeiten und so ist mit diesem CMS wirklich sehr einfach und ist vielleicht nicht so verbreitet oder umfassend wie Wordpress, aber dafür für kleine einfache Seiten sehr viel schneller. Das Blog-Modul wird momentan auch nochmal überarbeitet.
Ein öffentliches Release des CMS unter MIT-Lizenz folgt wohl in den Wintermonaten.
Ich hab so viel liegen, was ich nie weiter entwickeln werde, aber doch verwendet habe und was gut funktioniert. Teilweise auch immer noch gut funktioniert.
Teil 1: cJS
Das kleine JavaScript Framework, mit dem genau so Controller entwickeln konnte wie mit JavaFX.. es was fast eine 1:1-Kopie. MP4toGIF.com nutzt es und es läuft gut. Es hat kein bidirectional-Binding wie Angular. Am Ende wurde eine Lib für AngularJS dafür, die ich auch oft verwendet habe. Das eigene Framework habe ich nie weiter entwickelt, dabei konnte man Controller ondemand per require.js nachladen und so lustige Dinge. Controller konnten Controller anhand des Namens laden.. wie Services in Symfony..
Ich hatte ja gehofft, dass sich AngularJS neben Angular gleichberechtigt halten wird und nicht von diesem ersetzt wird. Sieht wohl aber so aus als würde die Zeit von AngularJS jetzt doch zu Ende gehen (mit 3 Jahren LTS). Also werde ich mir dann doch mal wirklich, nach 1000 mal sich dieses vorzunehmen, genauer ansehen und ausprobieren.
Wenn es mir nicht gefällt gibt es ja noch immer Knockout.js. Lust mein eigenes kleines cJS-Framework doch nochmal weiter zu entwickeln habe ich dann doch nicht. Dem fehlt einfach eine gute Template-Engine und so eine zu schreiben oder einzubauen, wäre etwas zu viel Arbeit.
Mal gucken bei welchen Framework ich am Ende dann landen werde.
Ich hab mich die letzten Jahre doch etwas schwer getan mit JavaScript-Frameworks, die sich stärker von AngularJS unterscheiden. Knockout gefiel mir sonst auch ganz gut, auch wenn ich es ansich nie produktiv genutzt habe. Es war eben MVVC mit Templating direkt im HTML. Mein eigenes kleines Framework war auch genau so konzipiert und funktioniert bis heute gut in MP4toGIF.com.
Angular 2 sah immer interessant aus, aber irgendwie habe ich es dann doch nicht geschafft mir es mir als anzusehen. Dabei schreckte mich eher Typescript ab, was aber auch ja optional ist. Andere Sprachen und dann alles zu kompilieren mag ich bei JavaScript nicht so sehr.. da waren meine Erfahrungen mit Coffee-Script zu.. ja.. ernüchternd. Die Umgebung zum Entwickeln auf zu setzen ist vergleichbar mit dem Aufwand bei Java oder PHP. Das Debugging ist mit nativen JavaScript sehr viel einfacher gewesen.
Mit Shopware kam dann Ext JS in mein Leben. Seit Groupware und Tine 2.0 habe ich alles versucht diesem Framework aus dem Weg zu gehen. Man kommt damit zu recht, aber es ist echt nicht einfach sich dort einzuarbeiten und mal schnell eine kleine UI zu basteln, ohne sich wirklich einmal mit dem Framework auseinander zu setzen. Angular JS ist da sehr viel einfacher, aber dafür hat man eben auch nicht diese komplexe UI.
Um ehrlich zu sein, würde ich dann aber bei solchen UIs das Ext JS-Framework anderen Frameworks aus dem Desktop-Bereich wie SWT, Swing oder JavaFX vorziehen.
Heute habe ich mich mal durch die Dokumentation und die Beispiele von SAP OpenUI 5 geklickt. Es sieht etwas nach Ext JS aus, aber irgendwie spricht es mich spontan eher an. Nicht wie das erste mal mit AngularJS.. gesehen.. verstanden .. und gleich erfolgreich eingesetzt.Aber mein Gefühl war besser als bei Ext JS .. so ungefähr auf Angular 2 Niveau.
Vielleicht habe ich ja mal die Gelegenheit was damit zu machen. Momentan habe ich weder Projekt noch Zeit dafür. Aber es sieht so interessant aus, dass ich gerne was dafür hätte... gerade der Planning Calendar sieht echt gut aus.
Die nächsten Wochen und Monate werden sehr stressig. Meine Pläne sind:
- Umziehen und Renovieren (vielleicht mit Blog-Post über Netzwerk, Server und Überwachungskameras)
- Ein einfaches Shopware Plugin in den Community Store zu bekommen (Das Plugin ist so gut wie fertig.. jetzt kommt die Upload-Theorie* .. schlimmer als der App-Store für Firefox OS kann es sicher nicht sein)
- Einen kleinen aber etwas speziellen Shop online bringen (ich werde berichtigen wie es läuft und ob es am Ende erfolgreich war)
- Zwei Termine mit dem Switch GmbH Time-System stehen an, wo ich auch Blog-Post und so liefern werde.. mehr als letztes Jahr
- Ein Video über die manuelle Zeitmessung mit dem Time-System
- Und nach dem Umbau der letzten 3 Monate am aoop PHP-Framework mit MVC, neuer Verzeichnisstruktur, PHP 7, Namespaces, Composer-Autoloader, etc müsste ich wirklich mal eine neue Version releasen.. ich bin doch relativ stolz auf die neue Version ,weil sie doch etwas ist was man als modern bezeichnen kann
Den ersten Test hat mein Framework schon geschafft. Es hat SMS empfangen und durch die Pipeline an das Dummy-Plugin weiter gegeben. Jetzt muss nur noch mal getestet werden, dass die Patterns und Value-Checks alle richtig greifen.
Dann hoffe ich ein es einem ersten Projekt verwenden zu können.
Zum 10. Geburtstag meines PHP-Frameworks wird sich da viel ändern und es damit dann wieder etwas mehr zu anderen Frameworks aufschließen können.
Mein eigener Class-Loader fliegt raus und es wird noch der ClassLoader vom Composer verwendet. Meiner kann zwar auch mit PSR4 umgehen, aber nach dem Umstieg muss ich dann auch alles darauf umstellen und habe keine Ausrede mehr, weil die Kompatibilität weg fällt.
Es gibt nun ein public-Verzeichnis so dass alle Config-Dateien und Classes außerhalb des Bereiches liegen, auf dem Benutzer zugreifen können. Das sorgt für mehr Sicherheit, macht das Laden von CSS und Bildern aus dem Theme-Verzeichnis aber komplizierter. Ich überlege hier auf Assetic umzusteigen. Momentan läuft meine Lösung aber sehr gut.
Und das Beste und wichtigste was aber auch am meisten Arbeit machen wird (darum habe ich ganz viele alte Module erst einmal gelöscht und lasse auch die alten PHP-Pages drin) ist, dass Module-Pages nun wirklich mit Controller und Twig-Template gerendert werden. Die Twig-Templates könenn vom Theme und von eigenes Templates in der Instance überschrieben werden und so kann man nun endlich das Aussehen der Module leicht und schnell anpassen.
Smarty war schon länger drin, wurde aber nie benutzt und ist jetzt raus geflogen.
Mein erstes Projekt damit wird sein, die Zeiterfassung für Kunden-Projekte neu zu schreiben und für alle brauchbar zu machen. Das wird wohl am Ende nur 1-2 Tage dauern. Also nichts im Vergleich zum Umbau des Frameworks.
Während ich in den letzten 3 Jahren bei aoop immer mehr Framework-Charakter im Vordergrund gesehen habe und den CMS-Teil davon mehr oder weniger komplett vernachlässigt habe (bis auf die Integration von TinyMCE und Code-Mirror), habe ich jetzt mal wieder angefangen in die Richtung etwas zu tun und die ersten Änderungen sind schon aus dem Feature-Branch in den Master gewandert.
Seiten sind nun Grids mit Content-Modulen als Inhalt. Der Vorteil von so einem Grid ist, dass es responsive ist und so die Anpassung für Mobile-Devices sehr vereinfacht wird. Während in der Desktop-Ansicht man das Grid sieht wird bei der Unterschreitung einer gewissen Breite einfach alles untereinander angeordnet. Momentan verwende ich das Grid von Bootstrap, weil man dieses auch allein super in vorhandene Templates integrieren kann ohne Angst haben zu müssen, dass das Design oder Layout Schaden nimmt.
Der Editor nutzt auch das Grid um eine brauchbare Vorschau zu liefern.
Dieses neue Seiten-Model und der dazu gehörige Editor werden nie den Umfang und die Qualität der Shopping Worlds in Shopware. Ich überlege ein Modul zu schreiben, das ähnlich wie das Digital Publishing in Shopware repsonsive Banners ermöglicht, aber auch hier natürlich nicht in dem Umfang, sondern in einer einfachen und grundlegenden Version.
Wenn ich eine Lib oder ein Framework sehe, kommt bei mir immer die Frage auf: "Wie macht man so etwas?" Das gipfelte heute darin, dass ich ein kleines Logging-Framework geschrieben habe. Etwas an
Log4j erinnernd aber erst einmal nur mit Output in eine Datei. Andere Outputs könnte man noch integrieren durch Appender-Types.
Die LoggerFactory
class XWLoggerFactory{
private static $config=[];
private static $appenderCache=[];
/**
* @return XWLogger
* @param string $clazz
*/
public static function getLogger($clazz){
if(count(self::$config)==0 && file_exists("system/config/log.json")){
self::$config=json_decode(file_get_contents("system/config/log.json"),true);
foreach(self::$config["appenders"] as $appender){
self::$appenderCache[$appender["name"]]=$appender;
}
}
$appenders=[];
$levels=[];
foreach(self::$config["classes"] as $cla){
if(preg_match("/^".$cla["name"]."/i", $clazz)){
foreach($cla["appenders"] as $app){
$appenders[]=self::$appenderCache[$app["name"]];
$levels[]=$app["level"];
}
}
}
return new XWLogger($clazz, $appenders, $levels);
}
}
Nach 9 Jahren geht es mit aoop doch mal los. Ein weiters Projekt mit meinem Framework startet morgen. Es basiert auf der neusten Version mit dem Blog-Modul.
Ich bin auch technischer Admin und betreue alles auf technischer Ebene. Logos und Design stammen von meiner Frau und sind wirklich toll. Wer es sich mal ansehen möchte findet es unter http://www.tentacle-news.net.
In meinen 11 Jahren habe ich schon einige Frameworks geschrieben. Ich mag Frameworks und lieb es so etwas zu entwickeln. Aber Frameworks sind schwer richtig zu entwickeln. Die meisten Framework-Entwicklungen Enden ohne etwas Brauchbares in der Hand zu halten. 50% der Frameworks, die ich im Laufe der Zeit geschrieben habe waren einfach Schrott.
Neben diesen gibt es dann die, die am Ende nutzlos sind. Das kann damit zusammen hängen, dass die Vorteile und die Arbeitszeitersparnis einfach nicht eintreten. Die wirklich brauchbaren kann ich an paar Fingern abzählen. Aber auch viele große Frameworks haben ihre Probleme, es ist also kein Problem was nur die Arbeit einzelner Entwickler oder kleiner Gruppen betrifft. Ein gutes Beispiel für so ein Framework ist JavaFX 1.x. Viele Ideen, viel Arbeit wurde investiert und am Ende wollte es niemand verwenden. JSF 1.x war auch noch weit davon entfernt wirklich rund zu laufen bei der Entwicklung und zeigte oft Unzulänglichkeiten. Allein dass mit Tomahawk alle möglichen HTML-Tags wie DIV nochmal für JSF implementiert wurden, weil es kaum möglich war JSF und HTML sinnvoll zu mischen.
Aber das Scheitern großer Frameworks soll hier gar nicht das Thema sein. Es soll darum gehen, wie man es richtig macht bzw. wie man weniger falsch macht.
Ich hatte vor einiger Zeit APF2 (annonyme php framework 2) angefangen. Es sollte alles richtig machen was ich bei aoop falsch gemacht hatte. Es sollte nicht der Content direkt raus geschrieben werden beim Funktionsaufruf. Es war so nicht möglich über den Content-Bereich aus den Title zu ändern und so war auch die Möglichkeit nicht da einen Titel eines Blog-Post zu setzen, wenn man den BLog-Post geladen hatte, weil dann der HTML-Head schon gesendet worden war.
Es sollte ein richtiges Routing haben, um so zum Zend Framework 2 aufschließen zu können. Damit sollte SEO einfacher werden, weil nicht alles auf die index.php ging.
APF2 ist tot. Es fehlte einfach viel was aoop schon hatte, denn ein unvollständiges Framework ist sinnlos und aoop zu "reparieren" ging schneller als gedacht. Alles komplett neu und besser zu machen braucht viel Zeit und man kann es nicht alles besser machen und dabei kompatibel bleiben. ZF1 zu ZF2, JSF 1.x zu JSF 2.x, AngularJS 1.x zu AngularJS 2.x.. JavaFX. Ein Framework neu zu schreiben lohnt sich nur wenn man auch etwas komplett neues damit entwickeln will. Das Framework nur neu zuschreiben und die darauf basierende Anwendung portieren zu wollen endet eigentlich immer damit dass man die Anwendung auch fast komplett neu schreibt. Man hat ja damals nichts auf Hinsicht eines neuen noch nicht existenten entwickelt. Deswegen werden alte Framework Versionen auch ewig weiter gepflegt, weil das Portieren auf ein komplett neues Konzept nicht so einfach möglich ist, weil man sich eben auf das alte Konzept eingelassen hat und sich daran orientiert hat bei der Entwicklung.
Also der erste Punkte: Man muss für die Zukunft etwas neues machen und nicht versuchen alte Sachen zu reparieren. Eine neue Version ist auch ein neues Framework.
Auch die Frage, ob es in einem bestimmten Bereich wirklich ein noch ein weiteres Framework braucht, dass wieder nur Nuancen anders macht. Ja.. die Konzepte sind alle sehr ähnlich, die meisten kommen bei den selben Problemen zu den selben Lösungen. Es gibt viele Lösungen aber nur wenig gute und man ist nicht so genial, dass nicht auch viele andere zu der Lösung kommen. Außerdem ist man durch viele bekannte Konzept schon so geprägt, dass man diese auch aufgreifen wird. MVC und MVVM... am Ende kann
man noch so viel nachdenken.. die Konzepte sind schon gut. MVC, MVC2 oder MVVM sind auch sehr ähnlich und oft ist es auch Interpretation ob nicht eines der Konzepte, dass andere schon vorweg genommen hat und es nur nicht in der Masse erkannt wurde.
Würde ich heute noch cJS neu entwickeln? Nein. Es funktioniert echt toll und als ich vor paar Tagen mp4togif.com doch mal wieder erweitert habe, ging es einfach, schnell und problemlos. Aber AngularJS kann das auch alles und noch mehr und gerade das Handling von Arrays "item.name for item in items tracking by item.id".. so eine kleine Sache macht es für mich so toll. Das Wichtigste ist aber, dass AngularJS aktiv und mit soviel Man-Power weiter entwickelt wird, wie ich es nicht neben bei leisten könnte. Ich entwickle aoop aktiv weiter. Das ist schon viel Arbeit.
Also Punkt Nummer 2: Wenn man nicht die Zeit hat es durch gehend weiter zu entwickeln, sollte man es lassen und eines von jemanden verwenden, der oder besser die die Zeit investieren. Also auch mal an die Framework Entwickler denken und diese auch bei Gelegenheit etwas unterstützen. Denn die geben ihre Arbeit meistens kostenlos ab und sparen uns damit so viel Zeit, die wir wieder in etwas investieren, mit dem wir Geld machen oder es jedenfalls hoffen mal Geld zu machen :-)
Aber was ist, wenn es kein anderes Framework gibt, das das macht was ich brauche? Dann sollte man versuchen möglichst viele Leute zu finden, die es verwenden und somit den Bedarf schaffen, Zeit zu investieren. Gerade in Teams mit einem eigenen Framework (bei mir war es eins um XML-Templates in PDFs umzuwandeln, man also kein iText lernen musste sondern HTML und CSS reichte) muss es sich wirklich durch setzen. Wenn man nicht den Rückhalt hat, wird jede investierte Zeit als verschwendete Zeit gesehen.
Wenn man HTML + CSS Templating für ein Team entwickelt, dass zum großen Teil nie mehr als Java-Code und dort nur SWT für GUI gesehen hat, hat man schon einmal einen schlechten Start. Wenn das Framework dann besonders schnell entwickelt wurde, an einigen Stellen noch Probleme hat und nicht besonders schnell ist, hat es es sehr schwer sich jemals wieder von diesem Ruf zu erholen.
CSS ist teilweise etwas undurchsichtig und wenn sich dann Entwickler nicht merken können ob # nun sich auf eine Id oder eine Class bezieht, hat das Framework einfach keine Chance.
Damit wäre Punkt 3: Das Framework muss von den Entwicklern benutzt werden können. Wenn man nur ein Framework für sich selbst schreibt, scheint dieses egal zu sein, aber man weiß nie, ob nicht doch jemand anderes mal ein Projekt von einem übernehmen wird. Wenn man in einem festen Team arbeiten, muss man sich nach dem Wissen und den Vorlieben des Teams richten, damit das Framework angenommen wird.
Wenn wir nun ein neues Projekt mit einem Framework beginnen wollen, wollen wir nicht erst einmal viel Doku lesen oder einrichten müssen. Wir wollen (ich gehe mal vom Webbereich aus) das Framework deployen, es aufrufen und eine kleine Seite sehen. Vielleicht weißt das Framework einen nochauf eine fehlende Datenbank-Verbindung hin. Was wir an sich nicht machen wollen ist, den Server erstmal umständlich konfigurieren zu müssen. Erstmal die Config des Tomcats oder Apaches ändern zu müssen nervt. Wenn wir aber nun das Framework an sich zum Laufen bekommen haben, wollen wir unsere Anwendung anfangen zu entwickeln. ZF2 braucht gefühlt sehr viel Konfiguration und es müssen viele Dateien angelegt werden. Die Modul-Klasse, das Mapping des Namespaces, das Laden der Config-Dateien, was man alles in PHP umsetzen muss. Als Anfänger hat man sehr damit zu kämpfen, wil man oft auch nicht genau weiß, in welcher der Dateien nun was noch mal stand. Default-Werte sind unbekannt und die endlose Verschachtelung der Arrays ist
alles andere als übersichtlich.
Ich habe ein SWT-Framework erlebt wo man erst einmal 5 Klassen ableiten musste, mindestens 6 Methoden überschreiben sollte, die aber auch nicht abstract waren und man sowie so noch alle möglichen Pfade und Klassen an den richtigen stellen anpassen musste. Das war schon keine Konfiguration mehr sondern wirkliches Ändern und Anpassen von elementaren Code-Teilen.
Ein Update auf eine aktuellere Version des Frameworks,war also auch kein einfaches Kopieren von Dateien sondern man musste wieder den Code anpassen und hoffen, dass es immer noch die selben Stellen waren, wo es zu ändern war.
Punkt 4: Die Installation sollte an sich lauffähig sein und das Anlegen eines eigenen Moduls oder ähnlichen sollte über eine einzige Datei möglich sein. Diese Datei sollte kein Programm-Code sein und deutlich strukturiert sein. Auch Default-Werte sollten immer vorhanden sein, falls man einen Wert nicht in der Config setzt.
Und gleich Punkt 5 dazu: Wenn man ein Update macht sollte man die Dateien einfach kopieren können ohne eine der Dateien ändern zu müssen oder Angst haben zu müssen die momentane Config ausversehen wieder mit der mitgelieferten Default-Config zu überschreiben. Am besten ist ein zentrales Verzeichnis für die Config und dass ohne Inhalt einfach auf die default-Config zurück springt.
Fazit: Wenn man diese Punkte beachtet, steigen die Chancen, dass das eigene Framework brauchbar ist und auch von anderen Entwicklern angenommen wird. Zusätzlich sollte das Framework natürlich gut, schnell und möglichst fehlerfrei sein. Aber meistens scheitert das eigene Framework einfach daran, dass man zu wenig Zeit investiert, nur auf den momentanen eigenen Bedarf hin entwickelt und sich zu wenig Gedanken macht wie man selbst oder andere beim nächsten Projekt damit einen möglichst einfachen und entspannten Einstieg haben.
Auch im ZF1 ist es sehr einfach einen REST-Service zu implementieren.
public function restAction(){
$this->getHelper('Layout')->disableLayout();
$this->getHelper('ViewRenderer')->setNoRender();
$this->getResponse()->setHeader(
'Content-Type', 'application/json; charset=UTF-8'
);
$data=............;
echo json_encode($data);
return;
}
Man muss nur das Layout und den ViewRenderer deaktivieren und schon kann man sein Response ganz nach Belieben gestalten. Das Vorgehen über das Response als return Wert im Zend Framework 2 finde ich aber insgesamt klarer und strukturierter als die Art und Weise um ZF1.
REST mit dem Zend Framework 2 soll ganz einfach gehen. Geht es auch. Bestimmt gibt es viele verschiedene Möglichkeiten, aber diese scheint erstmal ganz gut zu funktionieren. Den XWJSONConverter hatte ich shcon in einem vorherigen Blog-Post vorgestellt. Man kann natürlich auch JSON:encode aus dem ZF2 verwenden oder json_encode().
class IndexController extends AbstractRestfulController{
private function _getResponseWithHeader(){
$response = $this->getResponse();
$response->getHeaders()
//make can accessed by *
->addHeaderLine('Access-Control-Allow-Origin','*')
//set allow methods
->addHeaderLine('Access-Control-Allow-Methods','POST PUT DELETE GET')
//change content-type
->addHeaderLine('Content-Type', 'application/json; charset=utf-8');
Gerade im Zend Framework 2 kommt man immer mehr in Bereiche wo man auf altbekannte Konzept aus der Enterprise Welt und dort auch auf viel bekanntes aus Java (EE) trifft. Neben Depenency-Injection und Factories, findet man immer wieder gute Möglichkeiten Konzept wie DAO oder
auch POPOs als PHP-Variante der POJOs anzuwenden (wobei ich hier POJO und Bean gleichsetzen würde).
Auch Getter und Setter gehören hier genau so zum Alltag wie in Java.
Ich möchte hier ein paar Beispiele geben, wie man eine einfache Umsetzung in einem ZF2-Modul realsieren kann. Ich gehe einfach mal davon aus, dass man in der Lage ist ein einfaches Module in ZF2 zu erstellen und auch sich mit Controllern ViewModel und TableGateway zu mindest einmal beschäftigt hat. Der Einstieg ist nicht besonders einfach, wenn man keine lauffähige Anwendung hat, in die man sich einarbeiten kann.
Die hier umgesetzten Ansätze, sollen die Entwicklung möglichst beschleunigen und viel Code sparen, der in vielen Beispielen auch mit drin ist und alles sehr unübersichtlich macht. Auch wenn hier einige Ableitungen vorkommen halte ich das exesive Ableiten und Vererben für einen falschen Ansatz. Factories und Dependency-Incetion halte ich für einen besseren Weg eine Klasse mit bestimmten Eigenschaften auszustaten.
Ich leite auch vom TableGateway ab, wobei die bessere Methode es wohl wäre in der Factory mit Hilfe des ServiceManagers ein TableGateway zuerstellen und dieses an den entsprechenden Constructor zu übergeben.
Aber fanden wir einfach mal mit dem Model bzw der Entität an.
public function setName($name){
$this->_name=$name;
}
public function getValue(){
return $this->_value;
}
public function setValue($value){
$this->_value=$value;
}
}
Die voran gestellen _ entsprechen dem Zend Code-Style und sollen private und protected Attribute der Klasse deutlicher hervor haben.
Eigentlich sollte ja jedes Attribute der Klasse private oder protected sein. Nur wer die PHP eigenen JSON Funktionen oder Klassen verwendet, könnte man in die Verlegenheit kommen etwas public zu machen, aber auch hier gibt es bessere Lösungen.
Ich halte wenig davon alle Attribute grundsätzlich auf protected zu setzen, nur weil die Möglichkeit besteht mal eine Klasse ableiten zu wollen.
In den meisten Fällen, sollte man dann überlegen, ob es wirklich eine andere Entität ist oder man die vorhandene erweitern oder anpassen könnte so, dass keine weitere sehr ähnliche Entität nötig wird. Ableiten von einer BasicEntity oder einem BasicModel ist natürlich sinnvoll. Aber konkrete fachliche
Entitäten abzuleiten ist meistens weniger sinnvoll.
Nun kommen wir zu einem Punkt, der in der ZF2-Welt oft anders gesehen wird. Ich leite das Model nicht direkt vom TableGatway ab. Das Problem ist hier, das man für das TableGateway einen DBAdapter benötigt den man mit Hilfe des ServiceManagers bekommt. Also muss man beim Erzeugen des Model-Objekts immer diesen übergeben und das TableGateway instanzieren. Das kann man natürlich super mit den Factories des ZF2 erledigen. ABER.. wenn ich eine Liste des Models aus der DB lade und in einer Schleife mir für jede Row aus der DB eine Instanz der Klasse erzeuge ist das Vorgehen jede Instanz über diesen Factory bauen zu lassen, alles anderes als elegant oder schnell.
Also bleiben wir bei unserem einfachen POPO und erstellen für die Zugriffe auf die Datenbank nutzen wir eine weitere Klasse. Für jedes Model/Entity erzeugen wir uns eine DAO-Klasse. Diese enthält alle Methoden zum Laden, Speichern und Löschen sowie Listen laden des Models. Wie für fast jedes DAO benötigen wir hier eine Factory um die Einstellungen des Systems (DB-Verbindung) dem DAO bekannt zu machen.
Die Factory tragen wir in der module.config.php ein, die wir in der Methode getConfig der Module.php laden.
$sm ist der ServiceManager, den wir hier an den Constructor des DAOs übergeben. Der Constructor nutzt diesen um den DBAdapter zu bekommen und an das TableGateway weiterzugeben. Wie schon weiter oben geschrieben, hätte man dies auch in der Factory machen können und das TableGateway hier an das DAO übergeben können. Könnte einen etwas Code sparen es so zu machen.
Nun möchte man den DAO in dieser Art und Weise gerne verwenden:
Dafür schreiben wir uns jetzt einen eifnachen DAO, der erstmal nur die load-Methode enthält:
class XWTestDAO extends TableGateway{
$this->_sm=null;
public function __construct($serviceManager){
$this->_sm=$serviceManager;
parent::__construct(
$this->_tableName,
$serviceManager->get('dbAdapter')
);
}
//eine einfache Methode zum Kopieren der Daten aus dem Array in das Objekts
private function _copyData($entity,$array){
$dbm=new XWDBMapper();
return $dbm->setValuesFromArray($entity,$array);
}
public function loadTest($id){
$entity=new XWTest();
if($id!=null && $id>0){
$rsetItem=$this->select(
array('test_id' => $id)
)->current();
Ideal wäre es hier, wie man deutlich sehen kann 'test_id' auch später mal durch Annotationen zu ersetzen. Dafür wäre eine Annotation wie @tableid dann geeignet nach der man sucht und sich dann den @dbcolumn-Eintrag aus dem selben DocComment-Block heraus liest.
Aber so weit ist es ja schon mal ganz schön. Wie brauchten kein Array zu erzeugen und sonst haben wir wenig Code schreiben müssen.
Das wichtigste fehlt hier aber natürlich noch. Wie mappe ich die Annotationen auf das Array und umgekehrt?
Dieser Mapper ist ansich auch nicht wirklich kompliziert und basiert hauptsächlich darauf mit der RefelcetionClass zu arbeiten und mit deren Hilfe die ReflectionProperties zu bekommen.
class XWDBMapper{
public function getColumnNameFromDoc($doc){
$result=null;
if(preg_match("/@dbcolumn=[a-zA-Z0-9_]+/",$doc)){
$result=preg_replace("/^.+@dbcolumn=([a-zA-Z0-9_]+)\s.+$/Uis","$1",trim($doc));
}
return $result;
}
Sehr wenig Code und erleichtert einen das Leben sehr. Ist auch relativ schnell. Das händische Schreiben bzw Mappen der Arrays war doch immer sehr fehleranfällig und wenn man mal eine Column zur Datenbanktabelle hinzugefügt hat, müsste man an vielen stellen diese nachpflegen und hoffen, dass man keine Stelle vergessen hat. Jetzt muss man nur noch eine Annotation einbauen und es wird immer richtig gemappt.
Nachdem wir also nun das Laden einmal durchgegangen sind, kommt hier nur kurz die Methode für den Mapper, wie man ein Array aus einem Objekt erhält (die meisten werden schon wissen wie man die Methode da oben umdrehen kann). Deswegen brauche ich hier wohl auch nicht viel dazu schreiben.
Um jetzt alles noch schneller zu machen könnte man sich einen Cache für die Propert-Liste schreiben, dass diese nicht immer und immer wieder erzeugt werden muss. Beim Laden von Listen wäre das ein großer Vorteil. Aber selbst so ist alles schon sehr schnell. Jeden Falls habe ich zwischen den beiden Varianten bis jetzt in der Benutzung der Anwendungen keinen gravierenden Unterschied feststellen können, was die Performance betrifft. Mit XDebug durch gemessen habe ich noch nicht.
So haben wir mit nur eine paar kleinen Zeilen Code uns viel Arbeit erspart.. vielleicht habe ich hiermit noch anderen deren Arbeit vereinfacht.
In der letzten Zeit habe ich mit CSS-Frameworks zu tun gehabt. Bootstrap, Foundation und UIKit. Mit Bootstrap hatte ich ja schon etwas länger Kontakt. Foundation jetzt so 3 Wochen und UIKit 2 Tage. Bootstrap gefällt mir von der standard Optik aber immer noch am Besten. Bei UIKit gefallen mir die mitgelieferten Icons. Foundation macht was es soll, aber sieht mir an einigen Stellen doch zu sehr nach plain-HTML aus und die Dokumentation sagt mir am wenigsten von den Dreien zu.
Aber am Ende machen doch alle drei genau das Selbe und das auch sehr ähnliche Weise. Was ich mit dem einen hinbekomme, kann ich ohne große Probleme auch mit den anderen erledigen. Oft muss man nur die CSS-Class's austauschen.
Ob man nun soviele ähnliche Frameworks braucht lasse ich mal dahin gestellt und versuche erstmal für mich heraus zu finden, welches ich nun als primäres verwenden sollte.
Meine erste Reallife-Erfahrung mit dem ZF2 und Models war eine eher weniger positive. Das TableGateway braucht unbedingt den Service-Manager bzw den DB-Adapter daraus. Meine Vorgängerin hat sich dazu entschlossen eine Basis-Entität zu bauen, die wiederum von TableGateway ableitet und man so relativ einfach save() und
load()-Methoden in die Model-Klasse einbauen konnte. Der Service-Manager wurde dann durch den Constructor der Model-Klasse durch gereicht bis man den Constructor des TableGateways mit dem DB-Adapter aufrufen konnte. Auch zwischen durch wurde der Service-Manager immer mal benötigt. Weil.. man ohne ihn keine Instanz einer Model-Klasse bekommen konnte.
Um so eine Instanz zu bekommen wurde eine Factory verwendet:
/**
* By default, the ServiceManager assumes all services are shared (= single instantiation),
* but you may specify a boolean false value here to indicate a new instance should be returned.
*/
'shared' => array(
'sModel' => false
)
)
Jedes mal aber die Factory zu bemühen eine neue Instanz zu erzeugen ist nicht gerade performant und mit den ganzen Ableitungen ist es auch sehr unübersichtlich. Ich wollte einfach schnell eine Instanz einer Model-Klasse haben und nicht ein riesiges Object bekommen. Also sowas wie in POPO .. eine POJO in PHP eben.
Ein Cosntructor ohne Argumente und eine Klasse nur mit Attributen ohne Logik. Also find ich an mir zu überlegen, ob diese ganzen Ableitungen überhaupt nötig sind oder man mit der Dependency-Injection nicht was viel besseres bauen könnte.
Ich bin dann schnell zu DAOs gwechselt. Die Factory injeziert einmal den Service-Manager und kann immer die selbe Instanz des DAOs liefern. Die DTO/Model-Klasse ist schön klein und beim Befüllen in Schleifen viel schneller als eine Intanz über die Factory anfordern zu müssen.
Das Zend Framework 2 ist das JEE der PHP-Welt. Endlos viele config-Files mit denen man so viel falsch machen kann und man erstmal nicht versteht, wo man was einstellt und welche Einstellungen zusammen hängen, und warum die Verzeichnisstruktur für Module so aussehen muss, wie sie aussieht. Aber mit Kopieren von vorhanden Dingen und etwas Testen kommt man doch zum Ziel und einfache Dinge sind dann doch schnell erledigt. Aber ACL und Resources sind genau so schlimm wie Principales und JAAS.. wenn es einmal läuft.. am Besten so lassen und nicht mehr anfassen :-)
Das Geheimnis beim Class-Loading in PHP ist die Funktion __autoload, diese Funktion wird immer aufgerufen bevor eine Instanz einer Klasse erzeugt wird.
function __autoload($classname){
}
Hier kann man also anhand des Klassennamens den Code der Klasse nachladen. Man kann natürlich auch per Hand in jeder Datei über include() die Klassen laden, die man braucht. Meistens läuft es dann darauf hinaus, dass man zu viel lädt und Zugriffe auf das Dateisystem ist eben sehr teuer. Mit der autoload-Funktion ist sicher gestellt nur das zu laden, was auch wirklich benötigt wird und sort dafür, dass möglichst wenige Dateizugriffe durch geführt werden. Wenn also eine Klasse in einem Code-Block verwendet wird der nie ausgeführt wird, wird der Code der Klasse nicht aus dem Dateisystem nachgeladen.
Ein sehr simpler Class-Loader kann also so aussehen:
function __autoload($classname){
if(!class_exists($classname)){
include_once("classes/".$classname.".php");
}
}
Alle Klassen-Dateien müssen an einem bestimmten Ort legen, hier im Order "classes/". Wenn man nun mit Modulen arbeitet, wo ein Modul die Klassen eines übergeordneten Modules nutzen kann, hat man das Problem, dass man nicht immer genau weiß wo eine Klasse liegt und man muss diese Suchen. Bekannt ist das Problem beim Class-Loading in Java, wo ein Package über mehrere JAR-Files verteilt sein kann und man also in allen JAR-Files nach einer Klasse muss, weil man durch Package und Klassennamen nicht auf die JAR schliessen kann in welcher die Klassen-Datei liegt.
Suchen ist natürlich auch sehr teuer, gerade wenn man rekursiv durch Verzeichnisstrukturen laufen will. Wenn man nun bei jeder Klasse alle Verzeichnisse durchläuft bis man eine Klasse gefunden hat, würde alles sehr lange dauern.
Eine Lösung ist, bekannte Pfade sich zu merken, damit man nicht immer wieder das selbe Suchen muss. Wenn man in einem Modul unterwegs ist, hat man es mit maximal zwei Händen voll von Klassen zu tun, die immer und immer wieder verwendet werden. Wenn ich aber durch eine Liste von Dateien laufe und bei jeden Item in der Liste prüfe, ob es das passende ist (ok.. man könnte auch file_exists() innerhalb des Verzeichnisses verwenden...) kann man sich die gefunden Klassen und deren Pfade bis zum Pfund der gesuchten Klasse merken.
function __autoload($classname){
if(!class_exists($classname)){
if(!isset($_SESSION["XWCLASSCACHE"])){
$_SESSION["XWCLASSCACHE"]=array();
}
Hier wird alles in einen Cache geladen. XWRecursiveClassSeeker durchläuft alle Verzeichnisse rekursiv und vermerkt jeden Pfad zu jeder Klasse auf die er trifft. Wenn die gesuchte Klasse gefunden wurde bricht er ab. Dann wird der Code der Klasse nachgeladen. Alles wird auch in de Session gespeichert so dass man pro Request kaum noch Dateisystemzugriffe zum Suchen hat und nur noch für die includes der Klassen-Datein.
Das Problem ist, wenn man Klassen-Dateien umkopiert, weil dann die Pfade im Cache nicht mehr stimmen. Hier werden diese in dem Fall aus dem Cache entfernt, so dass beim nächsten Versuch die Klasse zuladen wieder neu gesucht wird und es dann auch klappen sollte.
Über dieses Vorgehen, kann man auch in PHP einen relativ peformanten und flexiblen Class-Loader schreiben und muss sich nie wieder selbst um includes von Klassen kümmern!
Lange Jahre war aoop mein CMS und PHP-Framework für die meisten Projekte, die etwas mehr brauchten als nur JavaScript. Es begann als CMS für meine Homepages. Deswegen unterstützte es die Verwaltung von Pages, konnte mit einer Installation mehrere Domains bedienen und verhielt sich dabei jeweils wie eine komplett eigene Installation. Benutzer-Verwaltung und Logins waren mit im Kern implementiert. Es konnten Module erstellt und für jede Instanz einzelnd deployed werden (jede Instanz konnte sogar eine eigene Version haben, da man später auch pro Instanz eine eigene Datenbank verwenden konnte). Es wurde zu einem doch sehr großem System Vergleich mit einem einfachen kleinen App-Server. Ein Server und eine Installation für alles. Module und Pages wurden immer wieder direkt eingelesen und Menüs automatisch erstellt. Also Modul rein kopieren und damit stand es gleich zur Verfügung.
In letzter Zeit ging ich aber auch dazu über für jeden Bedarf eine eigene Installation mit eigener Datenbank anzulegen, da man bei Problemen so nur eine Installation anfassen musste und bei Updates nur eine Seite für paar Minuten anfassen musste. Die letzten Projekte waren auch Web-Apps die das Framework nutzen aber die Verwaltungsfunktionen des CMS-Teils nicht benötigten. Das Framework ist gut und ich komme damit super zurecht, aber für Web-Apps war dies alles nur Ballast. Web-Apps bestehen auch bei mir momentan aus AngularJS und einem REST-Service. Der REST-Service-Teil von aoop ist relativ neu und nutzt nur wenige andere Klassen des Kern-Systems. Dann kam ich noch mit dem Zend Frameworks in Berührung, die viel hatten, was mir in aoop noch fehlte (Seiten-Aufrufe über URL-Parsing und so.. was aber für die REST-Services schon existierte).
Ich überlegte also mal den REST-Teil heraus zu lösen, um einfacher meine Apps bauen zu können. Ein Problem bei den Apps waren aber die Auslegung auch von AngularJS auf OnePage-Apps. Beruflich hatte ich mit Clients von einem ERP-System zu tun, die nicht ein paar Views und Dialoge hatten sondern pro Modul gerne mal 50 oder mehr und im Client waren auch gerne mal 20 Module installiert. So eine Anzahl an Views und Controllern ist für eine einfache AngularJS-Anwendung zu viel. Also kam ich auf die Idee jeden View/Dialog und seinen Controller als einzelne Komponente zu betrachten und weiterhin Seiten per Request aufzurufen, aber in diesen die Oberfläche aus fertigen Komponenten zusammen zu stellen. Das Laden der Daten und auch Speichern und so sollte die Komponenten dann nur über REST erledigen. Im Grund ein System für 2 Schichten einer 3 Schichten Architektur. REST und Client-View Erzeugung in einem System zusammen gefasst.
Also habe ich mir meine Ideen mal aufgeschrieben und dann angefangen es umzusetzen. Einiges wurde direkt aus aoop übernommen (was auch weiter existieren wird für normale Homepages und so etwas, wo man eben ein CMS braucht). Class-Loader ist eine 1:1 Kopie wo nur ein paar Pfade angepasst wurden.
Damit fing die Entwicklung dann auch an. Class-Loader, neue Modul-Klasse und Klasse zum einlesen aller installierten Module. Dann wurde der REST-Service-Teil kopiert wobei nur ein Klasse ersetzt werden musste, weil eben die Modul-Liste geändert hatte. Damit liefen die REST-Services auf jeden Fall schon mal wieder. PDBC für Datenbankzugriffe musste auch nur
Kopiert werden.
Dann folgte der Teil wo aus Komponenten eine Seite zusammen gebaut werden sollte. Diesmal sollte erst die Page geladen und erzeugt werden bevor angefangen wird das Template zu füllen, was den Vorteil hat, dass jede Seite ihren <title> selbst bestimmen kann und man damit sehr viel flexibler ist. Bei einer Blog-Anwendung können also auch Tags mit in den Title geschrieben werden, obwohl das Template auch für Übersichten und so verwendet werden kann. Also am Ende werden Platzhalter ersetzt.. um es mal genauer zu erklären.
Das URL-Schema ist eigentlich das des REST-Teils geworden:
Also Basis-URL, dann folgt der Type an dem entschieden wird ob eine Page oder ein Service gemeint ist, dann der Modulname und nun folgt etwas beliebiges, das durch das Routing oder Mapping der entsprechenden Teile des Frameworks interpretiert wird und am Ende auf einen Service oder eine Page zeigt.
Meine Planung für den Blog ist momentan, dass ich parallel zur Entwicklung ein paar Beiträge schreibe:
* Class-Loader
* REST-Service
* Pages und Komponten
* ein kleines Beispiel
* Zugriff auf Datenbank und automatisches Mapping von Resultsets auf Objekte
Es ist ein kleines Framework an dem man eigentlich leicht verstehen sollte wie man so etwas bauen kann und wie man bestimmte Dinge darin umsetzen kann (nicht muss.. aber meiner Erfahrung nach funktionieren die Dinge sehr gut :-) )
Wenn man ein Angestellter Entwickler ist und in relativ großen Teams an interner Software arbeitet, die nur durch andere Abteilungen verwendet wird, wird man nicht wirklich über den Begriff des ROI (Return of Investment) stolpern. Wenn man aber eine kleinere Firma hat und diese mit dem was entwickelt wird, ist dieser Begriff allgegenwärtig. Man bekommt nicht einfach erst einmal viel Gehalt und dann wird geguckt ob man etwas kann oder nicht. In großen Firmen ist es auch nicht so schlimm mal weniger zu können wenn man im Team arbeitet oder einfach erst einmal angenommen wird, dass man die Stärken und Begabungen noch finden muss und man vielleicht dafür eben auch mal das Team wechseln muss.
Außerdem ist es einfach schwer zu bestimmen wie hoch der ROI bei etwas ist. Was ist besser? Wenn ich von JavaFX auf AngularJS wechseln möchte und damit mir 3 Wochenarbeit spare oder wenn mein Teamleiter, der ja mehr verdient, selbst noch mal Zeit investieren muss um meinen Wunsch verstehen, bewerten und nachvollziehen zu können. Beides kostet Geld. Am Ende würde auch die Abteilung von den 3 Wochen profitieren. Entweder weil die die Anwendung 3 Wochen früher bekommen und 3 Wochen früher als gedacht produktiver arbeiten können oder weil die Zeit in weiter Verbesserungen fließt und dann die Abteilung noch effektiver und produktiver arbeiten kann.
In kleinen Firmen mit direkten Draht zu Kunden ist so etwas immer sehr viel einfacher zu messen. Ich kann pro Monat so und so viele Auftrage der Kunden erledigen und bringe so und so viel Geld. Geld ist messbar.. spätestens auf den Kontoauszügen.
Schwer den ROI zu bestimmen ist, wenn du interne Frameworks entwickelst. Weil es ist nichts was eine andere Abteilung oder ein Kunde jemals bemerken wird. Die anderen werden schneller Entwickeln und einen höheren ROI haben. Aber man muss sehr hinterher sein auch immer mal fest zu stellen, dass es auch am guten Framework liegt. In Meetings immer erzählen, was sich verbessert hat und am besten ein Beispiel bringen, was nun ganz einfach möglich ist, was vorher andere viel Zeit gekostet hat. Ein gutes Framework ist für den Anwender unsichtbar.. ein schlechtes.. dann wird man nicht so schnell übersehen.
Am Ende finde ich es aber doch momentan sehr gut, direkt mit so etwas zu tun zu haben. Etwas wo Zeit Geld ist und gute Lösungen, die einen Zeit sparen, nicht als etwas neues und damit potenziell unsinniges gesehen wird und Zeitersparnis eher neben sächlich ist.
Im Grund ist das, was die meistens Frameworks machen, doch irgendwie sehr primitiv. Das OR-Mapping jetzt mal dabei nciht berücksichtigt. Es geht eigentlich immer darum ein URL mit der Hilfe der definierten Routes auf die Methode einer Controller-Klasse zu lenken. Dabei ist die Methode manchmal noch durch eine Action definiert.
Erinnert mich am Ende alles sehr stark an die alten JSF-Webanwendungen. Damit zur arbeiten war nicht immer einfach. Aber mit JSF2.2 soll sich da viel getan haben. Aber eigetnlich waren die Probleme immer bei den Templates zu finden und deren Unfähigkeit mit normalen HTML gemischt zu werden (damals.. zu 1.2 Zeiten).
Die Templates die ich bei Laravel und Symphony2 gesehen habe sind jetzt auch alles andere als "hübsch". Die besten Templates momentan kenn ich von AngularJS. Die sind einfach und übersichtlich.
In diesen Controller-Methoden wird dann meist der Renderer angestossen, der das Model un die View zusammen bringt und das Ergebnis wird dann von der Controller-Methode zurück geliefert.
Aber das zentrale sind immer die Routen. ORM ist dass wo sich alle unterscheiden. Aber ansich finde ich die ORMs jetzt alle nicht so berauschend. JPA ist schon sehr gut und dass hat ja auch seine Probleme. Es wäre für Anfänger in den meisten Fällen sehr viel übersichtlicher, wenn die ganzen Tutorials das ORM erstmal weg lassen würden. ORMs sind meistens der Teil wo Tutorials anfangen unübersichtlich zu werden, weil da eben viel automatisch passiert und es teilweise nicht so benannt wurde, dass man gleich erkennt, worum es geht. up() und down().. warum nicht execute() und rollback()? Dann wäre sehr schnell klar wozu die beiden Methoden gedacht sind. Auch dass man bei Laravel so viel über das CLI machen muss, finde ich eher irritierend. Der Aufruf der Views und so ist einem schnell klar. Artsan und migrate machen einfach zu viel "magic" um für einen Einsteiger ohne Vorkenntnisse sofort verständliche Ergebnisse zu liefern.
Aber an sich sieht Laravel auch nicht verkehrt aus. Es werden wohl viele SingleTons verwendet, was wohl dafür spricht, dass es ein wohl ein relativ schnelles Framework sein wird.
Gute Tutorials für Laravel sind (jedenfalls nach meinem Gefühl):
Das Zendframework zu installieren sieht erstmal komplexer aus als es ist. Hier wird es gut erklärt. Wenn man mit dem WAMP-Paket von Bitnami das Framework mit installiert hat, findet man es unter frameworks/zendframework
Wenn man sich jetzt den Stress mit dem VirtualHost nicht machen will.. oder wir bei mir wo es einfach nicht so recht klappen wollte... kopiert man sich das Verzeichnis einfach in apache2/htdocs.
Wenn es mit dem VirtualHost nicht klappt, darauf achten dass der include der VirtualHost-Datei aus extra nicht auskommentiert ist.
Ausser dem:
Require all granted
Anstelle von
Order allow,deny
Allow from all
Dann sollte es auch klappen. Ansonsten dem hier folgen.
Nachdem mir geraten wurde, als Einstieg in das Zend Framework 2 mich mit der Skeleton Application auseinander zusetzen, bin ich auf einen doch ganz guten und verständlichen Artikel gefunden, der alles in kleine und verständliche Brocken herunter bricht. Geht es nur mir so oder haben auch andere Probleme mit diesen Tutorials und Beispiel die immer alles im Kontext einer einzelnen riesen Anwendung erklären wollen, anstatt in einigen kleinen und einfachen Code-Beispielen die fachlich nichts machen außer dass eine was zu zeigen ist zu zeigen?
Jedenfall hat der Artikel sehr Recht damit, dass am Ende alle mit Wasser kochen und es im Zend Framework 2 auch nur Lösungen für Probleme sind, die jeder der schon mal ein Framework geschrieben hat auch hatte oder hat. Wenn man mal sein Framework mit dem fremden vergleicht, erkannt man auch viele Gemeinsamkeiten, da am Ende viele auf die selbe Lösung gekommen sind. Also sich immer an den Gemeinsamkeiten orientieren und man sollte eigentlich sich schnell in neue Frameworks einarbeiten können.
Das Bootstrapping ist im Grunde immer gleich. Config-Dateien finden und laden. Dann aus den Verzeichnissen die entsprechenden Klassen und weitere Config-Daten laden.
Was mir gleich vertraut vorkam war der ServiceManager, der von der Aufrufstruktur und der Beschreibung genau dem entspricht was bei mir de AddonManager macht. Namen angeben, man bekommt die Instance mit wobei der Manager als Factory agiert und er sorgt dafür, das nur eine Instance davon existiert und nicht unnötig viele neue erzeugt werden müssen, was ja wieder sehr kosten intensiv wäre.
Wenn es so weiter geht sollte die Einarbeitung garnicht so schwer sein.. hoffe ich.
Nach langen Jahren der XAMPP Treue habe ich heute mir mal das WAMP Paket von Bitnami installiert.
Positiv war auf jeden Fall schon mal dass ich das Zend Framework bei der Installation gleich mit installieren
konnte (ist auch sogar gleich das ZF2). Also kann ich mir dann sicher dort auch mal das Beispiel drauf ansehen oder ein neues einrichten.
Der Rest wie aoop war wieder schnell eingerichtet. Einfach Einstellungen aus der Apache Config und der php.ini übernommen. Dann Datenbank importiert und Benutzer angelegt. Lief alles gleich wieder ohne Probleme und auch das Mapping für den REST-Service funktionierte gleich.
Also wird es ab jetzt dann einfach mit WAMP weiter gehen.
Damit habe ich auch gelich den Test von aoop auf PHP 5.4.40 abgeschlossen.. wie erwartet.. lauft!
Momentan überlege ich die auf XML basierenden Config-Dateien in meinem PHP-Framework durch JSON-Dateien
zu ersetzen. Das Parsing bei JSON scheint gefühlt schneller zu sein. Gerade bei der Implementierung der
REST-Services muss die XML-Datei mit den Mappings bei jeden Aufruf neu geparst werden und ich vermute, dass es sehr viel schneller gehen würde, wenn man mit JSON und einen assoc-Array arbeiten würde.
Ich werde wohl demnächst mal paar Tests durchführen. In Java hatte man den Vorteil, dass man die Objekte im Servlet halten konnte und es deswegen relativ egal war wie lange das Parsen dauerte, da es nureinmal erledigt werden musste. Bei PHP kann man die Methoden Mappings in der Session halten, muss aber das Object, dass als Service Endpoint agiert, jedes Mal neu aus der XML lesen.
Die neue Page-Implementierung des Framework verwendet JSON und ist alles andere als langsam dabei.
Den Großteil meiner Zeit habe und verbringe ich momentan noch mit Java. Tomcat, JavaFX, REST-Services und Clients. Neben JavaFX sehr verstärkt auch AngularJS. Nun wird es gegen Sommer dahin gehen, dass ich Java soweit hinter mir lassen werde (als Option halte ich mir Daten-Importer mit Multithreading frei.. weil da Java gegenüber einem PHP-Script doch weit vorne liegt).
Jetzt stellt sich mir die Frage wie man sich am besten in PHP einarbeitet.. wobei es eher weniger um PHP geht als um das Zend Framework 2. PHP kann ich... und ich bin der Meinung, dass wenn ich mir mein eigenes PHP Framework schreiben kann (das schon relativ viel kann und seit der Erweiterung um eine native REST-Unterstützung und das bald neue foglende Page-Format wirklich gut super für meine eigenen Apps auf Angular-Basis funktioniert), ich mich wohl auch ohne größere Probleme darin einarbeiten können sollte.
Viele Konzepte sind mir auch nicht neu und vieles er kennt man auch wieder, wenn man mal ein eigenes Framework geschrieben hat (ich bei JavaScript-Frameworks das selbe, wobei ich da beschlossen habe cJS zu Gunsten von AngularJS nicht mehr weiter zu entwickeln und cJS nur noch
für die kleinen gepackten Firefox OS Apps zu verwenden).
Erstmal muss ich heraus finden welche Umgebung zum Entwickeln unter Windows ideal wäre und man wenig per Hand nach installieren müßte. PHPStorm habe ich schon gestestet und das Generieren von Gettern und Settern ist schon mal super. Aber Eclispe ist schon mehr fertig eingerichtet.
XAMPP oder WAMP? WAMP scheint eine Zend Framework Installation mit Beispiel Modul mitzubringen.
Aber dann mal gucken ob als VM oder Installation. Eine VM mit Linux und Spiegeln des Verzeichnisses über WinSCP hätte natürlich schon seine Vorteile.
Aber meien Feststellungen bis jetzt ist, dass das Zend Framework 2 mit seinen Namespaces sehr viel dichter an Java dran ist, als die 1.x Version oder auch mein eigenes aoop-Framework.. das bald mal umbenannt wird.
Aslo werde ich erstmal in den nächsten Tagen, analysieren welche Umgebung für mich die beste ist und sich am einfachsten Installieren läßt.
Wenn man sich etwas mit JavaScript beschäftigt und auch sich mit Java gut auskennt, lernt man schnell die Vorteile von nicht statischen Typen zu schätzen (kein aufwendiges Parsen und Casten bei REST-Operationen auf Basis von JSON, etc). Aber manchmal fehlen Typen und so doch etwas.. hier wird sehr gut erklärt wie man moderne und struktirierte JavaScript Anwendungen schreibt, die wartbar beleiben und auch in Unternehmen dann vielleicht akzeptiert werden.
AngularJS, require.js, JQuery, TypeScript, Bower.. wird alles mal kurz angesprochen und erklärt.
zum Jahres Ende kommt mal ein Update von aoop auf 0.6, was sich jetzt immer mehr zur Middleware für JS-Webapps entwickelt. Die Neuerungen sind:
* mehr Singletons für bessere Performance
* seperates Theme für das Admin-Panel einstellbar
* REST-Services Unterstützung im Kernsystem (definierbar über module/desploy/rest.xml)
* Login Sicherheit (Sperrung für 5min nach 3 gescheiterten Loginversuchen)
* Begonnen requireJS für JS-Module zu integrieren
* schon mal der Begin einer Entwickler-Dokumentation um selbst aoop als Middleware zu verwenden.
Neben bei entsteht ein eigenes kleines JS-Framework, das Controller-Objekte für Views und passendes Databindung ermöglicht. Kein Templating.. dafür aber sehr klein und Übersichtlich. Erste Test-App gibt es schon damit: