Utrzymanie luźno sprzężonego modelu MVC z DB?

9

Lubię, aby mój kod był testowalny i zdecydowałem się na strategię Dependency-Injection dla mojego obecnego frameworka MVC, który zdecydowanie okazał się świetnym sposobem na zapewnienie luźno powiązanego kodu, testowalności i modułowości.

Ale ponieważ jestem dalekim od mistrza we wzorcach projektowych, trudno mi znaleźć dobry sposób na utrzymanie moich modeli tak luźno powiązanych z klasami łączników bazy danych, jak to możliwe.

Jak można to zrobić?
Ponieważ nie podałem żadnego kodu fizycznego wraz z tym pytaniem, naprawdę docenię kilka przykładów logiki / kodu lub informacji, które mogłyby skierować mnie w kierunku zrozumienia wyżej opisanego problemu.

Przemysłowy
źródło
To pytanie należy do inżynierii oprogramowania , ponieważ dotyczy bardziej strukturyzacji i myślenia wokół tego tematu, a nie implementacji w kodzie.
Lasse V. Karlsen

Odpowiedzi:

6

Jednym ze sposobów jest zaprojektowanie modeli przed zaprojektowaniem bazy danych. Podczas projektowania modeli nacisk kładziony jest na uchwycenie logiki biznesowej i znaczeń w dziedzinie problemów. Powinno to zostać zarejestrowane w sposób, który ma sens dla firmy, obejmujący więcej niż tylko podmioty i pola danych. Niektóre elementy danych są interpretowane na podstawie innych, niektóre są zależne od innych, itp. Dodatkowo do tego modelu można dodać dowolną podstawową logikę, taką jak wewnętrzna reakcja obiektu, gdy określony element ma określoną wartość.

Jest całkiem prawdopodobne, że skończysz z czymś, co jest w ponad 90% identyczne z tym, w jaki sposób utrwalisz dane. W porządku. Może być całkowicie identyczny bez połączenia.

Zauważ też, że modelowanie domeny we mgle prawdziwej uporczywej ignorancji jest trochę świętym Graalem w projektowaniu oprogramowania. Jeśli możesz to zrobić, fantastycznie. Ale jeśli domena problemowa jest w ogóle znacząca i ma jakąkolwiek złożoność, to dobrze jest od czasu do czasu wycofać się z modelowania domeny, aby sprawdzić poprawność trwałości danych, aby upewnić się, że nie malowałeś się w kąt.

Pamiętaj tylko o rzeczywistych rolach różnych komponentów i zachowaj je oddzielnie podczas ich projektowania. Przy każdej decyzji projektowej zadaj sobie pytanie, czy któraś z tych ról została naruszona:

  1. Baza danych - przechowuj dane, zachowaj integralność danych, utrzymuj dane w spoczynku.
  2. Modele - zawierają logikę biznesową, modelują domenę problemów, utrzymują dane w ruchu, reagują na zdarzenia na poziomie biznesowym itp.
  3. Widoki - Prezentuj dane użytkownikom, wykonuj logikę po stronie użytkownika (podstawowe sprawdzanie poprawności przed przeprowadzeniem prawdziwej weryfikacji w modelach itp.).
  4. Kontrolery - Odpowiadaj na zdarzenia użytkownika, przekaż kontrolę modelom, kieruj żądania i odpowiedzi zwrotne.
David
źródło
Cześć David. Dziękujemy za wyczerpującą odpowiedź! Utrzymując wysoki poziom luźnych połączeń, w jaki sposób połączyć modele ze złączem bazy danych?
Przemysłowy
1
@Industrial: Istnieje wiele sposobów łączenia modeli z trwałością, ale jak dotąd jedyną znalezioną metodą, która naprawdę zaspokaja moje pragnienie oddzielenia problemów, jest posiadanie interfejsów repozytorium w domenie, które są zewnętrznie implementowane przez DAL. Metody repozytorium akceptują i zwracają modele domen oraz wewnętrznie konwertują między tymi i dowolnymi wygenerowanymi jednostkami bazy danych. (Szczerze mówiąc, nie zrobiłem zbyt wiele w PHP.) Możesz więc użyć frameworka DAL do automatycznego generowania wszystkich DB CRUD itp., A następnie napisać repozytoria jako interfejs między tymi rzeczami a modelami.
David
@ Przemysłowy: na przykład, jeśli używasz ORM, wtedy do ORM będzie odwoływał się Twój DAL (który jest odizolowany od modeli domen) i odpowiednio przekształci twoje modele w dostęp do danych. Lub jeśli robisz bezpośredni dostęp do bazy danych za pomocą ręcznego SQL, robisz to w metodach repozytorium DAL i tłumaczysz wyniki zapytań SQL na modele domen przed ich zwróceniem.
David
@ Przemysł: Należy również pamiętać, że metody repozytorium nie muszą być po prostu CRUD. W tym kodzie można wprowadzić wiele inteligencji. Wiele bardziej złożonych może zawierać wiele wewnętrznych kodów, które przekształcają dane z bazy danych. Lub, jeśli te złożone wymagają wielu podróży do bazy danych, to w celu zwiększenia wydajności można umieścić logikę w procedurze przechowywanej, a metoda DAL po prostu przechodzi do tej procedury i tłumaczy wyniki na modele.
David
Cześć David! Chciałem jeszcze raz podziękować za tę odpowiedź. Zdecydowanie jeden z najlepszych, jakie otrzymałem na StackExchange!
Przemysłowy
2

Chcesz mieć dwie rzeczy.

  1. Twoje modele (akcesoria do DBAL i wykonywanie większości logiki aplikacji).
  2. Twoje „Modele domeny”, czyli encje danych, reprezentują byty twojego systemu, takie jak użytkownicy, posty, produkty itp.

    class PPI_Model_User {
    
        protected $_conn = null;
    
        function __construct(array $options = array()) {
            if(isset($options['dsnData'])) {
                $this->_conn = new PPI_DataSource_PDO($options['dsnData']);
            }
        }
    
        function getAll() {
            $rows = $this->_connect->query("SELECT .....")->fetchAll();
            $users = array();
            foreach($rows as $row) {
                $users[] = new PPI_Entity_User($row);
            }
            return $users;
        }
    
    }

Kod użytkowania

    $model = new PPI_Model_User(array('dsnData' => $dsnData));
    $users = $model->getAll();
    foreach($users as $user) {
        echo $user->getFirstName();
    }

Oto, jak tworzysz modele domen (Encje) i masz modele MVC wykonujące połączenia z DB i manipulujące danymi.

Jeśli zastanawiasz się, czym jest PPI, przejdź do Google dla „PPI Framework”.

Powodzenia w wyszukiwaniu.

Pozdrawiam, Paul Dragoonis.

Paul Dragoonis
źródło
1

Pamiętaj, MVC powstało w smalltalk, który ma automatyczną trwałość dla wszystkich obiektów. Tak więc wzorzec MVC nie zaleca żadnego rozwiązania dla separacji modelu / trwałości.

Preferuję obiekt „Repozytorium”, który wie, jak tworzyć obiekty modelu z bazy danych i przechowywać obiekty modelu w bazie danych. Wtedy Model nie wie nic o wytrwałości. Niektóre działania użytkownika będą musiały uruchomić zapis, więc prawdopodobnie kontroler będzie wiedział o repozytorium. Zwykle używam jakiejś formy wstrzykiwania zależności, aby nie dopuścić do połączenia kontrolera z repozytorium.

Sean McMillan
źródło