Zrozumienie widoków MVC w PHP

Muszę wydawać się problemy z pojęciem widoków w MVC, są one, zgodnie z tym, co czytałem, warstwą, która zarządza prezentacją w aplikacji, ale wiele z materiału, który czytałem, wydaje się być inny w tej sprawie od PHP Master.com .

Widok jest klasą z funkcjami, które zwracają jakiś kod HTML, gdzie jest reszta mojego HTML? należy go umieścić w niezależnym .strony html, które mają dostęp do tego kodu widoku?

W tym artykuł z php-html.net widok jest prostym plikiem HTML zrozszerzenie php, ale jak mają dostęp do tych danych? Nie widzę require() ani czegoś podobnego do instancji w pierwszym tutorialu.

Author: Matt Busche, 2013-05-16

7 answers

Uwaga: wzorce inspirowane MVC i MVC są zaawansowanymi konstrukcjami. Są one przeznaczone do użycia w bazach kodowych, w których zwykły obiektowy (zgodnie z SOLID i innymi wytycznymi) kod zaczyna stać się niemożliwy do zarządzania. Wprowadzając ten wzorzec, narzucisz dodatkowe ograniczenia, które pozwolą Ci zawierać bardzo złożone aplikacje. MVC jest nie przeznaczone dla aplikacji "hello world".


Zacznijmy od początek ...

Główną ideą wzorców projektowych inspirowanych MVC i MVC jest rozdzielenie trosk . Powiedziane rozdzielenie jest dwojakie:
  • warstwa modelu jest oddzielona od warstwy UI:
  • widoki są oddzielone od kontrolerów

Tutaj wpisz opis obrazka

Warstwa modelu (nie "klasa" lub "obiekt") zawiera kilka grup struktur, z których każda zajmuje się innym aspektem logiki biznesowej. Główne części to:

  • domain objects: validation, business rules
  • W 2007 roku firma została założona przez firmę Microsoft, która od 2007 roku zajmuje się dystrybucją i dystrybucją danych.]}
  • usługi: logika aplikacji

Również mogą być mieszane w repozytoriach, jednostki pracy i inne.

Warstwa UI składa się głównie z widoków i kontrolerów. Ale oboje wykorzystują usługi do interakcji z warstwą modelu. Usługi zapewniają kontrolerom drogę do Zmień stan warstwy modelu i aby widoki zbierały informacje na podstawie tego nowego stanu.

W kontekście sieci Web widoki i kontrolery tworzą luźną parę, ze względu na charakter żądania-odpowiedzi, jaki wykazują aplikacje internetowe.

Należy zauważyć, że chociaż Kontrolery mogą bezpośrednio zmieniać stan bieżącego widoku, częściej zmiany te są dokonywane za pośrednictwem modelu. Jednym z powodów, aby zmienić widok bezpośrednio jest, na przykład, gdy zamiast XML musisz odpowiedzieć za pomocą JSON.

Chociaż można również argumentować, że można łatwo stworzyć inny widok dla każdego formatu wyjściowego i skorzystać z polimorfizmu.


Czym nie jest widok?

Istnieje powszechne błędne przekonanie, że widoki są po prostu gloryfikowanym plikiem szablonu. Ten błąd stał się niezwykle popularny po wydaniu prototypowego frameworka RubyOnRails.

Widoki nie są szablonami . Jeśli używasz ich jako w ten sposób łamiesz podstawową zasadę wzorców inspirowanych MVC i MVC.

Jeśli udajesz, że szablony są widokami, ma to ogromny wpływ na Twoją architekturę. W widoku nie ma miejsca na logikę prezentacji, dlatego logikę prezentacji można przesuwać w warstwie kontrolera lub modelu. Zwykle wybiera się "kontroler", ponieważ większość ludzi rozumie, że logika prezentacji nie ma miejsca w warstwie modelu.

Zasadniczo powoduje to połączenie poglądów i Kontrolery.


Co robi view?

Zadaniem poglądu jest radzenie sobie z logiką prezentacji. W kontekście sieci celem widoku jest wygenerowanie odpowiedzi dla użytkownika (który, btw, jest przeglądarką, a nie człowiekiem).

technicznie możliwe byłoby tworzenie widoków po stronie klienta, że user web sockets obserwować warstwę modelu, ale w praktyce jest to praktycznie niemożliwe do zaimplementowania. Szczególnie Nie w PHP środowisko.

Aby utworzyć ten widok odpowiedzi pobiera informacje z warstwy modelu i na podstawie zebranych danych, albo montuje odpowiedź poprzez dystrybucję danych do szablonów i renderowanie, albo czasami po prostu wysyła nagłówek lokalizacji HTTP.

Podczas używania Post/Redirect/Get , część przekierowania jest wykonywana przez Widok, a nie Kontroler, jak to często robią ludzie.


wysoce subiektywne bit:

Ostatnio wolałem interakcję z MVC za pomocą następującego podejścia:

  // the factory for services was injected in constructors
  $controller->{ $method.$command }($request);
  $view->{ $command }();
  $view->respond();

