복붙노트

MVC와 비슷한 페이지에서 예쁜 URL을 기반으로 클래스를로드하는 방법은 무엇입니까?

PHP

MVC와 비슷한 페이지에서 예쁜 URL을 기반으로 클래스를로드하는 방법은 무엇입니까?

이 문제를 해결하는 방법에 대한 몇 가지 팁을 요청하고 싶습니다. 내 MVC 웹 사이트를 만들려고합니다. 나는 URL의 기초를 배웠다.

http://example.com/blog/cosplay/cosplayer-expo-today

블로그 -> 컨트롤러 코 -> 컨트롤러 코 플레 이어 - 엑스포 - 오늘의 메소드 -> 메소드의 변수

내 블로그 컨트롤러에서 카테고리를 동적으로 확장하면 어떻게 될까요? 메소드를 생성해야합니까, 아니면 자동으로 그렇게 할 수 있습니까? 제 말은 ... 지금 코스프레, 게임, 영화, 시리즈입니다. 그래서 컨트롤러에서 이러한 메소드를 생성해야하지만, 모두 똑같은 일을합니다. 즉, 데이터베이스에서 다른 카테고리를 선택하십시오.

자동으로 컨트롤러를 작성하는 방법에 대한 좋은 조언이 있습니까? 내 데이터베이스에 새 카테고리를 업로드해도 컨트롤러를 수정하고 싶지는 않습니다. 가능한가? 도와 주셔서 감사합니다!

최신 정보

내 URL 탐색기 클래스는 다음과 같습니다.

class Autoload
{
    var $url;
    var $controller;
    function __construct()
    {
        $this->url = $_GET['url'];
        //HNEM ÜRES AZ URL
        if($this->url!='' && !empty($this->url))
        {
            require 'application/config/routes.php';
            //URL VIZSGÁLATA
            $this->rewrite_url($this->url);

            //URL SZÉTBONTÁSA
            $this->url = explode('/', $this->url);

            $file = 'application/controllers/'.$this->url[0].'.php';
            //LÉTEZIK A CONTROLLER?
            if(file_exists($file))
            {
                require $file;
                $this->controller = new $this->url[0];

                //KÉRELEM ALATT VAN AZ ALOLDAL?
                if(isset($this->url[1]))
                {
                    //LÉTEZIK A METÓDUS? ENGEDÉLYEZVE VAN?
                    if(method_exists($this->controller, $this->url[1]) && in_array($this->url[1], $route[$this->url[0]]))
                    {
                        if(isset($this->url[2]))
                        {
                            $this->controller->{$this->url[1]}($this->url[2]);
                        }
                        else
                        {
                            $this->controller->{$this->url[1]}();
                        }
                    }
                    else
                    {
                        header('location:'.SITE.$this->url[0]);
                        die();
                    }
                }
            }
            else
            {
                header('location:'.SITE);
                die();
            }
        }
        else
        {
            header('location:'.SITE.'blog');
            die();
        }
    }

    /**
     * Első lépésben megvizsgáljuk, hogy a kapott szöveg tartalmaz-e nagybetűt. Amennyiben igen átalakítjuk kisbetűsre.<br/>
     * Második lépésben megnézzük, hogy a kapott szöveg '/'-re végződik-e. Amennyiben igen levágjuk azt.<br/>
     * Harmadik lépésben újra töltjük az oldalt a formázott szöveggel.
     * 
     * @param string $url Korábban beolvasott URL.
     */
    private function rewrite_url($url)
    {
        //HA NAGYBETŰ VAN AZ URL-BEN VAGY '/'-RE VÉGZŐDIK
        if(preg_match('/[A-Z]/', $url) || substr($url, -1)=='/')
        {
            //NAGYBETŰS AZ URL KICSIRE ALAKÍTJUK
            if(preg_match('/[A-Z]/', $url))
            {
                $url = strtolower($url);
            }
            //HA '/'-RE VÉGZŐDIK LEVÁGJUK
            if(substr($url, -1)=='/')
            {
                $url = substr($url, 0, strlen($url)-1);
            }
            header('location:'.SITE.$url);
            die();
        }
    }




}

여기 .htaccess가 있습니다.

Options +FollowSymLinks
RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d  
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l

RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

