Arbeiten mit einer Datenbank - Part 3 - PHP Soziales Netzwerk programmieren

Поделиться
HTML-код
  • Опубликовано: 27 сен 2024

Комментарии • 45

  • @VitalijMik
    @VitalijMik  Год назад +1

    ruclips.net/video/cEWlm-iXeF8/видео.html das video hat mich überzeugt UUIDs zu nutzen

  • @pinkeHelga
    @pinkeHelga Год назад +2

    Frohes neues Jahr auch Dir. :)

  • @pinkeHelga
    @pinkeHelga Год назад +4

    Das Schöne an der Serie ist, daß ich noch einen haufen nützlicher Pakete kennenlerne. Was ich davon längerfristig als brauchbar einstufe, wird sich zeigen.
    Vor allem müssen bei mir Pakete auf Performanz ausgerichtet sein. Native Zend-Module ziehe ich im Zweifel vor.

    • @VitalijMik
      @VitalijMik  Год назад +1

      ach PHP ist sowieso total performant. Ich habe statistiken gesehen wo PHP schneller ist als NodeJS ;) die Performance Probleme kommen meist über das IO. Filestorage, DB, API.

    • @pinkeHelga
      @pinkeHelga Год назад

      @@VitalijMik Wobei ja gerade in dem Punkt Node punkten kann mit seiner Asynchronität. Es kann mehrere Systemoperationen gleichzeitig anstoßen, und die Verarbeitung erfolgt, sowie die einzelnen Ergebnisse bereitstehen.

    • @pinkeHelga
      @pinkeHelga Год назад

      Drupal >= 7 ist so ein Negativbeispiel. Drupal 6 fand ich klasse. Seit Version 7 bin ich schockiert, wie lange schon die vorinstallierte Begrüßungsseite braucht, um vom lokalen System geladen zu werden.

    • @VitalijMik
      @VitalijMik  Год назад

      @@pinkeHelga amphp.org/ php kann auch asynchron arbeiten und bei nodejs ist letzendlich garnicht so viel Asynchron weil man ja festgestellt hat dass die Programmierung ja doch nicht so schnell ist. du siehst viele stellen mit async await und da wartet der code tatsächlich auf die antwort.
      NodeJS ist wie ein Hybrid Auto, nur weil es ein Akku hat, heißt es nicht dass es immer genutzt wird ;)

    • @VitalijMik
      @VitalijMik  Год назад

      @@pinkeHelga wer weiß was im Hintergrund so passiert. und wer weiß was da für ein server ist. ich habe keine Erfahrung, kann nichts dazu sagen

  • @dennisbrieske8051
    @dennisbrieske8051 Год назад +1

    Die Frühstückspause morgen ist gerettet mit deinem neuen Video Vitalij😀 schönen Abend und ebenso ein frohes Neues nachträglich 🎉

    • @VitalijMik
      @VitalijMik  Год назад +1

      Dankeschön viel Spaß damit:D

  • @pinkeHelga
    @pinkeHelga Год назад +1

    #videorequest Falls Du noch kein solches unentdecktes Video in der Sammlung hast:
    Eine kleine Anleitung, wie man selbst Composer-Pakete erstellt und ggf. veröffentlicht, wäre cool.
    Und kann man da auch ein nicht-öffentliches, lokales Repo pflegen und einbinden?
    - eigenes Repo in Verzeichnis oder LAN, das nur die eigene Entwicklung enthält (kein Mirror)
    - in Projekte beides einbinden - öffentliche Repos und lokales Repo
    - mit PHPStorm ein Package erstellen, das möglichst automatisch im Repo verzeichnet wird
    Ich werd da nicht ganz schlau aus den Anleitungen im Netz. Wie und wo erstelle ich die packages.json richtig? Was hat Satis damit zu tun? Geht's auch per Hand?
    Da wär ein Tutorial mal mega. :)

    • @VitalijMik
      @VitalijMik  Год назад +1

      Du kannst in composer ein repository path angeben. Das habe ich bei einem anderen Projekt so umgesetzt
      github.com/Opentribes/Framework/blob/main/composer.json#L16-L24
      Composer schaut erst in den pfaden nach ob es da eine composer.json finden kann und wenn ja, wird es die composer .json nutzen, ansonsten gibt es ein fallback auf packagist wo die repositories registriert sind.
      Du kannst ein Projekt anlegen und ihm einen namen und version über die composer.json angeben und dann später im eigentlichen Projekt via repository drauf verweisen

  • @_victorandreas
    @_victorandreas Год назад +1

    Hallo Vitalij, echt mal wieder alles super erklärt, aber ich habe noch ein paar Fragen/Anmerkungen/Gedanken:
    Vorab: ich habe noch nie mit DIs oder PHP8 gearbeitet^^
    1. warum übergibst du beim UserEntity jedes Feld als einzelnen Parameter und nicht ein Array? Das macht es doch viel aufwändiger neue Felder hinzuzufügen.
    =>
    public function __construct(array $data) {
    foreach($data as $key => $value) {
    if(property_exists($this, $key)) {
    $this->$key = $value;
    }
    }
    }
    2. Hast du vor ein ORM zu implementieren?
    3. würde es nicht mehr Sinn machen ein "globales" Repository Interface zu erstellen, statt für jede Entity Klasse ein eigenes, in dem immer wieder die gleichen Logiken abgearbeitet werden? Ebenso PDOUserRepository als "PDORepository" und in PDOUserRepository einfach die Felder definieren bzw sich diese aus UserEntity ziehen per Reflection ziehen oder eine Methode UserEntity->persistData()?
    4. müsste die Dependency UserRepository::class nicht automatisch erkennen, dass PDO als Parameter erwartet wird? Also UserRepository::class => PDOUserRepository::class?
    Grüße gehen raus ;-)
    -Victor

    • @VitalijMik
      @VitalijMik  Год назад

      hi dankeschön
      also zu 1
      solche konstrukte sind immer schwer zu lesen. du weiß nicht was in $this steht und welche felder es gibt usw. es ist viel einfacher wenn die Variablen explizit übergeben werden, dann kannst du auch den code nachvollziehen ohne einen debugger zu starten
      zu 2: nein ORM werde ich nicht einbauen, einfache SQL statements sind eifnacher zu debuggen und zu prüfen
      zu 3: nein denn eine klasse die für alle mögliche fälle ausgelegt ist, ist schwierig zu debuggen. mit einzelnen repository klassen weiß ich dann genau welche Klasse für welches Objekt steht. außerdem will ich später einige Dinge nicht in der DB speichern sondern in anderen quellen, das zeige ich dann später. in der action soll es aber keine rolle spielen wo man die daten letzendlich abspeichert. eine allgemeine PDO klasse würde unnötig komplexität ins projekt reinbringen
      4) eigentlich schon, es kann sein dass ich da noch vergessen habe irgendwas zu konfigurieren, deshalb bin ich den einfachen weg erstmal gegangen damit wenigstens etwas funktioniert.
      hoffe ich konnte deine Fragen beantworten.
      Viele Grüße

    • @_victorandreas
      @_victorandreas Год назад +1

      @Vitalij Mik Ja, Danke für die schnelle Antwort.
      Angenommen Du möchtest beim User den Vornamen hinzufügen, müsste man durch X Dateien gehen:
      - UserEntity __construct / getter
      - PDOUserRepository::persist()
      - Register::__invoke()
      - RegisterValidator::isValid()
      - UserHydrator::hydrate()
      Ich bin ein Freund davon so viel wie möglich an einer Stelle zu haben
      Könnte man nicht einiges in die UserEntity class verlagern und Interfaces nutzen?
      class UserEntity implements Hydratable, Validatabe, Persistable
      - UserEntity::hydrate($data) { /*$id = ...*/ return new static($id, ...); }
      - UserEntity::isValid(Validator $validator, $data) {$errors=[]; /*do checks*/$validator->errors = $errors; return $validator->hasErrors();} // called in Register::__invoke() {/*...*/ if($isPostRequest && UserEntity::isValid($this->validator, $body){/*...*/} /*...*/}
      - UserEntity::registrationData(ServerRequestInterface $request) {} // called in Register::__invoke()
      - UserEntity->persistData() { return ['id' => $this->id, 'username' => $this->username/*, ...*/]; } // called in PDOUserRepository::persist() {/*...*/} foreach($this->created as $index => $user){ $userData = $user->persistData(); foreach($userData as $k => $v) {$insertData[":$k$index"] = $v;}} /*...*/ }
      - interface Hydratable {public static function hydrate(array $data);}
      - interface Validatabe {public static function isValid(Validator $validator, $data);}
      - interface Persistable {public function persistData():array;}
      Das wäre meine persönliche Vorangehensweise. Somit hätte ich alles in einer Datei im Blick :-)

    • @VitalijMik
      @VitalijMik  Год назад

      @@_victorandreas ich verstehe was du meinst, aber das Problem ist, du verstößt dadurch gegen das Single Responsiblity Principle. Eine Klasse hat eine Zuständigkeit. Wenn du jetzt in dein UserEntity alle möglichen Features hinzufügst, dann hat die Klasse zu viele Zuständigkeiten.
      Ja erweitern von einem Feld bedeutet etwas Fleißarbeit. Allerdings kommt eine erweiterung nicht einfach so dazu. Dahinter steht ja eine Entscheidung und das muss dokumentiert werden.
      Dass der Validator und der Hydrator da einzelne Variablen kriegt finde ich auch nicht schön, aber das wäre nicht die Zuständigkeit von der Entity. Ich werde da vermutlich eine Request Klasse erzeugen und dann die getter auslesen.

    • @_victorandreas
      @_victorandreas Год назад

      @@VitalijMik Ahhh... Single Responsiblity Principle^^ das kenne ich noch nicht. Aber der Name verrät schon ein bisschen was man sich darunter vorstellen kann. Da werde ich mich mal schlau machen ;-)

    • @VitalijMik
      @VitalijMik  Год назад

      @@_victorandreas ich bin ein Freund davon, dass ich den Code bewusst verändere weil sich die Anforderungen geändert haben statt einen Code zu erstellen der auf alle möglichen Anforderungen abdeckt obwohl die eventuell nicht gebraucht werden.
      Ein Code zu erstellen der alles handhaben soll bedeutet ja oft dass man nicht weiß was die Software tun soll. YAGNI Prinzip. You aint gonna need it. Dafür baut man dann oft Magischen Code weil man möglichst alle Fälle abdecken will. Das führt wiederum zu erschwerter Lesbarkeit, Performance Verlust.
      Fürs Rapid Development ist das natürlich schwierig.

  • @RealLexable
    @RealLexable Год назад +1

    And the winning price goes to Mr.Mik as usual...please never stop that project Mister!

  • @pinkeHelga
    @pinkeHelga Год назад +1

    7:30 _sprintf_ könnte man hier noch halbwegs rechtfertigen, um kurz und unkompliziert den _Null Coalescing Operator_ `??` zu benutzen. Die Funktion wird zu häufig mißbraucht. Interpolation mit Ausdrücken wie "Text {$var??'Vorgabe'} ausgeben" funktioniert leider nicht. Da ist Concatenating doch keine so schlechte Alternative, oder man definiert vorher Variablen, die interpoliert werden.
    `$_ENV['DB_NAME'] ??= "DefaultDB";` wäre auch nicht schlecht, wenn es im ganzen Projekt keine Rolle spielt, ob die Environment-Variable ursprünglich gesetzt war oder nicht. Spart den Overhead der mehrfachen Prüfung ein.
    Interessant und die Performanzkosten wert (aber nicht alternativlos) werden die printf-Funktionen erst bei echter Formatierung wie:
    setlocale(LC_ALL, 'de_DE.utf8');
    printf('Zahl: %08.2f'.PHP_EOL, 123.456);
    => Ausgabe: "Zahl: 00123,46"
    Oder man hat einen Satz von unterschiedlichen Formatstrings bei Internationalisierung, wo numerierte Paramerter auch noch in unterschiedlicher Reihenfolge auftreten. Da macht _printf_ absolut Sinn.

    • @pinkeHelga
      @pinkeHelga Год назад

      Ich möchte einfach anregen, in größeren Projekten darüber nachzudenken, ob man wirklich _printf_ exzessiv zur vermeintlichen Code-Kosmetik mißbrauchen möchte, insbesondere an kritischen Stellen innerhalb von Schleifen.
      Und in vielen Fällen macht es den Code durch die Trennung sogar unlesbarer, wo interessant ist, _was_ da gerade eingefügt wird.

    • @VitalijMik
      @VitalijMik  Год назад

      tatsächlich sehe ich printf wirklich nur in seltenen fällen in php. meistens wenn man bei einer Zahl die nuller vor anstellen möchte sonst nie. sprintf nutze ich immer wieder in error messages. weil es einfacher ist, den satz der Fehlermeldung anders zu schreiben und die platzhalter bequem verscheiben. Die Fehlermeldungen hat man ja nicht von anfang an so sinnvoll gewählt dass diese auch jemand außerhalb des projekts versteht.
      Bezüglich performance, da bin ich mir nicht sicher, ich glaube das fällt unter der Kategorie microoptimization

    • @pinkeHelga
      @pinkeHelga Год назад

      @@VitalijMik Kommt drauf an wo. Bei einmaliger Ausführung ist quasi jede Optimierung micro optimization :)
      Durch die Mächtigkeit der Formatierungen ist fprint schon deutlich langsamer als Concatenation, Interpolation und Heredocs. Interpolation war auch mal eine Bremse, wurde als Sprachkonstrukt im Laufe der Zeit aber schon starkt optimiert, nimmt sich mit Concatenation praktisch nichts mehr. Versteht der Laufzeitcompiler beides sehr gut.

  • @florianmertens2431
    @florianmertens2431 Год назад +1

    Hallo Vitalij, warum machst du für die Datenbank kein Interface, sondern gehst direkt auf PDO?

    • @VitalijMik
      @VitalijMik  Год назад

      Weil für das Repository ein interface da ist. Das Konkrete PDO Repository ist von PDO Abhängig also brauche ich kein Interface dafür. Die Klassen nutzen das Repository interface

    • @florianmertens2431
      @florianmertens2431 Год назад +1

      ​@@VitalijMik Habe glaube meinen Gedankenfehler gefunden, ich dachte du hättest für alle Klassen ein eigenes Interface erstellt damit es austauschbar ist, beim genauen angucken hast du das aber nur beim TemplateRenderer gemacht

    • @VitalijMik
      @VitalijMik  Год назад

      @@florianmertens2431 ne, nur für die Klassen, die ich auch in Zukunft ersetzen will. PDORepository ist halt eine konrekte PDO implementierung