Dấu gạch chéo trong tham số tuyến đơn hoặc các cách khác để xử lý đuôi menu với số lượng thông số động


8

Theo tài liệu Symfony , một tuyến đường được xác định như dưới đây sẽ kích hoạt bộ điều khiển được chỉ định cho cả hai /hello/bob/hello/bob/bobby:

_hello:
  path:     /hello/{names}
  defaults: { _controller: \Drupal\mymodule\Controller\Main::Controller }
  requirements:
    _access: 'TRUE'
    names: .+

Trong trường hợp yêu cầu /hello/bob/bobbycác {names}param sẽ là "bob / bobby" (giảm còn nguyên vẹn) và nó sẽ lên tới bộ điều khiển để phá vỡ thành nhiều biến hoặc để lại nó như là một chuỗi duy nhất. Thủ thuật cho điều đó là regex đã thay đổi (". +") Được sử dụng để lọc {names}param đó .

Bài đăng stackoverflow này cũng ngụ ý rằng regex tùy chỉnh có thể được sử dụng để cho phép dấu gạch chéo trong một tham số tuyến (ít nhất là trong Symfony 2).

Nếu tôi thử điều này với Drupal 8.0.0-beta15 thì nó không hoạt động và bộ điều khiển được chỉ định chỉ được kích hoạt cho một yêu cầu /hello/bob. Tuy nhiên, tôi có thể xác nhận rằng điều này đã từng hoạt động trong các betas trước đó (tôi nghĩ cho đến ~ beta13).

Có điều gì đó đã thay đổi theo cách Drupal tích hợp với thành phần định tuyến Symfony sẽ giải thích điều này? Có lẽ có một cách khác để thực hiện việc truyền các dấu gạch chéo trong các thông số định tuyến? Tôi biết có một phong trào hướng tới Symfony 3.0 trong cốt lõi, nhưng tôi không chắc liệu điều đó có thể giải thích mọi thứ hay không.

Tôi cũng biết rằng các thuê bao tuyến có sẵn để quản lý các cấu trúc tuyến động. Tuy nhiên, trường hợp tôi đang làm việc đòi hỏi một sự kết hợp / số lượng tham số động gần như vô hạn ở cuối đường dẫn cơ sở (nhưng không đáng kể để phân tích cú pháp trong bộ điều khiển của tôi). Tôi cũng đang cố gắng tránh các chuỗi truy vấn (ví dụ /hello?names[]=bob&names[]=bobby) cho trường hợp này.

Chủ yếu tôi chỉ bối rối khi ngắt kết nối với tài liệu Symfony, dường như nói rằng điều này là có thể.


Ghi chú bổ sung

Sau khi đăng câu hỏi này tôi phát hiện ra cuộc thảo luận này trong hàng đợi lõi D8: [Thảo luận] Thả tự động thông qua lập luận thêm: Y / N . Dường như kết luận rằng hỗ trợ "menu đuôi" (về cơ bản là những gì tôi sẽ theo sau) sẽ chính thức bị loại bỏ trong D8. Cuộc thảo luận đó đã kết thúc 3 năm trước và vì vậy tôi chỉ có thể đoán rằng một số chi tiết triển khai tổng quát hơn chưa được thực hiện đầy đủ cho đến gần đây (~ beta13). Điều này có thể giải thích tại sao bây giờ tôi chỉ nhận thấy sự thay đổi này.

Tôi đoán rằng Drupal (không phải Symfony) hiện đang tạo phản hồi 404 dựa trên yêu cầu được phân cách bằng dấu gạch chéo thô trước khi bất kỳ logic định tuyến cụ thể nào của Symfony phân tích tuyến đường (và đó là biểu thức chính quy cụ thể, v.v.). Nếu đây là trường hợp nó có thể giải thích tại sao kỹ thuật trên ngừng hoạt động. Tuy nhiên, tôi vẫn tự hỏi liệu có cách nào khác để giải quyết nhu cầu này mà tránh sử dụng thông số truy vấn và người đăng ký tuyến tùy chỉnh.


Từ những gì tôi biết về Symfony, tôi sẽ mong đợi / hello / {username} khớp với / hello / bob nhưng không phải trên / hello / bob / smith. Nếu bạn muốn các tham số bổ sung, bạn phải đặt mặc định cho chúng như trong stackoverflow.com/questions/11980175/ . Nhưng có lẽ tôi không hiểu câu hỏi.
cilefen

