2008-12-01 11 views
6

Mam to oznaczone jako PHP, ale tylko dlatego, że będę używać kodu PHP, aby pokazać mój problem.Jak obsługiwać szablony stron internetowych MVC?

Więc mam trochę kodu podobnego do kontrolera:

switch ($page) 
{ 
    case "home": 
     require "views/home.php"; 
     break; 
    case "search": 
     require "views/search.php"; 
     break; 
} 

Oczywiście istnieje więcej stron, ale powinno to zilustrować mój problem. Istnieje wspólny nagłówek, nawigacja i stopka dla obu tych stron (i dla wszystkich stron w witrynie). Czy powinienem używać wielu instrukcji żądań? Moje pierwsze przypuszczenie to:

switch ($page) 
{ 
    case "home": 
     require "templates/header.php"; 
     require "templates/navigation.php"; 
     require "views/home.php"; 
     require "templates/footer.php"; 
     break; 
    case "search": 
     require "templates/header.php"; 
     require "templates/navigation.php"; 
     require "views/search.php"; 
     require "templates/footer.php"; 
     break; 
} 

W jakiś sposób moje jelito mówi mi, że to nie jest poprawne.

Odpowiedz

5

Kontroler powinien po prostu skonfigurować dane dla widoku i wybrać widok do wyświetlenia. Widok powinien być odpowiedzialny za układ strony, w tym strony udostępnione. Lubię twoją pierwszą próbkę przez sekundę.

+2

To nie jest odpowiedź na moje pytanie, nie wiem myślę, że mając ten sam nagłówek/stopkę/nawigację na obu plikach w smart. Zwłaszcza, że ​​rażąco sprzeciwia się zasadzie DRY. –

+0

Niekoniecznie. ASP.NET MVC oferuje strony wzorcowe, które umożliwiają zarówno rozdzielenie spraw (o których mówiłem), jak i zasady DRY. Nie wiem wystarczająco dużo o frameworkach php, aby wiedzieć, czy jest taki z podobną funkcją. Dla mnie utrzymanie SOC jest ważniejsze niż DRY – tvanfosson

1

Tak, należy rozdzielić nagłówek, stopkę itp.

Dla konkretnego pokazanego przykładu, czy to nie działa lepiej?

require "templates/header.php"; 
    require "templates/navigation.php"; 
    require "views/$page.php"; 
    require "templates/footer.php"; 

(gdzie $ strona jest „dom”, „szukaj”, itd.)

-2

Czy jest jakiś szczególny powód, dla którego nie używasz ram MVC takich jak Symfony lub CakePHP?

Wiem, że to nie odpowiada bezpośrednio na pytanie, ale może być pomocne.

+1

