2008-09-24 29 views
15

Vì vậy, tôi đang viết một khuôn khổ mà tôi muốn dựa vào một vài ứng dụng mà tôi đang làm việc (khung làm việc ở đó để tôi có một môi trường làm việc và hệ thống sẽ cho tôi , ví dụ: sử dụng một lần đăng nhập một lần)PHP Application URL Routing

Tôi muốn tạo khung này và các ứng dụng mà nó đã sử dụng Kiến trúc định hướng tài nguyên.

Bây giờ, tôi muốn tạo một lớp định tuyến URL có thể mở rộng bởi các nhà văn APP (và cũng có thể bởi người dùng ứng dụng CMS, nhưng đó là WAYYYY trong tương lai) và tôi đang cố gắng tìm ra cách tốt nhất để làm bằng cách xem các ứng dụng khác hoạt động như thế nào.

Trả lời

12

Tôi thích sử dụng reg ex hơn khi tạo định dạng của riêng mình vì đó là kiến ​​thức phổ biến. Tôi đã viết một lớp nhỏ mà tôi sử dụng cho phép tôi lồng các bảng định tuyến cũ. Tôi sử dụng để sử dụng một cái gì đó tương tự đã được thực hiện bởi thừa kế nhưng nó không cần thừa kế vì vậy tôi viết lại nó.

Tôi thực hiện reg ex trên khóa và ánh xạ tới chuỗi điều khiển của riêng tôi. Lấy ví dụ dưới đây.Tôi ghé thăm /api/related/joe và lớp router của tôi tạo ra một đối tượng mới ApiController và gọi đó là phương pháp relatedDocuments(array('tags' => 'joe'));

// the 12 strips the subdirectory my app is running in 
$index = urldecode(substr($_SERVER["REQUEST_URI"], 12)); 

Route::process($index, array(
    "#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags", 

    "#^thread/(.*)/post$#Di" => "ThreadController/post/title", 
    "#^thread/(.*)/reply$#Di" => "ThreadController/reply/title", 
    "#^thread/(.*)$#Di"   => "ThreadController/thread/title", 

    "#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags", 
    "#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id", 
    "#^ajax/reply/(.*)$#Di"  => "ArticleController/newReply/id", 
    "#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle", 

    "#^$#Di"     => "HomeController", 
)); 

Để giữ lỗi xuống và đơn giản lên bạn có thể chia nhỏ bảng của bạn. Bằng cách này bạn có thể đặt bảng định tuyến vào lớp mà nó điều khiển. Lấy ví dụ trên, bạn có thể kết hợp ba cuộc gọi luồng thành một cuộc gọi duy nhất.

Route::process($index, array(
    "#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags", 

    "#^thread/(.*)$#Di"   => "ThreadController/route/uri", 

    "#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags", 
    "#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id", 
    "#^ajax/reply/(.*)$#Di"  => "ArticleController/newReply/id", 
    "#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle", 

    "#^$#Di"     => "HomeController", 
)); 

Sau đó, bạn xác định ThreadController :: tuyến đường như thế này.

function route($args) { 
    Route::process($args['uri'], array(
     "#^(.*)/post$#Di" => "ThreadController/post/title", 
     "#^(.*)/reply$#Di" => "ThreadController/reply/title", 
     "#^(.*)$#Di"   => "ThreadController/thread/title", 
    )); 
} 

Ngoài ra, bạn có thể xác định bất kỳ giá trị mặc định nào bạn muốn cho chuỗi định tuyến ở bên phải. Chỉ cần đừng quên ghi lại chúng hoặc bạn sẽ gây nhầm lẫn cho mọi người. Tôi hiện đang gọi chỉ mục nếu bạn không bao gồm tên hàm ở bên phải. Here là mã hiện tại của tôi. Bạn có thể muốn thay đổi nó để xử lý lỗi như thế nào bạn thích và hoặc hành động mặc định.

+0

Ví dụ thứ hai là rất nhiều những gì tôi thực sự nghĩ đến việc làm ... (kiểu RoR) - Tôi sẽ xem qua mã của bạn. – Mez

+0

Nó rất giống với Django Python. – kta

1

Sử dụng một danh sách các regexs để phù hợp với đối tượng mà tôi nên sử dụng

