Doctrine ORM w PHP - kilka dobrych praktyk

Поділитися
Вставка
  • Опубліковано 12 січ 2025

КОМЕНТАРІ • 31

  • @maciejfiglarz4871
    @maciejfiglarz4871 4 роки тому +2

    świetny materiał!

  • @marcin.k.7
    @marcin.k.7 4 роки тому +1

    Z mojego doświadczenia, sporo problemów powodują ogólnie filtry doctrinowe. Przy softdelete trzeba dodawać, fetch eager do relacji. Gdy musiałem dobrać się do usuniętych obiektów to nie jednokrotnie filtr trzeba było wyłączać, a co gorsze po masie bugów jakie mnie przez to dopadły konieczne było każdorazowe włączenie filtra.
    W małych e-commercach do archiwizowania np. produktów w zamówieniu korzystałem z serializacji i zapisu w osobnym polu/encji trochę pracy to wymagało bo trzeba było nadpisywać serializowanie ale mnie jeszcze to nie zawiodło i nie znalazłem na tą chwilę lepszego rozwiązania, zawsze można było zapisać na boku cenę i nazwę ale wygodniej pracuje się na całym obiekcie, choćby częściowo wypełnionym.

    • @Koddlo
      @Koddlo  4 роки тому +1

      Jasne. Chociaż być może właśnie obiekt może zostać oznaczony jak zarchiwizowany i to jest sensowne rozwiązanie bo tak wychodzi z domeny. Co do zapisu obiektu zserializowanego to rozwiązanie może rodzić problemy jeśli jakieś pola w obiektach się pozmieniają (dodamy coś, edytujemy itp). To okaże się że ciężko się migruje tak zapisane obiekty - ale fakt jest to wygodne. W każdym razie soft-deletowanie wszystkiego co się da z natury jest słabym pomysłem - przynajmniej według mnie.

  • @kubaleman3440
    @kubaleman3440 4 роки тому +4

    świetny film, można sie sporo ciekawostek dowiedzieć.
    Jednakże mam coś do dodania. Zauważyłem, że w takich filmach często prowadzący używają słów, które określają jakąś czynnośc. Np: u Ciebie pojawiło się hydrowanie (o ile dobrze zrozumiałem wymowę). Nie znałem go wcześniej, jednakże z kontekstu można domyśleć się, że chodzi o ładowanie obiektów z bazy (popraw mnie jeśli się mylę.).
    Proponuje dodawać na ekranie w momencie kiedy pierwszy raz pojawia się na filmie jego wyjaśnienie.
    Ewentualnie dodać to do opisu filmu.
    A druga sprawa czy planujesz zrobić film na temat DDD lub architektury hexagonalnej? Ciężko znaleźć dobry materiał po polsku. Przerobiłem kilka zagranicznych ale zawsze warto byłoby potwierdzić wiedzę, z lokalnego podwórka.
    PS. więcej przykładowego kodu proszę! np. w N+1 mogłeś pokazać jak to wszystko wygląda od strony kodu i repo
    daj znać, że odczytałeś :))

    • @Koddlo
      @Koddlo  4 роки тому +1

      Dziękuje za podzielenie się opiniami.
      Co do używanych słów to zawsze jest problem, ciężko tłumaczyć wszystko. Sam czasem oglądam coś i nie rozumiem jakiegoś słowa ale wtedy we własnym zakresie szukam w internecie znaczenia. Co do hydracji upraszczając dobrze zrozumiałeś.
      Na razie dotykam konceptów z DDD tylko w wąskim zakresie, który można przenieść do kodu nawet nie wykorzystując w pełni DDD, na przykład Encja czy Repozytorium. Samego DDD dopiero się uczę i nie czuję żebym był kompetentny do szkolenia z tego. Polecam Ci na przykład posłuchać podcastu Better Software Design. Tam znajdziesz kilka ciekawych materiałów. Co do architektury hexagonalnej na razie nie mam w planach, ale gdybym kiedyś jakiś projekt pokazowy tworzył to pomyślałbym czy nie wpleść tego dodatkowo.
      Kod ciężko pokazywać w takich prezentacjach, to raczej teoria. 🙂

  • @gdulaukasz3947
    @gdulaukasz3947 3 роки тому +4

    Co do UUID, nie wspomniales o minusach a jest nim miedzy innymi nierownomierny rozklad wartosci co w polaczeniu z tym jak dziala mechanizm cachowania w MySQL (InnoDB), uzycie takiej wartosci na kluczach glownych spowoduje masakrycznie slaba wydajnosc juz przy stosunkowo niewielkich zbiorach danych.

    • @Koddlo
      @Koddlo  3 роки тому +1

      To prawda, bo nie jestem ekspertem w temacie baz danych, a temat nie jest taki zerojedynkowy. Z tego co kojarzę to faktycznie może zadziałać to słabo na wydajność przy UUID jako klucz główny, ale są sposoby jak tego UUID używać dobrze, tak by wydajność nie spadła. I też bym zdefiniował co masz na myśli mówiąc niewielkie zbiory.

    • @Koddlo
      @Koddlo  3 роки тому +1

      Z tego co wiem to binary UUID działa optymalnie.

    • @gdulaukasz3947
      @gdulaukasz3947 3 роки тому

      @@Koddlo Niewielkie (to z praktycznego przykladu) 200k rekordow i tabela laczaca 3 encje po uuid. Ten sam serwer nie mial problemu z obsluzeniem tabel po 45m rekordow, laczonych w tradycyjny sposob.
      Binary pomaga ale nieznacznie ze wzgledu na specyfike cache w InnoDB (w High Performace MySQL jest caly rozdzial na ten temat)

    • @Koddlo
      @Koddlo  3 роки тому +1

      Wtedy to nie jest UUID. Jest to ID. Oczywiście może być, jeśli masz taką potrzebę. Niestety musisz wówczas gdzieś zapisywać informację o najwyższym ID albo pytać bazę w momencie tworzenia obiektu, co niestety może powodować też problem tego typu, że stworzysz kilka obiektów z tym samym identyfikatorem. UUID daje Ci unikalność na poziomie tabeli i całej bazy. ID, które opisałeś tylko na poziomie tabeli.

  • @szczeczaczoszczeczek5077
    @szczeczaczoszczeczek5077 4 роки тому +1

    Bardzo interesujący materiał. Kiedyś gdy czytałem o miękkim usuwaniu, było napisane że każda informacja jest cenna i zachęcali do miękkiego usuwania. A jeśli chodzi o takie zapytania, można mieć kolumnę w bazie "statusSoftDelete" lub coś takiego? W doctrine nie ma na wbudowanych metodach findAll, findOne lub find, findById parametrów typu findAll([ "where" => ["statusSoftDelete => false]] dla bardzo prostych zapytań i trzeba wtedy własne pisać?
    Pokażesz w przyszłości jak odbierać dane z frontu w formacie json gdy piszemy np. w Symfony REST API? Chodzi mi o najbardziej polecany sposób i jak takie dane przechowywać gdy w jsonie przyjdzie obiekt który ma inne obiekty i tablice, jak się takie rzeczy trzyma w relacyjnych bazach, bo jeśli chodzi o mongoDB nie ma z tym problemu (wszystko w składni jsowej więc łatwo)?

    • @Koddlo
      @Koddlo  4 роки тому +1

      Dzięki za komentarz. To po kolei:
      - można mieć takie pole (ale jeśli wsłuchasz się w to o czym mówiłem w wielu przypadkach okaże się, że nie powinno go tam być).
      - można skorzystać z wbudowanej metody findBy() do której przekażesz właśnie parametry dla klauzuli WHERE. Jednakże ja uważam, że lepiej jest robić swoje własne w każdym przypadku - o czym mówię w prezentacji i też podaję argumenty dlaczego.
      - kto wie, może i na taki materiał przyjdzie pora. Co do odbierania danych w jsonie i tak jeśli trzyma się to w relacyjnej bazie danych pisze się jakieś normalizery/serializery, które tego jsona przekształcą na faktyczny obiekt, ale oczywiście to nie jedyne rozwiązanie. Da się przetrzymywać jsony też w bazach relacyjnych, ale ma to swoje zalety i wady - dużą rolę odgrywa tutaj też silnik bazodanowy. W sieci na pewno znajdziesz o tym sporo materiałów, a może i ja coś kiedyś takiego przygotuję.

    • @jakubksiazek4740
      @jakubksiazek4740 4 роки тому +1

      Jeśli już koniecznie potrzebujemy używać soft-delete to chciałbym dorzucić dwie rady - pierwsza, żeby zamiast flagi trzymać datę usunięcia, np. deletedAt - dzięki temu będziemy mieć informację czy encja została usunięta (jeśli nie deletedAt będzie puste) oraz kiedy. Druga rada dotyczy tego, że istnieje sposób na to aby rozszerzyć Doctrine o globalne filtry, które będą aplikowane zawsze i przez to będzie można wrzucić tam przykładowy where sprawdzający naszą datę w każdym zapytaniu. Niestety trzeba do tego napisać własny sqlWalker i wpiąć go przez hint w entityManagerze.
      www.doctrine-project.org/projects/doctrine-orm/en/2.7/cookbook/dql-custom-walkers.html

    • @hubert7855
      @hubert7855 3 роки тому

      Skoro są potrzebne ale usunięte i nie można ich zmienić (bo przecież już są usunięte) to lepiej zrobić identyczną tabelę np. z suffixem archive, która nie ma relacji.
      Unią można wyciągnąć dane z oby dwóch tabel. Opcjonalnie do tabeli _archive tylko dodawanie i odczyt bez modyfikacji.

    • @jakubksiazek4740
      @jakubksiazek4740 3 роки тому

      ​@@hubert7855 Twoje rozwiązanie jest interesujące, ale jeśli chciałbyś to zamodelować obiektowo to podczas operacji usuwania musielibyśmy utworzyć dodatkową encję i przekopiować właściwości z tej usuwanej do tej archiwalnej. Podobnie wyciąganie takich rekordów przez jakiegoś ORMa może być bardziej skomplikowane niż prostej kolekcji. Jest to bardziej skomplikowane niż ustawienie flagi, a jeśli chodzi o ilość danych to jest bez zmian w stosunku do soft-delete. Gdybym miał zrobić sam changelog do przeglądania informacji co stało się w systemie to raczej utworzyłbym jedną tabelę zawierającą eventy i dane przekształcanych obiektów w jakimś jsonie. Może się mylę?

    • @hubert7855
      @hubert7855 3 роки тому

      @@jakubksiazek4740 dokładnie, kopiujesz na event usunięcia encje np Order do OrderArchived

  • @rafargdy
    @rafargdy 4 роки тому

    Paginatora nie używamy do dużych zbiorów danych? Ciekawa teza... chyba właśnie głównie tam...

    • @Koddlo
      @Koddlo  4 роки тому +2

      Źle się wyraziłem albo Ty źle zrozumiałeś. W ogromnych bazach raczej nie będzie używany ze względu na wydajność. Tam już jakiś inny read model zapewne będzie.

    • @rafargdy
      @rafargdy 4 роки тому

      To jak on działa? Nie robi po prostu SQLowego "LIMIT" w zapytaniu, tylko pobiera całość i paginuje na kolekcji?

    • @Koddlo
      @Koddlo  4 роки тому +2

      1. Robi COUNT z użyciem DISTINCT.
      2. Podzapytanie z LIMIT, żeby znaleźć wszystkie ID dla aktualnej strony.
      3. Zapytanie z WHERE IN i wrzuca tam wcześniej znalezione ID dla aktualnej strony.