Định cấu hình mặc định hoạt động như mong đợi (nghĩa là có thể đặt {tên} làm tham số tùy chọn). Vì vậy, vâng, tôi cho rằng tôi có thể có một lộ trình tuyến đường như /hello/ đũaarg1spl / nbarg2spl / nbarg3opez / ... / nbargN}, có thể hoạt động với các thông số 0-N. Tuy nhiên, điều đó đặt ra giới hạn tĩnh cho số lượng thông số và cảm thấy khá lộn xộn. Tôi hiểu rằng nên có thể làm điều này khác đi, thông qua dấu phân cách gạch chéo trong một thông số duy nhất, dựa trên tài liệu Symfony ( symfony.com/doc/master/cookbook/routing/slash_in_parameter.html ) cùng với kinh nghiệm trước đây với Drupal cũ betas cốt lõi.
rjacobs

1
Không rõ những gì path: /hello/{names}username: .+phải làm với nhau.

@chx, xin lỗi, tôi đã chỉnh sửa câu hỏi của mình ngay sau khi đăng bài với nỗ lực làm cho nó chung chung hơn. Trong quá trình đó, tôi đã quên cập nhật đoạn mã yml. Tôi đã sửa nó. Nó nên đọc "tên :. +"
rjacobs

Tôi chỉ nhận thấy rằng bình luận cuối cùng của tôi có thể cho ấn tượng rằng tôi đã giải quyết mọi thứ. Xin lưu ý rằng tôi chỉ có một lỗi đánh máy trong bài viết của tôi. Câu hỏi / vấn đề vẫn còn tồn tại như bây giờ được đặt ra.
rjacobs

Câu trả lời:


9

Bạn có thể thay đổi đường dẫn bằng cách thêm một lớp thực hiện InboundPathProcessorInterface

namespace Drupal\mymodule\PathProcessor;

use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;

class HelloPathProcessor implements InboundPathProcessorInterface {

  public function processInbound($path, Request $request) {
    if (strpos($path, '/hello/') === 0) {
      $names = preg_replace('|^\/hello\/|', '', $path);
      $names = str_replace('/',':', $names);
      return "/hello/$names";
    }
    return $path;
  }

}

Bằng cách này, router sẽ giải thích con đường /hello/bob/bobbynhư /hello/bob:bobbyvà bạn sẽ nhận được các thông số phân cách bằng :(hoặc bất kỳ ký tự khác sẽ không mâu thuẫn với các thông số) trong điều khiển của bạn.

Bạn cũng sẽ cần phải đăng ký lớp dưới dạng dịch vụ trong mymodule.service.yml (đảm bảo mức độ ưu tiên được đặt cao hơn 200)

services:
  mymodule.path_processor:
    class: Drupal\mymodule\PathProcessor\HelloPathProcessor
    tags:
      - { name: path_processor_inbound, priority: 250 }

Vâng, đây là một điểm tốt, và tôi cho rằng đây là cùng một cơ chế được sử dụng để thực hiện khử răng cưa? Nếu đi theo tuyến này, tôi giả sử rằng đường dẫn của bộ định tuyến sẽ không thay đổi (/ hello / {name}) và sau đó "tên" vẫn có thể được xử lý như một tham số tuyến duy nhất. Vì vậy, nếu một URL sử dụng tuyến đường này được tạo theo tên lập trình sẽ vẫn phải được xây dựng với các dấu phân cách tùy chỉnh (bob: bợm), nhưng hệ thống vẫn tương thích với đầu vào URL "thân thiện" hơn (bob / bOB)?
rjacobs

1

Bạn có thể thực hiện các thao tác sau để truy xuất thông số đường dẫn: Trong trường hợp này, tôi muốn truy xuất mọi thứ xuất hiện sau / rest / dưới dạng một chuỗi các chuỗi.

Tệp yourmodule.routing.yml của bạn sẽ trông giống như thế này.

yourmodule.rest:
  path: /rest/{path_parms}
  defaults:
    _controller: 'Drupal\yourmodule\Controller\YourController::response'
    _title: 'Rest API Title'
  requirements:
    path_params: '^[^\?]*$'
    _permission: 'access content'

hoặc trong đường dẫn \ đến \ yourmodule \ src \ Routing \ RouteProvider.php

