Your problem is quite common. I've had it when I started working with CodeIgniter as well. What I found out to be the best way to overcome it, was to create a Custom_Router
, which extends the CI_Router
class. Doing that allows you to overwrite the controller class include/require logic and allow the usage of subdirs. This is a working example:
<?php
class Custom_Router extends CI_Router
{
public function __construct()
{
parent::__construct();
}
public function _validate_request($segments)
{
if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
{
return $segments;
}
if (is_dir(APPPATH.'controllers/'.$segments[0]))
{
$this->set_directory($segments[0]);
$segments = array_slice($segments, 1);
while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.DIRECTORY_SEPARATOR.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->directory = $this->directory . $segments[0] .DIRECTORY_SEPARATOR;
$segments = array_slice($segments, 1);
}
if (count($segments) > 0)
{
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
{
show_404($this->fetch_directory().$segments[0]);
}
}
else
{
$this->set_class($this->default_controller);
$this->set_method('index');
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
{
$this->directory = '';
return array();
}
}
return $segments;
}
show_404($segments[0]);
}
}
?>
The code above works fine with as many subdirs as you'd want, although I wouldn't advice using this approach. I usually specifically state the path to my controllers in the route.php
file.
Regarding your second problem - the templates. I never liked messy code and even messier viewers which contain <?php echo $something; for(...){}; foreach(){}... ?>
all over the place. For me, that makes the code really hard to read and specially harder to debug. That's why I've been using the Twig template engine. There are tutorials how to get it working in CodeIgniter (I've used this one). Once you're done with it, in your controller you would simply need to write:
class Login extends Custom_Controller
{
/**
* Index Page for this controller.
*/
public function index() {
$data = array();
$error_message = "Invalid user!";
if($this->session->getUserId() != null){
redirect('/welcome');
}
// other logic....
// depending on how you configure twig, this will search for "login.html.twig"
// in "application/views/". If your file is located somewhere in the subdirs,
// you just write the path:
// admin/login.html.twig => application/views/admin/login.html.twig
$this->twig->display('login.html.twig', $data);
}
}
If Twig is not an option for you, then you will need to create a new class which extends the CI_Loader
class and overwrite the public function view(){}
method.
By the way, if you're creating a web application with a backend, you might find it easier to manage and maintain your code if you separate your applications in different directories. If you choose to go this way, you will need to create application/public
and application/admin
folders preserving the directory structure of a CodeIgniter "application". Here are the steps:
-
Create separate applications
/applications
-- public (a standard application directory structure)
---- cache
---- config
---- controllers
---- models
---- views
---- ...
-- admin (a standard application directory structure)
---- cache
---- config
---- controllers
---- models
---- views
---- ...
Open /index.php
and change $application_folder
to point to applications/public
Create a copy of /index.php
, name it backend.php
(or whatever you want). Open the file and change $application_folder
to point to the applications/admin
folder.
-
Open .htaccess
and add a rule to pass all URI starting with /admin
to backend.php
# Route admin urls
RewriteCond %{REQUEST_URI} admin([/])?(.*)
RewriteRule .* backend.php?$1 [QSA,L]