学习Model-Glue框架的系列教程-Building your first Model-Glue Application中文理解通俗版(6)

来源:互联网 发布:短刀极化数据 编辑:程序博客网 时间:2024/06/06 04:30
  1. <cffunction name="logout" access="public" returntype="void" output="false" hint="I log the user out.">
  2.    <cfargument name="event" type="ModelGlue.Core.Event" required="true">
  3.    <cfset structDelete(session, "loggedIn")>
  4. </cffunction>
      今天照例欢迎大家的到来。我想我们得回过头去,添点“调味剂”。什么?调味剂?得体的层次?这讲主要是讲如何应用分层到一个Model-Glue应用。当然,我们还会添加一些功能(因为你们中的一些很在意这点)
      你也许会问的一点是一个层次模板如何在Model-Glue中应用。也许讨论一下分层在CF应用中如何实现这点会有所帮助。
       如果你建立过Web应用,你也许会发现,你时常会改诸如字体大小,样式和颜色等模式,老实说,我不相信设计师,但是,嘿,我们必须不得不和他们一起工作,不是吗?因为老是这样改来改去,你很快意识到:有必要将这些抽象出来(CSS?)。这点可在文件层次和包含CSS层叠样式的HTML文件实现。这讲里我会着重在文件层次
       也许大多人解决这点的代码像这样:
  1. <cfinclude template="header.cfm">
  2. Code for the page.
  3. <cfinclude template="footer.cfm">
在上面代码里,你创建了一个header.cfm文件,但有问题。且不说header.cfm可能被其他人改变而你又不知道,还可能存在变量命名冲突。
这里附上我的做法:

  1. <cfmodule template="/site/customtags/layout.cfm" title="Star Wars is Art">
  2. Code for the page.
  3. </cfmodule>
