├── .gitignore ├── .htaccess ├── src ├── Middlewares │ ├── MiddlewareInterface.php │ └── Middleware.php ├── Http │ ├── HttpDataTrait.php │ ├── Response.php │ └── Request.php ├── Container.php ├── Render.php ├── App.php ├── Route.php └── Router.php ├── CONTRIBUTING.md ├── composer.json ├── README.md ├── LICENSE.md └── git-update-fork /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /views 3 | index.php -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteCond %{SCRIPT_FILENAME} !-f 3 | RewriteCond %{SCRIPT_FILENAME} !-d 4 | RewriteRule ^(.*)$ index.php/$1 [QSA,L] -------------------------------------------------------------------------------- /src/Middlewares/MiddlewareInterface.php: -------------------------------------------------------------------------------- 1 | Todos os pull request devem aderir ao padrão PSR-2 de estilo

-------------------------------------------------------------------------------- /src/Http/HttpDataTrait.php: -------------------------------------------------------------------------------- 1 | data[$key])); 11 | } 12 | 13 | public function __set($key, $val) 14 | { 15 | $this->data[$key] = $val; 16 | } 17 | 18 | 19 | public function __get($key) 20 | { 21 | return $this->data[$key]; 22 | } 23 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lukasdev/drouter", 3 | "description": "Um sistema simplista de roteamento, com o intuito de ser utilizado em aplicacoes web pequenas e webservices REST", 4 | "keywords": ["router", "REST", "microframework", "api"], 5 | "homepage": "https://github.com/lukasdev/DRouter", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Lucas Silva", 10 | "email": "dev.lucassilva@gmail.com", 11 | "role": "Developer" 12 | } 13 | ], 14 | "support": { 15 | "email": "dev.lucassilva@gmail.com" 16 | }, 17 | "require": { 18 | "php": ">=7.0.0" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "DRouter\\": "src/" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DRouter 2 | 3 | Um sistema simplista de roteamento, com o intuito de ser utilizado em aplicações 4 | web pequenas e webservices REST. 5 | 6 | ## Instalação 7 | via composer 8 | 9 | ``` bash 10 | $ composer require lukasdev/drouter 11 | ``` 12 | 13 | ## Utilização 14 | 15 |

Iniciando uma instancia e criando uma rota

16 | 17 | ``` php 18 | $app = new DRouter\App(); 19 | 20 | //Rota com request GET: 21 | $app->get('/', function(){ 22 | echo 'Hello World'; 23 | }); 24 | 25 | $app->run(); 26 | ``` 27 |

Documentação completa

