For some reasons, I do not want to access from url like examples.com/controller/method. I want to force Codeigniter to use routes.php instead. I do not want to use private, protect or _method.
Please, help! I am using Codeigniter 3
In codeigniter, the methods you write in controllers are to be accessed in the url that is its mvc structure.
If you want to avoid a function in the controller to be seen in the url, simply make that function private/protected or prepend an _ in the function name.
private func_name
or
public _func_name
or
protected func_name
any of the options in your functions won't allow access to your functions in the url.
If you want you controller function to be accessed by other subclasses, you ll need to make the function public or protected as required and to avoid it to be accessed by the url simply prepend an underscore _
I found a solution in Codeigniter 4, just go to routes and set autoroute to false
$routes->setAutoRoute(false);
Related
I am a Java developer (I often used Spring MVC to develop MVC web app in Java) with a very litle knowledge of PHP and I have to work on a PHP project that use CodeIgniter 2.1.3.
So I have some doubts about how controller works in CodeIgniter.
1) In Spring MVC I have a controller class with some annoted method, each method handle a specific HTTP Request (the annotation defines the URL handled by the method) and return the name of the view that have to be shown.
Reading the official documentation of CodeIgniter it seems me that the logic of this framework is pretty different: https://www.codeigniter.com/userguide3/general/controllers.html#what-is-a-controller
So it seems to understand that in CodeIgniter is a class that handle a single URL of the application having the same name of the class name. Is it correct?
So I have this class:
class garanzieValoreFlex extends CI_Controller {
.....................................................
.....................................................
.....................................................
function __construct() {
parent::__construct();
$this->load->helper(array('form', 'url'));
$this->load->library(array('form_validation','session'));
}
public function reset() {
$this->session->unset_userdata("datiPreventivo");
$this->load->view('garanziavalore/garanzie_valore_questionario_bootstrap',array());
}
public function index() {
$this->load->model('Direct');
$flagDeroga = "true" ;
$this->session->userdata("flagDeroga");
$data = $this->session->userdata("datiPreventivo");
$this->load->model('GaranzieValoreFlexModel');
$data = $this->session->userdata("datiPreventivo");
$this->load->model('GaranzieValoreFlexModel');
$this->load->view('garanziavalore/index_bootstrap',$data);
}
public function back() {
$this->load->model('Direct');
$flagDeroga = "true" ;
$this->session->userdata("flagDeroga");
$data = $this->session->userdata("datiPreventivo");
$this->load->model('GaranzieValoreFlexModel');
//$this->load->view('garanziavalore/garanzie_valore_questionario_bootstrap',$data);
$this->load->view('garanziavalore/index_tornaIndietro_bootstrap',$data);
}
.....................................................
.....................................................
.....................................................
}
So, from what I have understand, basically this controller handle only the HTTP Request toward the URL: http://MYURL/garanzieValoreFlex.
So from what I have understand the method performed when I access to the previous URL is the index() that by this line:
$this->load->view('garanziavalore/index_bootstrap',$data);
show the garanziavalore/index_bootstrap.php page that I found into the views directory of my prohect (is it a standard that have to be into the views directory?)
Is it my reasoning correct?
If yes I am loading the view passing to id also the $data variable that I think is the model containing the data that can be shown in the page, this variable is retrieved by:
$data = $this->session->userdata("datiPreventivo");
What exactly does this line?
The last doubt is related the other back() method that I have found in the previous controller: is it a method of CodeIgniter CI_Controller class or something totally custom defined by the developer that work on this application before me?
A controller can handle more than one URL and the class garanzieValoreFlex is an example of such a class.
The URL http://MYURL/garanzieValoreFlex will call the index method.
The URLs http://MYURL/garanzieValoreFlex/back and http://MYURL/garanzieValoreFlex/reset will call the back() and reset() methods of the class respectively. These two function are custom additions to the extended class CI_Controller.
Codeigniter (CI) URLs follow the pattern example.com/class/function/argument/
The function and argument segments are optional.
When a URL uses only a class name such as example.com/class then CI will look for and call the index() method if it exists. If index() does not exist you will get 404 Page Not Found display.
Your reasoning about $this->load->view('garanziavalore/index_bootstrap',$data); is correct. It is standard to put such files in the views directory. Optionally, subdirectories of views can be used as in /views/garanziavalore/.
CI uses a file structure that associates different classes (libraries) with certain paths. Controllers, Models and View classes are stored in their respective folders. Then the loader class will know exactly where to start looking for any given "type" of class. For instance, the call to $this->load->view('garanziavalore/index_bootstrap',$data); tells the loader class to get the file index_boostrap.php from the /application/views/garanzivalore/ directory. The code $this->load->model('GaranzieValoreFlexModel'); tells the loader to use the file GaranzieValoreFlexModel.php in /application/models/.
Find documentation of the loader class here.
The line of code
$data = $this->session->userdata("datiPreventivo");
is calling the userdata method of the session class (library). Think of session data as an array. If the array was defined this way. (This is only pseudo-code for what is accomplished).
$userdata = array(); //empty array structure
The call $this->session->userdata("datiPreventivo") is in effect returning the value of $userdata["datiPreventivo"].
Your reasoning is wrong. I would really recommend you to read the official codeigniter tutorials so that you may understand how the MVC works:
Below are the links
Codeigniter 2:
http://www.codeigniter.com/userguide2/
Codeigniter 3:
http://www.codeigniter.com/user_guide/
CI controllers handles different urls. If you create a function called index in a controller, it will be loaded automatically when the controller is accessed. For your case, http://MYURL/garanzieValoreFlex should access the function.
To access any other function, you will need to http://MYURL/garanzieValoreFlex/**MyFunction**
(Read more http://www.codeigniter.com/user_guide/general/urls.html?highlight=url#codeigniter-urls) The back function is a user defined function.
Im wondering if someone can clear things up for me.
In my codeigniter form validation rules i have a callback called email_exists, its set as follows
->set_rules( 'login', 'Email Address', 'trim|valid_email|required|xss_clean|callback__email_exists' )
In the same controller i have the function it calls as follows
function _email_exists()
{
// Code here
}
This works perfectly, and i cant access the method from the URL because of the _ before the method name ... So its working perfect.
I have looked at the CI documentation and it says for callbacks to use a private method ... but everytime i put 'private' before the method name, it doesnt work at all.
Is it ok to just leave it as it is.
Cheers,
The method cannot be private as the validation class is not able to access the callback method.
The documentation also shows that the callback method should be declared as public.
You should leave it as it is.
It is ok to leave it as it is, because CodeIgniters _ prefix will prevent public access to the method (which means its not possible to access the function by URL as you mentioned).
The manual might be a bit confusing on this part, as they define functions prefixed by _ as private (what they really mean is hidden from public access). However a function might still be declared public (like you have in your code) but still be hidden from public access.
I'm making a model in CodeIgniter and I don't want any of the functions to be accessible to the user. For controllers you would do something like:
private function _myfunction()
{
dosomething();
}
I know this will also work for models but my question is, is this needed? I don't think users can initiate these functions via the URL. The reason I'm asking is because I'd like to follow best practice but if possible I'd also like to avoid prefixing everything with '_' when I call it.
No, that is not necessary. It's an unusual situation for a user to have access to a class method through URL, and it's only implemented in codeigniter for controllers.
It's not necessary, and in fact prefixing private objects with "_" is depreciated with the actual use of the "private" and "protected" keywords in PHP 5+.
No its not necessary. To prevent access to the method from the browser, just add an underscore before the method: _method() . This is Ideal if you want to use/call it as a module(HMVC).
I don't know if my question should be asked here or not. Please let me know or move it/delete it if that is the case.
Question:
For the sake of learning, I'm making my own little MVC "library" for a very small personal website. Here is the process being used (please correct me if I'm not even close to doing it the right way):
All requests (except images, etc.) get sent through index.php (boostrap file).
The bootstrap file parses the request and extracts the controller and action, ex:
http://www.Domain.com/Controller/Action/Argument1/Argument2/...
Where Controller is the controller, action is the method called on the controller. In this case, it would end up being: Controller->Action ( Argument1, Argument2 );
Now, what if a user visits:
http://www.Domain.com/Controller/__destruct
or
http://www.Domain.com/Controller/__get/password
Current solution(s):
Run the request through a $config->getURIFilter () method or something
Do a check for method_exists () and is_callable (), etc.
Don't have any methods in the controller that aren't for handling a request
It just seems like this shouldn't be an issue to begin with and my design is wrong.
P.S. I've already looked at plenty of good MVC PHP frameworks (CodeIgniter, Yii, CakePHP, Zend, Swiftlet, etc.)
Either make your Controllers only handle specific actions, e.g.
/controllers
/user
loginController.php
logoutController.php
and then have classes that only do that one thing
class LoginController implements RequestHandler
{
public function handleRequest(Request $request, Response $response)
{
…
}
private function someAuxiliaryMethod() {
…
so that example.com/user/login will create a new LoginController and call the interface method handleRequest. This is a Strategy Pattern.
Or - if you dont want to split your controller actions like this - suffix your actions with a word (Zend Framework does this):
class UserController
{
public function loginAction() {
…
and in your bootstrap you add the suffix and invoke those methods then.
Yet another option would be to introduce a Router that can map URLs to Controller Actions and which can optionally do sanitizing to filter out malformed URLs, e.g. strip underscores.
I suggest that you treat any method preceded with an underscore as a private method (just show a not found page when you do your method_exists check if it starts with an underscore).
Just mark methods that you don't want to expose to your controller as private or protected.
Keep it simple!
I rolled my own MVC structure once for the same reason you're doing it, and the way I solved this was simply making an architectural decision to prefix all routable controller actions with the word "action", ie:
public function actionGetData(){
}
public function actionUpdateSomething() {
}
etc.
The reasons I did this:
You maintain full control over public/protected/private scope in your class without worrying about whether a method is inadvertently exposed via some URL.
It makes the routable actions obvious to the programmer. public function actionDoSomething() is clearly accessible via a public URL (/controllerName/doSomething), whereas public function getErDone() is not.
You're not forced to jump through hoops to identify routable actions. Simply prefix your incoming parameter with "action" and see if the method exists. Fast and simple.
I found this worked really well.
I'm codeing in codeigintier but this question equally applies to any MVC framework.
How do I abstract the logic for determining if a parameter for a controller method is valid across mutlple methods that take some of the same parameters?
EDIT: More detail
For example in the application I'm building at the moment there are multiple 'sites' and nearly all the data in different tables belongs to a site and a user can only view a subset of the sites. So lots of my methods start method($site_id,...) so it would be really nice if I was able to have a pre_controller hook which could look at the parameters for the methods and detect if there was a $site_id in the parameters, and if there was check the permissions.
The problem is that not all the methods in those controllers will all have a $site_id parameter, so I cannot do the checking automatically in the constructor of my extension of CI_Controller
For CodeIgniter one way of going about abstracting the logic is to create a super class as such:
class MY_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
//...do stuff...
}
//...do stuff...
}
/* End of file MY_Controller.php */
/* Location: ./application/core/MY_Controller.php */
All your controllers that you want to share the same logic should then extend MY_Controller instead of CI_Controller
Now in your MY_Controller you can create functions to "handle incorrect parameters across multiple methods".
UPDATE
Your controller function params are coming from your route. e.g. mydomain.com/mycontroller/myfunction/param1/param2/ would go to the mycontroller public function myfunction($param1, $param2)
$site_id is just your variable naming. You can't tell what it's named and even if you could i doubt it's a good idea to based any logic on how you name your variables.
A simple way is just to explicitly call the validating function (stored once in your base controller, a library or a helper) in each controller's function that require it, that gives you fine grain control.
UPDATE
Extending the controller would only work if my parameters were the same for each method. I'd like to detect automatically the parameters and perform checks. I suppose a call to a helper might be the best I can do, but Id just like to be able to completely abstract it away from the method. I suppose one option would be to have an array of which controllers and methods have $site_id as their first parameter and have a pre_controller hook to do the checking. But this would mean keeping the array up-to-date which kind of defeats the object of my question which is to make things as DRY as possible!
Generally, to gain automation you must give up flexibly and follow conventions.
so to not go the "use helper" way and to go the auto detect way... create your own convention.
in your base controller use $this->uri->segment(n) to check if a certain URL pattern exist, if it does you know that the site_id param is incoming and that you can run automatic validation on it.
Extend the same controller and do some validation in a preDispatch or init method.
Or abstract the validation into a controller-helper and use it in both controllers.