codeigniter routing wont route correctly - php

I'm new to codeigniter and i'm doing a project now..
I have a home controller which controlls all the pages and it is working fine.
The website contains an article page where it displays all the articles and if some one clicks on the read more it will redirect to article details page
The problem is if i click the read more link (eg : http://example.com/articles_details/2/sample-slug) on the articles page, it automatically redirects to http://example.com/articles_details/2 .... can somebody help me to fix this.
below is the details of my project files
Folder structure
website_folder/
–––– application/
---------- controllers/
---------------- admin/
---------------- home.php
---------- views/
---------------- templates/
--------------------- articles.php
--------------------- article_details.php
---------------- _main_layout.php
–––– assets/
–––– system/
---- .htaccess
–––– index.php
home controller
class Home extends Frontend_Controller
{
function __construct()
{
parent::__construct();
}
public function index()
{
$slug = $this->uri->segment(1) ? $this->uri->segment(1) : 'home';
$this->data['page'] = $slug;
$method = '_'.$slug;
if(method_exists($this,$method))
{
$this->$method();
}
else
{
show_error('Could not load template '.$method);
}
$this->data['subview'] = $slug;
$this->load->view('components/page_head');
$this->load->view($layout,$this->data);
$this->load->view('components/page_tail');
$this->load->view('components/'.$script);
}
private function _home()
{
//fetch datas to be shown in homepage
}
private function _articles()
{
//fetch datas to be shown in article page
}
private function _article_details()
{
//fetch datas to be shown in article detail page
$aid = $this->uri->segment(2);
$query = $this->db->query("select * from articles where id = ".$aid);
$this->data['articledetails'] = $query->row();
count($this->data['v']) || show_404(uri_string());
$rslug = $this->uri->segment(3);
$sslug = $articledetails->slug;
if($rslug != $sslug)
{
redirect('article_details/'.$aid.'/'.$sslug,'location','301');
}
}
}
routes.php
$default_controller = "home";
$controller_exceptions = array('admin');
$route['default_controller'] = $default_controller;
$route["^((?!\b".implode('\b|\b', $controller_exceptions)."\b).*)$"] = $default_controller.'/index/$1';
$route['404_override'] = '';
Htaccess File
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
</IfModule>
articles.php (views file)
<div id="articles">
<?php if($pagination) echo $pagination; ?>
<ul class="articles">
<?php
if(count($articles))
{
foreach($articles as $val)
{
?>
<li>
<h2><?php echo $val->heading; ?></h2>
<p><?php echo truncate(strip_tags($val->details),200); ?></p>
[ Read More ]
</li>
<?php
}
}
else
{
echo '<li><strong>No records found..</strong></li>';
}
?>
</ul>
</div>
articles_details.php (views file)
var_dump($articledetails);

You should have a controller named article_details or in your main controller , define a function as article_details and index(as exist) . but Do Not control everything by a function , while you can have lots of it.
So the right way is that you should have a index function , and fetch rows then pass it to the view to show it.
in your view :
foreach($articles as $i){
echo '[ Read More ]';
}
And in your controller , define a function named : article_details . It will be public and you can handle the article ID and fetch details and pass it to the view.

As CI 2.2.0 , method or functions that starts with an underscore _
"..will not be served via a URL request.."
.
have a look here, and find PRIVATE FUNCTIONS.
The logical question here is why would you want to redirect a VISIBLE controller/method to a HIDDEN one?. you will not be able to access anything since you want in Hidden the first place.
Remove the underscores and change the property to public. If you want int to be accessed correctly.
Or maybe you have a typo or forgot to type something from the tutorial you were following.

Related

URI not working and just adding to URL

I'm trying to get my head around custom URIs. I would like my view_county to have the URL:
http://localhost/chipadvisor2/controller_ca/all_county/1
and my view_all to have the URL:
http://localhost/chipadvisor2/controller_ca/all_chippers
If anyone can help me I would greatly appreciate it. The link works for view_county but when I click on the view_all link it shows:
{
"status": false,
"error": "Unknown method"
}
and if I click into view_county first then the view_all link it just keeps adding controller_ca/all_chippers to the URL and doing nothing. Any ideas why?
model_ca
<?php
class Model_ca extends CI_Model {
function __construct() {
parent::__construct();
}
function get_chipper() {
$query = $this->db->get('chipper_reviews');
return $query->result();
}
function get_county($id) {
$this->db->where('location', 'Westmeath');
$query = $this->db->get('chipper_reviews');
return $query->result();
}
}
?>
controller_ca
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require APPPATH.'/libraries/REST_Controller.php';
class Controller_ca extends REST_Controller {
public function __construct() {
parent::__construct();
$this->load->helper('url');
$this->load->model('model_ca');
}
public function index_get() {
$this->all_chipper_get();
}
public function all_chipper_get() {
$data['chipper'] = $this->model_ca->get_chipper();
$this->load->view('view_all', $data);
}
public function all_county_get() {
$id = $this->uri->rsegment(3);
$data['location'] = $this->model_ca->get_county('location',$id);
$this->load->view('view_county', $data);
}
}
?>
view_county
and
view_all
<html>
<head> </head>
<body>
<div class="container">
View All Chippers
<br/>
View County
<?php echo "<br/><br/>";
foreach ($chipper as $chipperdata) {
echo "<b>Name: </b>".$chipperdata->name." "."<br/>"."<b>County: </b>".$chipperdata->location." "."<br/>"."<b>Description: </b>".$chipperdata->description." "."<br/>"."<br/>";
} ?>
</div>
</body>
</html>
I have added this to the route.php file also but don't know how to put it into effect or how to add the value 'westmeath' to the end. Ideally I would like to pass it as a variable rather than hardcoding it:
$route['default_controller'] = 'Controller_ca';
$route['404_override'] = '';
$route['translate_uri_dashes'] = false;
$route['all_chipper'] = 'controller_ca/all_chippers';
$route['all_county'] = 'controller_ca/all_county/$1';
Try to give controller method name same as url. Change all_chipper_get() to all_chipper(). Same for other method and check.
Regarding the issue:
and if I click into view_county first then the view_all link it just
keeps adding controller_ca/all_chippers to the URL and doing nothing.
Any ideas why?
Please add base_url() at the starting of URL in anchor tag. It will resolve the append issue in URL. Example:
View All Chippers
<br/>
View County
Also, change your routing as:
$route['controller_ca/all_county'] = 'controller_ca/all_county/$1';
$route['controller_ca/all_chipper'] = 'controller_ca/all_chippers';

MVC - Looking for a better way to get from URL to view

The below example shows how I am currently doing things.
index.php includes index_controller.php then index_template.php.
index_controller.php
$uri = explode('/', $_SERVER['REQUEST_URI']);
$action = $uri[1];
$call = $uri[2];
$tmp = explode('?', $call);
$call = $tmp[0];
$call = preg_replace('/-/', ' ', $call);
switch ($action) {
case "about":
$page = "about.inc.php";
$title = "About Us";
$description = "Description of page";
break;
case "category":
try {
//PDO query to make sure category ($call) exists
}
catch (PDOException $e) {
logError($e->getMessage());
}
if (query->rowCount() < 1) {
$page = "404.inc.php";
$title = "404 Error";
}
else {
//Meta information for selected category pulled from DB and put into variables.
$page = "category.inc.php";
break;
default:
$page = "404.inc.php";
$title = "404 Error";
}
The above example shows 2 of around 12 different page options in the switch statement. A simple request (about) and a more complex request (category).
index_template.php has all my head, body, and footer HTML. It sets the meta data for the page, sets up the sites structure, and includes whatever file the $page variable is set to in index_controller.php
Using the above example, if someone goes to mysite.com/category/books index_controller.php will see if the books category exists and if it does category.inc.php will be included.
category.inc.php does another PDO query to get all the items and information required to display a list of items for the selected category. It also includes a template file to structure the display of the returned items.
I am trying to achieve a MVC type structure (without using a framework like Codeigniter or CakePHP), but I don't really have the model end down.
How can I get the user from the URL to the view using classes and/or functions instead of all the includes I am currently using?
If you feel I didn't do a good job explaining the other files mentioned I can provide code examples from those files as well.
Any help, input, or suggestions will be greatly appreciated.
EDIT: Clarified question as per comment below.
With a little trick and with .htaccess you can make this much easier.
I use this method in my self made MVC based application. You can copy paste the whole code or just use a part of it. The main logic is in the Bootstrap class.
.htaccess
Options -Indexes
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
RewriteRule ^$ /news [R]
index.php
require 'brInit.php';
$app = new \brInclude\brClasses\mvc\Bootstrap();
I use brInit to automatically include classes and to include my config file
Bootstrap.php
class Bootstrap {
private $url = array();
/** #var Controller $controller */
private $controller;
function __construct(){
try {
$this->_getUrl();
$this->_loginUser();
if(!$this->_setController($this->url[0]))
throw new Exception('404');
if(!$this->_executeControllersMethod())
throw new Exception('404');
} catch(Exception $e){
$this->_error($e->getMessage());
}
}
private function _error($msg){
$this->url = array('Error', 'error', $msg);
$this->_setController($this->url[0]);
$this->_loginUser();
$this->_executeControllersMethod();
}
private function _getUrl(){
if(isset($_GET['url']))
$this->url = explode('/', rtrim($_GET['url'], '/'));
else
$this->url = array('news');
unset($_GET['url']);
}
private function _setController($name){
$path = 'brInclude/brMVC/controller/';
if(!file_exists($path)) return false;
$url = ucfirst($name) . 'Controller';
$namespace = str_replace('/', '\\', $path);
$file = $path . $url . '.php';
if(!file_exists($file)) return false;
$classWithNamespace = $namespace . $url;
$this->controller = new $classWithNamespace;
$this->controller->view->name = $name;
return true;
}
private function _loginUser(){
$model = new UserModel();
$user = $model->login();
Controller::$user = $user;
}
private function _executeControllersMethod(){
if(isset($this->url[1])){
if(method_exists($this->controller, $this->url[1])){
$count = count($this->url);
if($count > 2)
call_user_func_array(
array($this->controller, $this->url[1]),
array_slice($this->url, 2)
);
else
$this->controller->{$this->url[1]}();
} else {
return false;
}
} else {
$this->controller->index();
}
return true;
}
public static function isLoginRequired(){
return self::$loginRequired;
}
}

How to pass variable that contains path file as parameter to controller in codeigniter

Can someone help me with this issue? I'm new in codeigniter and stack overflow.
So I have this controller that renders my website pages:
class Pages extends CI_Controller {
public function view($page = 'home') {
if ( ! file_exists(APPPATH.'/views/pages/'.$page.'.php')) {
show_404();
} else {
$this->load->view('templates/menu');
$this->load->view('pages/'. $page);
}
}
This method loads views that are placed into the 'pages' directory and it works for all views inside this directory. Now the menu view contains a link that should load 'test' view placed in pages/admin/test.php.
<a href="<?php echo site_url('pages/view/admin/test')?>">
This anchor doesn't work, anyway, because of the URI that is incorrectly passed by the menu view to the controller.
How can I ask my controller that it has to load that view?
Many thanks to everyone that will help me!
You can make double check of locations if contain required file
if ( ! file_exists(APPPATH.'/views/pages/'.$page.'.php') &&
! file_exists(APPPATH.'/views/pages/admin/'.$page.'.php')) {
show_404();
} else {
$view = file_exists(APPPATH.'/views/pages/'.$page.'.php');
$viewadmin = file_exists(APPPATH.'/views/pages/admin/'.$page.'.php');
$this->load->view('templates/menu');
if ($view) {
$this->load->view('pages/'. $page);
} else {
$this->load->view('pages/admin/'. $page);
}
}
But personally, I would separate those in second method that would check for subfolder file exists just to avoid name collition issue.

URL parameter in Codeigniter separated by slashes

In my project, I am passing parameters through URL like,
http://site.org/project/controllername/function?id=1&type=free
What I want is to change the URL to
http://site.org/project/controllername/function/1/free
Actually I am creating the URLs dynamically like
<a href="<?php echo base_url()?>controllername/function?id=<?php echo $defaultrow->id;?>&type=free">
Controller Code :
// Inside VideoController
function search()
{
$userid=$this->tank_auth->get_user_id();
$data['userid']=$userid;
$time=time();
$data['defaultvideoquery']=$this->db->query("select cv.videotitle,cv.video,cv.thumbnail,
cv.added_on,cp.description,cv.id,cv.likes,cv.dislikes,cv.views from channel_programmes as cp INNER JOIN channel_videos as cv
ON cp.programme_source=cv.id and cp.channel_id=0 and $time>=cp.starttime and $time>=cp.endtime and cp.status=1");
$data['videonum']=$data['defaultvideoquery']->num_rows();
$data['page']='video/search';
$this->load->view('layout/template',$data);
}
// Inside ChannelsController
function playchannel()
{
if (!$this->tank_auth->is_logged_in())
{ // not logged in
redirect('auth/login');
}
$data['id']=$userid;
$id=$this->input->get('id');
if($this->input->get('type'))
{
if($this->input->get('type')=="free")
{
$time=time();
$data['currentdate']=$time;
$pgmquery=$this->db->query("select cp.channel_id,cp.title,cp.programme_source,cp.url,cp.description,cv.status,cv.video,cp.starttime,cp.endtime from
channel_videos as cv INNER JOIN channel_programmes as cp ON cv.id=cp.programme_source where cp.status=1 and cv.id=$id");
}
else
{
$query=$this->db->query("select id,title,thumbnail,channel_type,created_on,status,channel_type,description from videochannel
where created_for=$userid and id=$id");
$data['queryresult']=$query->row();
$data['channeldata']=$query->result();
}
$data['pgmnum']=$pgmquery->num_rows();
$data['pgmresult']=$pgmquery->result();
}
$data['page']='channels/playchannel';
$this->load->view('layout/template',$data);
}
View Code:
if(isset($videonum))
{
if($videonum>0)
{
foreach($defaultvideoquery->result() as $defaultrow)
{?>
<a href="<?php echo base_url()?>channels/playchannel?id=<?php echo $defaultrow->id;?>&type=free">
<?php if($defaultrow->thumbnail=="")
{ ?>
<img src="<?php echo base_url();?>images/No_image.png" class="videothumb" alt="Video thumbnail <?php echo $defaultrow->videotitle;?>">
<?php }
else
{ ?>
<img src="<?php echo base_url();?>channel/<?php echo $defaultrow->id;?>/<?php echo $defaultrow->thumbnail;?>" class="videothumb" alt="Video thumbnail <?php echo $defaultrow->videotitle;?>">
<?php } ?>
</a>
}
}
}
Htaccess Code :
RewriteEngine On
RewriteBase /projectname/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule \.htaccess - [F]
RewriteRule (.*)(css\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(css\/smoothness\/images\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(js\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(js\/user\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(js\/user\/timeslots\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(channel_data\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(images\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(sliders\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(secure\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(userdata\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(channel\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(css\/admin\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(css\/screen\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(css\/skins\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(css\/fonts\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(css\/images\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(css\/smoothness\/)(.*)$ $2$3 [QSA,L]
RewriteRule (.*)(fonts\/)(.*)$ $2$3 [QSA,L]
RewriteCond %{request_uri} !^index\.php
RewriteRule ^(.*)$ index.php?/$1 [QSA,L]
Is there any method to do this in Codeigniter without using htaccess. I tried adding
//$route['(:any)'] = 'controllername/function/$1';
$routes['channels/playchannel/(:any)'] = 'channels/playchannel/$1';
in application/config/routes.php file. But it returned 404 (Page Not Found) Error.
Can anyone help me to achieve this. Thanks in advance.
Isn't this already built in?
The segments in the URL, in following with the Model-View-Controller approach, usually represent:
example.com/class/function/ID
The first segment represents the controller class that should be invoked.
The second segment represents the class function, or method, that should be called.
The third, and any additional segments, represent the ID and any variables that will be passed to the controller.
The URI Class and the URL Helper contain functions that make it easy to work with your URI data. In addition, your URLs can be remapped using the URI Routing feature for more flexibility.
source: http://ellislab.com/codeigniter/user-guide/general/urls.html
Your URL should be like: example.com/Controllername/Functionname/ID/OtherID
In your class you get the ID like this:
class Controllername
{
function Functionname($ID = FALSE, $OtherID = FALSE)
{
$ID_from_url = $ID;
$OtherID_from_url = $OtherID;
}
}
To create such an URL like that you can do multiple things.
$this->load->helper('url');
echo site_url("news/local/123"); // http://example.com/index.php/news/local/123
echo base_url("blog/post/123"); // http://example.com/blog/post/123
New code based on your application:
// function
function playchannel($id = false, $condition = false)
{
if (!$this->tank_auth->is_logged_in())
{ // not logged in
redirect('auth/login');
}
$data['id']=$userid;
if($condition)
{
if($condition=="free")
{
$time=time();
$data['currentdate']=$time;
$pgmquery=$this->db->query("select cp.channel_id,cp.title,cp.programme_source,cp.url,cp.description,cv.status,cv.video,cp.starttime,cp.endtime from
channel_videos as cv INNER JOIN channel_programmes as cp ON cv.id=cp.programme_source where cp.status=1 and cv.id=$id");
}
else
{
$query=$this->db->query("select id,title,thumbnail,channel_type,created_on,status,channel_type,description from videochannel
where created_for=$userid and id=$id");
$data['queryresult']=$query->row();
$data['channeldata']=$query->result();
}
$data['pgmnum']=$pgmquery->num_rows();
$data['pgmresult']=$pgmquery->result();
}
$data['page']='channels/playchannel';
$this->load->view('layout/template',$data);
}
//view
if(isset($videonum))
{
if($videonum>0)
{
foreach($defaultvideoquery->result() as $defaultrow)
{?>
<a href="<?php echo base_url()?>channels/playchannel/<?php echo $defaultrow->id;?>/free">
<?php if($defaultrow->thumbnail=="")
{ ?>
<img src="<?php echo base_url();?>images/No_image.png" class="videothumb" alt="Video thumbnail <?php echo $defaultrow->videotitle;?>">
<?php }
else
{ ?>
<img src="<?php echo base_url();?>channel/<?php echo $defaultrow->id;?>/<?php echo $defaultrow->thumbnail;?>" class="videothumb" alt="Video thumbnail <?php echo $defaultrow->videotitle;?>">
<?php } ?>
</a>
}
}
}
This should work.
In CodeIgniter, you can do this through your routes.php.
In your routes.php,
$routes['controller/method/param1/param2'] = 'controller/method/$1/$2';
for example, you want to have a URL something like this:
http://example.com/video/playchannel/13/free
You can rewrite it via your routes.php like this:
$routes['video/playchannel/(:any)/(:any)'] = 'video/playchannel/$1/$2';
And then on your video.php controller,
Class Video {
function __construct() {
}
public function playchannel( $id, $type ) {
// do process
if (!$this->tank_auth->is_logged_in()) {
// not logged in
redirect('auth/login');
}
$data['id'] = $userid;
if( $type == 'free' ) {
// do something here
}
}
}
So the URL should look like this:
http://example.com/video/playchannel/13/free
Don't use $this->input->get('something') when you are not using a query string on your URL.
Hope this helps!
In Codeigniter you can get segments using $this->uri->segment(n); // n=1 for controller, n=2 for method, etc
This provides you to retrieve information from your URI strings
consider this example http://example.com/index.php/controller/action/1stsegment/2ndsegment
it will return
$this->uri->segment(1); // controller
$this->uri->segment(2); // action
$this->uri->segment(3); // 1stsegment
$this->uri->segment(4); // 2ndsegment
For the below link you can get the values using input->post
http://site.org/project/controllername?id=1&type=free
example: to get the id & type
//add this in controller function.
$this->input->post('id');
or for the other link http://site.org/project/controllername/function/1/free
generally for every name from controller seperated with '/' are segments of URL
$this->uri->segment(n);
<a href="<?php echo site_url();?>controllername/function?id=<?php echo $defaultrow->id;?>&type=free">
for more information visit this link

Changing title of the page - determining whats the current page

I'm working on codeigniter and I wonder whats the best way to change title dynamically. Eg. title will change depending if you are on home page, single post page, category pages, etc.
The only solution i can think of is to make separate function and compare current URL ( from address bar ) with structure of the single post page, category page, home page
Something like this:
public function current_title() {
if($this->uri->segment(2) == 'post') {
// will return post title
}
if($this->uri->segment(2) == 'category') {
// will return archive title
}
if(current_url() == base_url()) {
// this is home page
}
If anyone worked with this before, any advice highly appreciated
I would not use the uri for this, but instead the controller and action name and the language class :
public function current_title()
{
$this->lang->load('titles.php', 'en');
return $this->lang->line(
$this->router->fetch_class().'.'.$this->router->fetch_method()
);
}
You will have a key like MyClass.myMethod for your translation. Just add your titles in your titles.php file :
$lang['MyClass.myMethod'] = "The title";
$lang['MyOtherClass.myOtherMethod'] = "The other title";
Read more about translation :
http://ellislab.com/codeigniter/user-guide/libraries/language.html
http://ellislab.com/codeigniter/user-guide/helpers/language_helper.html
//in the controller you should do like this:
class Home extends your_Controller {
public function __construct() {
parent:: __construct();
}
function index()
{
$this->data['pageTitle'] = 'Your page title';
$data['main_content'] = 'home';
$this->load->view('includefolder/viewname', $data);
}
}
This is how I do it:
$PHPFile = basename($_SERVER['PHP_SELF'],'.php');
switch ($PHPFile) {
case 'index': $PageTitle = 'Home'; break;
case 'products': $PageTitle = 'Products'; break;
case 'services': $PageTitle = 'Services'; break;
}
You can use string searches or whatever is needed. I use this method since I have the header of the page as a function in library.
As we have a controller function for each view so you can easily get function name from url
$this -> router -> fetch_module();
so you can work with it.

Categories