/**
 * @file
 * Contains \Drupal\yourmodule\Routing\RouteProvider.
 */

namespace Drupal\yourmodule\Routing;

use Symfony\Component\Routing\Route;

/**
 * Defines dynamic routes.
 */
class RouteProvider
{
    /**
     * Returns all your module routes.
     *
     * @return RouteCollection
     */
    public function routes()
    {
        $routes = [];

        // This route leads to the JS REST controller
        $routes['yourmodule.rest'] = new Route(
            '/rest/{path_params}',
            [
              '_controller' => '\Drupal\yourmodule\Controller\YourController::response',
              '_title' => 'REST API Title',
            ],
            [
              'path_params' => '^[^\?]*$',
              '_permission' => 'access content',
            ]
        );

        \Drupal::service('router.builder')->setRebuildNeeded();

        return $routes;
    }
}

Tiếp theo, thêm bộ xử lý Path vào mô-đun của bạn như sau. đường dẫn \ đến \ yourmodule \ src \ PathProcessor \ YourModulePathProcessor.php

namespace Drupal\yourmodule\PathProcessor;

use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;

class YourModulePathProcessor implements InboundPathProcessorInterface {

    public function processInbound($path, Request $request) {
        // If a path begins with `/rest`
        if (strpos($path, '/rest/') === 0) {
            // Transform the rest of the path after `/rest`
            $names = preg_replace('|^\/rest\/|', '', $path);
            $names = str_replace('/',':', $names);

            return "/rest/$names";
        }

        return $path;
    }
}

Cuối cùng, trong trình điều khiển của bạn, hãy thực hiện việc này: path \ to \ yourmodule \ src \ Controller \ YourControll.php

namespace Drupal\yourmodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

/**
 * Controller routines for test_api routes.
 */
class YourController extends ControllerBase {

    /**
     * Callback for `rest/{path_params}` API method.
     */
    public function response(Request $request) {
        $params = explode(':', $request->attributes->get('path_params'));

        // The rest of your logic goes here ...
    }

}

nó không hoạt động với drupal 8.7.9
Ekta Puri

Có thật không? Bạn đã tìm thấy một sự thay thế mặc dù?
GuruKay

chưa, nếu bạn có bất kỳ giải pháp nào xin vui lòng chia sẻ
Ekta Puri

Xin lỗi, tôi mất quá nhiều thời gian, tôi đã cập nhật bài viết của mình để hiển thị những gì cuối cùng tôi đã làm để có được thông số đường dẫn. Trong trường hợp của riêng tôi, tôi cần nó cho API REST tùy chỉnh của mình.
GuruKay

0

Giải pháp thay thế:

Tạo một tham số tuyến đường nhận được một mảng json.


mymodule.routing.yml

_hello:
  path:     /hello/{names}
  defaults: { _controller: \Drupal\mymodule\Controller\Main::index }
  requirements:
    _access: 'TRUE'

\ Drupal \ mymodule \ Trình điều khiển \ Chính

public function index($names_json) {
  $names = Json::decode($names_json);
  // Do something with $names
}

Có, mã hóa nhiều đối số thành một tham số tuyến chắc chắn là một tùy chọn. Tôi giả sử bạn đang ám chỉ rằng "tên" param sẽ là một mảng php chính thức được mã hóa / tuần tự trực tiếp? Nếu vậy, sẽ không có tùy chọn mã hóa phù hợp hơn cho thành phần đường dẫn JSON đó chứ? Lưu ý rằng điều này cũng sẽ làm cho một đường dẫn thân thiện với người dùng hơn nhiều bất kể kỹ thuật mã hóa (một vấn đề tiềm năng đối với đầu vào của con người, nhưng không nhất thiết là tạo đường dẫn lập trình).
rjacobs

Tất nhiên bạn có thể sử dụng bất kỳ kỹ thuật mã hóa nào bạn muốn. Tôi thích JSON vì nó được chuẩn hóa với bộ mã hóa (/ bộ giải mã) trong hầu hết các ngôn ngữ. Điều này sẽ làm cho đường dẫn ít thân thiện hơn nhiều. Nếu đường dẫn bị lộ ra bên ngoài thì tôi nghĩ việc chuyển tên trong truy vấn (name [] = Ben & name [] = George) sẽ dễ đọc hơn nhiều.
Mắt
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.