CAkePHP calling one controller action from a different controller - model-view-controller

In my app, I want to add a user notification each time a user receives a comment on an image or other page. Therefore in my add action in my images controller, I'd like to also call the addNotifications action which is in my Notifications controller. I'm trying to stay away from requestAction based on the warnings, but is there another way?
Workflow is this:
New event occurs -> trigger addition of notification in notifications table -> email user that notification exists.

If it's going to be a notification for all sorts of things, then I would consider something in the app_controller as this will make it available across your whole application. Meaning you'll be able to call something like
$this->Notify($user['User']['email'], 'MyNotifyType', 'MyTemplateName');
Then you can deal with the other bits in your app controllers notify function. You might need to add your User model to your app_controller, which could be tricky.
I would try using uses() as this could allow you to add the model and thus pull user data from your app_controller if you wanted to say include the users last login details, username or formal greeting etc. http://api.cakephp.org/class/controller

If you want to call a method that is based on another model, you need to place it in the model class, so in your example in the the Notification model. You can then call it from your Images controller with
$this->Image->Notification->add($params);
if the Models are associated. If they are not, you could either connect them on the fly or go with the previous proposal and add the function in the appController (which is not really perfect, because functions in the AppController should not depend on a certain model but be generic)

Related

MVC - Should be there a master View, Model and Controller or should they be implementation-specific?

I'm interested in the concept, not the implementation. Consider a CarBookingRequest scenario where user through an interface requests for booking a car. Let's discuss it under the following constraint and taking only View in perspective by keeping Controller and Model simple:
There is one controller class/code which contains all the functions representing relevant actions
There is one model class/code that deals only with single database with few tables (no other data models)
There can be many interfaces through which a request can be made:
1. Desktop Application
A user clicks a Button that fires the Click event which in turn is pre-programmed to make a call to BookingController with request NewBooking. Something like:
Event OnClick() {
C = New BookingController
C.Request('NewBooking')
}
2. Mobile Application
A user taps a Button that fires the Touch event which in turn is pre-programmed to make a call to the same BookingController with request NewBooking. Something like:
EventListener OnTouch() {
C = New BookingController
C.Request('NewBooking')
}
3. Vending Machine
A user presses a PushButton on the machine that fires the event which is pre-programmed to make a call to the same BookingController with request NewBooking. Something like:
Event OnPress() {
C = New BookingController
C.Request('NewBooking')
}
Assume similar implementation for a Web Interface and Service Interface where the request is made by another system or a scheduled task. Obviously all these implementation are different versions of BookingViews written in very different languages and platform. Now if I knew these implementations beforehand and I am making a Booking MVC, what should be my View, Controller and Model Class like? or how many? and why?
Should I have a "Main" BookingView class that has a function such as:
Function CallController(Command) {
If Command = 'NewBooking' {
Return New BookingController
}
or some good implementation of controller/action registry to fetch appropriate controller
}
and every specific View should in-turn call this function which then will call the BookingController as:
Event OnClick {
C = MainView.CallConroller('NewBooking')
}
Or should each View call the controller separately in its own way?
May be too many questions but I am of the view that my View, Controller and Model should be reusable and every new Interface (Mobile, Machine or Web) should require only their specific handling of the View (events or displays) while the connecting and fetch data code remains untouched.
The core idea of MVC patterns is to separate the three aspects of the application - model, view and controller - from each other.
The way you describe your solution, doesn't seem to adhere to this principle. Let me suggest a method that helps you to achieve good MVC, following these rules. I am describing the generic rules, you can then modify according to the specifics of your application, frameworks etc:
Your controller should not know about the views. This rule helps to separate "view" from control. If you follow this rule, your controller, instead of worrying about types of client, can just return one type of resource (e.g. a JSON resource, in this case a Booking). Then, each client (Web, mobile, machine) has to handle presentation of this resource, whichever way they want. But the important point is that, it is not the concern of controller.
Your Model should not know about the controller. The concern of Model is to implement a car booking. It does not know what is being done with it (like whether a controller wants to access it to then pass it to someone else or so). For example, it may have an interface such as
CarBooking:
constructor();
book();
unbook();
...
It performs the business logic of constructing a request, booking a request or removing a booking. Period.
How do you achieve this, proper separation of Model, View and Controller? Well, one method is to start from within, and then move outward. That is, start from Model, then controller, then view. In reality, you may not do it in this order as you has to consider all of these aspects. But, what I am saying is more in the logical sense.

Sails.js - Multiple Controller/models in one page

I'm new to MVC pattern and Sails. From my understanding, it seems like I should create a controller for each model. A controller is like one page.
So, if I want create a page containing product category, product list and user authentication, there are 3 models in my page. How should I structure the controllers?
You don't have create separate controllers for each model.
Controllers handle the request from the client and return views, JSON, etc.
You may be being influenced by how sails documentation explains things due to their blueprints.
Mvc does not require a 1 to 1 of controller to model. Your controller should take care of massing the data and rules needed to show your view or a group of different views. A controller may have a link to a group of your functionality e.g. user management where you handle registrations, login, forgotten credentials etc. This may require a few different models and not just your user model. It may also display a number of different views too.
Sails.js comes with blueprints enabled which means a user model will have create,update,find,findone etc against a user model. Infact sails doesnt need a controller in this instance but you could make one to over ride logic or add additional logic. There is however nothing stopping you calling a user.find method in the user controller as well as a pets.find. Just think of the controller as the conductor telling and calling everything to fire and bringing this information together to push into a view or number of views.