해결법

  1. ==============================

    1.코드를 게시 한 모습에서 다음 작업을 담당하는 단일 클래스가 있다는 것이 확실합니다.

    코드를 게시 한 모습에서 다음 작업을 담당하는 단일 클래스가 있다는 것이 확실합니다.

    OOP에는 Single Responsibility Principle [짧은 버전]이라는 것이 있습니다. 기본적으로 클래스는 하나의 특정 사항을 처리해야한다는 것을 의미합니다. 위의 목록은 귀하의 Autoload 클래스에 대해 최소한 4 가지 다른 책임을 구성합니다.

    당신이 지금 가지고있는 것 대신에, 이들 각각의 일반적인 임무는 별도의 반에 의해 처리되어야합니다. 오토로더의 경우 하나의 기능으로 벗어날 수 있습니다.

    내가 보는 문제의 일부는 PHP에서 오토로드가 실제로 어떻게 작동하는지에 대한 혼란입니다. include 또는 require의 호출은 인스턴스가 작성되는 곳에서 수행 될 필요가 없습니다. 대신 이전에 정의되지 않은 클래스를 사용하려고하면 ** 자동 * 호출되는 핸들러를 등록합니다 (spl_autoload_register () 함수 사용).

    가장 간단한 예는 다음과 같습니다.

    spl_autoload_register( function( $name ) use ( $path ) {
        $filename = $path . '/' . $name . '.php';
        if ( file_exists( $filename ) === true ) {
            require $filename;
            return true;
        }
        return false;
    });
    

    이 특별한 예제는 PHP 5.3에서 소개 된 기능 중 하나 인 익명의 함수를 사용하지만, spl_autoload_register ()의 매뉴얼 페이지는 객체 나 일반적인 함수로 어떻게 달성하는지 예제를 보여줍니다.

    자동 로딩과 밀접한 관련이있는 또 다른 새로운 기능은 네임 스페이스입니다. 이런 맥락에서 네임 스페이스는 두 가지 즉각적인 이점을 제공합니다. 동일한 이름을 가진 여러 클래스를 가질 수 있고 여러 디렉토리에서 클래스 파일을로드하는 옵션입니다.

    예를 들어 다음과 같은 코드를 사용할 수 있습니다.

    $controller = new \Controllers\Overview;
    $view = new \Views\Overview;
    
    $controller->doSomething( $request );
    

    이 경우에는 /project/controllers/overview.php와 /project/views/overview.php 파일 각각에서 오토로더가 클래스를 가져올 수 있습니다. spl_autoload_register ()는 "\ Controllers \ Overview"와 "\ Views \ Overview"를 핸들러 함수에 전달하기 때문입니다.

    오토로더를 구현하는 방법에 대한 권장 사항도 있습니다. 여기에서 찾을 수 있습니다. 몇 가지 중대한 문제가 있지만 좋은 기반을 제공해야합니다.

    아파치의 mod_rewrite가 예쁜 URL로 할 수있는 일은 매우 제한적이라는 것은 비밀이 아닙니다. 그리고 광범위한 서버이지만 웹 서버를위한 유일한 옵션은 아닙니다. 이것이 최대 유연성을 위해 PHP 개발자가 PHP 끝에서 URL을 처리하도록 선택한 이유입니다.

    그리고 초보자가 할 첫 번째 일은 폭발 ( '/', ...)입니다. 그것은 자연스러운 선택이지만, 당신은 곧 그것이 실제로 할 수있는 것에 또한 극도로 제한된다는 것을 알게 될 것입니다. 라우팅 메커니즘이 확장되기 시작합니다. 처음에는 세그먼트 수를 기반으로 나중에 세그먼트별로 다른 조건 값을 추가하여 다른 동작이 필요합니다.

    본질적으로 이것은 거대하고 허약하며 통제 할 수없는 혼란을 야기 할 것입니다. 나쁜 생각.

    대신 정규 표현식의 목록을 가지고, 꽤 예쁜 URL과 일치시켜야합니다. 예 :

    '#/(?P<resource>[^/\\\\.,;?\n]+)/foobar#'
    

    위의 정의 된 패턴은 첫 번째 세그먼트에 텍스트가 있고 두 번째 세그먼트에 "foobar"라는 두 세그먼트가있는 모든 URL과 일치합니다 ... "/ testme / foobar"와 같습니다.

    또한 각 패턴을 각 일치에 해당하는 기본값으로 연결할 수 있습니다. 이 모든 것을 합치면 다음과 같은 구성으로 끝날 수 있습니다 (5.4+ 배열 구문을 사용합니다. 어떻게 쓰는지 알고 싶습니다).

    $routes = [
        'primary' => [
            'pattern'   => '#/(?P<resource>[^/\\\\.,;?\n]+)/foobar#',
            'default'   => [
                'action'    => 'standard',
            ],
        ],
        'secundary' => [
            'pattern'   => '#^/(?P<id>[0-9]+)(?:/(?P<resource>[^/\\\\.,;?\n]+)(?:/(?P<action>[^/\\\\.,;?\n]+))?)?$#',
            'default'   => [
                'resource'  => 'catalog',
                'action'    => 'view',
            ]
        ],
        'fallback'  => [
            'pattern'   => '#^.*$#',
            'default'   => [
                'resource'  => 'main',
                'action'    => 'landing',
            ],
        ],
    ]; 
    

    다음 코드를 사용하여 처리 할 수 ​​있습니다.

    // CHANGE THIS
    $url = '/12345/product';
    
    $current = null;
    
    // matching the route
    foreach ($routes as $name => $route) {
        $matches = [];
        if ( preg_match( $route['pattern'], $url, $matches ) ) {
            $current = $name;
            $matches = $matches + $route['default'];
            break;
        }
    }
    
    
    // cleaning up results
    foreach ( array_keys($matches) as $key ) {
        if ( is_numeric($key) ) {
            unset( $matches[$key] );
        }
    }
    
    
    // view results
    var_dump( $current, $matches );
    

    라이브 코드 : 여기 또는 여기

    좀 더 읽을 수있는 표기법으로 매칭을위한 정규 표현식을 생성하고 싶을 것이다. 예를 들어 구성 파일에서 다음 표현식은 다음과 같습니다.

    '#^/(?P<id>[0-9]+)(?:/(?P<resource>[^/\\\\.,;?\n]+)(?:/(?P<action>[^/\\\\.,;?\n]+))?)?$#'
    

    .. 아마 뭔가와 같이 보일 것입니다.

    '/:id[[/:resource]/:action]'
    

    여기서 : : param은 URL 세그먼트를 나타내고 [...]는 URL의 선택적 부분을 나타냅니다.

    이를 기반으로 자신의 라우팅 시스템을 완성 할 수 있어야합니다. 위의 코드는 단순화 된 핵심 기능의 예입니다. 완전히 구현되었을 때 어떻게 보일지에 대한 약간의 관점을 얻기 위해이 대답에서 코드를 살펴볼 수 있습니다. 자신의 API 버전에 대한 아이디어를 제공해야합니다.

    라우팅 클래스 (또는 클래스)의 어딘가에 컨트롤러 실행을 묻는 것은 흔히있는 실수입니다.이 때문에 두 가지 문제가 발생합니다.

    라우팅은 맞춤 작성된 응용 프로그램에서도 코드베이스의 "프레임 워크 틱"부분으로 자연스럽게 끌리는 작업입니다.

    (정말로) 단순화 된 버전은 다음과 같습니다.

    $matches = $router->parse( $url );
    
    $controller = new {'\\Controller\\'.$matches['controller']};
    $controller->{$matches['action']( $matches );
    

    이렇게하면 라우팅 결과가 일부 MVC와 같은 아키텍처에서 사용되는 것이 필요하지 않습니다. 어쩌면 정적 HTML 파일을 제공하기 위해 영광스러운 가져 오기 메커니즘이 필요할 수도 있습니다.

    당신은 그것을 잘못보고 있습니다. 컨트롤러에 동적으로 메소드를 추가 할 필요가 없습니다. 귀하의 예제에서 실제로 하나의 컨트롤러 메소드가 있습니다.

    public function getCategory( $request ) {
        $category = $request->getParameter('category');
    
        // ... rest of your controller method's code
    }
    

    여기서 $ category는 "코스프레", "게임", "영화", "시리즈"또는 추가 한 다른 카테고리를 포함하게됩니다. 컨트롤러가 모델 계층에 전달하여 기사를 필터링합니다.

    요즘, 모든 사람들 (글쎄 .. 단서가있는 모든 사람)이 작곡가를 사용하기 때문에, 최상의 옵션을 자동 로딩하려면 작곡가와 함께 제공되는 로더를 사용하는 것이 가장 좋습니다.

    단순히 require __DIR__을 추가하십시오. '/vendor/autoload.php'그리고 약간의 구성으로 작동 할 것입니다.

    라우팅과 관련하여 FastRoute 또는 Symfony의 Routing Component라는 두 가지 주요 "독립형"솔루션이 있습니다. 이러한 것들은 추가적인 두통없이 프로젝트에 포함될 수 있습니다.

    그러나 일부 사용자는 프레임 워크를 사용할 것이기 때문에 각 사용자는 프레임 워크를 사용하여 요청을 라우팅 할 수 있습니다.

    MVC 아키텍처 패턴에 대해 더 자세히 알고 싶다면이 게시물에 나열된 모든 자료를 살펴 보길 강력히 권합니다. 그것을 독서 / 시청 필수 목록으로 생각하십시오. 또한 MVC와 관련된 주제에 대한 이러한 오래된 게시물을 다소 유용하게 사용할 수 있습니다. 여기, 여기, 여기

  2. ==============================

    2.나는 너가 이걸 생각하는 것보다 ....

    나는 너가 이걸 생각하는 것보다 ....

    그래서 컨트롤러 / 리소스는 블로그입니다 .... 그들 모두가 실행해야하는 메소드는 "읽기"입니다 (crud를 사용합니다 ... 저는 보통 데이터라고 부릅니다. 그러나 기본적으로 당신의 선택이라고합니다). 이제는 URL을 기반으로 자동 매핑되는 카테고리 값을 허용하는 메소드를 사용하십시오.

    여기에 예제가 있습니다 ... 완전히 테스트되지 않았지만 단지 당신에게 아이디어를 보여주기 위해서 (pdo 사용)

    public function data($id = 0, $category = 0){
        if (isset($id) AND $id != 0){
             $bind = array(":id", $id);
             $results = $db->query("SELECT * FROM blog WHERE blog_id = :id", $bind);
             return $results[0];
        } else if (isset($category) AND $id != 0){ 
             $approved_categories = array("cosplay","game","movie","series");
             if (in_array($category, $approved_categories)){
                  $bind = array(":cat", $category);
                  $results = $db->query("SELECT * FROM blog WHERE blog_cat = :cat", $bind);
             } 
             return $results;
        }
    }
    
  3. from https://stackoverflow.com/questions/18727186/how-to-load-classes-based-on-pretty-urls-in-mvc-like-page by cc-by-sa and MIT license