28 | drouter.downsmaster.com 29 | 30 | ## Contribuições 31 | 32 | Por favor veja [CONTRIBUTING](CONTRIBUTING.md) para detalhes. 33 | 34 | ## Créditos 35 | 36 | - [Lucas Silva](https://github.com/lukasdev) 37 | - [All Contributors](https://github.com/lukasdev/DRouter/contributors) 38 | 39 | ## Licença 40 | 41 | The MIT License (MIT). 42 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Lucas Silva 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /git-update-fork: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Adiciona um novo remote "upstream" 4 | # Serve exclusivamente para os contribuidores 5 | # Atualizarem seus forks com os commits atuais do repositorio principal 6 | 7 | git remote add upstream https://github.com/lukasdev/DRouter.git 8 | 9 | # Obtenha todos os branches deste novo remote, 10 | # como o upstream/master por exemplo: 11 | 12 | git fetch upstream 13 | 14 | # Certifique-se de que você está no branch master: 15 | 16 | git checkout master 17 | 18 | # Reescreva o seu branch master, de forma que os seus commits 19 | # que não estão no projeto original apareçam, e que os seus 20 | # commits fiquem no topo da lista: 21 | 22 | git rebase upstream/master 23 | 24 | # Se você não quiser reescrever o histórico do seu branch master 25 | # (talvez porque alguém já o tenha clonado) então você deve 26 | # substituir o último comando por um 27 | 28 | git merge upstream/master 29 | 30 | # No entanto, para fazer com que futuros pull requests fiquem o mais 31 | # limpos possível, é uma boa ideia fazer o rebase. 32 | 33 | # Se você fez o rebase do seu branch a partir de upstream/master, talvez 34 | # você precise forçar um push para o seu próprio repositório do Github. 35 | # Você pode fazer isso com: 36 | 37 | git push -f origin master 38 | 39 | # VocÊ vai precisar fazer isso com o -f apenas na primeira vez que você 40 | # faz um rebase. -------------------------------------------------------------------------------- /src/Middlewares/Middleware.php: -------------------------------------------------------------------------------- 1 | response instanceof \DRouter\Http\Response) { 19 | $container->response = self::call($middleware, function($request, $response){ 20 | return $response; 21 | }, $container->request, $container->response); 22 | } else { 23 | throw new \Exception('Todo middleware deve retornar \DRouter\Http\Response'); 24 | break; 25 | } 26 | } catch (\Exception $e) { 27 | echo 'Erro: '.$e->getMessage(); 28 | die; 29 | } 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Container.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright 2016 Lucas Silva 8 | * @link http://www.downsmaster.com 9 | * @version 2.0.0 10 | * 11 | * MIT LICENSE 12 | */ 13 | namespace DRouter; 14 | 15 | class Container 16 | { 17 | /** 18 | * Array de dependencias 19 | * @var $data array 20 | */ 21 | private $data; 22 | 23 | public function __construct(array $params) 24 | { 25 | $this->setData($params); 26 | } 27 | 28 | /** 29 | * Guarda os parametros passados para Container na propriedade $data 30 | * @return void 31 | */ 32 | private function setData(array $params) 33 | { 34 | if (!is_array($params)) { 35 | throw new \InvalidArgumentException('Dados do container deve ser um array'); 36 | } 37 | 38 | $this->data = $params; 39 | } 40 | 41 | /** 42 | * Retorna o Array de dependencias 43 | * @return array 44 | */ 45 | public function getData() 46 | { 47 | return $this->data; 48 | } 49 | 50 | /** 51 | * recebe a chamada $obj->property e cria um novo indice para o mesmo no 52 | * array de dependencias 53 | */ 54 | public function __set($key, $val) 55 | { 56 | $this->data[$key] = $val; 57 | } 58 | 59 | /** 60 | * Intercepta o $obj->property e caso exista no array de dependencias 61 | * retorna seu valor. Caso seja um closure, o retorna executado. 62 | */ 63 | public function __get($key) 64 | { 65 | if ($this->data[$key]) { 66 | if ($this->data[$key] instanceof \Closure) { 67 | $fnc = $this->data[$key]; 68 | return $fnc(); 69 | } else { 70 | return $this->data[$key]; 71 | } 72 | } 73 | } 74 | 75 | /*** 76 | * Cria instancias compartilhadas dentro do container, 77 | * Persistindo o retorno de um dado closure ao longo de sua execução. 78 | */ 79 | public function shared(\Closure $callable) 80 | { 81 | return function () use ($callable) { 82 | static $object; 83 | 84 | if (is_null($object)) { 85 | $object = $callable(); 86 | } 87 | 88 | return $object; 89 | }; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Http/Response.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright 2019 Lucas Silva 8 | * @link http://www.downsmaster.com 9 | * @version 2.5.0 10 | * 11 | * MIT LICENSE 12 | */ 13 | namespace DRouter\Http; 14 | 15 | class Response 16 | { 17 | use HttpDataTrait; 18 | 19 | protected static $messages = [ 20 | //Informational 1xx 21 | 100 => '100 Continue', 22 | 101 => '101 Switching Protocols', 23 | //Successful 2xx 24 | 200 => '200 OK', 25 | 201 => '201 Created', 26 | 202 => '202 Accepted', 27 | 203 => '203 Non-Authoritative Information', 28 | 204 => '204 No Content', 29 | 205 => '205 Reset Content', 30 | 206 => '206 Partial Content', 31 | 226 => '226 IM Used', 32 | //Redirection 3xx 33 | 300 => '300 Multiple Choices', 34 | 301 => '301 Moved Permanently', 35 | 302 => '302 Found', 36 | 303 => '303 See Other', 37 | 304 => '304 Not Modified', 38 | 305 => '305 Use Proxy', 39 | 306 => '306 (Unused)', 40 | 307 => '307 Temporary Redirect', 41 | //Client Error 4xx 42 | 400 => '400 Bad Request', 43 | 401 => '401 Unauthorized', 44 | 402 => '402 Payment Required', 45 | 403 => '403 Forbidden', 46 | 404 => '404 Not Found', 47 | 405 => '405 Method Not Allowed', 48 | 406 => '406 Not Acceptable', 49 | 407 => '407 Proxy Authentication Required', 50 | 408 => '408 Request Timeout', 51 | 409 => '409 Conflict', 52 | 410 => '410 Gone', 53 | 411 => '411 Length Required', 54 | 412 => '412 Precondition Failed', 55 | 413 => '413 Request Entity Too Large', 56 | 414 => '414 Request-URI Too Long', 57 | 415 => '415 Unsupported Media Type', 58 | 416 => '416 Requested Range Not Satisfiable', 59 | 417 => '417 Expectation Failed', 60 | 418 => '418 I\'m a teapot', 61 | 422 => '422 Unprocessable Entity', 62 | 423 => '423 Locked', 63 | 426 => '426 Upgrade Required', 64 | 428 => '428 Precondition Required', 65 | 429 => '429 Too Many Requests', 66 | 431 => '431 Request Header Fields Too Large', 67 | //Server Error 5xx 68 | 500 => '500 Internal Server Error', 69 | 501 => '501 Not Implemented', 70 | 502 => '502 Bad Gateway', 71 | 503 => '503 Service Unavailable', 72 | 504 => '504 Gateway Timeout', 73 | 505 => '505 HTTP Version Not Supported', 74 | 506 => '506 Variant Also Negotiates', 75 | 510 => '510 Not Extended', 76 | 511 => '511 Network Authentication Required' 77 | ]; 78 | 79 | public function __construct(){ 80 | 81 | } 82 | 83 | 84 | public function setStatus($key) { 85 | $status = self::$messages[$key]; 86 | header("HTTP/1.1 ".$status); 87 | } 88 | 89 | 90 | public function setHeaders(array $headers){ 91 | foreach ($headers as $key => $value) { 92 | header("$key:$value"); 93 | } 94 | } 95 | 96 | 97 | public function setJsonResponse(int $status, array $data) 98 | { 99 | $this->setStatus($status); 100 | $this->setHeaders([ 101 | 'Content-Type' => 'application/json' 102 | ]); 103 | 104 | die(json_encode($data)); 105 | } 106 | } -------------------------------------------------------------------------------- /src/Render.php: -------------------------------------------------------------------------------- 1 | '', 25 | 'footer' => '' 26 | ]; 27 | 28 | /** 29 | * Define qual o arquivo de header e qual o arquivo de footer do template 30 | * @param string $header 31 | * @param string $footer 32 | */ 33 | public function setHf($header, $footer){ 34 | $this->hf['header'] = $header; 35 | $this->hf['footer'] = $footer; 36 | } 37 | 38 | /** 39 | * Define variaveis que serão globais para qualquer view 40 | * no momento do extract 41 | * @param array $data 42 | */ 43 | public function setAsGlobal(array $data) 44 | { 45 | $glob = $this->getGlobals(); 46 | if (!empty($glob)) { 47 | $data = array_merge($glob, $data); 48 | } 49 | 50 | $this->globals = $data; 51 | } 52 | 53 | /** 54 | * Retorna o array de globais 55 | * @return array 56 | */ 57 | public function getGlobals() 58 | { 59 | return $this->globals; 60 | } 61 | 62 | /** 63 | * Seta a pasta de viewss 64 | * @param string $viewsFolder 65 | */ 66 | public function setViewsFolder($viewsFolder) 67 | { 68 | $this->viewsFolder = $viewsFolder; 69 | } 70 | 71 | 72 | /** 73 | * Carrega uma view e injeta valores 74 | * @param string $fileName 75 | * @param array $data 76 | */ 77 | public function load($fileName, $data, $hf = true) 78 | { 79 | if (empty($this->viewsFolder)) { 80 | throw new \Exception('A pasta de views não foi definida!'); 81 | } 82 | 83 | $data = array_merge($data, $this->getGlobals()); 84 | 85 | extract($data); 86 | 87 | if (file_exists($this->viewsFolder.$fileName)) { 88 | if ($hf === true && $this->hf['header'] != '') { 89 | include_once $this->viewsFolder.$this->hf['header']; 90 | } 91 | 92 | include_once $this->viewsFolder.$fileName; 93 | 94 | if ($hf === true && $this->hf['footer'] != '') { 95 | include_once $this->viewsFolder.$this->hf['footer']; 96 | } 97 | } 98 | } 99 | 100 | public function renderNotFoundPage() 101 | { 102 | header("HTTP/1.0 404 Not Found"); 103 | echo ' 104 | 105 | 106 | Pagina não encontrada 107 | 124 | 125 | 126 |

