Page, View, Controllers – where to put my code?

Thursday, August 19th, 2010|Brainstorming, Core changes, Version 3, Version 4|by Romans

Hi. Few people have had difficulties understanding which approach is better to choose, since so many things can be done in different ways. This post will clarify you regardless where you should put your code.

Quick-project (goal = develop fast)

For a quick project, we would focus on re-using as many components as possible. We also probably want to go with default templates.

If project is small in size, then it’s better if you put all your code into the API class. You can add function such as page_index($p), page_order_add($p), etc.

Inside those functions you should be manipulating standard Form, Grid and other view classes. Use setSource() to point to a right table in the database.

If you run into a form which needs to appear on multiple pages, then create lib/Form/OrderForm.php and then use this class instead of add(). When you redefine Form class use submitted() method instead of isSubmitted(). That would allow you to do all the checks and saves but still inside page you can use isSubmitted() (which calls submitted()), and perform some trickery.

Currently forms and grids do not use javascript, however you might take a look at ui.atk4_form.js. It turns form into ajax-form. All you need to do is call $form->js(true)->_load(‘ui.atk4_form’)->atk4_form(); If you want to use Ajax forms, then you better create new Form class. We usually would call this form similar to project code, for example AWForm, ASForm, etc. Extra initialization is added into init()

Finally if you start to feel that some pages needs to inherit other pages, then it’s time to create class such as Page/Preview.php, and then create page/user/preview.php which will inherit Page_Preview and set necessary property. You can also set $api->page_class if you want pages to use certain class by default.

If you follow this pattern, that your initially small and simple project can gradually grow and is not going to require you to refactor.

Large projects (goal = flexibility and control)

As your project grows, you might start having difficulties with this approach. Especially with data management. So you should take advantage of some of the advanced features.

Models and Controllers

If you are interested in current implementation of MVC – please email me.

Model creates the role of basic entities in your system. You will be able to define for each model, which field it has and how it relates to other models. Model takes care of field types, validation. It also supports calculated fields – which are implemented as sql expressions or even sub-selects.

Models also allow you to implement methods. Those methods are very suitable to put business logic into it. The basic rule of a method – if method fails, then whole operation should fail. For example, you might have $subscription->extend(), which would involve numerous actions. If one of those fails – others have to be reverted (rolled back).

In contrast – on the pages if something fails, you may choose to continue with other visual elements.

So if you are interested in using MVC, please email me.

JavaScript extending

Agile Toolkit provides you with univ() chain, which you can extend easily. look into atk4_univ(), create copy, clear funcitons out and import your own functions. However in larger projects you might need to group functionality. It’s recommended that you create jQuery UI widgets and include them with $this->js()->_load() when needed. While univ() usually is being loaded in API::init(), a specific functionality / widgets can be loaded directly from page::init()

Page extending

With addition of sub-pages, you can now create your lib/Page/Entity.php – which will combine functionality of editing, adding and deleting. You can rely on DSQL or Models to define behavior of particular entity, when you create page/entities/countries.php for instance.

Layout

API::addLayout() allows you to add dynamic functionality on global template. This could be a global log-in form for instance,which appears on all pages. It also can be menu or filter. Page content itself is implemented as layout_Content();

Multiple shared templates

Sometimes in larger projects you will need to switch the big template. For example you might add document printing. You don’t need menu for that. Approach of Agile Toolkit is that you define this in API::defaultTemplate(). You can look at $this->page or certain GET arguments to decide which template to use. Note that layout_Menu and other layout elements will look into your template and will not be initialized unless you have spot for them. So if your alternative template does not have <?Menu?> then it won’t be inserted.

Object add-ons (in future – controllers)

This is quite a powerful technique. It allows you to add additional functionality to the object by associating other class with it. Currently good example would be grid paginator and quick search. You use stock grid, and do $grid->addPaginator(). It includes additional object which does something extra.

Similarly you can write your own classes you might add into things. Good example is View_Hint(). Then add function into your form $form->addHint() which will properly work this out with the templates.

Hooks

Certainly learn how to use hooks, especially if you are planning to create add-ons.

What goes where?

api

You put the stuff which will be needed on all pages in here, inside init. You also can add pages through functions, but it’s for smaller projects – you might want to keep pages consistently in the files for larger ones.

you can also add generic business-related methods here if you are not using models, such as sendClientInvoice(). Although highly recommended to clean those out, once your project grows bigger and either place them into respective models or use object add-ons. A good add-on sample is logger. So you might create class “Calculator” and then you reference it thoguh $this->api->calc->doBizLogic().

