CodeIgniter: some doubts about HMVC and Views - php

I've just discovered HMVC Modular Extension for CodeIgniter https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc/wiki/Home and it seems perfect for my needs but I have some question.
Let's say I have two controllers:
Site which is the main controller and is used to show site's pages and may call methods of Users controller for example to show a form
User controller is used to authenticate users, to show login/sign up forms...
Now I have these questions:
If the user access the User controller directly (mysite.com/user/method) I want to show a full page while if i load a method of User from within the Site controller I want to show only a form (for example), is this possible?
What happens to view of a module loaded from another module: is the view shown automatically or i need to show it manually and how does the view behave?

If you method is being called via Modules::run()
There is a third optional parameter lets you change the behavior of
the function so that it returns data as a string rather than sending
it to your browser.
Eg:
//put underscore in front to prevent uri access to this method.
public function _module1()
{
$this->load->view('partial_view', array('some data'=>'some data'), TRUE)
}
call it inside your SITE view easily
Modules::run('User/_module1')
// should show whatever is in partial_view ie: a form
//an alternative is to pass in any params if the method requires them
Modules::run('User/_module1', $param)

Related

CodeIgniter - Select controller based on database

I'm building a simple CMS using Code Igniter version 3.0.0
The site's URLs are all customizable by the user and so do not follow the standard MVC structure of /controller/method/parameter-1/parameter-2/. Instead, all frontend traffic gets directed to PublicController's index method. This method searches the database for the current URL to return the correct page, and also the page type. Each page type corresponds to a controller.
How do I call that controller from the PublicController without doing a redirect?
I can't use the redirect() method because that would change the URL in the browser window and cause an un-need additional page request.
if you look at the url /about/who-we-are/
about is the controller and who-we-are is a function in the controller that loads one or more views.
The same for /locations/stores/
the functions stores in the controller locations.
read the documentation and it will be easy to understand.
http://www.codeigniter.com/user_guide/overview/mvc.html
I am pretty sure that configuring a route is your answer:
// routes.php
$route['(:any)'] = "PublicController/index/$1";
// PublicController.php
public function index()
{
var_dump(func_get_args());
}

Removing controller name and function namein URL in Codeigniter CMS

I am building a cms in codeigniter and i want to remove controller name and function name form the url and just print the alias.
I will be having two controllers one for static pages and other for blog posts with categories.
Please help, Suggestions reagrding modification of two controllers are also welcome.
You will need to override the default 404 controller in application/config/routes.php.
$route['404_override'] = 'content';
Any request that can't be mapped to a controller will be passed to the application/controllers/content.php controller
Your Content controller, or whatever you decide to call it, will parse the uri [$this->uri->segment(1)] and check for a matching reference in your CMS database.
If there is no match in the database, then you can look for a static view in the views folder and load it.
if(is_file(FCPATH.'views/'.$this->uri->segment(1).'.php')) {
$this->load->view($controller,$this->data);
}
If no static view is found, and there is no matching content in the db, call the show_404() function.
Using this method, you will keep the default CI functionality of uri mapping, so at any time, you can add controllers as you normally would and the app will perform like a vanilla CI install.

URL routing patterns for frontend pages in PHP

