RESTful URL Oluşturmak için Yeniden Yazma API'sını Kullanma


19

RESTful API için yeniden yazma kuralları oluşturmaya çalışıyorum. Bu işi yapmanın olası her yeniden yazma kombinasyonunu yazmaktan daha iyi bir yol olup olmadığını görmek istiyorum.

Tamam, URL'de hesaplamak için 4 sorgu değişkenim var

  • Gösterge
  • ülke
  • Tepki
  • anket

Temel url www.example.com/some-page/ olacaktır. 4 değişkenin sırası tutarlı olacaktır, ancak bazı sorgu değişkenleri isteğe bağlıdır.

Böylece ...

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

veya ... (yanıt yok /)

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

veya...

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

Bunu başarmanın, rewrite_rules_arrayel ile oluşturulan yeniden yazma kurallarımın bir dizisini filtrelemekten ve eklemekten daha iyi bir yolu var mı ? Misiniz add_rewrite_endpoint()rewrite_endpoint veya add_rewrite_tag()bana herhangi bir kullanım?

Yanıtlar:


18

Bence en iyi seçenek bir son nokta. Tüm verileri basit bir dize olarak alırsınız, böylece nasıl ayrıştırılacağına karar verebilirsiniz ve diğer yeniden yazma kurallarıyla çarpışma konusunda endişelenmenize gerek yoktur.

Uç noktalar hakkında öğrendiğim bir şey: ana işi olabildiğince soyut tutmak, WordPress API'sındaki aksaklıkları veri agnostik bir şekilde düzeltmek.

Mantığı üç bölüme ayırırdım: bir kontrolör bir model ve bir görünüm, uç noktayı işlemek için bir model ve bazı yararlı veri veya hata mesajlarını döndürmek için bir veya daha fazla görünüm seçer .

Kontrol eden, denetleyici

Kontrolör ile başlayalım. Çok fazla bir şey yapmaz, bu yüzden burada çok basit bir işlev kullanıyorum:

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

Temel olarak, modeli yükler T5_CRA_Modelve bazı parametreleri ve tüm işleri teslim eder. Kontrolör, modelin veya mantığın iç mantığı hakkında hiçbir şey bilmiyor. Her ikisini de birbirine bağlar. Tekrar kullanamayacağınız tek bölüm bu; bu yüzden onu diğer parçalardan ayrı tuttum.


Şimdi en az iki sınıfa ihtiyacımız var: API'yı kaydeden model ve çıktı oluşturmak için görünüm .

Model

Bu sınıf:

  • bitiş noktasını kaydet
  • herhangi bir ek parametre olmadan uç noktanın çağrıldığı durumlarda yakalama
  • üçüncü taraf kodundaki bazı hatalar nedeniyle eksik olan yeniden yazma kurallarını doldurun
  • için statik ön sayfaları ve uç noktaları olan bir WordPress aksaklığını düzeltme EP_ROOT
  • URI'yı bir diziye ayrıştırın (bu da ayrılabilir)
  • bu değerlerle geri arama işleyicisini ara

Umarım kod kendisi için konuşur. :)

Model, verinin iç yapısı veya sunum hakkında hiçbir şey bilmiyor. Böylece, bir satırı değiştirmeden yüzlerce API kaydetmek için kullanabilirsiniz.

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

Görünüm

Şimdi verilerimizle bir şeyler yapmalıyız. Ayrıca eksik talepler için eksik verileri yakalayabilir veya işlemeyi diğer görünümlere veya alt denetleyicilere devredebiliriz.

İşte çok basit bir örnek:

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

Önemli olan nokta: manzara son nokta hakkında hiçbir şey bilmiyor. Tamamen farklı istekleri işlemek için kullanabilirsiniz, örneğin AJAX istekleri wp-admin. Görünümü kendi MVC modeline bölebilir veya yalnızca basit bir işlev kullanabilirsiniz.


2
Hane. Bu tür bir deseni severim.
kingkool68
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.