Pagina não encontrada

127 |

A pagina que você procura não está aqui, verifique a url!

128 | 129 | '; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Http/Request.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2016 Lucas Silva 9 | * @link http://www.downsmaster.com 10 | * @version 2.0.0 11 | * 12 | * MIT LICENSE 13 | */ 14 | namespace DRouter\Http; 15 | 16 | class Request 17 | { 18 | use HttpDataTrait; 19 | 20 | /** 21 | * Retorna o metodo atual ou GET por padrão 22 | * @return string 23 | */ 24 | public function getMethod() 25 | { 26 | return (isset($_SERVER['REQUEST_METHOD'])) ? $_SERVER['REQUEST_METHOD'] : 'GET'; 27 | } 28 | 29 | /** 30 | * Retorna o content-type do request atual 31 | * @return string 32 | */ 33 | public function getContentType() 34 | { 35 | return (isset($_SERVER['CONTENT_TYPE'])) ? $_SERVER['CONTENT_TYPE'] : null; 36 | } 37 | 38 | /** 39 | * Retorna os dados "crus" da requisição http para ser tratado 40 | * @return string 41 | */ 42 | public function getRawData() { 43 | return file_get_contents('php://input'); 44 | } 45 | 46 | /** 47 | * Retorna a coversão dos dados json do request em array 48 | * @return array 49 | */ 50 | public function getJsonRequest() { 51 | return json_decode($this->getRawData(), true); 52 | } 53 | 54 | /** 55 | * Retorna o conteudo do request parseado para GET, POST, PUT e DELETE 56 | * ou lança uma exceção caso o tipo de content-type seja inválido 57 | * @return array 58 | */ 59 | public function getParsedBody() 60 | { 61 | if (!in_array($this->getMethod(), ['GET', 'POST'])) { 62 | if ($this->getContentType() == 'application/x-www-form-urlencoded') { 63 | $input_contents = $this->getRawData(); 64 | 65 | if (function_exists('mb_parse_str')) { 66 | mb_parse_str($input_contents, $post_vars); 67 | } else { 68 | parse_str($input_contents, $post_vars); 69 | } 70 | if (count($_GET) > 0) { 71 | $post_vars = array_merge($post_vars, $_GET); 72 | } 73 | return $post_vars; 74 | } else { 75 | throw new \UnexpectedValueException('Content-type não aceito'); 76 | } 77 | } elseif ($this->getMethod() == 'POST') { 78 | if (count($_GET) > 0) { 79 | $_POST = array_merge($_POST, $_GET); 80 | } 81 | 82 | return $_POST; 83 | } elseif ($this->getMethod() == 'GET') { 84 | return $_GET; 85 | } 86 | } 87 | 88 | /** 89 | * Retorna o valor de um indice no corpo do request, caso exista! 90 | * @param $key string 91 | */ 92 | public function get($key) 93 | { 94 | $data = $this->getParsedBody(); 95 | if (isset($data[$key])) { 96 | return $data[$key]; 97 | } 98 | } 99 | 100 | /** 101 | * Retorna o RequestUri atual 102 | * @return string 103 | */ 104 | public function getRequestUri() 105 | { 106 | if (isset($_SERVER['ORIG_PATH_INFO'])) { 107 | $pathInfo = $_SERVER['ORIG_PATH_INFO']; 108 | } elseif (isset($_SERVER['PATH_INFO'])) { 109 | $pathInfo = $_SERVER['PATH_INFO']; 110 | } 111 | 112 | //correção para alguns hosts 113 | if (isset($pathInfo)) { 114 | $pathInfo = str_replace('/index.php', '', $pathInfo); 115 | } 116 | 117 | $rota = (!isset($pathInfo)) ? '/' : strip_tags(trim($pathInfo)); 118 | 119 | return $rota; 120 | } 121 | 122 | /** 123 | * Define a url default do site, para o caso de ignorar um prefixo inicial 124 | * exemplo: site.com/v1, o v1 pode ser ignorado ao ser passado como parametro 125 | * esta função nao aceita parametros dinamicos, ex: v1/:number 126 | */ 127 | public function setDefaultPath($pattern = null){ 128 | if ($pattern) { 129 | $pattern = rtrim($pattern, '/'); 130 | $pattern = ltrim($pattern, '/'); 131 | 132 | $uri = ''; 133 | if (isset($_SERVER['ORIG_PATH_INFO'])) { 134 | $uri = $_SERVER['ORIG_PATH_INFO']; 135 | $uriRel = &$_SERVER['ORIG_PATH_INFO']; 136 | } elseif (isset($_SERVER['PATH_INFO'])) { 137 | $uri = $_SERVER['PATH_INFO']; 138 | $uriRel = &$_SERVER['PATH_INFO']; 139 | } 140 | 141 | $exp = array_values(array_filter(explode('/', $uri))); 142 | $expPattern = array_values(array_filter(explode('/', $pattern))); 143 | 144 | foreach ($expPattern as $i => $key) { 145 | if ($exp[$i] != $key) { 146 | $redirect = $this->getRoot().'/'.$pattern; 147 | header('Location: '.$redirect); 148 | die; 149 | } 150 | 151 | unset($exp[$i]); 152 | } 153 | 154 | $newUri = '/'.implode('/', $exp); 155 | #echo $newUri; 156 | $uriRel = $newUri; 157 | } 158 | } 159 | 160 | /** 161 | * Retorna a base da aplicação, exemplo /projetos/aplicacao 162 | * caso a aplicaçao esteja em localhost/projetos/aplicacao 163 | */ 164 | public function getRoot() 165 | { 166 | $base = substr(explode('index.php', $_SERVER['SCRIPT_NAME'])[0], 0, -1); 167 | return $base; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/App.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright 2016 Lucas Silva 8 | * @link http://www.downsmaster.com 9 | * @version 2.0.0 10 | * 11 | * MIT LICENSE 12 | */ 13 | namespace DRouter; 14 | 15 | use DRouter\Http\Request; 16 | use DRouter\Http\Response; 17 | 18 | class App 19 | { 20 | /** 21 | * Objeto \DRouter\Router 22 | * @var $router Router 23 | */ 24 | protected $router; 25 | 26 | /** 27 | * Objeto \DRouter\Request 28 | * @var $request Request 29 | */ 30 | protected $request; 31 | 32 | /** 33 | * Objeto \DRouter\Response 34 | * @var $request Response 35 | */ 36 | protected $response; 37 | 38 | /** 39 | * Objeto DRouter\Container 40 | * @var $container Container 41 | */ 42 | protected $container; 43 | 44 | /** 45 | * Objeto \DRouter\Render 46 | * @var $render Render 47 | */ 48 | public $render; 49 | 50 | /** 51 | * Pagina notFound modificada 52 | * @var $notFoundModified false|callable 53 | */ 54 | protected $notFoundModified = false; 55 | 56 | /** 57 | * Exceptions adicionais da App a serem lançadas! 58 | * @var $addedExceptions array 59 | */ 60 | protected $addedExceptions = array(); 61 | 62 | public function __construct($paramsContainer = array()) 63 | { 64 | $this->request = new Request(); 65 | $this->response = new Response(); 66 | $this->render = new Render(); 67 | $this->router = new Router($this->request); 68 | 69 | $content = [ 70 | 'request' => $this->request, 71 | 'response' => $this->response, 72 | 'render' => $this->render, 73 | 'router' => $this->router 74 | ]; 75 | $params = array_merge($paramsContainer, $content); 76 | $this->container = new Container($params); 77 | } 78 | 79 | /** 80 | * @return \DRouter\Http\Request 81 | */ 82 | public function getRequest() 83 | { 84 | return $this->request; 85 | } 86 | /** 87 | * @return \DRouter\Container 88 | */ 89 | public function getContainer() 90 | { 91 | return $this->container; 92 | } 93 | 94 | /** 95 | * Recebe um callable e retorna sua referencia de acordo 96 | * @return callable 97 | */ 98 | private function validCallable($callable) 99 | { 100 | if (is_callable($callable)) { 101 | if ($callable instanceof \Closure) { 102 | $callable = $callable->bindTo($this->container); 103 | } 104 | 105 | return $callable; 106 | } elseif (is_string($callable) && count(explode(':', $callable)) == 2) { 107 | return $callable; 108 | } 109 | 110 | $this->addedExceptions['\InvalidArgumentException'] = 'Callable inválido'; 111 | return false; 112 | } 113 | 114 | /** 115 | * Emula metodos get, post, put, delete e group do objeto Router 116 | */ 117 | public function __call($method, $args) 118 | { 119 | $methodUpper = strtoupper($method); 120 | $accepted = $this->router->getRequestAccepted(); 121 | 122 | if (in_array($methodUpper, $accepted)) { 123 | if (count($args) == 3) { 124 | $conditions = $args[2]; 125 | } elseif (count($args) == 2) { 126 | $conditions = array(); 127 | } 128 | if ($args[0] == '/[:options]') { 129 | $this->addedExceptions['\InvalidArgumentException'] = 'Route pattern /[:options] inválido'; 130 | } else { 131 | $callable = $this->validCallable($args[1]); 132 | 133 | return $this->router->route($methodUpper, $args[0], $callable, $conditions); 134 | } 135 | } elseif ($method == 'group' && count($args) == 2) { 136 | $callable = $this->validCallable($args[1]); 137 | return $this->router->group($args[0], $callable); 138 | } else { 139 | $this->addedExceptions['\Exception'] = 'O metodo '.$method.' não existe'; 140 | } 141 | } 142 | 143 | /** 144 | * Define uma pagina notfoud 145 | * @param callable $fnc 146 | */ 147 | public function notFound($fnc) 148 | { 149 | if (is_callable($fnc)) { 150 | if ($fnc instanceof \Closure) { 151 | $this->notFoundModified = $fnc; 152 | } else { 153 | $this->addedExceptions['\InvalidArgumentException'] = 'O callable do metodo notFound deve ser um closure!'; 154 | } 155 | } else { 156 | $this->addedExceptions['\InvalidArgumentException'] = 'App::notFound, callable invalido'; 157 | } 158 | } 159 | 160 | /** 161 | * Retorna o path root via request 162 | * @return string 163 | */ 164 | public function root() 165 | { 166 | return $this->request->getRoot(); 167 | } 168 | 169 | /** 170 | * Lança exceções adicionais do objeto App. 171 | */ 172 | private function runAddedExceptions() 173 | { 174 | if (!empty($this->addedExceptions)) { 175 | foreach ($this->addedExceptions as $exception => $message) { 176 | throw new $exception($message); 177 | break; 178 | } 179 | } 180 | } 181 | 182 | 183 | public function add(array $routeNames, array $middewares){ 184 | $this->router->add($routeNames, $middewares); 185 | } 186 | /** 187 | * Da inicio a App. Executando as rotas criadas, renderizando uma pagina 404 188 | * ou exibindo a mensagem de uma exceção que tenha sido lançada 189 | */ 190 | public function run() 191 | { 192 | /*echo '
';
193 |         print_r($this->router->getRoutes());
194 |         die;*/
195 |         try {
196 |             $this->runAddedExceptions();
197 | 
198 |             if ($this->router->dispatch()) {
199 |                 $this->router->execute($this->container);
200 |             } else {
201 |                 if ($this->notFoundModified) {
202 |                     $fnc = $this->notFoundModified->bindTo($this->container);
203 |                     $fnc();
204 |                 } else {
205 |                     $this->render->renderNotFoundPage();
206 |                 }
207 |             }
208 |         } catch (\Exception $e) {
209 |             echo $e->getMessage();
210 |         }
211 |     }
212 | }
213 | 


