Ember.js: Where/when/why declare properties in model or controller? - model-view-controller

It seems like I can declare computed properties in the model and in the controller. I'm getting to the point where I'm not sure which one to look in for a given property.
What dictates whether a property should be placed in the controller vs the model?

Typically, place in the controller if the property is presentational in nature (e.g. display, labels, formatting), and place in the model if the property is inherent to the record itself (e.g. calculations, associations)
In practical terms though:
Model if the property
needs to be accessed by other models, since models don't have access to their controllers
needs to be accessed in routes before controllers are setup
needs to persist across controllers (e.g. order.subtotal is used in OrderNewController and OrderController)
Controller if the property
only needs to be accessed by the view or template
only needs to be accessed by other controllers
You can probably go with putting most properties in the controller, until you run into situations where you need to access the property from other models, or if you find yourself writing {{controllers.modelName.property}} too many times.

Related

Laravel - Updating DB in Controller vs Model

I have a model that I require to update, such as User. In a large application, this User will also have relationships, and updating it would be more than a mere User::find($id)->update(Input::all()).
Should the updating be performed in the Controller, or be a method within the User model itself?
I always thought that I should put it in the model, since it is model specific. But I've seen most people perform the task in the controller. What is the reasoning for this?
As said in the pattern names, the controllers control any model query or update. Based on this, the controller will be responsible for fetching, changing and saving the model.
If some actions are to be reused in many controllers, acting on a set of models, they would go in a "repository".
In your example, you are using Input::all() to hydrate your model, which you definitely have to change. Any user value has to be checked and/or sanitized. I would also recommend against using all and prefer either get or post, so you set up a minimal restriction.
So, I definitely let the controller be responsible for the "glue", having repositories for any collection matter, services and hydrators to change the object, and the model itself staying for only getters and setters, managing their own data in their own scope.

Ember multiple instance of controllers

I've been using Ember for a while but still struggling sometimes to find out the best practices. So one of the Ember ways regarding controller and view is
an opinion of Ember's designers, that is enforced by the router is that for a given BaseName (e.g. "Application," "CustomerEntry," "My Items") there should be a BaseNameView and a BaseNameController. -- Ember guide
The problem is that what if I want multiple instances of the same view on a page. Since the controller is created during initiation of the application, they are singletons under the application namespace, which will not be able to hold two instances of the model data.
One solution I see is to create controllers(and model data) manually and pass them to views. But in this case, I'd like Ember not create controllers automatically for me. Put it another way, why would Ember creates controllers as singletons during application startup.
I think there are many use cases where a View type doesn't have a corresponding Controller type. Especially when the type of view is more like a UI widget than a full-fledged application feature. Many views can share the same controller. Take a look at this applicationView template:
<h1>Here are two files, compare them</h1>
{{view App.MyFileView contentBinding="leftFileContent"}}
{{view App.MyFileView contentBinding="rightFileContent"}}
This creates two instances of my view class and binds their content properties to two different properties on the applicationController. The controller property for both of those views is set to the singleton applicationController instance.
One possible reason why controllers are singletons could be that they're able to be addressed in the global namespace via something like App.router.myController.

MVC paradigm: exposing model and controller from view

I find myself needing to have a View expose its Model and Controller references. Is this the smell of bad design? Or is this considered "safe" practice?
For example: I have a list (composed of a ListView, ListController, and ListModel) and many list items (composed of a ItemView, ItemController, and ItemModel).
When I create the ItemModel, ItemView, and ItemController for each list item, I pass the ItemView instance off to the ListView. But, at some later point, my ListController needs a reference to the corresponding ItemController instance.
So, would it be more proper to pass both the ItemView and the ItemController in to ListView::addItem(), or just pass in ItemView and expose an instance method such as ItemView::getController()?
Or doesn't it matter? Is each approach equally viable? If followed to their logical conclusion, does either tactic result in an anti-pattern?
But, at some later point, my ListController needs a reference to the corresponding ItemController instance
Why? If you're decoupling your classes properly, you shouldn't need this.
Controllers almost always address a functional domain. An example of such a domain might be "Sales" or "Admin." In addition, MVC also supports the use of "Areas," which provides an additional hierarchical level of organization.
Adding references to controllers from other controllers is at cross-purposes with this organizational structure. If you need to combine functionality to make your code more DRY, ordinary refactoring will accomplish that. You can also inherit controllers from a base class containing common functionality.
In the mvc pattern the users request shall be routed to a controller, say invoicecontroller, that has actions.
Lets say the default action, Index, returns a list of invoices; the controller then creates a model with a list of invoice objects, instantiates the correct view and injects the model into the view.
Now it is the views turn to do its magic. It renders the best view it can with the data it has, which may include routes to one or more controllers.
In NO instance should the view (or model) do business logic themselves.
That said, I totally agree with Jakub. Hope that helps.
Considering you are not actually showing any code at all.
In my opinion, you should change your design. A controller is not supposed to communicate with another controller (directly), MVC dictates it: reference.
If you need to invoke a controller action from another controller, consider using delegates or composition. Instead of directly invoking the controller action.

Is there a reason why the default modelbinder doesn't bind to fields?

