How do you create relative links in CodeIgniter? - codeigniter

Example I have the following code in Controller:
class Main extends CI_Controller {
public function index()
{
$this->load->view('main_view');
}
public function create ()
{
$this->load->view('create_view');
}
}
If I want to create a relative link to create, how do I accomplish that? The following link in view doesn't always work. What is apporpiate way to create relative links in CodeIngiter?
Create

Create
or simply:
<?= anchor('/main/create', 'Create'); ?>
Make sure you have loaded the URL Helper.

You don't have to do anything special or load any helpers, just keep in mind that paths will be relative to the url and not the filesystem or controller.
Assuming your installation is in the root directory of your domain, let's say your current URL is http://localhost/class/method/var:
Will work from anywhere
Will go to http://localhost/class/method/var/create
Will go to http://localhost/class/method/create
Relative paths are not your friend in Codeigniter, you are better off sticking with full urls (typically using the helper functions like base_url() and site_url()), or to use the forward slash (relative from root). People have mentioned using the <base> html tag, but I don't personally recommend it. You are going to have some very wacky urls if you use ../../relative paths when you get deeper into the url segments. Example:
If you are here:
http://localhost/controller/method/var1/var2/var3
A link might look like this:
Probably not what you want, but it's an option you may choose. I recommend using one of the other two.

Just to point another alternative, if you dont like the idea of writing a php fragment in each href, and if the other approaches don't satisfy you. You can use put a common <BASE > tag in your html header (for example that points to the root of your application), and then remember that every relative url in your pages will be with respect with that url.

Related

CodeIgniter pagintation - appending the page number to "page" string

What I am trying to achieve is urls outputting via pagination like this:
http://www.mysite.com/users/page5
or
http://www.mysite.com/users/page-5
At present, it will be using the URI segments like this:
http://www.mysite.com/users/page/5
I can modify the routes.php config file to route the path if the first two URLs are used. So, that's not the issue.
What I am having trouble with is, how do I initialize the settings for the pagination, so that the $this->pagination->create_links() will create a pagination with items having links like in the first or the second format?
Let me know if you need more explanation or examples regarding this. I'm not much good in explaining things. :)
Thank you
This functionality already exists in the in-development version of CodeIgniter 3.0. You can view the Pagination class as it sits here.
To use this library, you can either A) use all of CI 3.0 (it's pretty stable), or B) extend (or, more realistically, replace) the Pagination library by creating application/libraries/MY_Pagination.php and filling it with the contents of the link above. (Full disclosure: it's been a while since I tinkered with CI, so I don't know if anything has changed since that may result in errors with any of this answer.)
To use the feature you want, specify your base URL minus the page-X segment, set that you want to use page numbers instead of offset in your URI segment, and then specify a prefix.
$config['base_url'] = site_url('users');
$config['use_page_numbers'] = true;
$config['prefix'] = 'page-';
Make sure to include your other obvious items as well, such as per_page, etc.
To change the functionality of the Pagination library, you can extend the library and override the create_links() function.
Create a file named MY_Pagination.php in application/libraries/
The file should have the following structure, so you can change or add additional functionality to CI's native Pagination library. (It is bad practice to directly change the Pagination library in the system directory.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Pagination extends CI_Pagination {
public function __construct()
{
parent::__construct();
}
}
You'll then need to add the create_links() function to your MY_Pagination class, allowing you to override its default functionality. Below is an explanation of what you could change to achieve your desired output (you may want to add flexibility, by adding a parameter to the function, but this is the simplest change that I could think of.)
function create_links()
{
// You can copy the exact functionality of this function from:
// system/libraries/Pagination.php
// The line you want to change is:
// $this->base_url = rtrim($this->base_url, '/') .'/';
// Changing to this: $this->base_url = rtrim($this->base_url, '/') .'';
// Will create links in this format: ../page5
// Or changing to this: $this->base_url = rtrim($this->base_url, '/') .'-';
// Will create links in this format: ../page-5
}

Cakephp response (sending files) breaks when model functions are added