--------------------------------------------------------------------------------
/src/Route.php:
--------------------------------------------------------------------------------
  1 | 
  8 |  * @copyright   2016 Lucas Silva
  9 |  * @link        http://www.downsmaster.com
 10 |  * @version     2.0.0
 11 |  *
 12 |  * MIT LICENSE
 13 |  */
 14 | namespace DRouter;
 15 | 
 16 | class Route
 17 | {
 18 |     /**
 19 |     * String com o nome da rota em questão para uso futuro na aplicação
 20 |     * @var $name string
 21 |     */
 22 |     protected $name;
 23 |     /**
 24 |      * String com o padrão da rota, exemplo /user/:id
 25 |      * @var $pattern string
 26 |      */
 27 |     protected $pattern;
 28 | 
 29 |     /**
 30 |      * Callable a ser executado na rota. Pode ser [obj, method], 'fnc_name' ou obj
 31 |      * @var $callable callable|string|object
 32 |      */
 33 |     protected $callable;
 34 | 
 35 |     /**
 36 |      * Array com condições para parametros desta rota, exemplo
 37 |      * ['id' => '[\d]{1,8}'] para que o parametro :id seja um digito até 8
 38 |      * caracteres
 39 |      * @var $conditions array
 40 |      */
 41 |     protected $conditions = array();
 42 | 
 43 |     /**
 44 |      * Array associativo com os parametros desta rota, exemplo
 45 |      * ['id' => '5', 'tipo' => 8]
 46 |      * @var $params array
 47 |      */
 48 |     protected $params = array();
 49 | 
 50 |     /**
 51 |     * Array contendo todas as middleawres a serem executadas antes desta
 52 |     * rota
 53 |     * @var $middlewares array
 54 |     */
 55 |     private $middlewares = [];
 56 | 
 57 |     /**
 58 |     * Propriedade contendo caso exista, o prefixo de group dessa rota
 59 |     * @var null | string
 60 |     */
 61 |     private $groupPrefix = null;
 62 | 
 63 |     private $options = [];
 64 | 
 65 |     public function __construct($pattern, $callable, array $conditions)
 66 |     {
 67 |         $this->pattern = $pattern;
 68 |         $this->callable = $callable;
 69 |         $this->conditions = $conditions;
 70 |     }
 71 | 
 72 |     /**
 73 |     * Seta o prefixo de group da rota
 74 |     */
 75 |     public function setGroupPrefix($prefix)
 76 |     {
 77 |         $this->groupPrefix = $prefix;
 78 |     }
 79 | 
 80 |     /**
 81 |     * Retorna o prefixo de group da rota
 82 |     */
 83 |     public function getGroupPrefix()
 84 |     {
 85 |         return $this->groupPrefix;
 86 |     }
 87 | 
 88 |     /**
 89 |     * Adiciona um determinado middleware ao array de middlewares
 90 |     */
 91 |     public function addMiddleware($middleware)
 92 |     {
 93 |         $this->middlewares[] = $middleware;
 94 |     }
 95 | 
 96 |     /**
 97 |     * Adiciona um conjunto de middlewares ao array de middlewares
 98 |     */
 99 |     public function addMiddlewares(array $middlewares)
100 |     {
101 |         $this->middlewares = $middlewares;
102 |     }
103 | 
104 |     /**
105 |     * Retorna o array de middlewares
106 |     */
107 |     public function getMiddlewares()
108 |     {
109 |         return $this->middlewares;
110 |     }
111 | 
112 |     /**
113 |     * Configura o nome da rota em questão
114 |     * @var $name string
115 |     */
116 |     public function setName($name){
117 |         $this->name = $name;
118 |     }
119 | 
120 |     /**
121 |     * Retorna o nome da rota em questão
122 |     */
123 |     public function getName(){
124 |         return $this->name;
125 |     }
126 | 
127 |     /**
128 |      * Retorna o callable da rota atual
129 |      * @return callable
130 |      */
131 |     public function getCallable()
132 |     {
133 |         return $this->callable;
134 |     }
135 |     
136 |     /**
137 |      * Retorna os parametros encontrados desta rota
138 |      * @return array
139 |      */
140 |     public function getParams()
141 |     {
142 |         return $this->params;
143 |     }
144 | 
145 |     /**
146 |      * Retorna os padrão desta rota
147 |      * @return string
148 |      */
149 |     public function getPattern()
150 |     {
151 |         return $this->pattern;
152 |     }
153 | 
154 |     public function getParamNames()
155 |     {
156 |         preg_match_all('@:([\w]+)@', $this->pattern, $paramNames, PREG_PATTERN_ORDER);
157 |         return $paramNames[0];
158 |     }
159 | 
160 | 
161 |     public function getOptions() {
162 |         return $this->options;
163 |     }
164 |     
165 |     /**
166 |      * Verifica se o padrão da rota coincide com o padrão escrito na
167 |      * url da aplicação, e guarda os parametros encontrados sob suas
168 |      * respectivas - caso existentes - restrições
169 |      * @param $resourceUri
170 |      * @return bolean
171 |      */
172 |     public function match($resourceUri)
173 |     {
174 |         $paramNames = $this->getParamNames();
175 | 
176 |         $pattern =  $this->getPattern();
177 | 
178 |         if (preg_match('/\[:options\]/', $pattern)) {
179 |             $exp = explode('[:options]', $pattern);
180 |             $estatico = $exp[0];
181 |             $estaticoDinamico = explode($estatico, $resourceUri);
182 |             if (count($estaticoDinamico) == 2) {
183 |                 $estaticoUrl = explode($estaticoDinamico[1], $resourceUri);
184 |                 $estaticoUrl = $estaticoUrl[0];
185 | 
186 |                 if ($estaticoUrl == $estatico){
187 |                     //estou em uma rota dinamica valida
188 |                     $dinamico = $estaticoDinamico[1];
189 |                     $this->options = explode('/', $dinamico);
190 |                     return true;
191 |                 }
192 |             } else {
193 |                 return false;
194 |             }
195 |         } else {
196 |             $patternAsRegex = preg_replace_callback('@:[\w]+@', [$this, 'convertToRegex'], $this->pattern);
197 |             if (substr($this->pattern, -1) === '/') {
198 |                 $patternAsRegex = $patternAsRegex . '?';
199 |             }
200 |             $patternAsRegex = '@^' . $patternAsRegex . '$@';
201 | 
202 |             if (preg_match($patternAsRegex, $resourceUri, $paramValues)) {
203 |                 array_shift($paramValues);
204 |                 
205 |                 if (count($paramValues) > 0) {
206 |                     foreach ($paramNames as $index => $value) {
207 |                         $this->params[substr($value, 1)] = urldecode($paramValues[$index]);
208 |                     }
209 |                 }
210 |                 return true;
211 |             } else {
212 |                 return false;
213 |             }
214 |         }
215 |     }
216 | 
217 |     /**
218 |      * Converte uma variavel em regex, exemplo :id pode virar
219 |      * ([a-zA-Z0-9_\-\.]+) ou pode virar ([\d]{1,8}) caso seja
220 |      * encontrada tal restrição na $this->conditions
221 |      * @param $matches array
222 |      */
223 |     public function convertToRegex($matches)
224 |     {
225 |         $key = str_replace(':', '', $matches[0]);
226 |         if (array_key_exists($key, $this->conditions)) {
227 |             return '(' . $this->conditions[$key] . ')';
228 |         } else {
229 |             return '([a-zA-Z0-9_\-\.]+)';
230 |         }
231 |     }
232 | }
233 | 