What is the correct place/bundle to place this action

Say I have a CoreBundle, which has an entity called Event. In the CoreBundle, events can e.g. be shown (showAction). I also have a BackendBundle. The event's deleteAction can only be triggered from the backend. However, the deleteAction belongs to an entity that is defined in the CoreBundle. Both the CoreBundle and the BackendBundle have an EventController.
The question is: Should the deleteAction be placed in the BackendBundle's EventController or in the CoreBundle's EventController?
P.s. I know both will work, but this is more somewhat of a phylosophical question.
I would suggest you have a BackendBundle with an EventController and a deleteAction. This deleteAction may call a specific handler (or manager or whatever) inside the CoreBundle, but I would keep the controller code inside the BackendBundle.
First, it makes it easy to follow the code without switching bundles. I can see that the request comes in, that either the entity is deleted or that some manager is called and that a redirect is send or a template is rendered.
Second, and way more important, is that if you introduce another bundle which has a deleteAction for the backend, you can either have different ways of handling them (one inside it's own bundle and one inside the CoreBundle) or you have to name them different and create a big mess.
In generell, I stick to the rule to have the controller inside the same bundle where the route and the view lives and only share the model. In case of a CoreBundle, I handle deletion with a manager between the controller and the model. In your case the deleteAction would get a EventManager service and call a delete with either the object or an id (depending on my needs). This way the code executed to delete an event is in one place and can be changed easily.

Getting user input from Model Layer

Have a problem following the MVP or MVC design pattern (applies to either one). I can't figure out how to cleanly prompt for user input from the model layer? Depending upon certain values in the model, I may need to prompt the user for input during the middle of a process.
For example, we'll take a hypothetical PO entry process. Say after the user hits a button in the view it calls the presenter passing in the PO details from the view. The presenter then calls the model to validate and insert the new PO into a collection of POs. One of the validation checks in the model is to make sure another PO has not already been entered with the same items. If one has, the app needs to prompt the user to confirm the PO is not a duplicate. The app is currently deep into the model. How do I go all the way back up to the view to retrieve the operator input, then return to the model code where it left off to finish the PO entry process?
In a paper I read on presenter first it was suggested that the presenter had dependencies on the model and on the view and subscribed to events from both the model and the view.
This would mean that you could raise an event from the model at the point where the processing cannot continue. The presenter would handle the event from the model by calling some method on the view (which would prompt the user). The return value from the method on the model would then be returned to the model (an in/out parameter to the event like the EventArguments subclasses used by .NET).
You might want to look at some form of notification interaction between your model and the other components of your UI pattern.
Martin Fowler wrote about it here.
As far as being deep in the model, getting user input, then going back into the model: don't. Your controller is responsible for modifications to your model, and should do the validation before attempting to change your model. This may require separating your validation from your update code.

In MVC, where is the correct place to put authorization code?

In MVC, where is the correct place to put authorization code?
The controller?
The Model?
In the view?
All over the place?
I vote for putting it where it makes sense. Most of my authorization stuff is handled via decorating controller actions (or even some controllers) with the AuthorizeAttribute -- or an attribute derived from it. In a few cases -- like my menus -- I've resorted to putting the authorization check in the view code itself, rather than calculating it in each controller and passing flags down in ViewData. There are a few instances where certain aspects of the model are only available to particular roles and in those cases I've resorted to extending the model with methods that can take the current user and roles and do the check there.
I think authorization is a cross-cutting concern. Should be in one place - an aspect that can be declaratively applied where it's needed.
The Controller!
Your View should only handle user interface and display
Your Model should represent the data in your system.
Your Controller should handle the logic of how the system works.
Authorising a user involves taking the credentials provided from the View, checking them against some sort of authorisation list in the model and then performing a check.
This is done in the controller:
Get user credentials from View
if(compare with user list in model returns match)
authorise users
else
refuse access
If you have to choose between M, V or c, the C is the correct place. But, I recommend an architecture where your app is all contained in libraries and the UI is just a thin veneer. You end up calling down the stack from the Controller, but the code is not in the controller.
In MVC, the Model is just a model, or a "dumb data object", if you will. It is designed to hold state, and should not dictate behavior. The View is for the user to interact with and is also "dumb"; the view handles UI. The controller is where behavior sits, or is the entry point into behavior in the case where the app logic is in libraries. Make sense?
Model.
Controller is just for switching through different ways. View is just for... viewing.
So you should make all authorization codes in the Model layer. Ideally, everything will work just fine. If not, then the controller will take the user to the proper login box.

Resources