I have baked a File model and controller with default actions. Now I am trying to add an display function which can be used to show images in controlled manner.
I want to protect images so that display function can check does the user have an permissions to view image (image directory is not in a webroot).
I haven't been able to make it work, but when I started from the scratch I managed to find out that really minimal function did work.
Working function looks like this:
public function display($id) {
$this->response->file(ROOT.DS.'img'.DS.'noimage.jpg');
return $this->response;
}
When I add example:
$test=$this->File->findById($id);
to the starting of the function everything breaks.
--> http://www.example.com/files/display/1
The requested file /var/www/example.com/www/img/image.jpg was not found or not readable
Error: The requested address '/files/display/1' was not found on this server.
I have tried with debug zero, file can be found and is readable, obviously because the function without findById works.
Any ideas?
cakephp 2.4.3
You path is totally wrong.
Did you debug() what ROOT.DS.'img'.DS.'noimage.jpg' actually holds?
I bet all the money of the world that you would probably find the solution yourself if you did
The img folder is most likely in webroot
WWW_ROOT . 'img' . DS . 'noimage.jpg'
Note that paths usually end with a DS so no need to add it again.
So if it really is an image folder in ROOT:
ROOT . 'img' . DS . 'noimage.jpg'
Also note that you can easily check if a path is valid using
file_exists()
If the file has the correct file permissions this should return true.
EDIT:
$this->File->...: File is not a good choice for a model name as it collides with the existing core class in Utility. You need to be a little bit more creative with your model naming scheme.

How to build CodeIgniter URL with hierarchy?

I know this doesn't exactly match the form of www.example.com/class/function/ID/, but what I want to display to the user would make more sense.
This is what I would like to do:
www.example.com/project/id/item/item_id/
So, an example would be:
www.example.com/project/5/item/198237/
And this would be the behavior:
www.example.com/project/ --> This would show a list of projects (current implementation)
www.example.com/project/5/ --> This would show a list of items on project 5 (current implementation)
www.example.com/project/5/item/ --> This wouldn't really mean anything different than the line above. (Is that bad?)
www.example.com/project/5/item/198237/ --> This would show details for item 198237.
So, each item is directly associated with one and only one project.
The only way I can think how to do this is to bloat the "project" controller and parse the various parameters and control ALL views from that "project" controller. I'd prefer not to do this, because the model and view for an "item" are truly separate from the model and view of a "project."
The only other solution (that I am currently implementing and don't prefer) is to have the following:
www.example.com/project/5/
www.example.com/item/198237/
Is there any way to build a hierarchical URL as I showed at the beginning without bloating the "project" controller?
There are 3 options, sorted by how practical they can be:
Use URI Routing. Define a regular expression that will use a specific controller/method combination for each URL.
Something like that could help you, in routes.php:
$route['project/'] = 'project/viewall';
$route['project/(.+)'] = 'project/view/$1';
$route['project/(.+)/item/'] = 'project/view/$1';
$route['project/(.+)/item/(.+)'] = 'item/view/$2';
That is, considering your controllers are item and project respectively. Also note that $n in the value corresponds to the part matched in the n-th parenthesis.
Use the same controller with (or without) redirection. I guess you already considered this.
Use redirection at a lower level, such as ModRewrite on Apache servers. You could come up with a rule similar to the one in routes.php. If you are already using such a method, it wouldn't be a bad idea to use that, but only if you are already using such a thing, and preferably, in the case of Apache, in the server configuration rather than an .htaccess file.
You can control all of these options using routes.php (found in the config folder). You can alternatively catch any of your URI segments using the URI class, as in $this->uri->segment(2). That is if you have the URL helper loaded. That you can load by default in the autoload.php file (also in the config folder).

Routing document-relative static urls in MVC3

I'm integrating a JavaScript library into an ASP.NET MVC3 web app. The library assumes it will be installed next to the page that references it, and so it uses document-relative URLs to find its components.
For example, the default directory layout looks like
container-page.html
jslibrary/
library.js
images/
icon.png
extensions/
extension.js
extension-icon.png
However, I want to reference the library from the view in /Home/edit. I install the library in the default Scripts\jslibrary\ When I reference the library in the view in Views\Home\edit.cshtml, the library's document-relative links like
images/icon.png
end up as requests to
http://localhost/Home/images/icon.png
which results in a File Not Found (404) error. How do I construct a route to look for
{anyControllerName}/images/{anyRemainingPathInfo}
and serve up
http://localhost/Scripts/jslibrary/images/{anyRemainingPathInfo}
?
(full disclosure: I'm still on IIS 6 in Production, and not much chance of going to IIS7 any time soon, so if this is better done at the IIS level, please account for IIS6. Thanks!)
You could create a controller for handling you redirect logic - for example an "Images"controller. Register a global route in your Global.asax file, using the pattern (more on this type of pattern here:
routes.MapRoute(
"Images", // Route name
"{xyz}/{controller}/{path}", // URL with parameters
new {controller = "Images", action = "Index", path= UrlParameter.Optional} // Parameter defaults);
In your controller:
public ActionResult Index(string path)
{
//format path, parse request segments, or do other work needed to Id file to return...
return base.File(path, "image/jpeg"); //once you have the path pointing to the right place...
}
Not sure if this solution will work for you, wish I could come up with something more elegant. Best of Luck!
Short of rewriting the library and having it check for the appropriate directory the only solution I can think of is to include the views, library and supporting files in a directory structure that the library can access. This of course would break MVC's convention over configuration way of finding views, so you would have to write a custom override of the way Razor looks for views, which is not too complex to do, but you might be making life more difficult for yourself down the road depending on your application. Your call which is the lesser of the two evils :) (I'd go for fixing the library)
Make a help function
#functions{
public string AbsoluteUrl(string relativeContentPath)
{
Uri contextUri = HttpContext.Current.Request.Url;
var baseUri = string.Format("{0}://{1}{2}", contextUri.Scheme,
contextUri.Host, contextUri.Port == 80 ? string.Empty : ":" + contextUri.Port);
return string.Format("{0}{1}", baseUri, VirtualPathUtility.ToAbsolute(relativeContentPath));
}
}
Calling
#AbsoluteUrl("~/Images/myImage.jpg") <!-- gives the full path like: http://localhost:54334/Images/myImage.jpg -->
This example are from
https://dejanvasic.wordpress.com/2013/03/26/generating-full-content-url-in-mvc/

Resolve view helper location from within the controller or form

I have a few view helpers that add JavaScript files when they're needed (for instance, so that only forms use CKEditor and such). My directory structure (simplified to include only the relevant files) is this:
application
--forms
--Project
AddIssue.php
--modules
--default
--views
--helpers
JQueryUI.php
Wysiwyg.php
--project
--controllers
ProjectController.php
--views
--scripts
--project
version.phtml
issueadd.phtml
What I want to do:
include CKEditor in the view project/project/issueadd
include jQuery UI in project/project/version
When I'm inside the view script, calling <?php $this->jQueryUI(); ?> works like a charm, even though the helper is in the default module's helpers directory. However, the same is not true for the controller and the form.
In the controller ProjectController.php, versionAction(), I tried to call:
$this->view->jQueryUI();
and the effect was an exception:
Message: Plugin by name 'JQueryUI' was not found in the registry; used paths: Project_View_Helper_: C:/xampp/htdocs/bugraid/application/modules/project/views\helpers/ Zend_View_Helper_: Zend/View/Helper/
Similarly, in the AddIssue.php form, I tried this:
$this->getView()->wysiwyg();
and there was an exception again:
Message: Plugin by name 'Wysiwyg' was not found in the registry; used paths: Project_View_Helper_: C:/xampp/htdocs/bugraid/application/modules/project/views\helpers/ Zend_View_Helper_: Zend/View/Helper/
Obviously, both would work if my view helpers were in the helper directories of the modules/controllers they're being called from, but since they're used across many modules, I'd like to have them in the default module's view helpers directory.
So, my questions are:
How do I access those view helpers from within the controller and the form?
Is there a simpler way to get around this (apart from simply including all javascript files in the layout)? Like creating a plugin or an action helper? (I haven't done these things before, so I really don't know, I'm only starting my adventure with ZF).
Regarding Q1 (based on the comments). You should be able to access the helpers in a usual way. However since it does not work, I think there is a problem with the way you bootstrap your view resource and/or the way how you perform concrete registration of the helpers or how you add helper path to it. I paste an example of adding helper path in Bootsrap.php:
<?php
#file: APPLICATION_PATH/Bootstrapt.php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
public function _initViewHelperPath() {
$this->bootstrap('view');
$view = $this->getResource('view');
$view->addHelperPath(
APPLICATION_PATH . '/modules/default/views/helpers',
'My_View_Helper' // <- this should be your helper class prefix.
);
}
}
?>
This off course should normally work for modular setup of ZF.
Regarding Q2:
You can use headScript view helper to manage what scripts do you load in the head tag of your layout. Using this helper you can do it from your actions.
For example. If in a layout.php you have:
<head>
<?php echo $this->headScript(); ?>
</head>
then in, e.g. indexAction you can append some JS file as follows:
$this->view->headScript()->appendFile($this->view->baseUrl('/js/someJS.js'));
As much as I hate answering my own questions, there's one more solution I came up with, based on what Marcin has suggested in his answer. It can also be done in application.ini:
resources.view[] =
resources.view.helperPath.My_View_Helper = APPLICATION_PATH "/modules/default/views/helpers"
The caveat is that the lines need to appear in this order. Should it be reversed, anything before resources.view[] = will be ignored.
I'd rather get rid of your JQueryUI.php and would use ZendX. Something like that:
In controller:
ZendX_JQuery::enableView ($this->view);
$this->view->jQuery ()->enable ()->setRenderMode (ZendX_JQuery::RENDER_ALL);
In layout:
<?php echo $this->jQuery () ?>

Resources