这里将我的页面和模板分得很清了。变量不会冲突,我也很喜欢模板都在一个文件这点,这有益于分析样式问题。
这看起来很棒,但是在Model-Glue里我们怎么处理这点?我们有许多方法,今天让我们从简单的一种入手哈~,正如你所知,在Model-Glue里定义的事件都有视图部分、他们用来定义在消息广播后的视图。典型的流程如下面:

  • User requests an event.
  • Model-Glue runs any broadcasts for the event.
  • These broadcasts may store information in the event.
  • If a result doesn't send you away, then the view is run.
  • The view then can use data from the view state while rendering. This is the data the controller placed in the event.

  • 考虑我们的Home事件:
    1. <event-handler name="Home">
    2. <broadcasts>
    3.    <message name="getAuthenticated" />
    4. </broadcasts>
    5. <views>
    6.    <include name="body" template="dspBody.cfm" />
    7.    <include name="main" template="dspTemplate.cfm" />
    8. </views>
    9. <results>
    10.    <result name="notAuthenticated" do="Logon" />
    11. </results>
    12. </event-handler>

    在这个例子里,第一视图将会运行dspBody.cfm的模板,Model-Glue将会存储该视图结果在一个称为Body的变量里。这个变量存在于一个称为视图集合的容器里。接下来下个视图运行,就是dspTemplate.cfm。由于它是最后一个了,只有他将会显示。然而每个视图都能访问视图集合,并能取得先前的信息。我们怎么利用这点?打开dspTemplate.cfm,代码:
    1. <cfif viewCollection.exists("body")>
    2. <cfoutput>#viewCollection.getView("body")#</cfoutput>
    3. </cfif>

    Basically this code says, check for a "body" field in the viewCollection, and if it exists, display it. Guess what? That's it. Pretty simple, right? And to be honest, I even prefer this to my custom tag approach. Even though my layout custom tag keeps everything in one file, it is still separated by a CFIF branch for each execution mode. In my Model-Glue template, it simply has the code above in the middle. I find this even easier to read.

    Your next question is - how do I set a title, or other dynamic aspects, into the template? I've talked before about the viewState. This is like a shopping cart where you can place data to be used during the request.Normally, we have used the controller to set this information. However, a view can do so as well. Consider the logon template. It now has this on top:

    1. <cfset viewState.setValue("title", "PhotoGallery Logon")>

    This says, in the view state, create a variable called "title" with a value of "PhotoGallery Logon". Now if we go back to our template file, we can do this:


    1. <cfset title = viewState.getValue("title", "PhotoGallery")>

    This says, look into the view state for a value called title, and if you don't see one, use a default of PhotoGallery. In other words, let's see if an earlier view set a title, and if not, default it to PhotoGallery.

    At this point, it may be a good idea to take a look at the sample application and see the layout in action. For those who registered already, your username and password should still work, or you can just use admin/admin. Before ending this entry, I want to talk a bit more about views to give you something to chew on until the next entry.

    First off - in my example, I used views with different names. If you want, you can use two, or more, views with the same name. If you do that, normally, the last view will overwrite any previous view with the same name. You can get around this by using append. This example is stolen from the quick start:


    1. <include name="content" template="dsp.helloworld.cfm" />
    2. <include name="content" template="dsp.helloworld.cfm" append="true" />
    3. <include name="main" template="layout.main.cfm" />

    In this example, Model-Glue will first run dsp.helloworld.cfm and store it in a viewCollection variable named content. It will then run the template again, but this time the result will be appended to the content variable. Lastly it will run layout.main.cfm, and if it uses "content" from the viewCollection, you will see the HTML from that template twice. To be honest, I've never used this feature and can't imagine doing so. I can see one possible use. You may have multiple pods, for example, and you may want to append them all into a "pod" viewCollection variable. Your layout file would then simply use that variable, and not need to know how many different pods there were.

    Lastly, the way I've done the layout is not the only way you can do it. I've talked about using results before. For example, the Home event will fire the Logon event if you are not authenticated. Did you know you can also run an event if no specific value was set in the result? Consider this:

    1. <result name="DoLogin" do="DoLoginRegister" redirect="yes"/>
    2. <result do="Layout" />

    This logic says, if a "DoLogin" flag was added to the event result, run "DoLoginRegister." The last result, however, will always fire if the previous one does not. In this case, I've actually made a Layout event. Why do this? More complex sites may do a lot of logic in the layout. For example, CFLib shows information in the pods to the right. By using a Layout event, I can handle this a bit easier since I would only need to update one event in case of a change like this. I can say typically I almost always use this approach, but for simplicity's sake, I'm using the approach we have above. As I've mentioned (multiple times now), I plan a "What would I change" type article at the end to discuss possible updates we could do to the application.

    So, I mentioned above that I'd actually add a bit of functionality to the site. You may notice that the menu of the site has three options: Home, Photo Galleries, and Logout. The Photo Galleries event doesn't exist yet, but the Logout event was trivial so I added it. Here is the event from the ModelGlue.xml file:

    1. <event-handler name="Logout">
    2. <broadcasts>
    3.    <message name="logout" />
    4. </broadcasts>
    5. <views />
    6. <results>
    7.    <result do="Logon" />
    8. </results>
    9. </event-handler>
    1. I then added a logout listener to my controller block:
    2. <message-listener message="logout" function="logout" />

    1. And finally added a logout method to my controller:
    2. <cffunction name="logout" access="public" returntype="void" output="false" hint="I log the user out.">
    3.    <cfargument name="event" type="ModelGlue.Core.Event" required="true">
    4.    <cfset structDelete(session, "loggedIn")>
    5. </cffunction>

    As you can see, this was fairly trivial. In the next session will start working with photo galleries.

    That's it for this session! As always, you can play with the live application here:http://pg1.camdenfamily.com. You can also download the application by clicking the "Download" link at the end of this article.

    Summary:

    • This entry was all about looks. I call this the Paris Hilton entry. It's shallow and stupid, but somehow consider important by the majority of people.
    • I talked about views, and how views can be stacked, and use each other in order to create a layout template.
    • I then talked about other ways of using views, and about using a layout event instead of simply using another view.
    • Lastly I added a simple logout event. By now you should be getting the hang of how features are added. The normal process is:
      1. Add event to Model-Glue.xml file.
      2. Update Controller to "speak to" the Model if need be.
      3. Return data to the event to be used by the View if need be.
    • As a quick last note, I disabled debugging in the Model-Glue XML file. I'll discuss this change later on though. I just did it to make the layout a bit cleaner while I was testing.