I'm using ASP.NET MVC3 and i'm wondering that the default modelbinder binds to public properties but not to public fields.
Normally i just define the model classes with properties but sometimes i use some predefined classes which contains some fields. And everytime i have to debug and remember that the modelbinder just don't like fields.
The question: Whats the reason behind it?
but sometimes i use some predefined classes which contains some fields
While I cannot answer your question about the exact reason why the default model binder works only with properties (my guess is that it respects better encapsulation this way and avoids modifying internal state of the object which is what fields represent) I can say that what you call predefined classes should normally be view models. You should always use view models to and from your controller actions. Those view models are classes that are specifically defined to meet the requirements of the given view.
So back to the main point: fields are supposed to be modified only from within the given class. They should not be accessed directly from the outside. They represent and hold internal state of the class. Properties on the other hand is what should be exposed to the outside world. Imagine that in the property getter/setter you had some custom logic. By modifying directly the field this custom logic would be broken and potentially bring the object into an inconsistent state.
Maybe the reason for ignoring fields is to increase performance of the binder. Instead of searching all the Fields and properties. The Model Binder search for Properties only.
Though I think the Model Binder use cache to improve performance.
DefaultModelBinder exposes a public method:
DefaultModelBinder.BindModel, and a number of protected method available for overriding. All of them listed here.
Besides the model, these method refer to properties only, not fields, like
GetModelProperties,
GetFilteredModelProperties,
GetPropertyValue,
OnXYZValidating,
OnXYZValidated,
OnXYZUpdating,
OnXYZUpdated,
GetXYZValue,
where XYZ stands for either Model, or Property/ies, or both, and so on.
As you can see there is no Fields mentioned with these names whatsoever. As Darin explained no direct changes to Model's state are tolerated by the Binder. Hence no Field in its methods.
And also, you may wish to take a look at another important class: ModelBindingContext. An instance of this class gets passed to the BindModel, and subsequently to BindSimpleModel, and BindComplexModel, depending on model type (string, int,... are considered simple, everything else is complex).
So, this context has the following properties:
ModelXYZ, and
PropertyXYZ.
In other words you have no means to reference the fields in your ViewModel unless you do not override these classes and undertake special actions to do so.
But again, beware of fighting the framework, its always easier to follow it instead.
EDIT: The ModelMetadata class holds all the data needed to bind the model. Its code however, shows no sign of fields, field names, etc. Only properties are referenced and accessed. So, even if you try to inherit and override DefaultModelBinder and ModelBinderContext, you still won't be able to access fiellds, nevermind what their access modifier is: public, private, etc.
Hope this explains most of it.

How to implement polymorphism in sproutcore?

I am developing an application that involves a type hierarchy and started by defining the models for each type via inheritance. When it comes to writing the corresponding controllers I am not sure how to approach the whole thing in a clean way. Should I write only one controller for the base type that is able to handle derived models or should there be one controller for each subtype? How should the view-controller bindings be set up to work with the different controllers?
You might want to check out SproutCore's new experimental polymorphism support: http://groups.google.com/group/sproutcore-dev/browse_thread/thread/b63483ab66333d15
Here's some information on defining sub-classes and overriding properties and methods:
http://wiki.sproutcore.com/w/page/12412971/Runtime-Objects.
From my (limited) use of Sproutcore, I've only been able to bind 1 view to 1 controller.
As such, if you are planning to use a single view (e.g. ListView) to display your data, then I think you will only be able to bind that view to 1 controller. This means the 1 base type that is able to handle derived models seems to be the way to go.
Typically you populate the content of ArrayController instances with the results of App.store.find calls. SC.Store#find can take an SC.Query instance, which typically looks like:
MyApp.myController.set('content') = MyApp.store.find(SC.Query.local(MyApp.MyModel));
This should return all instances of MyApp.MyModel, including any instances of MyApp.MyModel's subclasses.
The first argument to SC.Query.local can either be an SC.Record subclass or a string referring to the subclass. So if you've got some intermediary SC.Record subclasses, you might want to try using them there.
Controllers should just be proxies for objects, when dealing with single instances of your model. In other words, ObjectController can proxy anything. Here is what I mean in code:
You have two objects, Person and Student.
App.Person = SC.Object.extend({
// person stuff here
})
App.Student = App.Person.extend({
// student stuff here, you have have all Person things because you are extending person.
})
You then want to define controllers:
App.personController = SC.ObjectController.create({
contentBinding: 'App.path.to.person'
})
App.studentController = SC.ObjectController.create({
contentBinding: 'App.path.to.student'
})
note that you would only bind the controller's content to something if the person/student is a result of a selection, or some other flow where bindings fire. In other words, if you set the person manually (say from a statechart, as the result of an interaction), you would still define the controller but would do
App.personController.set('content', person);
You set up the controller differently depending on whether the Person is a 'top level' object in your app, or some intermediate object that gets selected. Also, you might only need one controller, you would only have a studentController and a personController if you were acting on a person and a student at the same time. Both are just ObjectControllers, and those can proxy anything.
Finally, in your view you would bind the relevant view element to the controller:
...
nameView: SC.LabelView.design({
layout: {/* props */},
valueBinding: SC.Binding.oneWay('App.personController.name')
})
...
note that the oneway binding is if the name is not going to be changed on the view, if the view can change the name, then just do a normal binding. Also note the path here. I am not binding to
'App.personController.content.name'
Since the personController proxies the object, you bind to the
'namespace.controller.property-on-object-controller-proxies'
If you are putting a lot of business logic in your controller, you are doing it wrong. Controllers should just be for proxying objects (at least ObjectControllers should be). Business logic should be on the models themselves, and decision making logic should be in statecharts.

Resources