Zdaję sobie sprawę, że ten temat został wielokrotnie zadany i zaadresowany, i chociaż przeczytałem niezliczone podobne pytania i przeczytałem niezliczone artykuły, nadal nie potrafię zrozumieć kilku kluczowych problemów. Próbuję zbudować własne ramy MVC do celów edukacyjnych i lepiej zapoznać się z OOP. To jest do osobistego użytku prywatnego, aby nie sugerować, że jako pretekst do bycia leniwym, ale raczej nie jestem tak zatroskany o wszystkie dzwony i gwizdy bardziej solidnych ram.Zrozumienie/udoskonalanie szkieletowego szkieletu MVC
Moja struktura katalogów jest następująca:
public
- index.php
private
- framework
- controllers
- models
- views
- FrontController.php
- ModelFactory.php
- Router.php
- View.php
- bootstrap.php
Mam plik .htaccess z przekieruje wszystkie żądania do index.php, plik ten zawiera podstawowe ustawienia konfiguracyjne, takie jak stałe strefę czasową, globalnych, a to wtedy ładuje plik bootstrap.php. Bootstrap zawiera mój autoloader dla klas, rozpoczyna sesję, definiuje globalne funkcje do wykorzystania w całym moim projekcie, a następnie wywołuje router. Router odbiera żądanie z adresu URL, sprawdza poprawność za pomocą klasy ReflectionClass i wykonuje żądanie w postaci example.com/controller/method/params.
Wszystkie moje kontrolerów rozszerzyć FrontController.php:
<?php
namespace framework;
class FrontController
{
public $model;
public $view;
public $data = [];
function __construct()
{
$this->model = new ModelFactory();
$this->view = new View();
}
// validate user input
public function validate() {}
// determines whether or not a form is being submitted
public function formSubmit() {}
// check $_SESSION for preserved input errors
public function formError() {}
}
Ten przedni regulator ładuje ModelFactory:
<?php
namespace framework;
class ModelFactory
{
private $db = null;
private $host = 'localhost';
private $username = 'dev';
private $password = '********';
private $database = 'test';
// connect to database
public function connect() {}
// instantiate a model with an optional database connection
public function build($model, $database = false) {}
}
i podstawa Widok:
<?php
namespace framework;
class View
{
public function load($view, array $data = [])
{
// calls sanitize method for output
// loads header, view, and footer
}
// sanitize output
public function sanitize($output) {}
// outputs a success message or list of errors
// returns an array of failed input fields
public function formStatus() {}
}
Wreszcie, tutaj jest przykładowy kontroler, aby pokazać, jak przetwarzane jest żądanie:
<?php
namespace framework\controllers;
use framework\FrontController,
framework\Router;
class IndexController extends FrontController implements InterfaceController
{
public function contact()
{
// process form if submitted
if ($this->formSubmit()) {
// validate input
$name = isset($_POST['name']) && $this->validate($_POST['name'], 'raw') ? $_POST['name'] : null;
$email = isset($_POST['email']) && $this->validate($_POST['email'], 'email') ? $_POST['email'] : null;
$comments = isset($_POST['comments']) && $this->validate($_POST['comments'], 'raw') ? $_POST['comments'] : null;
// proceed if required fields were validated
if (isset($name, $email, $comments)) {
// send message
$mail = $this->model->build('mail');
$to = WEBMASTER;
$from = $email;
$subject = $_SERVER['SERVER_NAME'] . ' - Contact Form';
$body = $comments . '<br /><br />' . "\r\n\r\n";
$body .= '-' . $name;
if ($mail->send($to, $from, $subject, $body)) {
// status update
$_SESSION['success'] = 'Your message was sent successfully.';
}
} else {
// preserve input
$_SESSION['preserve'] = $_POST;
// highlight errors
if (!isset($name)) {
$_SESSION['failed']['name'] = 'Please enter your name.';
}
if (!isset($email)) {
$_SESSION['failed']['email'] = 'Please enter a valid e-mail address.';
}
if (!isset($comments)) {
$_SESSION['failed']['comments'] = 'Please enter your comments.';
}
}
Router::redirect('contact');
}
// check for preserved input
$this->data = $this->formError();
$this->view->load('contact', $this->data);
}
}
Z tego, co jestem w stanie zrozumieć, moja logika jest wyłączony z następujących powodów:
- Walidacja powinna odbywać się w modelu, a nie kontrolera. Jednak Model nie powinien mieć dostępu do zmiennych $ _POST, więc nie jestem całkowicie pewien, czy robię tę część poprawnie? Czuję, że to jest coś, co nazywają "grubym kontrolerem", co jest złe, ale nie jestem pewien, co trzeba zmienić ...
- Kontroler nie powinien wysyłać danych do widoku; zamiast tego Widok powinien mieć dostęp do Modelu, aby zażądać własnych danych. Czy przeniesienie właściwości
$data
z FrontController i do ModelFactory, a następnie wywołanie widoku z kontrolera bez przekazywania danych, rozwiązuje ten problem? Technicznie byłoby to zgodne ze schematem blokowym MVC, ale proponowane rozwiązanie wydaje się być tak nieistotnym lub nawet banalnym szczegółem, zakładając, że jest to proste, co prawdopodobnie nie jest. - Częścią, która mnie kwestionuje całe moje wdrożenie jest Mam obiekt User, który jest tworzony z odpowiednimi rolami i uprawnieniami użytkowników, i próbowałem dowiedzieć się, w jaki sposób lub bardziej szczegółowo, gdzie utworzyć metodę
isAllowed()
, którą można wywołać zarówno z kontrolera, jak i widoku. Czy byłoby sensownym zastosowaniem tej metody w Modelu, skoro zarówno Kontroler, jak i Widok powinny mieć dostęp do Modelu?
Ogólnie rzecz biorąc, czy jestem na dobrej drodze, czy też, jakie poważne problemy muszę rozwiązać, aby znaleźć się na właściwej drodze? Naprawdę mam nadzieję na osobistą odpowiedź specyficzną dla moich przykładów, a nie "przeczytaj to". Doceniam wszelkie szczere opinie i pomoc.
To pytanie wydaje się być nie na temat, ponieważ powinno być w http://codereview.stackexchange.com –