$method jest aktualnym REQUEST_METHOD , który został skorygowany jako REST-like API, a {[2] } jest tym, co ludzie zwykle nazywają "działaniem". Kontroler posiada osobne procedury dla żądań GET i POST (inne). Pomaga to uniknąć tego samego if w każdej "akcji".

W widoku wywołuję dwie metody. Pierwszy to dynamiczne wezwanie do zebrania danych. I druga / align = "left" /

Uwaga:podejrzewam, że ta konfiguracja zawiera SRP naruszenie. Przyjęcie go jako własnego może być złym pomysłem.


A co z suchym?

Jak zapewne już zauważyłeś, istnieje niewielki problem z wyświetlaniem widoków jako instancji. Skończyłbyś z powtarzaniem fragmentów kodu. Na przykład: menu lub paginacja.

Spójrzmy na paginację .. Paginacja zawiera logikę, ale ta logika nie jest związana z warstwą modelu. Model nie ma pojęcia "strona". Zamiast tego ten kawałek logiki rezydowałby w warstwie interfejsu użytkownika. Ale jeśli każdy z Twoich widoków zawiera lub dziedziczy paginację, to byłoby to wyraźne naruszenie SRP(a właściwie kilku innych zasad).

Aby uniknąć tego problemu, możesz (i powinieneś, IMHO) wprowadzać obiekty prezentacyjne do swoich poglądów.

Note: while Fowler calls them "modele prezentacji", myślę, że ta nazwa po prostu dodaje do całego zamieszania "czym jest model". Dlatego rekomendowaĺ ' bym zamiast nich nazywaÄ ‡ je "obiektami prezentacji".

Obiekty prezentacyjne zajmują się powtarzającymi się elementami logiki. To sprawia, że widoki znacznie są"lżejsze" , a w niektórych aspektach zaczynają odzwierciedlać strukturę usług z warstwy modelu.

Interakcja pomiędzy obiektami prezentacyjnymi i szablonami staje się podobna do interakcja pomiędzy obiektami domeny i maperami danych .


Czy zawsze tego potrzebuję?

Nie. to specyficzne podejście jest silnie ukierunkowane na kod, gdzie warstwa interfejsu użytkownika ma wiele złożoności i trzeba oddzielić obsługę wejścia od prezentacji tylko po rozsądne rozsądne.

Jeśli aplikacja ma bardzo prosty interfejs użytkownika, jak .. emm .. tworzysz REST API dla większego zintegrowanego projektu. W takim pragmatyczny opcją może być po prostu scalenie każdej pary kontroler-widok w jedną klasę.

Może to być również dobry krok podczas refaktoryzacji starszej bazy kodu, ponieważ to mniej ograniczone podejście pozwala przenieść całe fragmenty starego kodu. Po wyizolowaniu takich fragmentów starszego kodu i sprawdzeniu, że wszystko nadal działa (ponieważ kod legacy nigdy nie ma żadnych testów .. w ten sposób staje się "dziedzictwem"), można wtedy zacząć je dalej rozdzielać, skupiając się jednocześnie na oddzielaniu logiki biznesowej od UI.


P. S. sam wciąż zmagam się z wymyśleniem sposobu, jak najlepiej radzić sobie z poglądami. Ten post jest mniej odpowiedzi, a bardziej jak migawka mojego obecnego zrozumienia.

 70
Author: tereško,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-30 22:40:03

Drugi tutorial to sposób, w jaki działa Framework Code Igniter, do którego jestem przyzwyczajony. Śledzę go nawet wtedy, gdy nie używam żadnego frameworka.

W rzeczywistości programista musi wprowadzić zasady podobne do MVC w praktyce, w przeciwnym razie może zrobić lasagne lub spaghetti nawet przy użyciu najbardziej podobnych do MVC zorientowanych framework.

Używając podejścia "plik PHP jako szablon widoku", najlepiej byłoby użyć minimum instrukcji PHP, w zasadzie tylko dla struktur powtórzeń (foreach ($array as $item)), basic conditionals (if ($boolean)) i echo - jakby to był rzeczywiście język szablonów i nic więcej.

Zatem znaczniki <?php ?> w plikach szablonu widoku powinny być jedynie zastępczymi i niczym innym.

W pliku szablonu widoku nie należy wykonywać zapytań do bazy danych, dostępu do modelu, obliczeń itp. Powinien być traktowany zasadniczo jako plik HTML z symbolami zastępczymi. (Z powiązanymi CSS i JavaScript. Sprawy mogą stać się bardziej złożone, gdy aplikacja opiera się na JavaScript / AJAX dużo...)

[7]}zgodnie z tymi prostymi zasadami, skutecznie oddzielamy prezentację od logiki biznesowej. Nawet brzmi to tak prosto, jestem zmęczony radzeniem sobie z kodem Ignitera, który nie podąża za nim. Niektórzy używają "funkcji pomocniczych", aby ukryć wywołania modelu/bazy danych - i uważają, że jest to dobra praktyka! :-)