--------------------------------------------------------------------------------
/src/Router.php:
--------------------------------------------------------------------------------
  1 | 
  8 |  * @copyright   2016 Lucas Silva
  9 |  * @link        http://www.downsmaster.com
 10 |  * @version     2.0.0
 11 |  *
 12 |  * MIT LICENSE
 13 |  */
 14 | namespace DRouter;
 15 | 
 16 | use DRouter\Http\Request;
 17 | use DRouter\Route;
 18 | use DRouter\Middlewares\Middleware;
 19 | 
 20 | class Router
 21 | {
 22 |     /**
 23 |      * Array que define os metodos aceitos e guarda suas respectivas rotas
 24 |      * @var $routes array
 25 |      */
 26 |     protected $routes = array(
 27 |         'GET' => array(),
 28 |         'POST' => array(),
 29 |         'PUT' => array(),
 30 |         'DELETE' => array()
 31 |     );
 32 | 
 33 |     /**
 34 |      * Objeto DRouter\Request
 35 |      * @var $request Request
 36 |      */
 37 |     protected $request;
 38 | 
 39 |     /**
 40 |      * Objeto DRouter\Route - Rota a ser despachada
 41 |      * @var $machedRoute Route
 42 |      */
 43 |     protected $matchedRoute;
 44 | 
 45 |     /**
 46 |      * Prefixo do grupo de rota
 47 |      * @var $routePrefix null|string
 48 |      */
 49 |     protected $routePrefix = null;
 50 | 
 51 |     /**
 52 |      * Array de nomenclatura de rotas no formato [METHOD:index] = name
 53 |      * @var $routeNames array
 54 |      */
 55 |     protected $routeNames = array();
 56 | 
 57 |     /**
 58 |      * Ultimo metodo utilizado em uma rota
 59 |      * @var $lastRouteMethod null|string
 60 |      */
 61 |     protected $lastRouteMethod = null;
 62 | 
 63 |     /**
 64 |     * Rotas candidatas a serem despachadas
 65 |     * @var $candidateRoutes array
 66 |     */
 67 |     protected $candidateRoutes = [];
 68 | 
 69 |     /**
 70 |     * Array associativo de rotas a middlewares
 71 |     * @var $middlewares array
 72 |     */
 73 |     protected $middlewares = [];
 74 | 
 75 | 
 76 |     /**
 77 |     * Array contendo group prefixes e seus respectivos middlewares
 78 |     */
 79 |     protected $groupMiddlewares = [];
 80 | 
 81 |     /**
 82 |     * Group atual em utilização na aplicação
 83 |     */
 84 |     protected $currentGroup = null;
 85 | 
 86 |     public function __construct(Request $request)
 87 |     {
 88 |         $this->request = $request;
 89 |     }
 90 | 
 91 |     /**
 92 |      * Valida os paths das rotas, retirando a ultima barra caso exista
 93 |      * para evitar conflitos no dispatch
 94 |      * @param $path string
 95 |      */
 96 |     private function validatePath($path)
 97 |     {
 98 |         $last = strlen($path)-1;
 99 |         if ($path[$last] == '/') {
100 |             $path = substr($path, 0, -1);
101 |         }
102 |         return $path;
103 |     }
104 | 
105 |     /**
106 |      * Define uma rota sob um metodo criando sua representação no objeto Route
107 |      * @param $method string
108 |      * @param $pattern string
109 |      * @param $callable callable
110 |      * @param $conditions null|array
111 |      */
112 |     public function route($method, $pattern, $callable, $conditions)
113 |     {
114 |         //reseta currentGroups para rotas futuras não herdarem seus middlewares
115 |         $this->currentGroup = null;
116 | 
117 |         $method = strtoupper($method);
118 |         $pattern = $this->validatePath($pattern);
119 |         if (!is_null($this->routePrefix)) {
120 |             $pattern = $this->routePrefix.$pattern;
121 |         }
122 | 
123 |         $objRoute = new Route($pattern, $callable, $conditions);
124 |         if (!is_null($this->routePrefix)) {
125 |             $objRoute->setGroupPrefix($this->routePrefix);
126 |         }
127 | 
128 |         $this->routes[$method][] = $objRoute;
129 |         $this->lastRouteMethod = $method;
130 |         return $this;
131 |     }
132 | 
133 | 
134 |     public function getRoutes() {
135 |         return $this->routes;
136 |     }
137 | 
138 |     /**
139 |      * Define o prefixo para agrupamento das rotas
140 |      * @param $prefix string
141 |      * @param $fnc callable Closure
142 |      */
143 |     public function group($prefix, $fnc)
144 |     {
145 |         $this->routePrefix = $prefix;
146 |         if ($fnc instanceof \Closure) {
147 |             $fnc();
148 |         } else {
149 |             throw new \InvalidArgumentException('Callable do metodo group DEVE ser um Closure');
150 |         }
151 |         $this->routePrefix = null;
152 |         $this->groupMiddlewares[$prefix] = [];
153 |         $this->currentGroup = $prefix;
154 | 
155 |         return $this;
156 |     }
157 | 
158 |     /**
159 |      * Define o nome de uma rota recem criada
160 |      * @param $routeName string
161 |      */
162 |     public function setName($routeName)
163 |     {
164 |         $lastMethod = $this->lastRouteMethod;
165 |         $lastIndex = count($this->routes[$lastMethod])-1;
166 |         $indexName = $lastMethod.':'.$lastIndex;
167 |         $this->routeNames[$indexName] = $routeName;
168 | 
169 |         $rota = $this->routes[$lastMethod][$lastIndex];
170 |         $rota->setName($routeName);
171 |         $this->routes[$lastMethod][$lastIndex] = $rota;
172 | 
173 |         return $this;
174 |     }
175 | 
176 |     /**
177 |     * Encontra um objeto de uma rota por seu nome
178 |     */
179 |     public function findRouteByName($routeName) {
180 |         $routePath = array_search($routeName, $this->routeNames);
181 |         list($method, $index) = explode(':', $routePath);
182 | 
183 |         return $this->routes[$method][$index];
184 |     }
185 | 
186 |     /**
187 |     * Encontra o ultimo objeto de rota declarada idependente de seu name
188 |     */
189 |     private function findLastRoute()
190 |     {
191 |         $method = $this->lastRouteMethod;
192 |         $index = count($this->routes[$method])-1;
193 | 
194 |         return $this->routes[$method][$index];
195 |     }
196 | 
197 |     /**
198 |     * Adiciona middlewares sob varias circunstancias (rotas, globais, names e group)
199 |     */
200 |     public function add()
201 |     {
202 |         $args = func_get_args();
203 | 
204 |         if (count($args) == 1) {
205 |             list($middleware) = $args;
206 |             if (!is_null($this->currentGroup)) {
207 |                 //middlewares no group
208 |                 $this->groupMiddlewares[$this->currentGroup][] = $middleware;
209 |             } else {
210 |                 //middlewares na rota
211 |                 $lastRoute = $this->findLastRoute();
212 |                 $lastRoute->addMiddleware($middleware);
213 |             }
214 | 
215 |         } elseif(count($args) > 1) {
216 |             list($routeNames, $middlewares) = $args;
217 |             foreach ($routeNames as $routeName) {
218 |                 if (isset($this->middlewares[$routeName])) {
219 |                     $currentMiddlewares = $this->middlewares[$routeName];
220 |                     $this->middlewares[$routeName] = array_merge($middlewares, $currentMiddlewares);
221 |                 } else {
222 |                     $this->middlewares[$routeName] = $middlewares;
223 |                 }
224 |             }
225 |         }
226 |         return $this;
227 |     }
228 | 
229 |     /**
230 |     * Retorna os middlewares globais para posterior chamada
231 |     * @return array
232 |     */
233 |     public function getMiddlewares()
234 |     {
235 |         return $this->middlewares;
236 |     }
237 |     /**
238 |      * Encontra uma rota pelo seu nome dentro do array de rotas
239 |      * @param $routeName string
240 |      * @return DRouter\Route
241 |      */
242 |     protected function getRoute($routeName)
243 |     {
244 |         $routeIndex = array_search($routeName, $this->routeNames);
245 |         if ($routeIndex == false) {
246 |             throw new \RuntimeException('Rota '.$routeName.' não encontada');
247 |         } else {
248 |             $split = explode(':', $routeIndex);
249 |             $rota = $this->routes[$split[0]][$split[1]];
250 | 
251 |             return $rota;
252 |         }
253 |     }
254 | 
255 |     /**
256 |      * Retorna o callable de uma rota pelo seu nome
257 |      * @param $routeName
258 |      * @return callable
259 |      */
260 |     public function getRouteCallable($routeName)
261 |     {
262 |         $route = $this->getRoute($routeName);
263 |         return $route->getCallable();
264 |     }
265 | 
266 |     /**
267 |      * Retorna o path até uma rota nomeada, trocando seus parametros
268 |      * caso necessário
269 |      * @param $routeName string
270 |      * @param $params array
271 |      * @return string
272 |      */
273 |     public function pathFor($routeName, $params = array())
274 |     {
275 |         if ($rota = $this->getRoute($routeName)) {
276 |             $pattern = $rota->getPattern();
277 |             $qtdParams = count($rota->getParamNames());
278 | 
279 |             $withOptions =  preg_match('/\[:options\]/', $pattern);
280 | 
281 |             if ($qtdParams > 0 && count($params) == 0) {
282 |                 throw new \RuntimeException('A rota '.$routeName.' requer '.$qtdParams.' parametro(s)!');
283 |             }
284 | 
285 |             if ($withOptions && count($params) > 0) {
286 |                 $pattern = str_replace('[:options]', '', $pattern);
287 |                 $pattern .= implode('/', $params);
288 |             } elseif (count($params) > 0) {
289 |                 foreach ($params as $key => $value) {
290 |                     $pattern = str_replace(':'.$key, $value, $pattern);
291 |                 }
292 |             }
293 |             return $this->request->getRoot().$pattern;
294 |         }
295 |     }
296 | 
297 |     /**
298 |      * Efetua um redirecionamento para um path, passando gets opcionais
299 |      * convertidos de array, como parametros
300 |      * @param string $routeName
301 |      * @param array $query
302 |      * @param array $params
303 |      */
304 |     public function redirectTo($routeName, $query = array(), $params = array())
305 |     {
306 |         $path = $this->pathFor($routeName, $params);
307 | 
308 |         if (!is_array($query)) {
309 |             throw new \UnexpectedValueException('Router::redirectTo A query deve ser um array!');
310 |         }
311 | 
312 |         if (count($query) > 0) {
313 |             $path = $path.'?'.http_build_query($query);
314 |         }
315 |         $path = ($path == '') ? '/' :  $path;
316 |         header("Location: ".$path);
317 |         die;
318 |     }
319 | 
320 |     /**
321 |      * Retorna array com tipos de requests aceitos pelo roteamento
322 |      * @return array
323 |      */
324 |     public function getRequestAccepted()
325 |     {
326 |         return array_keys($this->routes);
327 |     }
328 | 
329 |     /**
330 |      * Pelo request method atual, navega pelas rotas definidas
331 |      * E encontra a rota que coincidir com o padrão do RequestUri atual
332 |      * Guardando-a no array de rotas candidatas
333 |      * @return bolean
334 |      */
335 |     public function dispatch()
336 |     {
337 |         $requestUri = $this->validatePath($this->request->getRequestUri());
338 | 
339 |         foreach ($this->routes[$this->request->getMethod()] as $rota) {
340 |             if ($rota->match($requestUri)) {
341 |                 $this->candidateRoutes[] = $rota;
342 |             }
343 |         }
344 | 
345 |         if (count($this->candidateRoutes) > 0) {
346 |             $this->dispatchCandidateRoutes($requestUri);
347 |             
348 |             return true;
349 |         }
350 |         return false;
351 |     }
352 | 
353 |     /**
354 |     * Retorno o que não for variavel de uma pattern, exemplo: /categoria/:slug
355 |     * Nestecaso :slug é umavariavel, e eu retornarei "categoria"
356 |     * @param $pattern string
357 |     */
358 |     public function getNonVariables($pattern) {
359 |         $exp = explode('/',$pattern);
360 |         $retorno = [];
361 |         foreach($exp as $i => $v) {
362 |             if(!preg_match('/^[\:]/i', $v)) {
363 |                 $retorno[$i] = $v;
364 |             }
365 |         }
366 | 
367 |         return $retorno;
368 |     }
369 | 
370 |     /**
371 |     * Determina qual rota deve ser despachada, com base em sua similaridade com
372 |     * a request URI,para evitar conflitos entre rotas parecidas.
373 |     * @param $requestUri string
374 |     */
375 |     public function dispatchCandidateRoutes($requestUri) {
376 |         $expUri = explode('/',$requestUri);
377 |         $similaridades = [];
378 | 
379 |         if (count($this->candidateRoutes) > 1) {
380 |             foreach ($this->candidateRoutes as $n => $rota) {
381 |                 $padrao = $rota->getPattern();
382 |                 if (preg_match('/\[:options\]/', $padrao)) {
383 |                     unset($this->candidateRoutes[$n]);
384 |                 }
385 |             }
386 |         }
387 | 
388 |         foreach ($this->candidateRoutes as $n => $rota) {
389 |             $padrao = $rota->getPattern();
390 |             if (preg_match('/\[:options\]/', $padrao)) {
391 |                 $this->matchedRoute = $rota;
392 |                 $this->candidateRoutes = [];
393 |                 return;
394 |             }
395 | 
396 |             $naoVariaveis = $this->getNonVariables($padrao);
397 | 
398 |             foreach ($naoVariaveis as $i => $valor) {
399 |                 if(!isset($similaridades[$n]))
400 |                     $similaridades[$n] = 0;
401 | 
402 |                 if (isset($expUri[$i]) && $expUri[$i] == $valor) {
403 |                     $similaridades[$n] += 1;
404 |                 }
405 |             }
406 |         }
407 | 
408 |         $bigger = max(array_values($similaridades));
409 |         $mostSimilar = array_search($bigger, $similaridades);
410 |         $this->matchedRoute = $this->candidateRoutes[$mostSimilar];
411 |         $this->candidateRoutes = [];
412 |     }
413 | 
414 |     /**
415 |      * Retorna a rota que coincidiu com a RequestUri atual
416 |      * @return DRouter\Route
417 |      */
418 |     public function getMatchedRoute()
419 |     {
420 |         return $this->matchedRoute;
421 |     }
422 | 
423 |     /**
424 |     * Agrupa um array de middlewares com outro array de middlewares
425 |     * UTilizado para a junção de middlewares globais com middlewares de rota
426 |     * @param array $middlewares1
427 |     * @param array $middlewares2
428 |     * @return array
429 |     */
430 |     private function joinMiddlewares(array $middlewares1, array $middlewares2)
431 |     {
432 |         return array_merge($middlewares1, $middlewares2);
433 |     }
434 | 
435 |     
436 |     /**
437 |      * Executa callable da rota que coincidiu
438 |      * passando como ultimo prametro o objeto container, caso necessário
439 |      * @param $container DRouter\Container
440 |      */
441 |     public function execute(\Drouter\Container $container)
442 |     {
443 |         $rota = $this->getMatchedRoute();
444 | 
445 |         $callable = $rota->getCallable();
446 |         $params = $rota->getParams();
447 | 
448 |         $middlewares = $this->getMiddlewares();
449 |         $routeName = $rota->getName();
450 |         $groupPrefix = $rota->getGroupPrefix();
451 | 
452 |         //Middlewares de group
453 |         if (!is_null($groupPrefix) && isset($this->groupMiddlewares[$groupPrefix])) {
454 |             $middlewares1 = $this->groupMiddlewares[$groupPrefix];
455 |             $routeMiddlewares = $rota->getMiddlewares();
456 |             $rota->addMiddlewares($this->joinMiddlewares($middlewares1, $routeMiddlewares));
457 |         }
458 | 
459 |         //Middlewares de routeNames armazenadas em memoria para adição posterior
460 |         if (isset($middlewares[$routeName])) {
461 |             $middlewares1 = $middlewares[$routeName];
462 |             $routeMiddlewares = $rota->getMiddlewares();
463 |             $rota->addMiddlewares($this->joinMiddlewares($middlewares1, $routeMiddlewares));
464 |             unset($this->middlewares[$routeName]);
465 |         }
466 | 
467 |         //rotas globais acima das indicadas com name
468 |         if (isset($middlewares['*'])) {
469 |             $middlewares1 = $middlewares['*'];
470 |             $routeMiddlewares = $rota->getMiddlewares();
471 |             $rota->addMiddlewares($this->joinMiddlewares($middlewares1, $routeMiddlewares));
472 |         }
473 | 
474 |         if (count($rota->getMiddlewares())) {
475 |             Middleware::executeMiddlewares($rota->getMiddlewares(), $container);
476 |         }
477 | 
478 |         if (is_string($callable) && preg_match('/^[a-zA-Z\d\\\\]+[\:][\w\d]+$/', $callable)) {
479 |             $exp = explode(':', $callable);
480 | 
481 |             $obj = filter_var($exp[0], FILTER_UNSAFE_RAW);
482 |             $obj = new $obj($container);
483 |             $method = filter_var($exp[1], FILTER_UNSAFE_RAW);
484 | 
485 |             $callable = [$obj, $method];
486 |         }
487 |             
488 | 
489 |         if (!empty($params)) {
490 |             $params = array_values($params);
491 |         }
492 | 
493 |         $container->options = $rota->getOptions();
494 | 
495 |         if (is_object($callable) || (is_string($callable) && is_callable($callable))) {
496 |             $params[] = $container;
497 |         }
498 | 
499 |         call_user_func_array($callable, $params);
500 |     }
501 | }
502 | 


--------------------------------------------------------------------------------