Controllers em subdiretórios no CodeIgniter com MY_Router

20 de maio de 2013, em Dicas, por

Por padrão, o CodeIgniter só aceita um subnível de diretórios para o armazenamento dos controllers (como pode ser visto na documentação oficial). Entretanto, pode surgir a necessidade de um projeto que precise de vários subníveis de diretórios. Nestes casos, como proceder?

Rotas

Uma solução que, dependendo do caso, pode funcionar, é trabalhar com rotas. Quer dizer, para cada subdiretório que você precise, você pode adicionar uma rota especialmente para o caso:

$route['admin/manage/user/:any'] = "admin/manage/user/$1";
$route['admin/admin']            = 'admin/home.php';

Mas, apesar de funcionar, esta solução para controllers em multiníveis de diretórios no CI é mais indicada para projetos pequenos (e sem muita pretensão de expansão), já que, para cada novo controller, seria preciso incluir uma nova instrução de roteamento.

Solução automatizada

Se trabalhar com HMVC no CodeIgniter também não resolver o caso, então é possível automatizar a solução de ter controllers em muitos níveis de pastas na estrutura do seu CI através de Router personalizado.

Lembra-se de como é possível estender controller no CI com MY_Controller? Na verdade, o mesmo pode ser feito com o Router, que é o responsável pelo roteamento das requisições no CI (conforme pode ser visto fluxograma de funcionamento do CodeIgniter).

Na prática, quer dizer que é possível criar um arquivo MY_Router.php em /application/core/ com código suficiente para que todas as requisições feitas passarem por ali e, dessa forma, conseguir “ensinar” ao CI e o fazer capaz de lidar com requisições de controller em muitos níveis de diretórios.

MY_Router

Usando a técnica do MY_Router, portanto, é possível alcançar o objetivo de fazer o CodeIgniter trabalhar com controllers em multipastas de maneira automática!

Para tanto, crie o arquivo /application/core/MY_Router.php e, nele, insira o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 
class MY_Router extends CI_Router {
 
    function __construct()
    {
        parent::__construct();
    }
 
    function _validate_request($segments)
    {
        if (count($segments) == 0)
        {
            return $segments;
        }
 
        // O controller requisitado existe no diretório raiz?
        if (file_exists(APPPATH.'controllers/' . $segments[0].'.php'))
        {
            return $segments;
        }
 
        // O controller está num subdiretório?
        if (is_dir(APPPATH . 'controllers/' . $segments[0]))
        {
            // Set the directory and remove it from the segment array
            $this->set_directory($segments[0]);
            $segments = array_slice($segments, 1);
 
            while (count($segments) > 0 && is_dir(APPPATH . 'controllers/' . $this->directory . $segments[0]))
            {
                // Set the directory and remove it from the segment array
                $this->set_directory($this->directory . $segments[0]);
                $segments = array_slice($segments, 1);
            }
 
            if (count($segments) > 0)
            {
                // O controlle requisitado existe em um subdiretório?
                if ( ! file_exists(APPPATH . 'controllers/' . $this->fetch_directory() . $segments[0] . '.php'))
                {
                    if ( ! empty($this->routes['404_override']))
                    {
                        $x = explode('/', $this->routes['404_override']);
 
                        $this->set_directory('');
                        $this->set_class($x[0]);
                        $this->set_method(isset($x[1]) ? $x[1] : 'index');
 
                        return $x;
                    }
                    else
                    {
                        show_404($this->fetch_directory() . $segments[0]);
                    }
                }
            }
            else
            {
                // O método foi especificado na rota?
                if (strpos($this->default_controller, '/') !== FALSE)
                {
                    $x = explode('/', $this->default_controller);
 
                    $this->set_class($x[0]);
                    $this->set_method($x[1]);
                }
                else
                {
                    $this->set_class($this->default_controller);
                    $this->set_method('index');
                }
 
                // O controller padrão existe no subdiretório?
                if ( ! file_exists(APPPATH . 'controllers/' . $this->fetch_directory() . $this->default_controller . '.php'))
                {
                    $this->directory = '';
                    return array();
                }
 
            }
 
            return $segments;
        }
 
 
        // Se o fluxo chegou até aqui, significa que o URI solicitado não se 
        // correlaciona a alguma classe de controller válida. Agora, é preciso 
        // testar se há o roteamento "404_override" para erros personalizados.  
        if ( ! empty($this->routes['404_override']))
        {
            $x = explode('/', $this->routes['404_override']);
 
            $this->set_class($x[0]);
            $this->set_method(isset($x[1]) ? $x[1] : 'index');
 
            return $x;
        }
 
 
        // Nada mais a fazer neste ponto a não ser mostrar um erro 404.
        show_404($segments[0]);
    }
 
    function set_directory($dir)
    {
        // Permite barra, mas não ponto.
        $this->directory = str_replace('.', '', $dir) . '/';
    }
 
}
 
/* End of file MY_Router.php */
/* Location: ./application/core/MY_Router.php */

Obrigado ao autor do Degrees of Zero por compartilhar este código!

E lembre-se de que, caso você já tenha criado o arquivo /application/core/MY_Router.php para alguma necessidade especial em seu projeto, você deve adequar o código para que o seu código e o código mostrado não entrem em conflito.

Com o uso do MY_Router, portanto, você agora pode usar quantos níveis de diretórios quiser para os controller no CodeIgniter de forma automatizada!

3 comentários em "Controllers em subdiretórios no CodeIgniter com MY_Router"

gravatar

jose soares  em 4 de agosto de 2015

PARABENS! Muito boa materia!!!

gravatar

Eduardo Silva  em 5 de abril de 2016

Boa tarde,
ele é compatível com o Codeigniter 3 ?

gravatar

Douglas Fernando  em 16 de dezembro de 2016

Não funciona no Codeigniter 3.1.2

    Comente!