Ví dụ

^/users/[\w-]+/bookmarks/(.+)/$ 
^/users/[\w-]+/bookmarks/$ 
^/users/[\w-]+/$ 

Ưu điểm: đẹp và đơn giản, cho phép tôi xác định các tuyến đường trực tiếp Nhược điểm: Sẽ phải được đặt hàng, không làm cho nó dễ dàng để thêm những điều mới mẻ trong (rất dễ bị lỗi)

Đây là, afaik, làm thế nào Django làm nó

-4

Hãy thử dùng xem 01 Mẫu.
Zend Framework sử dụng ví dụ này, nhưng cũng CakePHP, CodeIgniter, ...

Cá nhân tôi không thích mô hình MVC, nhưng phần lớn thời gian được triển khai là thành phần "Xem cho web".

Quyết định khá nhiều phụ thuộc vào sở thích ...

+0

Tôi đang sử dụng một điều MVC. Tôi đang nói về mặt kỹ thuật hoặc định tuyến URL. Vì vậy, không phải là câu trả lời cho câu hỏi của tôi – Mez

0

Tôi nghĩ rằng rất nhiều các khuôn khổ sử dụng một sự kết hợp của mod_rewrite của Apache và một bộ điều khiển phía trước. Với mod_rewrite, bạn có thể chuyển một URL như sau:/people/get/3 thành: index.php? Controller = people & method = get & id = 3. Index.php sẽ thực hiện bộ điều khiển phía trước của bạn để định tuyến yêu cầu trang dựa trên các tham số đã cho.

+0

Vì vậy, rõ ràng là bỏ qua url không phải ROA của bạn, nó giống như câu trả lời của tôi ở trên, nhưng sử dụng mod_rewrite với các quy tắc cụ thể và thực hiện "định tuyến" thông qua các tham số cụ thể, thay vì thông qua mã? – Mez

-1

khung MVC của Zend theo mặc định sử dụng một cấu trúc như

/router/controller/action/key1/value1/key2/value2 

