PHP Aplicação URL Routing
-
02-07-2019 - |
Pergunta
Então, eu estou escrevendo um quadro em que eu quero basear alguns apps que eu estou trabalhando (o quadro está lá, por isso tenho um ambiente para trabalhar com, e um sistema que vai me deixar, por exemplo, usar um single sign-on)
Eu quero fazer este quadro, e os aplicativos que tem usar um Resource Oriented Architecture.
Agora, eu quero criar uma classe de roteamento de URL que é expansível por escritores APP (e possivelmente também por usuários CMS App, mas isso é WAYYYY à frente no futuro) e eu estou tentando descobrir a melhor maneira de fazê-lo olhando como outros aplicativos fazê-lo.
Solução
Eu prefiro usar ex reg sobre fazendo meu próprio formato, uma vez que é de conhecimento comum. Eu escrevi uma pequena classe que eu uso que me permite ninho estes ex tabelas de roteamento reg. Eu uso a usar algo semelhante que foi implementado pela herança, mas ele não precisa de herança, então eu reescrevi-lo.
Eu faço um reg ex em uma chave e um mapa para a minha string de controle. Tomemos o exemplo abaixo. I visitar /api/related/joe
e minha classe roteador cria uma nova ApiController
objeto e chama isso de método 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",
));
A fim de manter os erros para baixo e simplicidade se você pode subdividir a sua mesa. Desta forma, você pode colocar a tabela de roteamento para a classe que ele controla. Tomando o exemplo acima, você pode combinar as três chamadas de rosca em um único.
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",
));
Em seguida, você define ThreadController :: rota para ser assim.
function route($args) {
Route::process($args['uri'], array(
"#^(.*)/post$#Di" => "ThreadController/post/title",
"#^(.*)/reply$#Di" => "ThreadController/reply/title",
"#^(.*)$#Di" => "ThreadController/thread/title",
));
}
Além disso, você pode definir o que quer que os padrões que você deseja para sua seqüência de encaminhamento à direita. Só não se esqueça de documentá-los ou você vai confundir as pessoas. Atualmente estou chamando índice se você não incluir um nome de função no lado direito. Aqui é meu código atual. Você pode querer mudá-lo para erros punho como você gosta e ou padrão ações.
Outras dicas
No entanto, outro quadro? - de qualquer maneira ...
O truque é com roteamento é passá-lo todo para o seu controlador de roteamento.
Você provavelmente gostaria de usar algo semelhante ao que eu tenho documentado aqui:
http://www.hm2k.com/posts/friendly-urls
A segunda solução permite que você use URLs semelhantes a Zend Framework.
Use uma lista de regexs a partida que objeto eu deveria estar usando
Por exemplo
^/users/[\w-]+/bookmarks/(.+)/$
^/users/[\w-]+/bookmarks/$
^/users/[\w-]+/$
Pros: Nice e simples, me permite definir rotas diretamente Contras: teria que ser encomendado, não torná-lo fácil de adicionar novas coisas em (muito propenso a erros)
Esta é, afaik, como o Django faz
Eu acho que um monte de estruturas de usar uma combinação de mod_rewrite do Apache e um controlador de frente. Com mod_rewrite, você pode transformar uma URL como esta: pessoas / / obter / 3 para o seguinte: index.php? controller = pessoas & method = get & id = 3. Index.php iria implementar o controlador de frente, que encaminha a solicitação de página com base nos parâmetros fornecidos.
Como você poderia esperar, há uma série de maneiras de fazer isso.
Por exemplo, em Magro Framework , um exemplo do mecanismo de roteamento pode ser a folllowing (com base na padrão ${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');
}
Assim, a instância inicializada ($app
) recebe um método por método de solicitação (por exemplo, get, post, put, excluir etc.) e recebe uma rota como o primeiro parâmetro e de retorno de chamada como o segundo.
A rota pode obter fichas - que é "variável" que vai mudar em tempo de execução com base em alguns dados (como nome de membro, o artigo id, nome da organização local ou qualquer outra coisa - você sabe, assim como em todos os controladores de roteamento).
Pessoalmente, eu gosto desta forma, mas eu não acho que vai ser o suficiente flexível para um quadro avançado.
Desde que eu estou trabalhando atualmente com ZF e Yii, eu tenho um exemplo de um roteador que eu criei como parte de um quadro para uma empresa que estou trabalhando para:
O motor de rota é baseado em regex (semelhante a um @ do gradbot), mas com uma conversa de duas vias, por isso, se um cliente seu não pode executar mod_rewrite (em Apache) ou adicionar regras de reescrita em seu servidor, ele ou ela ainda pode usar os URLs tradicionais com string de consulta.
O arquivo contém uma matriz, cada um dos que, cada item é semelhante a este exemplo:
$_FURLTEMPLATES['login'] = array(
'i' => array( // Input - how the router parse an incomming path into query string params
'pattern' => '@Members/Login/?@i',
'matches' => array( 'Application' => 'Members', 'Module' => 'Login' ),
),
'o' => array( // Output - how the router parse a query string into a route
'@Application=Members(&|&)Module=Login/?@' => 'Members/Login/'
)
);
Você também pode usar combinações mais complexas, tais como:
$_FURLTEMPLATES['article'] = array(
'i' => array(
'pattern' => '@CMS/Articles/([\d]+)/?@i',
'matches' => array( 'Application' => "CMS",
'Module' => 'Articles',
'Sector' => 'showArticle',
'ArticleID' => '$1' ),
),
'o' => array(
'@Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)@' => 'CMS/Articles/$4'
)
);
A linha de fundo, como eu penso, é que as possibilidades são infinitas, ele só depende de quão complexo você deseja que seu quadro ser eo que você deseja fazer com ele.
Se for, por exemplo, apenas a intenção de ser um serviço web ou simples invólucro website - basta ir com estilo de Slim quadro da escrita - muito fácil e code-boa aparência.
No entanto, se você deseja desenvolver sites complexos de usá-lo, eu acho que regex é a solução.
Boa sorte! :)
Você deve verificar se Pux https://github.com/c9s/Pux
Aqui está a sinopse
<?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);
framework MVC do Zend por padrão utiliza uma estrutura como
/router/controller/action/key1/value1/key2/value2
onde router
é o arquivo router (mapeados via mod_rewrite
, controller
é de um manipulador de ação do controlador que é definido por uma classe que deriva de referências Zend_Controller_Action
e action
um método no controlador, actionAction
nomeado. Os pares de chave / valor pode ir em qualquer ordem e estão disponíveis para o método de acção como uma matriz associativa.
Eu usei algo semelhante no passado no meu próprio código, e até agora tem funcionado bastante bem.
Tente tomar olhada MVC padrão.
Zend Framework usa-lo, por exemplo, mas também CakePHP, CodeIgniter, ...
Me pessoalmente não gosto do modelo MVC, mas é na maioria das vezes implementados como "Ver para web" componente.
A decisão praticamente depende da preferência ...