I am working on code someone wrote based on Fat-Free Framework. Basically its a CRM.
I have seen that he uses a dispatch function like the one i here:
What is the difference between URL Router and Dispatcher?
I have not found enough documentation on this approach.
Anyway he also put the authentication in the dispatcher like this:
function dispatch()
{
if(UserManager::isLogin())
{
$controller = $router->getController();
$actionName = $router->getAction();
$controller[$actionName]();
}
else
{
routeTo('/login');
}
}
My question is: Do you think it is correct to put one centralized authentication check inside the dispatcher for all the controllers or would you do a log in check inside each controller, or would you do something else? I appropriate examples from well known framework or CMS.
Thanks
First F3 does not allow dispatching by default so the approach is to use the beforeroute() function.
In your base controller(or class routed to) add
public function beforeroute($f3){
if(!UserManager::isLogin())
{
$f3->reroute('/login');
}
}
Then any time you call the class (which extends your base class with the above function), it first validates the login. Hope this helps.
Related
Since my app is getting bigger i would like to separate admin prefix actions and views from normal actions and views. The new folder for admin is Controller/admin/UsersController.php.
I would like to change my cakephp controllers and views folder structure to match the prefix I'm using.
Example for admin prefix:
Controller:
app/Controller/UsersController.php (contain view(), index() ...)
app/Controller/admin/UsersController.php (contain admin_view(), admin_index() ...)
View:
app/View/Users/index.ctp (for index() in UsersController.php)
app/View/Users/admin/index.ctp (for admin_index() in admin/UsersController.php)
How can I implement this structure using Cakephp 2.6?
Unlike in 3.x where this is the default behavior for prefixes, this isn't supported in 2.x.
You could try hacking it in using a custom/extended dispatcher (in order to retrieve the desired controller) or even dispatcher filters in case you are adventurous, and in your app controller modify the view template path with respect to the prefix.
That should do it, however I would probably simply go for using plugins instead, this will separate things just fine without any additional fiddling.
If you just want to separate logic you could do something like this. It's untested an just thought to give you just the idea. I'll explain the concept after the code:
public function beforeFilter() {
if ($this->request->prefix === 'foo') {
$name = Inflector::classify($this->request->prefix);
$className = $name . 'ChildController';
App::uses($className, 'Controller/Foo');
$this->ChildController = new $className($this);
}
}
public function __call($method, $args) {
if ($this->request->prefix === 'foo' && method_exists($this->ChildController, $method)) {
call_user_func_array([$this->ChildController, $method], $args);
}
}
Depending on the prefix you can load other classes. How you load that class and how you instantiate it, what params you pass to it is up to you. In my example I'm passing the controller instance directly. I think you could actually init a complete controller here but be aware that components like the Session might cause a problem because they might have been already initiated by the "parent" controller.
When you now call a controller method that doesn't exist it will try to call the same method with the same arguments on the ChildController. Not really a great name for it, but maybe you can come up with something better.
You'll have to implement some logic to load the views from the right place in your classes as well but this shouldn't be hard, just check the controller class.
But actually I don't see your problem, I've worked on an app that hat over 560 tables and not putting the code into sub folders wasn't a problem, it did in fact use a similar solution.
I think you have to much code in your controllers, get more code into your models and the controller shouldn't be a problem.
Another solution might be to think about implementing a service layer in CakePHP which implements the actual business logic while a model is reduced to a data handler. The service would sit between a controller and the model. I've done this a few times as well now and if done right it works very well.
Ok, i have a problem, but i think it is not so complicated, so it would be great if someone helped me.
1) I have UserController that extends AbstractRestfulController and it works fine.
2) Then i needed to check the permission to access actions of this controller. If I use "checkPermission" method in every controller it works pretty good, but I want to make this method done in a preDispatch event. And here are some problems:
I do like this:
Module.php
public function onBootstrap(MvcEvent $e)
{
$em = $e->getApplication()->getEventManager();
$em->attach('dispatch', array($this, 'preDispatch'), +100);
}
My method "checkPermission" checks like this (nothing special I think):
if (!$this->isAllowed($role, $this->routeMatch->getParam('controller'), $this->routeMatch->getParam('action'))) {
So the problem: getParam('action') returns null (It means, that in a preDispatch event application doesn't know what action it needs to execute). How can I make it work like I want? Or here is the main question: When does getParam('action') can return value? Only in onDispatch event?
since its a restful api, it will never return action name. in added with applying ACL to the Rest API is not a good practice.
Use Rest API Authentication HEADERS instead of ACL.
refer this link
--SJ
I'm trying to figure out if its bad practice to initiate a controller from within a router class. From what little I have been able to find about this, some say that the router shouldn't handle instantiating controllers. Below is how I started to develop my router class.
Example(note I'm omitting alot for the sake of typing.)
class Router {
private $url, $controller;
public function __construct($url)
{
$this->url = $url;
$this->map(); /* maps url to controller and action*/
/*dispatch controller*/
$this->dispatch();
}
private function dispatch()
{
$controller = new $this->controller();
$controller->executeAction();
}
}
To answer you question I'd so no it violates separation of concerns. The router shouldn't be worried what controller handles it's request, or rather how that controller came into being. It only needs to know that at some point, even in the event of a 404 that some controller will handle it.
Now injecting a controller into the route would be ok, then you could prototype it as an interface like so,
public function dispatch(ControllerInterface $Controller){
.....
}
otherwise you have to much hard linking, to much dependency, what if you need a second controller?
For example say you need an admin controller and a public controller, and a members controller. Do you then build 3 routers.
Personally the approach I am planning for a project I am working on is to use an event driven system, where there will be a group of controllers assigned by default as in a traditional routing system ( class/method/args... ) , say a controller folder will be searched for them. Other wise a controller will register itself to listen for a particular http request. So the flow is a bit like this.
Are there any registered listeners for this request,
if no are there any controllers in our controller folder that match the routing schema,
and at the very end is a 404 controller that will handle any request.
If any of these catch it the event ( that's being listened to is terminated ). The advantage of this over a purely hard wired route is, say I want to make a payment plugin, which needs a payment page, how do I put that in the controller folder as a third party vender? This way one only needs activate the plugin, which registers for the "payments" route, and listens within it's own package.
Maybe this is not a concern of you project but it's something to think about.
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.
For projects written in php, can I call more than one (or multiple) controller in class controller? Example in http://img192.imageshack.us/img192/7538/mvc03.gif
ASK: I need to call an action from another controller... And if I do like the picture above, I'm being out-ethics?
Thanks,
Vinicius.
I'm sure that you can do what you want with whichever framework you're using. If you can't do it natively for whatever reason, then you can extend your framework as required.
Having said that, I personally don't like the idea of a controller calling another controller. It seems to somewhat break the MVC paradigm if only from a theoretical standpoint. What I might do instead is build a library class that contains the functionality required and then have both controllers instantiate that class as a member and call the functions required.
For example, using CodeIgniter:
libraries/MyLib.php:
class MyLib
{
public function MyFunc()
{ /* do whatever */ }
}
controllers/ControllerA.php:
class ControllerA extends Controller
{
public function index()
{
$this->load->library('MyLib');
$this->mylib->MyFunc();
}
}
controllers/ControllerB:
class ControllerB extends Controller
{
public function index()
{
$this->load->library('MyLib');
$this->mylib->MyFunc();
}
}
out-ethics? Anywhose... back to reality.
Yes, a controller can call another controller's action. For instance, in cakePHP, this functionality is afforded via requestAction
// pass uri to request action and receive vars back
$ot3 = $this->requestAction('/stories/xenu');
If you're rolling your own, the details of how to implement it will be very specific to your framework.
then you need to modify framework, find place where controller is lounched and add there your second controller.
what framework you are using?
You can do it any way that you want. You don't have to use MVC if you don't want to. However, in MVC you really should only have one controller active at a time. You probably want multiple Views or Models, not another Controller. There is nothing at all wrong in loading, say, a header and footer view for the menu and footer of the site.
If you are building another Controller, then feel that you need to access the functionality of a previous Controller to access its functionality (because it works with a specific / desired Model), then the Model you developed for the latter probably needs to be refactored. IN plain speak, your target Model may be doing too much. Break it up.
You are trying to avoid repeating yourself (DRY) by using calling the methods of a Controller that has already been developed, but in doing so your are creating TIGHT coupling between both controllers! If something changes in the borrowed controller, it will have an effect on the borrowing controller. Not good, Dr. Jones.