Skip to content

Instantly share code, notes, and snippets.

@paresy
Last active December 3, 2019 10:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paresy/236bfbfcb26e6936eaae919b3cfdfc4f to your computer and use it in GitHub Desktop.
Save paresy/236bfbfcb26e6936eaae919b3cfdfc4f to your computer and use it in GitHub Desktop.
Best Practice zur PHP-Modul Erstellung

Best Practice zur PHP-Modul Erstellung

  1. Generelle Entwicklung

    1. Module sollten grundsätzlich auf Englisch erstellt und ins Deutsche übersetzt werden
    2. Fehlermeldungen dürfen mit @ nur verdeckt werden, wenn der Rückgabewert überprüft wird und bei einem echten Fehlerfall dies dem Nutzer mitgeteilt wird. Andernfalls findet man im Fehlerfall den Verursacher niemals heraus. Sichtbare Fehler können behoben werden. Unsichtbare Fehler bringen inkonsistentes Verhalten und frustrieren nur alle beteiligten.
    3. Daten, welche der Benutzer nicht benötigt, sollten auch nicht in Variablen erscheinen (z.B. irgendwelche Puffer / Temporäre Inhalte in String Variablen). Dafür bietet das SDK die SetBuffer/GetBuffer Funktionen, welches über eine JSON Kodierung auch mehrere Elemente enthalten können.
    4. Der Inhalt der library.json / module.json darf nur die von der Dokumentation definierten Felder enthalten. Andere Felder können in zukünftigen Version seitens IP-Symcon verwendet werden und sind vollständig reserviert.
    5. Module mit externen Abhängigkeiten müssen diese vollständig im speziell erlaubten libs Ordner mitliefern.
    6. Ein Modul darf niemals Abhängigkeiten aus einer anderen Bibliothek erfordern, sodass das Modul (ohne diese Bibliothek) "kaputt" ist (z.B. ein include auf eine benötigte PHP Datei). Eine Bibliothek muss immer in sich geschlossen und funktionsfähig sein. Optionale Funktionen können durch zusätzlich installierte Bibliotheken freigeschaltet werden. (Randfall: Ein Modul kann ohne sinvolle Funktion sein, solange keine anderen installierten Bibliotheken vorhanden sind. Sie muss aber darauf Hinweisen und trotzdem fehlerfrei installierbar sein. Sobald weitere unterstützte Bibliothken installiert werden, erweitert sich der Funktionsumfang)
    7. Objekte dürfen niemals über den Namen gefunden werden. Es muss immer ein Ident gesetzt und dafür verwendet werden.
    8. Insbesondere in überschriebenen Create und ApplyChanges Funktion, welche beim Start von IP-Symcon aufgerufen werden, sollte nicht darauf vertraut werden, dass andere Instanzen verfügbar sind, da dieser in zufälliger Reihenfolge erstellt werden können. Die Fehlermeldung "InstanceInterface is not available" kommt ansonsten zum Vorschein. Es sollte somit immer überprüft werden, ob der Kernel Runlevel gleich KR_READY ist. Alternativ ist auch Möglich per RegisterMessage und MessageSink auf die Nachricht IPS_KERNELSTARTED zu reagieren. Diese Einschränkung betrifft ebenfalls den Datenfluss, sodass keine SendDataToParent / SendDataToChildren Funktionen verwendet werden dürfen.
    9. Die seit IP-Symcon 5.0 enthaltene RequestAction Funktion löst in weiten Teilen die früher benötigten Public-Funktionen zum Schalten ab. Es ist somit nicht mehr erforderlich Public-Funktionen zum Schalten anzubieten.
  2. Die Hoheit des Benutzers wahren

    1. Eine Instanz sollte niemals automatisch Variablen im Archiv aktivieren. Dies ist allein die Entscheidung vom Benutzer, welcher dies explizit tun kann und soll. Bei einem Modul mit sehr vielen Variablen kann ein zusätzlicher Button im Aktionsbereich des Konfigurationsformulars platziert werden, welcher explizit gedrückt werden muss um diesen Vorgang zu automatisieren.
    2. Eine Instanz sollte im Normalfall die Sichtbarkeit/Bedienbarkeit nicht verändern. Wenn es dies tut, sollte die Dokumentation darauf hinweisen, dass diese Eigenschaften für die jeweiligen Objekte nicht dem Benutzer zur Verfügung stehen.
    3. Der Name/Position einer Variable darf nur über die RegisterVariable* Funktionen vorgegen werden. Nachträgliche Änderung und Sortierung obliegt vollständig dem Benutzer.
    4. Ein Modul darf niemals automatisch andere Instanzen erstellen. Ausnahmen bilden die RequireParent/ConnectParent/ForceParent Funktionen, welche automatisch die Datenflusskette erstellen. Wenn Instanzen automatisiert erstellt werden sollen, passiert dies nur über einen Button im Aktionsbereich der Konfigurationsformulare, sodass der Benutzer die vollständige Kontrolle hat, wann neue Instanzen erstellt werden. Bevorzugt wird das Erstellen von einzelnen Instanzen über das Konzept der Konfiguratoren.
    5. Eigenschaften (Properties) dienen zur Konfiguration durch den Benutzer. Ein Modul sollte sich niemals selber umkonfigurieren (z.B. über IPS_SetProperty oder IPS_SetConfiguration). Ebenfalls ein Aufruf aus einem Splitter Modul (siehe 5.1) ist nicht gestattet. Sollen Instanzen vorkonfiguriert erstellt werden, muss dazu ein Konfigurator erstellt werden, über den der Benutzer passende Instanzen erstellen kann.
  3. Profile

    1. Profile sollten mit PREFIX.NAME erstellt werden. (IP-Symcon und unsere Modul halten sich noch nicht daran - ich würde dies gerne als Konvention zur Diskussion in den Raum stellen)
  4. Datenfluss korrekt verwenden

    1. Um die Belastung im System gering zu halten, wird empfohlen die entsprechenden Data Filter zu setzen (SetReceiveDataFilter, SetForwardDataFilter)
    2. Siehe auch 5.1
  5. Kompatibilität für Sandboxing von Instanzen

    1. Es gibt nur wenige Ausnahmen, in denen eine Instanz eine anderen Instanz aufrufen darf. Insbesondere zum Übermitteln von Daten oder Schaltbefehlen zu anderen selbst erstellten Instanzen muss der offizielle Datenfluss genutzt werden. Eine andere Instanz darf nur angesprochen werden, wenn der Benutzer diese explizit im Konfigurationsformular ausgewählt hat. (z.B. wie im Shutter Control oder im USB Mapper (https://github.com/paresy/SymconMisc/blob/master/USBMapper/module.php), wo der Benutzer die zu verändernde Instanz angibt).
    2. Eine Instanz darf nur Objekte direkt unterhalb sich selbst verändern. Es ist niemals erlaubt z.B. andere Variablen von anderen Instanzen über SetValue zu verändern. Sollten weitere Instanzen unterhalb dieser Instanz platziert worden sein (Misachtung von Punkt 6.1) kann diese Instanz und alles unterhalb ebenfalls nicht verändert werden. Weiteres Beispiel: Ein Splitter darf niemals die Variablen der verknüpften Instanzen verändern. Dazu ist der Datenfluss zu verwenden.
  6. Usability

    1. Eine Instanz sollte Objekte nur direkt unter sich selbst erstellen. Weitere Verschachtelungen sind z.B. für die mobile Ansicht problematisch und sollten vermieden werden.
    2. Das Verlinken von Objekten unterhalb einer Instanz sollte, seit dem Vorhandensein der Listen, nicht mehr verwendet werden.
    3. Vorhandene Schaltmöglichkeiten (PHP-Befehle) sollten so gut wie möglich über den Aktionsbereich im Konfigurationsformular getestet werden können.
  7. Dokumentation

    1. Im Hauptverzeichnis sollte eine README vorhanden sein, welche auf die in der Bibliothek vorhandene Module mit einer kleinen Beschreibung verweist. (Beispiel: https://github.com/paresy/SymconMisc)
    2. Für jedes Modul sollte eine README vorhanden sein, welche mindestens folgende Punkte enthält
      • Funktionsumfang, welches erklärt was dieses Modul überhaupt kann
      • Voraussetzungen, z.B. die IP-Symcon Version
      • Kompatibilität, z.B. welche Geräte unterstützt werden
      • Die Modul-URL z.B. zu GitHub
      • Einstellmöglichkeiten der Konfigurationsseite
      • Exportiere PHP-Befehle
  8. Style Guide

    1. Um die Formatierung vom Code so konsistent wie möglich zu gestalten, sollte der PHP-CS-Fixer mit den Regeln aus folgendem Repository verwendet werden: https://github.com/symcon/StylePHP. Über GitHub Actions kann dies als Check vollautomatisch verifiziert werden: https://github.com/symcon/SymconStubs/blob/master/.github/workflows/style.yml
  9. Automatisierte Tests

    1. Unser Symcon Stubs Repository (https://github.com/symcon/SymconStubs) bietet eine gute Grundlage, um Module automatisiert zu testen. Insbesondere eine Basis-Validierung prüft die library.json und module.json der einzelnen Module und wird sehr empfohlen. (Beispiel: https://github.com/symcon/SymconStubs/blob/master/tests/CoreStubsValidationTest.php). Über GitHub Actions kann dies als Check vollautomatisch geprüft werden: https://github.com/symcon/SymconStubs/blob/master/.github/workflows/tests.yml
@Nall-chan
Copy link

Zu 3.1
Dafür.
Zusätzlich: Muss ein Profil eindeutig einer Instanz zugehören, so ist die InstanzID im Profilnamen mit [PUNKT][InstanzID] anzuhängen.
Ebenso sollten nicht mehr benötigte Profile z.b. beim löschen von Instanzen wieder entfernt werden.

@Nall-chan
Copy link

Zu 4.1
Anstatt 'wird empfohlen' bin ich für 'müssen'.

@Nall-chan
Copy link

Nall-chan commented Jul 28, 2019

Zu 1.9
Entspricht nicht der gewünschten Nutzung von ReqestAction anstatt von Instanzbefehlen in Ereignissen und Scripten.
Da jetzt vermehrt einfache Schaltfunktionen nicht mehr als Instanzbefehl zur Verfügung gestellt werden, ist der Passus nicht mehr aktuell.

@paresy
Copy link
Author

paresy commented Aug 21, 2019

Zu 3.1
Dafür.
Zusätzlich: Muss ein Profil eindeutig einer Instanz zugehören, so ist die InstanzID im Profilnamen mit [PUNKT][InstanzID] anzuhängen.
Ebenso sollten nicht mehr benötigte Profile z.b. beim löschen von Instanzen wieder entfernt werden.

Da wir in zukünftig "lokale" Profile anbieten wollen, würde ich das aktuell gar nicht mehr anfassen.

Zu 4.1
Anstatt 'wird empfohlen' bin ich für 'müssen'.

Für simple Fälle wäre ein müssen eine sehr harte Hürde für jemanden der kein RegEx kann.

Zu 1.9
Entspricht nicht der gewünschten Nutzung von ReqestAction anstatt von Instanzbefehlen in Ereignissen und Scripten.
Da jetzt vermehrt einfache Schaltfunktionen nicht mehr als Instanzbefehl zur Verfügung gestellt werden, ist der Passus nicht mehr aktuell.

Stimmt. Ich werde den Punkt abändern, dass es keine Public Funktionen geben muss, da RequestAction werdet werden soll.

@Nall-chan
Copy link

Zu 1.8:
Gilt nicht nur beim starten von Symcon, sondern auch bei Update des Modules.

@Brovning
Copy link

Brovning commented Dec 3, 2019

Hallo,
könnte man zu "Automatisierte Tests" noch ein paar Sätze hinzufügen?
Was muss ich im Detail machen, um CoreStubsValidationTest.php nutzen zu können?
Action ist erstellt und dann?
Welche Dateien müssen wo in meinem GitHub Modul-Verzeichnis hinzugefügt werden?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment