Welcome Guest, Not a member yet? Register   Sign In
how do I know which link has been clicked on web page? - CI newbie Q
#1

[eluser]Brian Dickson[/eluser]
As I'm learning CI / MVC OOP, I thought i'd learn how to replace my old procedural way of working at a simple level, before moving on to building applications proper.

If I have a simple web page with say 5 links in a list for navigation, from what I've read in the CI documentation I would have a method for every link, which in a real life situation is probably unrealistic, and I'm sure nobody does it that way.

so if I have this example menu on a page, what do I put in my controller and how do I know which link has been clicked?
Code:
<ul>
<li>link 1</li>
<li>link 2</li>
<li>link 3</li>
<li>link 4</li>
<li>link 4</li>
</ul>

I presumably wouldn't want to have a URI like: http://www.mysite/pageid=36 - for security reasons?

Apologies if this is too noobie, I'm just trying to find my feet, and maybe the answer is soo obvious I can't see it right under my nose.
#2

[eluser]WanWizard[/eluser]
The basic structure of a CI URL is:

http://www.yourwebsite/controllername/me...r2/value2/ ...

So the first two segments determine the controller to load, and the method within that controller to call.

You don't have to make a new combination for every function, if it's possisble (from a functional or design point of view) to group things in a single method, why not? You can easy convert your example to:
Code:
<ul>
<li>http://www.example.com/controllername/methodname/link/1</li>
<li>http://www.example.com/controllername/methodname/link/2</li>
<li>http://www.example.com/controllername/methodname/link/3</li>
<li>http://www.example.com/controllername/methodname/link/4</li>
<li>http://www.example.com/controllername/methodname/link/4</li>
</ul>
In which case the all call the same method. In the method, use $this->uri->uri_to_assoc() to convert the URI parameters to an array, which in this case will be
Code:
array( 'link' => '1')
You can use this info to process the request.

In a more complex case, you can use URI routing (see the manual) to consolidate URI requests (view this as a sort of rewriting of the URI), so you can use p.e. one single controller that handles all static HTML pages.

For example, if you have a controller called 'static_html', with a method 'render' that loads the view(s) and displays it, you can create a route that converts
Code:
http://www.example.com/about/company
to
Code:
http://www.example.com/static_html/render/about/company
and use the parameters 'about' and 'company' in the render() method to determine which views to load.
#3

[eluser]Brian Dickson[/eluser]
Thanks WanWizard, it seems like using a framework can sometimes make straight forward things more difficult. Shame there isn't a way to simulate a simple link to a page, as a browser would interpret it.

My thinking (out aloud) and understanding thus far:
So because CI is a framework and all calls are routed through index.php, from which the CI router decides what to do with it, and because there isn't a real file called, eg: "./about-us.html", then I have to build by own internal link references and structure, which I assume will be between a controller and a database?
#4

[eluser]WanWizard[/eluser]
I'm not sure I understand what you mean.

In the standard setup, http://www.example.com/controllername/methodname has a one-to-one connection to a controller, and a method in that controller. Is this not that different from the static html days or the procedural days, where 'controllername' was an individual php file that you would load directly.

You lose the one-to-one if you start routing multiple URI's to a single controller, but you gain simplicity in your application, as you don't have to duplicate code.

CI has a very flat structure, it only supports (without routing) http://www.example.com/controllername/methodname and http://www.example.com/directory/control...methodname (where 'directory' is a folder in your application controllers folder).

The controller is a sort of supervisor. It gets the request (i.e. a task to perform), delegates activities to models to fetch the data needed to complete the task, and passes the data to the view which hands the result (the finished task) back to the requestor. It is the model that has to do whatever needed to retrieve the data requested, either from a database or from another source.
#5

[eluser]Brian Dickson[/eluser]
Ahhh, so if I were to do a like-for-like, I would create a controller class for every 'page' I wanted to represent. Although you suggest this is not good practice and using the URI class/helper and one controller would be a neater option.... have I got that right now?
#6

[eluser]WanWizard[/eluser]
What people usually do, is to create directories in the controllers directory for major functions, for example 'admin'.

Then you could have a members controller in that directory, where the index method would list the defined users, the edit method allows you to edit a user record, the delete method to delete a user, and so on.

From a URL point of view, that would be
Code:
http://www.example.com/admin/members (no method defined, so it would call the index method)
http://www.example.com/admin/members/index (same as above)
http://www.example.com/admin/members/edit/1 (would edit user with ID 1)
http://www.example.com/admin/members/delete/1 (would delete user with ID 1)
Note that from a security point of view, it might not be wise to pass the ID in the URL for the edit or delete methods. It would be better to use a form POST to pass the ID to the controller, and protect the form with a nonce.


One advantage of grouping methods that functionally belong together in a single controller is that they can share private functions and class variables.

There is however nothing against giving every function its own controller. That would give you a lot more controllers to deal with, but each of them will not contain a lot of code, so from a maintenance point of view that might be handy.

There isn't really a set way of working with CI, it all boils down to what you feel the best way is.
#7

[eluser]charlie spider[/eluser]
Hi Brian,

you might like the solution I use.

I snaged this little bit of code from an Elliot Haughin tutorial ( www.haughin.com/ ) that allows me to route all requests for webpages that don't have a corresponding controller/method to one catch-all controller.

This allows me to have dedicated controllers for specific things and then one for all of the regular generic pages of a website. In fact I only use specific controllers for the admin section of my sites. All of the public pages go to a controller called "pages". Once I hit that controller I can pull the relevent page info from the database, load whatever resources, content, templates, etc, that are required, and serve the page.

Here's the routing code:

Code:
$exclude = array ( '.', '..', 'index.html', 'pages.php' );

$handle = opendir(APPPATH . 'controllers/');

while (false !== ($file = readdir($handle)))
{
    if ( ! in_array($file, $exclude))
    {
        if ( ! is_dir ( APPPATH.'controllers/' . $file ) )
        {
            $file = substr($file, 0, strlen($file)-4);
        }
        $installed_modules[] = $file;
    }
}

closedir($handle);

foreach ( $installed_modules as $module)
{
    // ie: index.php/news/
    $route[$module] = $module;
    
    // ie: index.php/news/view/hello/
    $route[$module . "/(.*)"] = $module . "/$1";
}

$route["(.*)"] = "pages/index/$1";

So this code builds an array of all of the "other" controllers in your application/controllers directory so that requests for them can be met, and then routes everything else to "pages" via a wildcard.


Since all of my public pages go to the one controller, and I don't use any other methods for that controller, I can simply grab the last segment of the uri to find out what page is being requested, like this:

Code:
$current_page = $this->uri->segment_array( $this->uri->total_segments() );

whether a page is a subpage (or a subpage of a subpage) is set in the database, and I just build the full url for navigation links, but basically I only ever care what the last segment of the uri is.

This allows me to dynamically add as many pages as I want anywhere in the sitemap tree without having to create a new controller for each page.

On the admin side of things I basically do what WanWizard talked about. Specific controllers with multiple methods logically grouped together based on functionality.

So I use the typical CI one-to-one webpage-to-controller/method system for my admin side of things but wildcard routing for the public pages.

Hope that helps you out.
#8

[eluser]Brian Dickson[/eluser]
Thanks Charlie, I think that's the kind of thing I'm looking for. I'll try and work my way through it and understand it. For me at this stage, it's a lot to take in, but not outside the scope of my ability.

I've been teetering on going back to procedural web development, cos it's what I know, but that is the 'woosies' way out. I'll persist till I understand, why I went from easier to complicated - LOL.




Theme © iAndrew 2016 - Forum software by © MyBB