Custom, database-driven 404 page -- can this be improved? |
[eluser]arlodesign[/eluser]
Using the code from this forum post, I was able to pull off something I really wanted from my CodeIgniter application: if the first segment of the URI doesn't have a matching controller, send the request to a page controller and check for content in the page database. I did it by extending the Router.php library, as described in that post, and changing _validate_requests() as so: Code: show_404($segments[0]); became Code: return array('page', 'index', $segments[0]); Here's my page controller: Code: class Page extends Controller { Here's where it gets interesting and I turn to you: I also wanted the content of my 404 page stored in the same pages database table so it could be edited by a user in an admin panel. So I created MY_Exceptions.php: Code: class MY_Exceptions extends CI_Exceptions { My question to the always brilliant CodeIgniter community: My solution to this 404 thing feels like a total hack. I had to manually invoke the output class to get the views to appear and, worst of all, I had to reuse an entire block of code which I would have to change in two places should I need to make adjustments. Any ideas on how I could improve on this idea? Can I actually call the page controller from the library item, or is that a terrible idea? UPDATE: It should also be noted that, while I'm not a total n00b, my programming skills are somewhere between novice and intermediate. I apologize now if I follow up your kind answer with a bunch of seemingly stupid questions. Thanks. ANOTHER UPDATE: Fixed link to forum post in first paragraph.
[eluser]wiredesignz[/eluser]
Actually your code is ok. Extending the CI core is always a hack in most cases, but so long as it works for you and it doesn't interfere with other CI libraries it's all good.
[eluser]Colin Williams[/eluser]
You can't just serve up the content from the Page controller with a 404 header? I only briefly checked. Instead of: Code: if (!$data['page']) show_404($this->uri->uri_string()); do: Code: if (!$data['page']) You'll probably have to do more, for sure, but no reason to call show_404
[eluser]nirbhab[/eluser]
Guys, As i was developing my website, i thought of something like this, but only difference or mistake i did was that i hacked or modified the core CI classes. http://www.nirbhab.com/controller-404error.html Please review once, did i performed the task without security issue, or whatever....is it fine on my website. thanx in advance!
[eluser]arlodesign[/eluser]
[quote author="Colin Williams" date="1216067066"] Code: if (!$data['page']) You'll probably have to do more, for sure, but no reason to call show_404[/quote] Thanks so much for the response. I tried that first, and it worked great for pages that didn't exist. Where I run into trouble would be if someone tries to request a function of another controller. For example, I have a portfolio controller with two functions: the index and item. If someone requests the URI /portfolio/something-else/ or requests /portfolio/item/item-that-does-not-exist, then I would have to redirect to /page/index/404, which would then change the URL in the browser. Or, I'd have to copy that page controller code into every new controller. Instead, I chose to copy it to my own show_404 function so I only had to copy it once. But my issue is that I shouldn't have to copy that code at all. Write once and reuse all over the place, right? So here's a thought: Could I make the page controller a front controller and then extend all of my other controllers from it? Something like: Code: class Portfolio extends Page Then maybe it would be a matter of: Code: if (!data['portfolio_item']) Could this work? I hunted through the forums and found this thread, but I can't figure out how to then actually use the function from the Page controller in the Portfolio controller.
[eluser]Colin Williams[/eluser]
Quote:but I can’t figure out how to then actually use the function from the Page controller in the Portfolio controller. Code: $this->method_to_call()
[eluser]arlodesign[/eluser]
[quote author="wiredesignz" date="1216064565"]Actually your code is ok. Extending the CI core is always a hack in most cases, but so long as it works for you and it doesn't interfere with other CI libraries it's all good.[/quote] Thanks for assuaging my guilt. I still know it can be done better, but at least I know I haven't done anything asinine.
[eluser]Colin Williams[/eluser]
Quote:For example, I have a portfolio controller with two functions: the index and item. If someone requests the URI /portfolio/something-else/ or requests /portfolio/item/item-that-does-not-exist, then I would have to redirect to /page/index/404, which would then change the URL in the browser. Or, I’d have to copy that page controller code into every new controller Hrm.. I'd make the 404 stuff a library, then. Even though it performs something very similar to $page->index(), your other controllers are still handling the request and serving the 404, just via your library.
[eluser]arlodesign[/eluser]
Hey, Colin. I took your advice and created a library: Code: class MYPage { So now my Page controller simply contains: Code: function index($link) and my show_404() function is now: Code: function show_404($page = '') And there are other controllers where I'll want to use the load_page() function, so this solution makes perfect sense. Thanks so much for the tip. Perhaps this thread will help others, and I'm still open to suggestions if there is a still sleeker way to do this. |
Welcome Guest, Not a member yet? Register Sign In |