Rewrite API를 사용하여 RESTful URL 구성


19

RESTful API에 대한 다시 쓰기 규칙을 생성하려고합니다. 가능한 모든 재 작성 조합을 작성하는 것 보다이 작업을 수행하는 더 좋은 방법이 있는지 알고 싶습니다.

Ok URL에 설명 할 4 개의 쿼리 변수가 있습니다.

  • 지시자
  • 국가
  • 응답
  • 서베이

기본 URL은 www.example.com/some-page/입니다. 4 개의 변수 순서는 일치하지만 일부 쿼리 변수는 선택 사항입니다.

그래서 나는 ...

/indicator/{indicator value}/country/{country value}/response/{response value}/survey/{survey value}/

또는 ... (/ 응답 없음 /)

/indicator/{indicator value}/country/{country value}/survey/{survey value}/

또는...

/indicator/{indicator value}/country/{country value}/

rewrite_rules_array수동으로 생성 한 다시 쓰기 규칙을 필터링 하고 추가하는 것보다이를 수행하는 더 좋은 방법이 있습니까? 겠습니까 add_rewrite_endpoint()rewrite_endpoint 또는 add_rewrite_tag()나에게 어떤 사용할 수?

답변:


18

최선의 선택은 끝점이라고 생각합니다. 모든 데이터를 간단한 문자열로 가져 와서 구문 분석 방법을 결정할 수 있으며 다른 다시 쓰기 규칙과의 충돌에 대해 걱정할 필요가 없습니다.

끝점에 대해 배운 한 가지 사항 : 가능한 한 주요 작업을 추상적으로 유지하고 WordPress의 API에서 결함을 데이터에 무관하게 수정하십시오.

컨트롤러 를 모델과 뷰, 엔드 포인트를 처리 할 모델 및 유용한 데이터 나 오류 메시지를 반환하는 하나 이상의 를 선택하는 세 가지 부분으로 로직을 분리 합니다.

컨트롤러

컨트롤러부터 시작하겠습니다. 많이하지 않으므로 여기에서 매우 간단한 기능을 사용합니다.

add_action( 'plugins_loaded', 't5_cra_init' );

function t5_cra_init()
{
    require dirname( __FILE__ ) . '/class.T5_CRA_Model.php';

    $options = array (
        'callback' => array ( 'T5_CRA_View_Demo', '__construct' ),
        'name'     => 'api',
        'position' => EP_ROOT
    );
    new T5_CRA_Model( $options );
}

기본적으로 모델을로드하고 T5_CRA_Model일부 매개 변수와 모든 작업을 전달합니다. 컨트롤러는 모델 또는 뷰의 내부 논리에 대해 아무것도 모릅니다. 둘 다 붙어 있습니다. 이것은 재사용 할 수없는 유일한 부분입니다. 그렇기 때문에 다른 부분과 분리하여 유지했습니다.


이제 최소한 두 개의 클래스, 즉 API를 등록하는 모델 과 출력을 생성 하는 가 필요합니다.

모델

이 수업은 :

  • 엔드 포인트 등록
  • 추가 매개 변수없이 엔드 포인트가 호출 된 캐치 케이스
  • 타사 코드의 일부 버그로 인해 누락 된 다시 쓰기 규칙 작성
  • 정적 프론트 페이지 및 엔드 포인트로 워드 프레스 결함 수정 EP_ROOT
  • URI를 배열로 구문 분석하십시오 (이것도 분리 될 수 있습니다)
  • 해당 값으로 콜백 핸들러를 호출하십시오.

코드 자체를 말하고 싶습니다. :)

모델은 데이터의 내부 구조 나 프리젠 테이션에 대해 아무것도 모릅니다. 따라서 한 줄을 변경하지 않고도 수백 개의 API를 등록하는 데 사용할 수 있습니다.

<?php  # -*- coding: utf-8 -*-
/**
 * Register new REST API as endpoint.
 *
 * @author toscho http://toscho.de
 *
 */
class T5_CRA_Model
{
    protected $options;

    /**
     * Read options and register endpoint actions and filters.
     *
     * @wp-hook plugins_loaded
     * @param   array $options
     */
    public function __construct( Array $options )
    {
        $default_options = array (
            'callback' => array ( 'T5_CRA_View_Demo', '__construct' ),
            'name'     => 'api',
            'position' => EP_ROOT
        );

        $this->options = wp_parse_args( $options, $default_options );

        add_action( 'init', array ( $this, 'register_api' ), 1000 );

        // endpoints work on the front end only
        if ( is_admin() )
            return;

        add_filter( 'request', array ( $this, 'set_query_var' ) );
        // Hook in late to allow other plugins to operate earlier.
        add_action( 'template_redirect', array ( $this, 'render' ), 100 );
    }