Nie widzisz require wewnątrz tych szablonów widoku PHP, ponieważ są one wymagane zamiast tego, z "budynku widoku" metody.

Oczywiście nie należy echo i / lub print z wnętrza funkcji kontrolera i modelu. Jest to również bardzo proste, ale jestem również zmęczony, aby zobaczyć spaghetti kod ECHA HTML z wewnątrz metod kontrolera CI.

W praktyce kontroler wywołuje metody modelu, buduje wszystkie niezbędne dane dla widoku, a jako ostatni krok wywołuje widok (tzn. buduje i wyprowadza go), przekazując do niego wcześniej uzyskane dane.

To ma sens? Nie wiem czy odpowiedział na twoje pytanie. Przynajmniej to moje "2 centy".
 10
Author: J. Bruni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 19:26:50

Różne struktury używają innej logiki do przypisywania zmiennych do wyświetlania i pobierania ich zawartości. Poniżej znajduje się prosty przykład użycia funkcji ob_start ().

<?php
     $title = 'Hello...';
     ob_start();
     file_get_contents('view.phtml');
     $viewContents = ob_get_clean();
     echo $viewContents;

?>

//view.phtml
<b>Hello the title is <?php echo $title; ?></b>

Mam nadzieję, że to odpowiedź na twoje pytanie...

 1
Author: Jay Bhatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 18:51:37

Powinieneś przekazać metodę w klasie view wszystko, czego potrzebuje, aby zbudować widok niezależny od formatu wyjściowego. Większość programistów użyje pewnego rodzaju silnika szablonów, aby zbudować większość strony, a następnie wypełnić treść żądaniem konkretnych informacji. Można to zrobić na wiele sposobów. Dobrze jest również mieć abstrakcyjną klasę widoku, która definiuje metody pomocnicze dla wspólnych elementów, takich jak formularze i wejścia.

Ta warstwa jest tak abstrakcyjna, że logika aplikacja nie musi się zmieniać, jeśli zdecydujesz się zmienić projekt lub format wyjściowy w jakikolwiek sposób.

Edit: Każdy moduł reprezentowany przez zestaw MVC będzie miał swój własny widok, który zawiera zbiór metod odpowiedzialnych za wysyłanie danych wyjściowych do przeglądarki. Istnieje wiele sposobów, ale tutaj jest jeden przykład:

class testModule_view extends viewAbstract {
    public function showTestData($title, $subtitle, $data) {
        $XHTML = '<h1>' . $title . '</h1>'
            . '<h2>' . $subtitle . '</h2>'
            . parent::data2table($data);

        parent::outputToBrowser(DEFAULT_TEMPLATE, $XHTML);
    }
}

To tylko krótki przykład, aby dać ci wyobrażenie o tym, jak może wyglądać prosta metoda wyświetlania.

 1
Author: ogc-nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 20:03:41

Gdy przeglądarka wywoła Stronę, zostanie załadowany kontroler dla tej strony. Kontroler zarządza cyklem życia aplikacji. Pobierze dane z modelu, który służy tylko do pobierania danych (może z bazy danych). Widok jest tylko HTML, kontroler będzie echo widoku, a jeśli konieczne, przekazać kilka parametrów do niego.

 0
Author: hice3000,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 18:39:18
<?php

Class View {

protected $data;

protected $path;

protected static function getDefaultViewPath() {
    $router = App::getRouter();

    if(!$router){
        return false;
    }

    $controller_path = $router->getController();
    $method_path = ($router->getMethodPrefix() !== "" ? $router->getMethodPrefix() . '_' : '') . $router->getAction();

    return ROOT . "/views/" . $controller_path . "/" . $method_path . ".phtml";
}

public function __construct($data = array(), $path = null) {

    if(!$path){
        //default
       $path = $this->getDefaultViewPath();
    }

    if(!file_exists($path)){
        throw new Exception("Error view file!");
    }

    $this->data = $data;
    $this->path = $path;
}


public function render(){
    $data = $this->data;

    ob_start();
    include ($this->path);
    $content = ob_get_clean();

    return $content;
}

}

 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-18 17:09:40

Sprawdź ten kod:

include_once(ROOT.'/'.'config/config.php');

function __autoload($class_name){
    $lib_path = ROOT . '/' . 'lib/class.'.$class_name . '.php';
    $controller_path = ROOT . '/' . 'controllers/'.str_replace("controller", "", strtolower($class_name)) . '.controller.php';
    $model_path = ROOT . '/' . 'models/'.strtolower($class_name) . '.php';

if(file_exists($lib_path)){
    require_once ($lib_path);
} else if (file_exists($controller_path)){
    require_once ($controller_path);
} else if(file_exists($model_path)){
    require_once ($model_path);
} else {
    throw new Exception("File {$class_name} cannot be found!");
}

}
 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-18 17:44:39