Nie zapomnij [Zend] (http://framework.zend.com/) – Zoredache

-2

Jeśli używasz prostych stron PHP jako szablonów, możesz zasadniczo ustawić zmienną globalną/sesyjną, aby przechowywać żądaną stronę. Będziesz mieć stronę główną "głównego szablonu", która będzie zawierała elementy nagłówka i stopki, a następnie wywoła dołączenie do strony $. Coś takiego w kontrolerze:

$_SESSION['page'] = sanitize_input($_GET['page']); 
require "templates/main.php"; 

a następnie w pliku szablonu main.php:

require "templates/header.php"; 
require "templates/navigation.php"; 
require "views/{$_SESSION['page']}.php"; 
require "templates/footer.php"; 
+0

Nieco ciekaw, dlaczego to jest odrzucane, gdy bezpośrednio odpowiada na pytanie OP. Jeśli nie chce używać tego formatu, użyj silnika szablonów lub architektury. Każda inna metoda spowoduje powtórzenie kodu. – Alarion

+0

$ _SESSION nie należy tutaj używać. Nie przenosimy danych na kolejne żądanie. W przeciwnym razie zmierzasz we właściwym kierunku. – Preston

+0

Po prostu używałem tego jako uproszczonego przykładu. Przechowywanie go w jakiejś strukturze danych, tak aby dołączone strony mogły się do niego odwoływać, jest w porządku. Nie przepadam za regularnymi zmiennymi "globalnymi". *wzruszać ramionami* – Alarion

0

tutaj jest uproszczoną wersją jak zrobić szablony z mojego obecnego projektu, jeśli to jakieś zastosowanie:

class Template { 
    var $pagename = 'index'; 

    function __construct() { 
     $this->pagename = basename($_SERVER['SCRIPT_NAME'], '.php'); 
     register_shutdown_function(array($this, 'do_output')); 
    } 

    function do_output() { 
     $this->header(); 
     $this->display($this->pagename); 
     $this->footer(); 
    } 

    function __call($template, array $params) { 
     call_user_func(array($this, 'display'), $template, params); 
    } 

    function display($template, array $params = null) { 
     include "templates/$template.php"; 
    } 
} 

Ideą jest to, że można napisać "Dołącz" Template.inc ", nowy szablon;" i włącza do_output() uruchamianie na końcu skryptu automatycznie. Zostało z niej kilka rzeczy, jak metoda używana do przekazywania zmiennych do szablonu.

Wspominałeś, że nie używasz PHP, a jest tam kilka PHP-names: register_shutdown_function() zapewnia, że ​​szablony zostaną wywołane przed destruktorami obiektów, ale po głównym skrypcie i wywołaniami do $ this- > header()/footer() to magiczne wywołania funkcji, które po prostu wyświetlają się ("nagłówek") i wyświetlają ("stopka"), mają być nadpisane.

Oczywiście nie ma nic złego w korzystaniu z przełącznika, takiego jak opublikowany przez Ciebie przykład, ale nie potrzebujesz nagłówków/stopek w każdym przypadku. Coś takiego mogłoby zrobić to samo:

require "templates/header.php"; 
require "templates/navigation.php"; 
switch ($page) 
{ 
    case "home": 
     require "views/home.php"; 
     break; 
    case "search": 
     require "views/search.php"; 
     break; 
} 
require "templates/footer.php"; 

...lub możesz zastąpić przełącznik() czymś opartym na nazwie pliku, takiej jak użyłem powyżej, jeśli działa w taki sposób, jak konfigurowane są twoje strony. Przełącznik jest najbezpieczniejszym sposobem, jeśli planujesz zrobić to za pomocą parametrów adresu URL.

0

Powtarzasz kod. To nigdy nie jest dobry pomysł. Pozostanie na poziomie zbliżonym do pierwotnego przykład coś takiego z pewnością byłoby korzystne:

require "templates/header.php"; 
require "templates/navigation.php"; 

switch ($page) { 
    case "home": 
     require "views/home.php"; 
     break; 
    case "search": 
     require "views/search.php"; 
     break; 
} 

require "templates/footer.php"; 

Trudno dać więcej porad nie wiedząc więcej o swoim podejściu architektonicznego. Na przykład wskazane byłoby posiadanie tej części kontrolera, która po prostu przygotowuje wyjście, w bardzo centralnym miejscu i aby rozpocząć buforowanie wyjściowe przed włączeniem szablonów widoku. W ten sposób możesz przechowywać dane wyjściowe w zmiennej, którą możesz chcieć przetworzyć, zanim zwrócisz jej zawartość w odpowiedzi HTTP.

0

Zgadzam się z tvanfosson i chcę wyjaśnić, dlaczego iw jaki sposób odnosi się do MVC.

Problem z drugim przykładem polega na tym, że kontroler jest narażony na sposób konstruowania widoku. W ścisłym sensie kontroler wkłada dane do widoku i przekazuje je do niego, i nic więcej.

Praktycznym sposobem myślenia jest zmiana widoku w zależności od wymagań aplikacji lub samych nakładów. Na przykład, jeśli widok generowany jest dla wyskakującego okienka JavaScript, może (i prawdopodobnie będzie) używać innego zestawu nagłówków, stopek, CSS, meta itp. W twoim drugim przykładzie wszystko, co jest wystawione na kontroler . W twoim pierwszym, to jest widok, który wie, jak wygenerować widok - właśnie o to chodzi.

Aby dalej przykładować, wyobraź sobie, że wyskakujące okienko JavaScript zostało przeprojektowane tak, aby stanowiło pełny widok strony lub jest refaktoryzowane dla AJAX (lub pytanie pop-up/page/AJAX jest określane przez dane wejściowe, takie jak ukryty element w polu). Teraz dzielisz kontroler, ponieważ widok się zmienił. Nie chodzi o to, że naruszyłeś MVC, ale nie powinieneś się tym przejmować.

0

Jeśli wszystkie nazwy plików zgodne z Twoimi oczekiwaniami view/stronę, jak pokazano w przykładzie wtedy wystarczy jeden wiersz i nie switch oświadczenie:

require "templates/header.php"; 
require "templates/navigation.php"; 
require 'views/' . $page . '.php'; // <-- one-liner 
require "templates/footer.php"; 
Powiązane problemy