    /**
     * Add endpoint and deal with other code flushing our rules away.
     *
     * @wp-hook init
     * @return void
     */
    public function register_api()
    {
        add_rewrite_endpoint(
            $this->options['name'],
            $this->options['position']
        );
        $this->fix_failed_registration(
            $this->options['name'],
            $this->options['position']
        );
    }

    /**
     * Fix rules flushed by other peoples code.
     *
     * @wp-hook init
     * @param string $name
     * @param int    $position
     */
    protected function fix_failed_registration( $name, $position )
    {
        global $wp_rewrite;

        if ( empty ( $wp_rewrite->endpoints ) )
            return flush_rewrite_rules( FALSE );

        foreach ( $wp_rewrite->endpoints as $endpoint )
            if ( $endpoint[0] === $position && $endpoint[1] === $name )
                return;

        flush_rewrite_rules( FALSE );
    }

    /**
     * Set the endpoint variable to TRUE.
     *
     * If the endpoint was called without further parameters it does not
     * evaluate to TRUE otherwise.
     *
     * @wp-hook request
     * @param   array $vars
     * @return  array
     */
    public function set_query_var( Array $vars )
    {
        if ( ! empty ( $vars[ $this->options['name'] ] ) )
            return $vars;

        // When a static page was set as front page, the WordPress endpoint API
        // does some strange things. Let's fix that.
        if ( isset ( $vars[ $this->options['name'] ] )
            or ( isset ( $vars['pagename'] ) and $this->options['name'] === $vars['pagename'] )
            or ( isset ( $vars['page'] ) and $this->options['name'] === $vars['name'] )
            )
        {
            // In some cases WP misinterprets the request as a page request and
            // returns a 404.
            $vars['page'] = $vars['pagename'] = $vars['name'] = FALSE;
            $vars[ $this->options['name'] ] = TRUE;
        }
        return $vars;
    }

    /**
     * Prepare API requests and hand them over to the callback.
     *
     * @wp-hook template_redirect
     * @return  void
     */
    public function render()
    {
        $api = get_query_var( $this->options['name'] );
        $api = trim( $api, '/' );

        if ( '' === $api )
            return;

        $parts  = explode( '/', $api );
        $type   = array_shift( $parts );
        $values = $this->get_api_values( join( '/', $parts ) );
        $callback = $this->options['callback'];

        if ( is_string( $callback ) )
        {
            call_user_func( $callback, $type, $values );
        }
        elseif ( is_array( $callback ) )
        {
            if ( '__construct' === $callback[1] )
                new $callback[0]( $type, $values );
            elseif ( is_callable( $callback ) )
                call_user_func( $callback, $type, $values );
        }
        else
        {
            trigger_error(
                'Cannot call your callback: ' . var_export( $callback, TRUE ),
                E_USER_ERROR
            );
        }

        // Important. WordPress will render the main page if we leave this out.
        exit;
    }

    /**
     * Parse request URI into associative array.
     *
     * @wp-hook template_redirect
     * @param   string $request
     * @return  array
     */
    protected function get_api_values( $request )
    {
        $keys    = $values = array();
        $count   = 0;
        $request = trim( $request, '/' );
        $tok     = strtok( $request, '/' );

        while ( $tok !== FALSE )
        {
            0 === $count++ % 2 ? $keys[] = $tok : $values[] = $tok;
            $tok = strtok( '/' );
        }

        // fix odd requests
        if ( count( $keys ) !== count( $values ) )
            $values[] = '';

        return array_combine( $keys, $values );
    }
}

보기

이제 데이터로 무언가를해야합니다. 불완전한 요청에 대해 누락 된 데이터를 포착하거나 처리를 다른 뷰 또는 하위 컨트롤러에 위임 할 수도 있습니다.

다음은 매우 간단한 예입니다.

class T5_CRA_View_Demo
{
    protected $allowed_types = array (
            'plain',
            'html',
            'xml'
    );

    protected $default_values = array (
        'country' => 'Norway',
        'date'    => 1700,
        'max'     => 200
    );
    public function __construct( $type, $data )
    {
        if ( ! in_array( $type, $this->allowed_types ) )
            die( 'Your request is invalid. Please read our fantastic manual.' );

        $data = wp_parse_args( $data, $this->default_values );

        header( "Content-Type: text/$type;charset=utf-8" );
        $method = "render_$type";
        $this->$method( $data );
    }

    protected function render_plain( $data )
    {
        foreach ( $data as $key => $value )
            print "$key: $value\n";
    }
    protected function render_html( $data ) {}
    protected function render_xml( $data ) {}
}

중요한 부분은 뷰가 엔드 포인트에 대해 아무것도 모른다는 것입니다. 이를 사용하여 완전히 다른 요청 (예 :의 AJAX 요청)을 처리 할 수 ​​있습니다 wp-admin. 뷰를 자체 MVC 패턴으로 분할하거나 간단한 기능 만 사용할 수 있습니다.


2
숫자. 나는 이런 유형의 패턴을 좋아한다.
kingkool68
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.