Y
Y
Yevhenii K2015-11-10 22:47:25
PHP
Yevhenii K, 2015-11-10 22:47:25

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');
    }
}

controller
<?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);
  }
}

model
<?
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);
}
}

After crutches, following this link dpwork.loc/fullnews/15, I received the desired article and general markup. But, the css file stopped loading, then, having figured it out, I realized that it was loaded not from index.php, but from template_view.php, which is located in a different folder.
How to correctly implement this issue?
Or how to bring to a crutch (but this is in the most extreme case)?
PS If you want to help with an answer, but something is not clear to you, due to a poorly described problem. Set additional question in the comments, I will answer immediately. Sorry if it's poorly described.

Answer the question

In order to leave comments, you need to log in

4 answer(s)
S
Sergey, 2015-11-10
Protko @Fesor

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.

D
Dmitry, 2015-11-10
@thewind

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);
}

S
Stalker_RED, 2015-11-11
@Stalker_RED

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 состоящий из букв и дефисов

Documentation: symfony-gu.ru/documentation/ru/html/book/routing.html Routing
code: https://github.com/symfony/routing
And yes, if you want, you can drag this module entirely into your project, instead of to write your own.
It also seems that everything is well arranged in Yii www.yiiframework.com/doc-2.0/guide-runtime-routing.html

N
Nick Murzin, 2015-11-13
@R0s0maxa

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 question

Ask a Question

731 491 924 answers to any question