Jump to: navigation, search

View architecture and control flow

3,468 bytes added, 23:00, 6 February 2008
no edit summary
So the main interesting thing your View code wants to do is access data from ServiceResponses. There are some convenience methods to deal with the somewhat complicated data structures easily. There are also some abstractions in place to try to preserve encapsulation and loose coupling between views, data, and the Service adaptor code responsible for creating the data and dealing with any idiosyncracies.
Views are almost always interested in dealing with responses on a type-by-type basis, for instance all of the 'fulltext' responses. View code will normally call the [ ResolveHelper] method #get_service_type(service_type). The argument should be the string name of the particular ServiceTypeValue type you are interested in--views are almost always interested in dealing with responses on a type-by-type basis. This will return an array of ServiceType join objects. But this is kind of tricky to deal with. This process does make a db trip with every call, so it's worth storing the results in a temporary variable rather than calling it multiple times.
What you really want is just the collection of key/value properties according to the standard conventions for keys and values in a ServiceType. (See the documentation of conventions [ ServiceResponse ).
=Control flow: Points of intervention for a Service=
==view_data generation==
When you call ServiceType.view_data, there is actually a somewhat indirected process that happens. This is to give the Service several points of intervention to customize the process of looking at the actual data stored in a ServiceResponse, and turn it into the conventional key/value pairs for view_data dictionary. There are actually probably more points of intervention than needed, some are legacy. The standard easiest thing to do is to let the ServiceResponse itself -be- that hash-like collection of keys and values, since ServiceResponse implements []. But there are several control points where this behavior can be customized.
ServiceType.view_data is actually just a convenience, it really calls service.view_data_from_service_type(self).
Service#view_data_from_service_type(service_type_join) will not normally be overridden by a subclass, although it could be for completely custom handling. But most service adaptor classes inherit the implementation from Service. Service#view_data_from_service_type will first look for a method in the Service adaptor subclass that is named to_[service type name] for the type in question, eg to_fulltext, or to_help. If such a method exists, it will be called, and is expected to return a hash-like object. So this is one place a Service can put custom logic for creating that hash-like object.
But if not found, the default implementation of Service#view_data_from_service_type will instead call Service#response_to_view_data( service_response ) (Note the argument is a ServiceResponse, not a ServiceType). So this is another method an individual service class ''can'' override to provide a custom implementation--in this case, a custom implementation that isn't worried about the particular type, since that information isn't available here.
And if ''that'' isn't provided, there is still an ultimate default action, which is just to return the ServiceResponse itself, which does implement the [] method to be a (duck-typed) hash-like object.
So the point of all this is that an individual Service adaptor doesn't ''need'' to implement any of these methods, it can just store a ServiceResponse with the appropriate keys. For the majority of services, that will be sufficient. But if instead, manipulation at the point of display is convenient, there are various control points where the Service can be asked to create the hash-like view data object on the fly, instead of just using the ServiceResponse.
==url generation==
Clicks on service resposnes are sent through the [ LinkRouterController], with the id of the ServiceType involved.
Again, the default behavior is for LinkRouterController to simply look at the view data under the key :url, and redirect the user to the value found there. But there are again points of intervention where the individual Service sub-class can customize this behavior--perhaps to only calculate the url at the point of need, not at the point of ServiceResponse generation.
The controller actually calls Service#response_url( service_response ). The individual Service subclass can over-ride this method, which should return a url, to provide custom url generation.

Navigation menu