Codeigniter - find out if class was called directly - php

I am attempting to create a controller that can detect if it is called from another controller in the application.
If it called directly via the URL, however, I need to know so I can perform some other actions.
i.e.
cheese/modulename calling potato/modulename is different to someone accessing site/cheese/modulename via URL - and I need to be able to pick up on this and act accordingly.
I am aware of:
$this->router->class
but it will not work as I may have the same named class in another module (HMVC pattern as an FYI) that may want to call this controller (cheese/modulename calling potato/modulename as an example would return 'modulename' - so I can't use that as a check to see if it was called by itself.)
I basically need a check for:
controller was called via another controller = true / false
can anyone tell me how (or if I am being thick!)
I am doing this in the __construct() just in case your solution will have a problem with that (can't see why but you never know!)
EDIT
Thank you to Mohammad Walid for his answer.
For clarity the structure is
CLIENTS
MODELS
CONTROLLERS
- Client
- Api
VIEWS
JOBS
MODELS
CONTROLLERS
- Jobs
- Api
VIEWS
I will be calling the API from Client - but may also call it from another API (possibly) That may be
In another Module
For Example the CLIENTS Api might get called from the JOBS Api Controller (I have no intention of doing this at present but it may be a possibility under different scenarios I haven't forseen and want to make it future-proof so I don't have a massive refactoring job in the future.)

You can try this:
function is_called_via_url($controller_object){
return $this->uri->segment(1) === get_class($controller_object);
}
and in your controller:
if(is_called_via_url($this)){
//do something
}
I'm not quite sure if passing $this as an argument in the constructor will work, but it worth try.
Reference and a hint from MonkeyZeus's comment.

From the comments there seems to be no way to do this without using debug_backtrace($options, $limit)
However the work-around I have ended up doing is to add a 'flag' within the authorisation module (which is called before all controllers)
The flag defaults to false.
If a controller from within my application calls the API page I turn this flag to true (is_application = true - I am currently just manually pasting this into the __construct of any controllers in my application that need to talk to my API)
I can then just do a simple
if(!is_application){
//this was called directly from the URL not from within the application
}
from within the API controller.
Hopefully this will be helpful for others who are attempting this sort of thing and once again thank you to the people who took the time to comment / answer.

Related

Why does Laravel allow us to render views in routes?

In the latest lecture at my University, my professor is returning the View template from the routes.
Route::get('/list', function() {
return View::make('list');
}
I don't understand how this is even possible. I thought ONLY the controller can interact with the View? How are routes interacting with the view? Does this mean any class in our app can call View::make and control what View template is rendered?
This raises the even larger question of what is the routes returning to? In other words, when our Laravel server gets a request, something in our server pings the routes and our routes returns a template. What is routes returning the template too? I'm presuming it is index.php, I know there are a lot of bootstrapping methods in there. Can someone explain the internal structure of how Laravel works and why we can render views from routes?
Laravel intentionally makes this possible for the sake of flexibility. That said, you'll want to let a controller return a view response in most cases.
There are times where this flexibility comes in handy; say you want to quickly setup a route to output some debug data. Building a controller action and view template would be overkill in this case when you can just output it directly from your route definition. There are other cases too, but the route -> controller -> view method handles most use cases.
Actually, when you make a request to your Laravel application the request goes through route matching and if the matching route found then the framework invokes the handler/action registered for that route. So, it's actually the handler and a handler could be anything which is callable. So, when you declare a route like this:
Route::get('url', 'action');
The framework just searches for the requested route and if that is available in the Route Collection then it invokes/calls/runs that action/handler and the handler returns the response (View). So, if it's somethiong like this;
Route::get('url', 'myHandler');
function myHandler()
{
//...
return View::make(...);
}
In this case your execution scope is the function and if it's a class method then the scope is different, but in both cases the handler is taking the control to return the response, that's all. So, while it's possible to return a View from a named function then it's also possible to return a View from an anonymous function as well. If you can access/use something (Some other class such as a service class for something) from your execution scope then it's possible to be used. The difference between a function and a class method is the scope. So it's possible and easy and also useful in some cases (for a single page or a small application) but not recommended way and neither it's good practice. Try to use a class instead of an anonymous function.
Why does Laravel allow us to render views in routes?
It's a framework and in other words, it's a toolbox with so many tools and this is (the question you asked) just another tool which increases it's (the framework's) usefulness. It's not the toolbox's job to make a better application but your's and the toolbox is just a helper which saves your effort and time to be more productive. So, you have shortcuts but you need to chose the right thing wisely.
Request lifecycle is quite well explained in Laravel documentation:
http://laravel.com/docs/4.2/lifecycle
Short answer: routes can return response (i.e. string, view), or can load controller which can return response as well. It's probably not very good practise to return view directly from routes, but can be useful in some cases.

Removing Controller name from URL in CodeIgniter

Currently in my CI project I have a single controller that handles all things account. Such-as register, login, activation, etc.
My routes work as such...
domain.com/account/login/ or domain.com/account/register/
How can I remove account from the route while also being about to remove the controller from other pages.
I basically want the controller to always be removed. One of my reasons for this is SEO, search engine rank the importunateness of a page based on how deep it is in a website.
The only way I have seem to achieve this is to do some thing like route['activate'] = 'account/activate'; for every single page, which would be a huge hassle.
$route['^(?!other|controllers).*'] = “account/$0″;
Try this :
$route['(:any)'] = "account/$1";
The answer to your question is that you DO have to explicitly set the routes.
How is it going to know which controller a given function is in????
You have to tell it.
use mod_rewrite (if the controller is always the same name)
Ok, I can think of one way to do this, but it is probably gonna be more of a pain than just writing out routes for each function.
You need to extend the Router.php with application/core/MY_Router.php and overide the _validate_request() method. Which basically decides if this this is a valid route or not.
it does a check to see if the controller class exists then fails if it doesn't exist.
You need to replace this with some code which assumes no controller segment, then scans thru each of your controllers and checks if it contains the method called (it will be segment 1, since theres no controller).
Now the tricky part, at this point in the CI lifecycle your controller obviously isnt loaded, so you cant examine it using method_exists() yet.
You need to load your controllers one at a time, and then for each one run
method_exists($loaded_class, $method_name)
and if its true, then set then go ahead and call:
$this->set_class('the_name_of_the_scanned_class_which_had_the_method');
Then CI can keep going on as normal and it will load your methods without the user ever know what controller it loaded from.
.. probably not worth the hassle imho. A much easier solution would be to just have one controller and one route to that controller.

Creating a RESTful application in Zend

I have a controller that extends Zend_Controller_Action. It contains some actions that I need to give people access to via a RESTful MVC web service.
I've seen some articles that have told me to extend using a different class (Zend_Rest_Controller) but this seems to mean I need to override certain abstract methods and really I no use for most of them (I have my own functions that are quite specific!).
I've seen some code that I've meant to copy into my bootstrap.php and makes use of the FrontController. However, everything I've seen is awfully documented.
Can anybody give me an example that will just work for a controller called, say 'catalog' that contains two actions 'getRoot' and 'checkLatest'? (It should be simple yet I can't get anything to work and have a deadline tomorrow!)
Or else, perhaps point me in the right direction... (I've no idea how to troubleshoot this and see, for example, what URL I should be using to test or where the route I have setup is directing this... I've been looking at this, btw: http://techchorus.net/create-restful-applications-using-zend-framework)
Thanks a lot! :)
In the article that you mention you have a class:
class ArticleController extends Zend_Rest_Controller
Just like that example you should create a CatalogController. The different methods that you require should be sent as parameters HTTP GET parameters. The getAction should perform the operations (depending on your request) and return a collection of of results in the response depending on different possibilities such as "getRoot" or "checkLatest" as you mention.

Way to bypass the controller in CodeIgniter?

I've been using the CodeIgniter framework for PHP and am enjoying it, but I notice that it seems to require a controller for every view. I'm wondering if there is a way to call a specific model from the view itself, rather than route through a controller. I understand that use of a controller is best practice in most cases, especially where the data from the model needs to be modified in some way, but I have cases where I just need to do a strict data pull to the view (which is loaded via ajax), and setting up a controller for that seems superfluous.
Any thoughts? Thanks in advance!
You're fundamentally misunderstanding MVC, at least as implemented in CI.
All URLs on your site (at least those that utilize the CI framework) are mapped to functions (methods) within controllers.
http://myCIsite.com/controller/method[/var1][/var2]...
It doesn't matter whether the URL is accessed via regular HTTP or via AJAX. This is always a one to one mapping. Because of this, you should think of the controller/method combination as the "web page". Do not think of the view as the web page.
Models and views are subordinate to controllers. The controller delegates specific responsibilities to them - database interaction for models, and page output to views.
Because models and views only serve to perform delegated responsibilities, their use is not required in any given controller/method. Help pages, for example, generally have no need to interact with a database, so there is no model utilized by the controller/method combination that serves a given help page. Likewise, form handlers frequently redirect to another page upon completion of processing. As such, there is no view corresponding to the form handler (but there is (likely) a view called from the controller/method in the redirected to page).
Furthermore, models and views do not necessarily correspond on a one to one basis with individual controllers/methods. Any given model can be loaded and used from within several controllers. Similarly, a controller could have a single monolithic view that is used by all methods, or each method could be assigned its own view. (Or, as I just said, a given controller/method could utilize no view at all.)
Finally, CI does not enforce strict MVC separation. You can interact with the database and echo HTML all from within the controller and CI will not complain. Nevertheless, this separation and delegation of responsibility is followed because logically separating the responsibilities makes the code easier to read and helps you follow the DRY principle in your coding.
The fundamental Understanding is that the "web page" corresponds to the controller/method. The view and model, when used, handle delegated responsibilities for the controller/method.
I'm wondering if there is a way to
call a specific model from the view
itself, rather than route through a
controller.
That's not possible as of what I know, the main abstract class of the CI controller imposes restriction to use a controller otherwise you will get a fatal error.
And actually what you say will break the best practice of MVC design pattern. You got to go to model through a controller not view.
I'm a bit confused as to exactly what you're trying to achieve. The controller's value, aside from just being a clean way to handle incoming requests, is to manage the interaction between the models and the views and to determine which views to load. It's also entirely reasonable to load model data directly from your views, but how did you get to your view in the first place?
I guess I'm just having a hard time seeing the context here..
To run a query via Ajax you still need to provide a URL / path in the javascript call. You can not get around the fact that a controller function has to "catch" this call; you can not map a url directly to a model. All you need is 3-4 lines of code in your controller.
Via URI routing you can map a URL to a different controller, so you don't "require a controller for every view". I always create a controller called "ajax" to handle those requests.
A basic ajax call with jquery can be something like this
$('#prod_img').load( "http://domain.com/ajax/get_img", {'color': 'blue', 'url_title': 'bla' } )
You can echo stuff in your controller, so rather than trying to bypass the controller you should be looking into how to do away with the views. This will actually be easy, you can load the db class in the controller just as you can in a model.
But if you really don't want to use MVC perhaps Codeigniter is not the framework for you.
You should read more into the principles of MVC.
Views are strictly for presentation of data, the model shouldn't communicate with views directly.
But still if that's what you want then just pass $this->db from the controller to the view and use it in the view.
Then again, this is NOT a good practice.

POST in PHP MVC Controller?

I am learning the PHP MVC pattern for my backend implementation. Looking at this excellent example:
Implementing MVC in PHP: The Controller
http://onlamp.com/pub/a/php/2005/11/03/mvc_controller.html
I feel comfortable with the execution flow in a GET.
But there is no mentioning of what happens in a POST. What would the typical controller code for the POST do? I wonder if I am misunderstanding something obvious here, since I can't find similar situations in previous SO posts or Google.
For example: An app to manage persons,(name, last, age) wants to add a record to db when a POST hits the controller.
What happens next?
My guess is that the 'View' is not used at all, or maybe for confirmation?
Is there just a call from the controller to a model class that adds a record to db?
Or do I skip the controller altogether for a POST and go directly to an "add record" script?
Is there any available example?
Thanks in advance,
Ari
Well, POST is basically the same as GET, just some random chunks of info client sended to server. So you can treat it the same way.
I worked with CodeIgniter MVC framework in PHP. It uses GET URI to route to controller and it's methods. When the POST request comes, it treats its URI in the same way. The later actions are in the hand of the programmer, who accesses POST request data directly or through some wrapper, and he can also don't use it at all.
I need to say that you focus on the wrong parts. MVC is not the model of everything, and it doesn't say how to treat POST or GET requests. It's just a simple principle known many years before the name "MVC" became famous as the principle about splitting of logic, data and representation. And most of software(from old to new) actually do this splitting, because it is very hard not to do this in most cases. In some apps the borders are not so evident, some of them even haven't object model. The implementation of the app is always up to you, because MVC doesn't say you what to write but just gives some clues about highest level organization of you code.
P.S. Sorry for my bad English.
Typically, the controller would process the request (the controller processes ALL requests), then call into the model to actually manipulate data based on the request, and then either redirect to somewhere else (triggering a new GET request), or invoke a view to output a resulting page.
Well, if you are going to build your own MVC pattern solution, you could make one tricky thing. Since you're handling MVC you're supposed to have a really reliable routing manager. So after parsing your URL and defining what controller/method you are supposed to trigger, you could make something like:
<?php
...;
$method_name = (count($_POST) > 0) ? "post_".$route_result : $route_result;
...;
and later in your controller class you could do something like:
<?php
namespace Controllers;
class MyController extends \System\Controller {
function my_method($whatever = null){
...;
return $this->view($model_or_whatever); // supposed that you prepared view Class in routes
}
function post_my_method($whatever = null){
...;
return $this->view($model_or_whatever); // supposed that you prepared view Class in routes
}
}

Categories