nơi router là file bộ định tuyến (ánh xạ qua mod_rewrite, controller là từ một handler controller action được định nghĩa bởi một lớp dẫn xuất từ ​​Zend_Controller_Actionaction tham chiếu một phương thức trong bộ điều khiển, có tên là actionAction Các cặp khóa/giá trị có thể theo bất kỳ thứ tự nào và có sẵn cho phương thức hành động như một mảng kết hợp.

Tôi đã sử dụng một cái gì đó tương tự t trong mã của riêng tôi, và cho đến nay nó hoạt động khá tốt.

+0

hành động không áp dụng cho hệ thống ROA, chỉ cho hệ thống kiểu RPC – Mez

+0

Bạn hoàn toàn đúng ... Tôi đã đọc sai câu hỏi. Điều đó, và ROA đã ném tôi đi. Tôi đã luôn luôn gọi nó là REST. –

+0

Tuy nhiên, đó không phải là RESTFul. Chỉ để cho bản ghi âm thôi. – DanMan

2

Một khung công tác khác? - anyway ...

Bí quyết là định tuyến là chuyển nó qua bộ điều khiển định tuyến của bạn.

Bạn có thể muốn sử dụng một cái gì đó tương tự như những gì tôi đã ghi nhận ở đây:

http://www.hm2k.com/posts/friendly-urls

Giải pháp thứ hai cho phép bạn sử dụng các URL tương tự như Zend Framework.

+5

Xây dựng một khuôn khổ làm việc là một nghi thức khởi đầu. tất cả mọi người lập trình php phải làm điều đó. – user1709251

0

Như bạn có thể mong đợi, có rất nhiều cách để làm điều đó.

Ví dụ, trong Slim Framework, một ví dụ về động cơ định tuyến có thể là folllowing (dựa trên mô hình ${OBJECT}->${REQUEST METHOD}(${PATTERM}, ${CALLBACK})):

$app->get("/Home", function() { 
    print('Welcome to the home page'); 
} 

$app->get('/Profile/:memberName', function($memberName) { 
    print('I\'m viewing ' . $memberName . '\'s profile.'); 
} 

$app->post('/ContactUs', function() { 
    print('This action will be fired only if a POST request will occure'); 
} 

Vì vậy, các trường hợp khởi tạo ($app) được một phương pháp cho mỗi phương thức yêu cầu (ví dụ như get, post, put, delete, vv) và lấy một route làm tham số đầu tiên và gọi lại như là tham số thứ hai.

Tuyến đường có thể nhận mã thông báo - thay đổi theo thời gian chạy dựa trên một số dữ liệu (chẳng hạn như tên thành viên, id bài viết, tên vị trí tổ chức hoặc bất kỳ thứ gì - bạn biết, giống như mọi bộ điều khiển định tuyến).

Cá nhân, tôi thực hiện theo cách này nhưng tôi không nghĩ rằng nó sẽ đủ linh hoạt cho một khung công tác nâng cao.

Kể từ khi tôi đang làm việc với ZF và Yii, tôi có một ví dụ về một router tôi đã tạo ra như một phần của một khuôn khổ cho một công ty tôi đang làm việc cho:

Động cơ tuyến đường dựa trên regex (tương tự như @ gradbot) nhưng có cuộc trò chuyện hai chiều, vì vậy nếu một khách hàng của bạn không thể chạy mod_rewrite (trong Apache) hoặc thêm quy tắc viết lại trên máy chủ của họ, họ vẫn có thể sử dụng truyền thống URL có chuỗi truy vấn.

Các tập tin chứa một mảng, mỗi người trong số đó, từng hạng mục tương tự như ví dụ sau:

$_FURLTEMPLATES['login'] = array(
    'i' => array(// Input - how the router parse an incomming path into query string params 
     'pattern' => '@Members/Login/[email protected]', 
     'matches' => array('Application' => 'Members', 'Module' => 'Login'), 
    ), 
    'o' => array(// Output - how the router parse a query string into a route 
     '@Application=Members(&|&)Module=Login/[email protected]' => 'Members/Login/' 
    ) 
); 

Bạn cũng có thể sử dụng kết hợp phức tạp hơn, chẳng hạn như:

$_FURLTEMPLATES['article'] = array(
    'i' => array(
     'pattern' => '@CMS/Articles/([\d]+)/[email protected]', 
     'matches' => array('Application' => "CMS", 
      'Module' => 'Articles', 
      'Sector' => 'showArticle', 
      'ArticleID' => '$1'), 
    ), 
    'o' => array(
    '@Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)@' => 'CMS/Articles/$4' 
    ) 
); 

Điểm mấu chốt , như tôi nghĩ, là khả năng là vô tận, nó chỉ phụ thuộc vào mức độ phức tạp mà bạn muốn khuôn khổ của bạn và những gì bạn muốn làm với nó.

Nếu đó là, ví dụ, chỉ nhằm mục đích trở thành một dịch vụ web hoặc trình bao bọc trang web đơn giản - chỉ cần đi với phong cách viết của khung công cụ mỏng - mã rất dễ dàng và đẹp mắt.

Tuy nhiên, nếu bạn muốn phát triển các trang web phức tạp bằng cách sử dụng nó, tôi nghĩ rằng regex là giải pháp.

Chúc may mắn! :)

0

Bạn nên kiểm tra Pux https://github.com/c9s/Pux

Dưới đây là tóm tắt

<?php 
require 'vendor/autoload.php'; // use PCRE patterns you need Pux\PatternCompiler class. 
use Pux\Executor; 

class ProductController { 
    public function listAction() { 
     return 'product list'; 
    } 
    public function itemAction($id) { 
     return "product $id"; 
    } 
} 
$mux = new Pux\Mux; 
$mux->any('/product', ['ProductController','listAction']); 
$mux->get('/product/:id', ['ProductController','itemAction'] , [ 
    'require' => [ 'id' => '\d+', ], 
    'default' => [ 'id' => '1', ] 
]); 
$mux->post('/product/:id', ['ProductController','updateAction'] , [ 
    'require' => [ 'id' => '\d+', ], 
    'default' => [ 'id' => '1', ] 
]); 
$mux->delete('/product/:id', ['ProductController','deleteAction'] , [ 
    'require' => [ 'id' => '\d+', ], 
    'default' => [ 'id' => '1', ] 
]); 
$route = $mux->dispatch('/product/1'); 
Executor::execute($route); 
+0

bạn có thể thêm tuyến đường cho 404 không? –