Generally – try to keep API for under 1k lines of code.

add-ons

Each addon would primarily focus on a single and very narrow functionality. For example DB is added as an add-on. In Agile Toolkit 4 our goal is to completely clean out APIs and move all functionality into addons/controllers.

Try not to make very wide-ranged addons, it have to be light and do what’s necessary. Try to keep code betwen 50 and 500 lines. Create multiple add-ons if necessary.

page

If you look at other MVC implementation, you often need model, view and controller bundled together. You would have choice to inherit them from whatever you want, but very often you don’t need to.

Concept of pages in Agile Toolkit 4 serves multiple roles:

  1. Routing. Saying which browser requests lang on which code, and security – do not allow access classes which are not meant to be accessed.
  2. Configuration. Page determines which controllers, models, views and templates you are going to use and how.

This is really powerful combination. You can use pages without controllers, views or templates, or even you can use templates without pages. Here are some usage examples:

  1. Terms and Conditions: you don’t create page at all, but instead your API will look for template in page/terms.html and will wrap it up with default page class.
  2. Statement: on that page you would want to use a view (Grid) to display table. You don’t need to redefine default template, also grid can work with default template. You can use grid either with static data, setSource / DQ query or model (if you are using MVCGrid)
  3. Welcome page: on this page you would have multiple objects, but they also need to be arranged in a fancy way. So you will want to have page template and insert objects into specific tags. You might want for your views to re-use part of the page template, so something like this would work: $this->add(‘CompleteLister’,null,’news_box’,'news_box’)->setController(‘Controller_News’); You can have similar effect with setSource().
  4. Sub-pages. Let’s say you want to have page which allows to list, edit, add and delete countries to the database. (Refrer to : http://blog.atk4.com/multi-page-pages-finally/) You would generally create generic abstract lib/Page/Entity.php which you will then inherit and configure to use specific data-tables or models.

So – the bottom line – Page is for “binding” and “configuration”. Do not get used to have a lot of business logic on the pages. Also pages do a lot of JS bindings and UI behavior. But clean up business logic from the pages as soon as you can.

Keep your page under 200 lines of code. Init methods can go quite large, but make sure they are very simple to read. We tend to use short variable names on the pages and code is often being copied from one page to another instead of inheriting. That’s because client will ask to tweak certain page and other pages must not be affected.

Layout

Layouts are defined as functions inside API. You will have to also add them inside initLayout() by addLayout. Do not do complicated logic here, simply add some views and be sure to use proper template tag.

Keep those functions under 20 lines of code. Put everything else into view.

Models

Here you keep model-related business logic. Depending on complexity certain models can grow up to 2k of code. You may want to work really hard on good inheritance. Also you should properly document all the external methods and make properties private where necessary. If you have to assign multiple developers, then put senior developers to work on the models, especially Java skills are beneficial here.

Models must not interact with Views in any way. They work only with data. They also do not have templates and should certainly do not output any HTML or JS.

Controllers

In Agile Toolkit 3 controllers are between Models and Views. Controllers can access $this->owner, and somehow affect the way how model is displayed. This is good to make certain modifications to all form using your Model/Controller combination.

Controllers in Agile Toolkit 3 also have default Model with the same name and when you should always add Controller and not model directly. This would most probably change in Agile Toolkit 4 thought.

Controllers are usually small in size, up to 20 lines of code.

View

View is generic in a way because it does not know anything about field names or table names. If you are making your own views, make sure they are not tied in to particular database. Views would usually have defaultTemplate(), but from inside page developer may choose to use different template.

View can use multiple templates or clone templates or even use other views. View also can use JS, although it’s recommended to have specific jQuery UI widget for your view, if it becomes JS-heavy.

View size may vary between 10 and 200 lines. If your view grows past that – you might need to split it into multiple views.

4 Comments

jancha
Posted August 20, 20109:49 am

nice doc. this should be FAQ or Read before use :)

romans
Posted August 20, 20106:37 pm

Sure..

I’m putting together “Path of Code Ninja” and “Path of Designer Ninja” document of some sort, which would walkthrough people through learning curve.

Svetlozar Kondakov
Posted September 24, 20108:15 pm

This could be extended to a good documentation of ATK :) Which ios really needed BTW.

jancha
Posted December 15, 20101:39 pm

also, I suggest adding visualization of the structure. that will make it faster to grasp for new developers. I think I have seen the visualization of the above somewhere.