Porting Prado application to YII. Questions to founders.

Hello, Qiang and Wei.

I've decided to port my Prado project to YII for many reasons. After investigating Yii for last 2 days I've stuck with porting my project to YII methodology. Probably, I misunderstand it's concept.

In my Prado project I had strict separation of presentation layer and functional layer. This is how it worked. In WebRoot/WebSites/*/ directories I has master templates, pages, skins and assets. Master template and pages were embedding portlets which, in turn, were functional controls based on TTemplateControl. With this sheme I was able to place multiple portlets on a single page and all of them were working independently. For example,

Master Layout: <com:TWebsitePollPortlet />

Contacts Page: <com:TSendMessagePortlet />

Both portlets have buttons and both portlets react to clicks on those buttons by showing operation status message (e.g. 'Your message was sent') in their matching place.

In Yii we still have logic/presentation separated but the concept is totally different. For example, if I want to implement 'SendMessageController' I will probably inherit it from something like 'XPortlet'. This controller will perfectly process it's actionSendMessage() and here is the question: how will YII know what page user was at before performing this action's POST?

Controller is always leading to a single view but I need views hierarchy:

Layout - Page (no code behind) - Portlet1, Portlet2 (functional code).

Is this implemented in YII? What is the best practice to implement this sheme?

Another question is how do I implement something like I had in Prado for accumulative configuration? For example:

application.xml + config.xml + config.xml + … = runtime config

This is primarily needed to configure pages permissions like it was in Prado,

<authorization> section.

Thanks for your great work.

First, a controller in Yii is not equivalent to a page in Prado. A controller consists of several actions, and each action (together with its associated filters) is roughly equivalent to a Prado page. For example, a PostController may have "create", "read", "update" and "delete" actions, while in Prado, this would need create, read and update pages.

Ultimately, the result of an action is to render a view, which by default would be decorated by a layout. Inside a view or layout, you can embed widgets (like Prado controls). A portlet is just a type of widget.

Unlike Prado controls, widgets in Yii do not have full life cycles and are not stateful by default. Therefore, they typically need to use hidden fields or form fields to remember things they have. See XLoginPortlet as an example.

Regarding “accumulative configuration”, Yii only uses a global application configuration. The rest configurations are scattered inside class files. For example, in order to do access control, you would use the accessControl filter together with access control rules. See http://www.yiiframew…-control-filter

Quote

First, a controller in Yii is not equivalent to a page in Prado. A controller consists of several actions, and each action (together with its associated filters) is roughly equivalent to a Prado page.

Yes, I know. This is what I meant by saying 'In Yii we still have logic/presentation separated but the concept is totally different'. What I actually meant here was pages with no code behind.

Quote

Unlike Prado controls, widgets in Yii do not have full life cycles and are not stateful by default.

This is why I primarily decided to port to YII. Stateful pages in Prado made it hard to implement callbacks due to page state being transferred twice. Plus avoid using huge prototypeJS. Plus better expandability versus straight standards in Prado.

I will prpbably need to implement some stuff to support previous concept. Could you please comment?

  1. TSiteController to map requested actions and views (site pages) with no code behind. For example, /index.php/contacts will simulate an action and render corresponding view file decorated by master website layout.

  2. TRecord*Controller(s) to hold application logic, inherot from XPortlet. For example, TManageAccountsController will have CRUD actions for managing user accounts.

  3. Implement project's widget library inherited from CWidget. Those widgets will be primarily used by portlets.

Do you find this idea meaningful and worth of implementing?

For codeless pages, you can use a CViewAction in your SiteController. If you access the URL /index.php?r=site/view&view=path.to.view, it will load a view file from protected/views/site/pages

I don't understand why you inherit from XPortlet? XPortlet is just a base widget class.

Quote

I don't understand why you inherit from XPortlet? XPortlet is just a base widget class.

I'll use TPortlet as a base class for all portlets. It will publish default form assets such as css for form header, form field, form footer, input elements & etc… This is required to supply default css styles for system portlets.

Separately I'll probably have another base class for widgets (basic controls) to serve presentation layer UI, TWidget.

I'm still thinking of implementing Prado's features such as:

  • XML application configuration.

  • XML auth configuration.

  • Overriding TPradoRenderer to support '<%= %>' in attributes, localization tags and directives.

First one is implemented as a php array but in production environment I use IonCube to encrypt app settings so it can't be included, just eval'd. Will definitely need to cache this as an array and encrypt cache file as well.

Second one is a logical continuation of the previous approach to configure with XML. WebSites directory is intended to be end-user's directory to easily create pages and place portlets there to plug functionality in. Of course, it implies that user doesn't have to be aware of PHP, arrays and other stuff to configure website and set page permissions.

Third one. I'm not sure whether Yii's CPradoRenderer supports constructs like this: <com:CTextBox Text="<%= $this->text %>" />? Localization and asset tags aren't implemented. Probably worth of? Directives could be also very useful to configure controller on-the fly. The only difficulty is that view gets into play at the very end of controller, when things are almost done. In Prado it was very useful to specify page's 'EnforceHttps' and 'MasterLayout' properties with a directives. It looks like in YII view isn't aware of it's layout. How can I implement something similar?

P.S. I'm sorry to be that persistent but I really need to plan things right at the very beginning to avoid painful refactoring in the future. Again, thanks in advance.

Qiang, I’m sorry for this mess. I was so used to Prado concept that just didn’t understand an elegance of Yii. To make my question short: is it possible in Yii to have two controllers being simultaneously embedded into a view/layout the same way as widgets do?

No. As I said, a controller is like a collection of prado pages. You can't embed a prado page in another page.

Here are some mappings between Yii's concepts and Prado's:

application : application

controller class : a collection of page classes

controller view  :  a .page file

widget class : a control class

widget view : a template control's template

Qiang, I know my question wasn't correct in the view of Yii. In Prado I could do the following:

<com:TLoginPortlet ValidateCaptcha="False" SessionLifetime="86400" />


...


<com:TFeedbackPortlet ValidateCaptcha="True" SendTo="admin@server.com" />


This was giving the following benefits:

  1. Ability to specify a place for a self-contained portlet in a page.

  2. Ability to configure portlet with properties from right where it's used.

  3. Have multiple portlets on a layout/page.

In Yii controllers are intended to be a primary place for application functionality but (as you said) only one controller is allowed. Moreover, it's started by an application based on request, not a view. And therefore cannot be configured by properties as widget can.

In turn, widgets can be embedded in a view multiple times, can be configured with properties, but have no filters/actions and have no support for being top-level functional entities (unlike controllers are with their actions and filters).

Do you think this might be implemented with YII somehow?

I see two ways:

  1. Override application to support controllers embedded into views.

  2. Extend CWidget for supporting actions and filters.

What do you think is more reasonable?

You should extend from CWidget to create your portlet classes.

If your widgets need actions, these actions should be written as action classes. And then the widgets should state clearly about how to declare these actions in the controller that would use the widgets.

That's clear but will probably require to tweak controller's lifecycle because controller will only know it's child portlets from the view, after all actions are executed.

Do you expect to implement actions-enabled widgets in Yii? If no, I can contribute with this functionality - just give me the clue how to implement this in a clean way.