Answer the question
In order to leave comments, you need to log in
How to make/modify router for MVC?
Good afternoon! Now I'm studying MVC and trying to adapt one of the examples ( habrahabr.ru/post/150267 ) to my news site.
There is a list of news on the main page, clicking on "Read more" ( <a href=/fullnews/{$v['id']}>)
redirects to dpwork.loc/fullnews/15 (I want to type like here https://toster.ru/q/265105) 15 is the article number.
But then the router writes 15 in the name of the action (method) and nothing works, the number must also be passed to the method in order to get the desired article using it
.
<?php
class Route
{
static function start()
{
// контроллер и действие по умолчанию
$controller_name = 'Main';
$action_name = 'index';
$id = "";
$routes = explode('/', $_SERVER['REQUEST_URI']);
// получаем имя контроллера
if ( !empty($routes[1]) )
{
$controller_name = $routes[1];
}
// получаем имя экшена
if ( !empty($routes[2]) )
{
$action_name = $routes[2];
if(is_numeric($action_name)) // ЕСЛИ action_name БЫЛ ЧИСЛОМ ПРИСВАИВАЛ ЕМУ имя по умолчания, после прописывал переменую с числом
{
$action_name = 'index';
$id = $routes[2];
}
}
// добавляем префиксы
$model_name = 'Model_'.$controller_name;
$controller_name = 'Controller_'.$controller_name;
$action_name = 'action_'.$action_name;
/*echo "Model: $model_name <br>";
echo "Controller: $controller_name <br>";
echo "Action: $action_name <br>";
echo $id;*/
// подцепляем файл с классом модели (файла модели может и не быть)
$model_file = strtolower($model_name).'.php';
$model_path = "application/models/".$model_file;
if(file_exists($model_path))
{
include "application/models/".$model_file;
}
// подцепляем файл с классом контроллера
$controller_file = strtolower($controller_name).'.php';
$controller_path = "application/controllers/".$controller_file;
if(file_exists($controller_path))
{
include "application/controllers/".$controller_file;
}
else
{
Route::ErrorPage404();
}
// создаем контроллер
$controller = new $controller_name;
$action = $action_name;
if(method_exists($controller, $action))
{
if (!is_null($id))
{
$controller->id = $id; // ЕСЛИ после первой проверки данные записывались в переменную id, Перед основным действием значения передавалось в свойство класса контролера для получения по нему статьи
}
// вызываем действие контроллера
$controller->$action();
}
else
{
Route::ErrorPage404();
}
}
function ErrorPage404()
{
$host = 'http://'.$_SERVER['HTTP_HOST'].'/';
header('HTTP/1.1 404 Not Found');
header("Status: 404 Not Found");
header('Location:'.$host.'404');
}
}
<?php
class Controller_fullnews extends Controller
{
public $id;
function __construct()
{
$this->model = new Model_fullnews;
$this->view = new View;
}
function action_index()
{
$data = $this->model->get_data($this->id);
$this->view->generate('fullnews_view.php','template_view.php',$data);
}
}
<?
class Model_fullnews extends Model {
public function get_data($id) {
$cat_news = "SELECT * FROM `news` WHERE `id` = $id";
$getnews = DB::obj()->connect()->query($cat_news);
if(is_null($getnews)) {
return [];
}
return $getnews->fetchALL(PDO::FETCH_ASSOC);
}
}
Answer the question
In order to leave comments, you need to log in
He can still write an article "what is MVC" ... otherwise people get confused ....
Here in the article, let's say ... amusing ... two arrows between the model and the view - this is one arrow, the view simply takes the current state models. And it is strictly in the direction of view, it describes the data flow. (moreover, in the canonical interpretation, for the GUI and not for the backend, this is an observable connection, that is, the view hangs event handlers on the model and adjusts to the current state of the model. The model has changed - the view has been updated. But on the server this usually cannot be because this moment can be lower).
view in the context of the server should not pull the controller (and in general he knows nothing about the controller). Well, that is, this is not the same view that pulls our model. This is some other view, or query view, inputs and buttons. http request.
Only one arrow is correct - that the controller asks the model to change the state.
So, I got distracted ...
Take any ready-made router, do not write your own, it's empty.
In the controller, you can make a magic __call method, which will be called for all your fullnews/XXX, and from it call some protected method of the same action_item() controller
protected function action_item($news_id){}
public function __call($method, $args){
return $this->action_item($method);
}
As far as I understand, you first wrote a simple URL parser that simply splits it on slashes and calls module/action. Now you want to add some exceptions, special rules for different pages or sections.
There is such a thing, these "special" rules are needed so often that, as a rule, these "special rules" make up most of the config :)
Look at how routing is arranged in modern frameworks, you might pick up fresh ideas.
Here is a snippet from symfony
video:
pattern: /watch/{id}/{slug}
defaults: { _controller: SiteBundle:Video:watch } # в URL не указан модуль, зато он прописан в конфиге роутинга
requirements: { id: "\d+", slug: "[\w-]+" # обязательные параметры: id в виде числа и slug состоящий из букв и дефисов
Writing something yourself is hellish nonsense, you will only waste your time in vain. Study and use ready-made solutions - for this they were created.
If you want to dig deeper, the best choice is to assemble your Frankenstein from ready-made modules.
Here is an interesting assembly tutorial for you, just with the author's comments about what patterns / anti-patterns he uses and why it is needed at all.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question