Im creating a MySQL database driven PHP (W)CMS application which follows the MVC pattern. First take a look at the framework:
The MVC framework handles the request and decides what to load/call based on the URL, like: http://domain.com/user/details/121 will load and instantiate a User controller object, and calls its details(121) method with the userid passed as a parameter, and then instantiate a User_Model and "ask" it for the detailed data of the user with the 121 userid, and at last display the result with a View. This is the basic concept of an MVC architecture. Nothing particular, everything is clear at this point.
Whereas this will be a CMS, I want to handle a Page model. A user with the nesessary permissions (mostly admin and/or root) can perform basic CRUD operations and other stuff on a page, for example:
I can create a page with the:
tile = 'About us' (this will be displayed as a headline of the page or the title of the browser tab like eg.: HTML title and h1 tags)
URL denomination = '*about_us*' (this will be the URI endpoint, like: http://domain.com/about_us)
reference name = 'Who we are' (This is the text displayed in the menubar)
page content = 'lorem ipsum...' (The actual content of the page...by a WYSIWYG html text editor)
and much more options like structuring the pages, to assign sub pages under a parent page, or making a page startpage (which means if I set 'About us' as a start page, then http://domain.com will automaticall load that page content)...
Or I can modify these properties, even I can delete a page...etc.
The MVC framework makes no difference between handling a frontend and a backend call.
For example we have some requests:
http://domain.com/user/details/121
http://domain.com/about_us
http://domain.com/our_products/1255
The first will load a backend controller as I detailed before,
but the others will load a frontend content.
When the Bootstrap loads the appropriate controller/action we look for the actual controller file, in the example above :
/controllers/Users.php
/controllers/About_us.php
/controllers/Our_products.php
The first can be loaded because that is a 'static' controller written before, but the About_us and Our_products are not existing controllers so If it is impossible to load the controller, the bootstrap searches the database if is there a page with the same URL denimination (like: about_us, our_products). If there is, we load a common FrontEndController and display the requested page data, if there isn't, display a 404 error.
I do this because I want the bootstrap to handle all requests the same way, but I dont want to every frontend URL compulsorily contain the FrontEndController (e.g.:http://domain.com/FrontEndController/our_products/1255). So this is how I hide it from the user, so the URL can remain more user friendly. My question is: Is this a good practice? Or are there any other proper ways to do this?
The MVC framework handles the request and decides what to load/call based on the URL
What you would normally is have is some sort of Router and Dispatcher class. The router would accept the the user/details/121, parse it and return a Route.
$route = $router->route( $request->getUri() );
The router could hold config values like the allowed space character in URI's, default allowed characters etc.
You can also add custom routes to the router
$router->addRoutes($routes);
The custom routes can be a simple associative array
$routes['requested-uri'] = 'custom-route'
In the example above you said when they visit the root of the website you want them to actually see the About Us page so that could be done like this:
$router->addRoutes([
'' => 'about-us
]);
Meaning when the URI is ''(blank) then go to the 'about-us' route. It shouldn't do a redirect, just transparently load up a different route while keeping the URI in the clients web browser the same.
Routing can obviously be more complex, using route objects added to a route collection for more advanced custom routing with more control. Some frameworks use annotations and all sort of different ways to achieve flexible routing.
The dispatcher could then accept the route returned from the router and dispatch it. That means verifying if the requested route actually exists i.e does the controller file exist and the requested method in the controller exist.
$view = $dispatcher->dispatch($route);
Inside the Dispatcher::Dispatch() method:
// Check if the controller file exists.
// Instantiate the controller file, preferably using a controller factory.
// Check if the controller method exists.
// Call the controller method
call_user_func_array([$controller, $route->getMethod()], $route->getParams());
$view = $controller->getView();
$action = $route->getAction();
// Call the view method.
if( method_exists($view, $action) ) {
$view->$action();
}
return $view;
I find the following a very easy to understand way of dealing with controller methods/actions. Let's say you have a login controller, the user sends a GET request to it first and a POST request to it when sending the login details in the form.
public function getIndex() { }
public function postIndex() {
$username = $this->request->post('username');
$password = $this->request->post('password');
}
The get and post in front of the method name is the request type, this prevents you having to do something like this
public function index() {
if( $this->request->getType() === 'POST' ) {
$username = $this->request->post('username');
$password = $this->request->post('password');
}
}
It also gives you more control over authorisation(if you do it at the routing layer) because you can easily allow a user to send a GET request to the controller but deny them access to sending a POST request.
Each controller has a one to one relationship with a view. The view get's injected into the controller on construction, preferably using a controller factory.
What would happen when you send a GET request http://domain.com/user/details/121 is the router would break up the URI and turn it into a route targeting the User controller, the getDetails() method with the parameter 121, the dispatcher checks if the controller and method exist, it then calls the method supplying the user ID as an argument, the controller sets the user ID in the view. Below is the User controller.
public function getDetails($userId) {
$this->getView()->setUserId( (int)$userId );
}
The view then has a method called details(). The same name as the method called in the controller, just without the request type in front of it.
The dispatcher then calls the details() method of the view which then fetches the required data.
Setting the title of the page is done in the view, as it is for presentation purposes only.
Part of the view that is related to the User controller
public function details() {
// Fetch the user by using the previously set user ID from the controller.
// If he doesn't exist set an error template, set the response code to 404,
// or redirect. Do whatever you want really.
$this->setTitle('User Details');
// Build template objects, bind the fetched user data to main template.
}
How you implement the setTitle method and all over view related stuff is up to you.
The view sends the response back to the client, whether it is HTML content, JSON, XML, or any other content type.
For example your application lets you search for users and export them to a Microsoft Excel Workbook file(.xlsx) and prompt the user to download it.
The view would:
Fetch the users
Generate the file
Set the HTTP response headers like Content-Type
Send the response

Working with CodeIgniter routes?

I think this is a route issue but I'm not sure. I have a page with this URL:
siteurl.com/kowmanger/titles/titles/edit/$id
I'm trying to find out that when I'm on this page I load the titles page it says page not found so I need to tell it that the $id is just a paramter so I can use it to get the data of the title.
UPDATE :
So I decided to change my titles controller so that there's a edit and add function inside of the titles controller that way they dont' have separate controllers when they are in fact methods.
So now I have:
kansasoutalwwrestling.com/kowmanager/titles/titles - list of titles
kansasoutalwwrestling.com/kowmanager/titles/titles/add - addnew form
kansasoutalwwrestling.com/kowmanager/titles/titles/edit/$id - edit form
I don't have any routes set up so far for this. For some reason though I"m getting the same page for both of these page.
kansasoutalwwrestling.com/kowmanager/titles/titles/add - addnew form
(right link url) kansasoutalwwrestling.com/kowmanager/titles/add -
addnew form
I need a route so that it'll show the correct url if the add method is accessed.
Also I need to set up a route so that if the correct edit link is accessed it sees the id attached to the end of the url and it'll accept it so that I can do a my database query to get the title data.
UPDATE: So to reiterate I have a module(subfolder) called titles. Inside of the module I have a controller called titles and inside of that controller I have 3 functions called index(), add(), edit().
I tried using Chris's suggestion on the routes but its not routing correctly. Also wanted to mention I'm using wiredesignz modular separation framework if that matters.
Any additional ideas?
Possible answer based on your post, not one hundred percent your entire structure but if i had to guess based off the post I would try this as my routes first..
$route['titles/titles/edit/(:any)'] = 'titles/titles/edit/$1';
$route['titles/titles/add'] = 'titles/titles/add';
$route['titles/titles'] = 'titles/titles';
$route['titles'] = 'titles/index';
Are you using custom routing in your configuration files ?
The general routing protocol used by codeigniter is like this:
domain.com/controller/methode/param1/param2/param3
This being said, your url
siteurl.com/kowmanger/titles/titles/edit/$id
corresponds to something like this :
class Kownmanger extends CI_Controller
{
public function titles($titles, $action, $id)
{
}
}
In case you are using sub-folders in your controllers folder, what I have just said will change, Could you please tell us what's your directory structure ?

Making a controller for home page

Can you tell me how to use a controller for home page because i'm trying to put a model's data in home.ctp (homepage view) with
<?php $this->user->find() ?>but it returns
Notice (8): Undefined property:
View::$user [APP\views\pages\home.ctp,
line 1]
You should check out the cookbook; it has some solid CakePHP tutorials, at http://book.cakephp.org/
You haven't really provided alot of information, but my guess is your Controller uses a model 'User', and you're putting $this->user->find() in your view, when it should be in your controller. In your controller's action you'll want/need to do something like this...
Users_Controller extends AppController {
function index() {
$arrayOfUsers = $this->User->find(...);
$this->set('users', $arrayOfUsers);
}
}
You can then - in your View - access 'users' like so:
pre($users);
... since you used the Controller method set() to send a variable $users to the view.
All you really need to do is create a new controller if that's the direction you want to go. If this is the only statement you have that requires data access, it might be worth faking it in only this method of the PagesController. For example, one of my projects' homepages is 99% static save for a list of featured events. Rather than move everything out to a new controller or even loading my Event model for the entire PagesController (where it's not needed), I just applied this solution in PagesController::home():
$attractions = ClassRegistry::init ( 'Attraction' )->featured ( 10 );
Works great. If your page is more dynamic than mine, though, it may well be worth routing your homepage through a different controller (one that is more closely related to the data being displayed).
The default controller for the home page i.e home.ctp view, is located in /cake/libs/controller/pages_controller.php. This controller can be overriden by placing a copy in the controllers directory of your application as /app/controllers/pages_controller.php. You can then modify that controller as deem fit i.e. use models, inject variables to be used in the home page etc

Categories