I'm using the template library for CodeIgniter, http://williamsconcepts.com/ci/codeigniter/libraries/template/reference.html, and now I want to implement custom error pages too. I found one method involving a MY_Router extending the default router: http://maestric.com/doc/php/codeigniter_404 but that only treats 404 errors. I want all errors to show a simple user-friendly page, including database errors etc, and I want it to go through a controller, partly so I can use the template library, and partly so I can also implement an email function to send myself information about the error that occurred.
Someone asked about extending the functionality of the above MY_Router method for other errors, like error_db, but got no answer from the author, so I'm turning here to see if anyone knows how to do this, along the lines of the above method or any other simple way of achieving it. Please note that I'm a newbie, so do not assume too much about my knowledge of basic CodeIgniter functionality :-)
I've created an extension for the Exceptions class.
In this extension I've replaced the $this->Exceptions->show_error(); method, witch is used by the show_error() function of CI.
when I call show_error('User is not logged in', 401); this custom method is looking for an error_$status_code file first. In the case of the example above, it will look for an error_401.php file.
When this file does not exists, it wil just load the error_general.php file, like the default $this->Exceptions->show_error(); does.
In your case, you can use the following code to use in your library, controller or whatever should throw an error.
<?php
if(!(isset($UserIsLoggedin))){
$this->load->view('template/header');
show_error('User is not logged in', 401);
$this->load->view('template/footer');
}
?>
Your error_401.php file should than look like this:
<div id="container">
<h1><?php echo 'This is an 401 error'; ?></h1>
<?php echo $message; ?>
</div>
/application/core/MY_Exceptions.php:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Exceptions extends CI_Exceptions
{
function show_error($heading, $message, $template = 'error_general', $status_code = 500)
{
if((!isset($template)) || ($template == 'error_general')){
if(file_exists(APPPATH.'errors/error_'.$status_code.'.php')) {
$template = 'error_'.$status_code;
}
}
if (!isset($status_code)) $status_code = 500;
set_status_header($status_code);
$message = '<p>'.implode('</p><p>', ( ! is_array($message)) ? array($message) : $message).'</p>';
if (ob_get_level() > $this->ob_level + 1)
{
ob_end_flush();
}
ob_start();
include(APPPATH.'errors/'.$template.'.php');
$buffer = ob_get_contents();
ob_end_clean();
return $buffer;
}
}
?>
I do it like this:
I create my own error page, and whenever I should throw a 404 error, I actually load my 404 page.
So say my default controller is site.php, my site.php looks like this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Site extends CI_Controller {
public function index()
{
$this->load->view('welcome_message');
}
public function view($page = "home" , $function = "index")
{
do_something();
if($status == "404")
{
$function = "404";
}
$this->load->view('templates/header', $data);
$this->load->view($page.'/'.$function, $data);
$this->load->view('templates/footer', $data);
}
}
/* End of file welcome.php */
/* Location: ./application/controllers/welcome.php */
So I serve the home/404.php whenever an error occurs. i.e., I don't allow CodeIgniter to call show_404(); therefore the 404 page looks like any other page.
p.s. I assume that you followed the nice tutorial in CodeIgniter's website.
The simplest way to create custom error pages is to edit the files at /application/views/errors/html/error_*.php such as error_404.php (for 404s), error_db.php (for database errors) and error_general.php (for most other errors).
As these pages are within your application directory, you are free to customise them to your needs.
If your normal view template looks something like this:
<?php $this->load->view('includes/header'); ?>
...
...
<?php $this->load->view('includes/footer'); ?>
You can adapt this in your /application/views/errors/html/error_*.php files like so:
<?php
$page_title = $heading;
include VIEWPATH.'includes'.DIRECTORY_SEPARATOR.'header.php';
?>
<div class="well">
<h1><?php echo $heading; ?></h1>
<?php echo $message; ?>
</div>
<?php include VIEWPATH.'includes'.DIRECTORY_SEPARATOR.'footer.php'; ?>
Notice that we're no longer using views, but instead including the view files for the header & footer.
Another thing to note:
In the header view, I'm passing a $data object which includes $data['page_title']. As the error pages don't use views, you have to add any variables that you'd normally pass into the view, hence the presence of $page_title.
config/routes.php
edit
$route['404_override'] = '';
type here your controller for example Error
create a function index and load your view
Related
I'm new to opencart. I want to create a custom theme and some custom controllers and models. I can't find any tutorials relative to this, but I tried to create a view along a controller. When I call that view from home or header view page, like $header (in home file) and $search (in header file), then it shows undefined variable.
My code looks like this. It's in controller (path is catalog\controller\common\test.php).
<?php
class ControllerCommonTest extends Controller{
public function index() {
if(file_exists(DIR_TEMPLATE.this->config->get('config_template').'/template/test/test.tpl')) {
$this->response->setOutput($this->render());
} else {
return $this->load->view('default/template/common/header.tpl');
}
}
}
?>
And my view is in \view\theme\MyTheme\template\common\test.tpl
<?php
echo "Test file";
?>
And in my home file, I call my controller like below...
<?php
echo $header;
echo $test;
echo $footer;
?>
When I run this it shows the below error:
Notice: Undefined variable: test in C:\xampp\htdocs\opencart\catalog\view\theme\MyCustome\template\common\home.tpl on line 4
So, please provide any tutorial links and any examples for developing a custom module in opencart.
Thanks in advance.
To display test module tpl i.e. test.tpl on home page, You have load test controller on home controller. Please add following code in catalog/controller/common/home.php
add this code
$data['test'] = $this->load->controller('common/test');
After
$data['header'] = $this->load->controller('common/header');
I'm having a rather odd problem with flash messenger in ZF2. I'm using it in quite a simple scenario, save a 'registration complete' message after registering and redirect to the login page and display the message however the messages are never returned by the flash messenger.
In controller register action:
$this->flashMessenger()->addMessage('Registration complete');
return $this->redirect()->toRoute('default', array('controller' => 'user', 'action' => 'login'));
In controller login action:
$flashMessenger = $this->flashMessenger();
$mes = $flashMessenger->hasMessages();
$cur = $flashMessenger->hasCurrentMessages();
Both $mes and $cur are false (I tried both just to be sure). Can anyone shed any light on this?
I'm using ZF 2.2.2 and PHP 5.3.14. Session save handler is using the dbtable adapter and I have tried disabling this as well as setting the flashmessenger session manager to the use the same dbtable save handler with no result.
To use the FlashMessenger controller plugin, you need to add the following in your controller:
<?php
class IndexController extends AbstractActionController {
public function indexAction() {
$this->flashMessenger()->addMessage('Your message');
return $this->redirect()->toRoute('admin/default', array('controller'=>'index', 'action'=>'thankyou'));
}
public function thankyouAction() {
return new ViewModel();
}
}
Add the following to the thankyou.phtml view template:
<?php
if ($this->flashMessenger()->hasMessages()) {
echo '<div class="alert alert-info">';
$messages = $this->flashMessenger()->getMessages();
foreach($messages as $message) {
echo $message;
}
echo '</div>';
}
?>
It seems that your code is as it should be, there must be something tricky in the workflow.
In this case, you can debug the old way : try var_dump($_SESSION) to see if it is populated by your flashMessenger.
Use
echo $this->flashMessenger()->renderCurrent(...
instead of
echo $this->flashMessenger()->render(...
I also faced same problem for (login flashmessage after registration) I solved it in the following way
Apply a check on your layout page like
<?php if($this->zfcUserIdentity()) { ?>
<div id="flashMessageDiv" class="hide">
<?php echo isset($flashMessages) && isset($flashMessages['0']) ? $flashMessages['0'] : ''; ?>
</div>
<?php } ?>
That means layout flashMessageDiv is accessible only to the logined user . now on your login view file (login.phtml)
apply the following code
<?php $pathArray = $_SERVER['HTTP_REFERER'];
$pathArray = explode("/",$pathArray);
?>
<?php if ($pathArray[4] === 'register') { ?>
<div id="flashMessageDiv" class="hide">
<?php echo "User details saved successfully"; ?>
</div>
<?php } ?>
In the above code i used HTTP_REFERER which will simply give us the referer url details check if referer url is register then show falshmessage.
Hope it will help you.
The FlashMessenger is now an official view helper in ZF2 and can be easily integrated in every view / layout:
FlashMessenger Helper — Zend Framework 2 2.3.1 documentation - Zend Framework
It works with TwitterBootstrap3 too and there is an alternative configuration for your module.config.php.
I have some experience with php, but I just recently started learning Codeigniter. I used to have a website with a fixed navigation pane and sidebar, but the main section of the site loaded dynamically based on a Get variable. It was basically
include head.php
include navbar.php
include sidebar.php
include the page requested from the get variable (home, about, contact, etc.)
include footer.php
I liked this because the entire site did not have to reload when the user navigated from page to page.
I can't figure out how do this with Codeiginiter. Should I be using a controller for each page or one controller with a function for each page? Do anyone know of a good tutorial that does something similar? All the tutorials I've seen reload the entire site for every page.
Edit: Essentially I want to do this but with Codeigniter
Since it looks like you want relatively static content, but loaded dynamically you can do with one controller and (maybe) one method in the controller.
To do it with one method, do this in the welcome controller:
public page( $page_id ){
// views/header.php
$this->load->view( "header" );
if( $page_id = "about" ){
$this->load->view("about"); // views/about.php
}
else if( $page_id = "contact" ){
$this->load->view("contact"); // views/contact.php
}
// views/footer.php
$this->load->view("footer");
}
This takes a single get variable and figures out what page to load in between the header and footer.
This way www.yoursite.com/page/about will load the about page, www.yoursite.com/page/contact will load the contact page
Now, if you want to get rid of the /page part, you need to do some URL rerouting in application/config/routes.php
Alternatively you could use several methods in one controller:
public about( ){
// views/header.php
$this->load->view( "header" );
$this->load->view( "about" );
// views/footer.php
$this->load->view("footer");
}
public contact( ){
// views/header.php
$this->load->view( "header" );
$this->load->view( "contact" );
// views/footer.php
$this->load->view("footer");
}
Now your URLs look nicer without routing, but you have to load the header/footer for every page.
do you really like to copy/paste many $this->load->view() to any controller function?
It's a spaghetti code. You can try next: for example we have main.php controller as default controller. This main controller contain main function:
public function index()
{
ob_start();
$this->load->model('mainmodel');
$data = $this->mainmodel->_build_blocks(); //return array with needed blocks (header, menu, content, footer) in correct order
foreach ($data->result_array() as $row) {
$this->load->module($row['block_name']);
$this->name = new $row['block_name'];
$this->name->index();
}
ob_end_flush();
}
So, each other controller also have index() function which can dispatch actions depends on url segments, prepare params etc.
Footer controller as example (I use Smarty as template engine):
public function index()
{
$this->mysmarty->assign('year', date("Y"));
$this->mysmarty->view('footer');
return true;
}
Content controller will have:
public function index()
{
$name = $this->uri->segment(1, 'index');
$act = $this->uri->segment(2, 'index');
$this->load->module($name);
$this->name = new $name;
$pageData = $this->name->_show($act);
if ($pageData)
{
$this->mysmarty->assign($name, $pageData);
}
$this->mysmarty->view($name);
}
Thats mean what if you want to show http://site.name/page/contactus , we do next:
1) main.php start cycle by needed blocks
2) firstly we show header.tpl by header controller
3) then we show menu
4) then we call content controller which parse url, found what he should call _show() function in Page controller and pass action='contactus' to it. _show() function can contain some switch/case construction which show templates depends of action name (contactus.tpl in this case)
5) in the end we show footer template
In such case we have flexible structure. All controllers should have index() functions and all controllers who can be called in content should have _show($act) function. Thats all.
In codeIgniter you can do that like this, you can load different views at the same time from your controller. for example:
for example in your navbar view you have a Contacts button in your menu that would look like this:
<a href='contacts'>Contacts</a>
In your controller:
public function contacts()
{
$this->load->view('header');
$this->load->view('navbar');
$this->load->view('sidebar');
$this->load->view('contacts_view');
$this->load->view('footer');
}
So we're assuming here that you have the following views already that is ready to be loaded (header.php, navbar.php, sidebar.php, contacts_view.php, footer.php).
UPDATE:
you don't need to have $_GET[] request, just provide the method name from your controller in the <a> anchor tag
in codeigniter i using template
first make template file in one folder with header.php, navbar.php, etc.
example : template.php
<?php
echo $this->load->view('header'); //load header
echo $this->load->view('navbar');//load navbar
echo $this->load->view('sidebar');//load sidebar
echo $this->load->view($body); //load dynamic content
echo $this->load->view('footer');//load footer
?>
second in controller
function index( ){
$data['body'] = 'home'; // cal your content
$this->load->view('template', $data);
}
I am creating a custom MVC style framework from scratch and am at the point where I need to implement the code to control what happens on POST.
At the moment I have a main index.php which acts as a controller and passes data to other controllers such as:
profilecontroller.class.php
forumcontroller.class.php
At the moment I see two options as to where the POST controllers can go ..
First Approach
Firstly for site wide posts such as login that can occur on any page I would use something like this in the very first index.php to redirect all POST to a specific POST controller that then sends the data to a model to be processed:
if($_POST)
//post controller, works on specific form id's
Alternate Approach
The other option I see would be to build the POST identifier into the model construction sections but I don't think this would be very manageable/wise as they'd always be checked and resulting in more loaded code?
Are there any good/simple examples out there?
I'm creating my mvc to be as light as possible so that's my reason for going from scratch.
In a RESTful setup, you would normally have a controller for an object, say news, and then actions such as add, edit, delete etc.
Within your actions, you should then assert what HTTP method should be used to access the method, if one should be. For example:
<?php
class NewsController extends AbstractController {
public function save() {
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
header('HTTP/1.1 405 Method Not Allowed');
die('Please use POST.');
}
// carry on knowing we're working with a POST request
}
}
Creating a separate controller for POST requests would, as you say, quickly becoming unruly and unmanageable.
If you're looking for a way of handling requests for different HTTP methods within different controller actions, then maybe check out ToroPHP. It's a lightweight (single file) router, where you map a request to a class that's referred to as a handler, and then that handler has methods for different HTTP methods. A quick example:
<?php
require 'lib/torophp/toro.php';
require 'classes/handlers/HomeHandler.php';
$toro = new ToroApplication(array(
array('/', 'HomeHandler')
));
$toro->serve();
And then your HomeHandler would look as follows:
<?php
class HomeHandler {
public function get() {
echo 'Hello, world!';
}
public function post() {
echo 'Try performing a GET request for the home page, buddy.';
}
// and so on...
}
Hope that helps.
This is my default Controller :
<?php
Class Controller_Home{
public $Registery = null;
final public function __construct($Registery){ $this->Registery = $Registery; }
final public function Init($Method=null){
# Quelle action on fait ?
if($Method){
$Split = explode('_', $Method);
$MethodName = 'Action';
foreach($Split as $Splitted){
$MethodName.= '_'.ucfirst($Splitted);
}
if(method_exists($this, $MethodName)){
$this->$MethodName();
} else {
echo '404';
die;
}
} else {
$this->Action_Default();
}
}
final public function Action_Default(){
$this->Registery->Import('Library.Account');
var_dump($this->Registery->Account);
echo 'Default Home';
}
}
As you can see, once you are in Action_Default, you can do whatever you want based on $_GET, $_POST, whatever you want ...
So with this code :
website.com/home/bob/ will use function Action_Bob inside the controller Home (Home::Action_Bob) ... if you see $_POST just put inside Action_Bob this
public function Action_Bob(){
if($_POST){
$this->Action_Bob_Post();
}
// continue
}
Suppose someone hits in url http://mysite.com/comments/view/13
But that absentaction is not present in comments controller.
Then it gets normal error like that =>
Error: The action view is not defined in controller CommentsController
Error: Create CommentsController::view() in file: app/controllers/comments_controller.php.
<?php
class CommentsController extends AppController {
var $name = 'Comments';
function view() {
}
}
?>
Notice: If you want to customize this error message, create app/views/errors/missing_action.ctp
What i'm trying to do is that if someone hits url http://mysite.com/comments/view/13 and if the action is not present then it will redirect to http://mysite.com/.
How can i do this for unknown/absent action?
This trick is actually working pretty well.
You need to create a file app/app_error.php
<?php
class AppError extends ErrorHandler {
public function error404($params){
extract($params);
if(!isset($url)){
$url = $action;
}
if(!isset($message)){
$message ="";
}
if(!isset($base)){
$base = "";
}
$this->controller->redirect(array('controller'=>'pages','action'=>'home'));
//Or the page you want...
}
}
?>
How does it work?
It actually override the error404() function from the ErrorHandler and redirect the user whith $this->controller->redict();
Notice at the bottom of the error message, it says you can customize it by creating app/views/errors/missing_action.ctp. So all you need to do is create that .ctp file and include a redirect in it like this:
<?php
header( 'Location: http://mysite.com' ) ;
?>
It says it right in the error...
create app/views/errors/missing_action.ctp
And that's what you should do...
Try using a header in the missing_action.ctp to redirect to where you want the page to go.
You can either customise app/views/errors/missing_action.ctp or you can turn off debugging in app/config/core.php