Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Estou fazendo um site usando estrutura MVC, minha dúvida é com a Friendly URL é a seguinte.
Até o momento fiz um script para ler da seguinte forma.
www.site.com/controller/action
Até aí foi fácil, mas pretendo fazer uma página de perfil de usuários usando a seguinte url
www.site.com/user ou profile/login_do_usuario
<?php
class System {
private $_uri;
private $_controller;
private $_action;
public function __construct() {
$this->setURI();
$this->setController();
$this->setAction();
}
public function setURI(){
$this->_uri = explode('/', $_SERVER['REQUEST_URI']);
$this->_uri = array_slice($this->_uri, 1);
}
public function setController() {
if ($this->_uri[0]) {
$this->_controller = $this->_uri[0];
}
}
public function setAction() {
if ($this->_uri[1]){
$this->_action = $this->_uri[1];
}
}
// Continua código...Irei pesquisar sobre @hinom, grato pelas dicas!
---------------------------------------------------------------------------------------------------------------------
Editado
@hinom, e se eu fizesse a controller checar a primeira controller e daí tratar os dados de forma diferente?
Será que seria meio que idiotisse fazer isso?
exemplo:
public function setController() {
if ($this->_uri[0]) {
$this->_controller = $this->_uri[0];
} else {
$this->_controller = 'default';
}
}
public function setAction() {
if ($this->_uri[1]){
$this->_action = $this->_uri[1];
} elseif ($this->_controller == 'user'){
$this->_action = 'id';
} else {
$this->_action = 'index';
}
}
Daí eu já daria um jeito de esquecer que a action existe na url e já comecaria a ler os parâmetros, algo assim.
O problema é que o sistema ficaria limitado caso eu fosse querer usar o sistema para outros projetos, mas não seria tão difícil de fazer as alterações nesse arquivo.
/applications/core/interface/imageproxy/imageproxy.php?img=http://img20.imageshack.us/img20/9875/qccf.png&key=42fc21887a127f542da154e671c847d016dbf332599bbbe3d6ccb368401dca8a" alt="qccf.png" />
/applications/core/interface/imageproxy/imageproxy.php?img=http://img208.imageshack.us/img208/1841/en9y.png&key=1660caca972266f65d05ff20fd955dfc3970b2f37e0caad7ab398be6240fd805" alt="en9y.png" />
/applications/core/interface/imageproxy/imageproxy.php?img=http://i.imgur.com/OlnCqe6.png&key=780783aed19d69aa2b7198e45375448a95d7aadbea1d06044fe2a020944a39e4" alt="OlnCqe6.png" />
A lógica é essa mesma.
O ponto chave é abstrair o trecho que identifica o controller ou módulo.
Identificado o controller, o restante são parâmetros.
Para facilitar o entendimento, veja como fica um exemplo usando a técnica na qual os nomes dos controladores são registrados
Uma técnica simples é fazer uma iteração no array $_uri
A idéia é ir montando o path até encontrar se o nome existe no array que contém o registro dos controladores.
Veja um exemplo:
$controllers = array( 'user' => array( 'name' => 'User', 'namespace' => 'Controller', ), 'adm/user' => array( 'name' => 'User', 'namespace' => 'Controller\Adm', ), 'user/profile/other' => array( 'name' => 'Other', 'namespace' => 'Controller\User\Profile', ), );/*** Dummy URIs for debug purposes*///$uri_dummy = 'users/1';//$uri_dummy = 'user/1/2/3';//$uri_dummy = 'user';//$uri_dummy = 'user/';$uri_dummy = 'user/profile/other/1/2/3';/*** Converting the parts to array*/$uri = explode( '/', $uri_dummy );/*** This variable will handle the final result.* If nothing was found, will keep as null.*/$path = null;if( isset( $controllers[$uri_dummy] ) ){ /** * Found exact key */ $path = $controllers[$uri_dummy]; $path['parameters'] = array( $uri_dummy );}else{ if( count( $uri ) > 1 ) { /** * Removing the last key. */ array_pop( $uri ); /** * Must be carefull with thisg because $path may return null. * The looping is interrupted by some conditionals inside it. */ while( empty( $path ) ) { /** * Mounting the key name from array to string */ $str = implode( '/', $uri ); /** * Checking if key exists in $controllers */ if( isset( $controllers[$str] ) ) { /** * If the original URI string length is bigger than $str var, means that probably have others parameters. */ if( strlen( $uri_dummy ) > strlen( $str ) ) { /** * The extra parameters. */ $params = explode( '/', substr( $uri_dummy, strlen( $str ) ) ); /** * Assign the key name to the first key. */ $params[0] = $str; }else{ /** * Have no extra parameters. * Assign the key name to the first key. */ $params = array( $str ); } /** * Assign the final array. */ $path = $controllers[$str]; $path['parameters'] = $params; break; }else{ /** * Still not found. * If array contains more then 1 key, continue interacting */ /** * Removing the last key */ array_pop( $uri ); /** * Nothing was found. * Breaking the loop */ if( count( $uri ) <= 1 ) { break; } } } }}//var_dump( $path );print_r( $path );
Note que é importante também conferir antes em algum array contendo aliases.
Os aliases devem ter precedência.
No caso na array $controller eu apenas adicionaria os que seriam por exemplo, user?
Eu estava pensando em fazer da seguinte forma, verificar se o controller e a action existe, caso não existir eu uso como user, colocando o código em um ___construct().
particularmente aconselho a não fazer isso pois estaria criando uma gambiarra.
sobre o array controller do exemplo,
Não.. no array controller do exemplo acima pode-se definir qualquer outro nome
exemplo
$controllers = array( 'outro_nome_qualquer' => array( 'name' => 'NomeDaClasse', 'namespace' => 'NameSpace\do\Modulo', ), );
acho que te confundi um pouco adicionando uns recursos...
só achei melhor não postar algo muito simplório..
mas tente entender a estrutura.. está tudo num nível bem simples.
Atente-se de que há mais detalhes para implementar.. isso é apenas um exemplo.
#6 show de bola!
>
particularmente aconselho a não fazer isso pois estaria criando uma gambiarra.
sobre o array controller do exemplo,
Não.. no array controller do exemplo acima pode-se definir qualquer outro nome
exemplo
$controllers = array(
'outro_nome_qualquer' => array(
'name' => 'NomeDaClasse',
'namespace' => 'NameSpace\do\Modulo',
),
);
acho que te confundi um pouco adicionando uns recursos...
só achei melhor não postar algo muito simplório..
mas tente entender a estrutura.. está tudo num nível bem simples.
Atente-se de que há mais detalhes para implementar.. isso é apenas um exemplo.
Como vou identificar a action se o resto são parâmetros?
Também preciso disso, mas com e array é só declarar seguindo seu exemplo no post #3
ficararia
return array(
'user' => array(
'name' => 'User',
'action' => 'index',
'namespace' => 'Controller',
),
'download' => array(
'name' => 'Download',
'action' => 'index',
'namespace' => 'Controller',
),
$uri_dummy = 'download';
Acho que isso :pinch:
Vamos aguardar = hinom
Mano, to sentido falta dos parametros, que vem além do controller e do action.
Seria legal se você fizesse algo assim:
$nomeControllerDinamico = Router::getController();
$objetoController = new $nomeControllerDinamico;
$action = Router::getAction();
$params = Router::getParams();
call_user_func_array(array($objetoController,$action),$params);
>
Mano, to sentido falta dos parametros, que vem além do controller e do action.
Seria legal se você fizesse algo assim:
$nomeControllerDinamico = Router::getController();
$objetoController = new $nomeControllerDinamico;
$action = Router::getAction();
$params = Router::getParams();
call_user_func_array(array($objetoController,$action),$params);
É parei na parte dos parâmetros, pois preciso diferenciar de quando ele vai buscar a action ou buscar o parâmetro de quando a url for site.com.br/user/nome_do_user. rs
No exemplo, temos esses esses parâmetros para teste (dummy uri)
/*** Dummy URIs for debug purposes*///$uri_dummy = 'users/1';//$uri_dummy = 'user/1/2/3';//$uri_dummy = 'user';//$uri_dummy = 'user/';$uri_dummy = 'user/profile/other/1/2/3';
Vamos modificar um pouco a URI de exemplo para algo mais prático:
$uri_dummy = 'user/profile/other/edit/1';
Nesse exemplo, o controlador e o action são:
Controller: user/profile/other
Action: edit
Resultado:
Array( [name] => Other [namespace] => Controller\User\Profile [parameters] => Array ( [0] => user/profile/other [1] => edit [2] => 2 [3] => 3 ))
O índice 'name' é o nome do controller.
Os outros índices dentro do array 'parameters' sãos parâmetros restantes, os quais podem ser usados para quaisquer finalidades.
Caso queira um identificador para o "Action", pode usar o índice 1, por exemplo, tal como já estava sendo usado no post #1.
O índice ZERO do array 'parameters' é apenas para manter um controle do parâmetro original que chamou o controler.
Também pode adicionar o nome do action ao array definido em $controller, conforme exemplo no post #9.
Aí depende da sua política, do seu modelo de negócios.
Enquanto escrevia o exemplo, adicionei "namespace" para poder facilitar no momento de carregar o controlador.
Assim fica mais simples caso já esteja usando autoloading.
De forma mais práica,
Após obter o resultado, basta ler o array.
// print_r( $path );/*** Mounting the class name*/$c = '\\' . $path['namespace'] . '\\' . $path['namespace'];/*** Instantiating the class*/$clss = new $c;/*** Clearing object*/unset( $c );// daqui pra frente vc segue com o seu modelo de negócios.// por exemplo, se quer chamar o action ou qulquer outro método dentro desse controller:/*** Checking if action parameter exists*/if( isset( $path['parameters'][1] ) && method_exists( $clss, $path['parameters'][1] ) ){ /** Loading the action method ie: ClassName::ActionName() */ $clss -> {$path['parameters'][1]}();}
Valeu hinom, seguindo seu exemplo deu tudo certo
load para namespace
spl_autoload_register( function( $classname ) { require_once str_replace( '\\', DIRECTORY_SEPARATOR, $classname ) . '.php'; });
code
$Router = new \Controller\Router;$UriDummy = 'sac/ticket/edit';$Router->setUriDummy( $UriDummy );// Chama a função dentro do namespace$path = $Router -> router();$c = '\\' . $path['namespace'];/*** Instantiating the class*/$clss = new $c;/*** Clearing object*/unset( $c );// daqui pra frente você segue com o seu modelo de negócios.// por exemplo, se quer chamar o action ou qulquer outro método dentro desse controller:/*** Checking if action parameter exists*///$clss -> Ticket();//echo $path['parameters'][1];if( isset( $path['parameters'][1] ) && method_exists( $clss, $path['parameters'][1] ) ){ /** * Loading the action method * ie: ClassName::ActionName() */ $clss -> {$path['parameters'][1]}();}
:clap:Estou implementando no meu sistema, só que com forma diferente.
Uma dúvida fora do assunto, há algum problema ultrapassar as 10 linhas sugerida pelo Netbeans?
Basicamente terá que remover setController e setAction e criar novas implementações.
O problema nesse estilo "controller/action" é ficar limitado a dois parâmetros
Pense quando precisar fazer algo como "/adm/user/edit/history/search/[id]"
Há dois caminhos básicos
1. registrar os nomes dos módulos e controllers
É bem mais simples de gerenciar, porém, terá algumas limitações onde terá um pouco mais de trabalho registrando cada controlador.
Uma parte um pouco mais complicada é quando um registro for um folder ou um file.
2. montar o path conforme os parâmetros.
É trabalhoso e complicado, porém, torna o sistema mais flexível, não exigindo registro dos parâmetros referentes a módulos e controladores.
O ponto fraco é que realmente se torna mais trabalhoso e consome mais performance.
Parâmetro para Idioma
Para ambos os casos, imagine quando necessitar usar um parâmetro especial no início como se fosse um folder.
Um caso bem específico é um site multi-idiomas.
exemplo:
localhost/pt/controller/action
localhost/en/controller/action
localhost/ru/controller/action
e por aí vai.. e note que o SEO modifica para cada idioma.
vc não vai querer uma URL em russo assim:
localhost/ru/noticias/semanal
Nesse ponto, precisa ter suporte a aliases para parâmetros traduzidos para cada idioma.
Parâmetro para paginação
Imagine uma lista com paginação.
O parâmetro que representa a página, precisa estar sempre numa única posição. Aliás, todos os parâmetros de uma URL amigável precisam estar sempre numa única posição na query.
localhost/user/list/[page_number]/other_parameter
exemplo que geraria erro:
localhost/user/list/other_parameter/[page_number]
Numa URL normal, os parâmetros possuem seus respectivos índices, por isso, podem estar em qualquer posição na query
localhost/?module=user/list&other=other_parameter&page=[page_number]
Cannonical
É importante definir qual estilo de URL será canonical.
Se as páginas forem amigáveis por padrão, então todo o acesso por url não amigável deve possuir links para a sua versão "canonicalizada"
Enfim.. o assunto é bem complexo. Esses são os pontos mais básicos.