Working with Posting Child Objects

Thus far we have seen the properties and methods of the Posting object that use intrinsic data types. This section will explore CMS-specific objects and collections of objects that are available from a Channel object. These are the principal objects graphically modeled in Figure 23-3, PAPI object model Posting.

NOTE: The PAPI object model is covered in detail in Chapter 23. The objects covered in this section will be covered in the same order as they are illustrated in Figure 23-3.


These objects require some special processing and consideration. As before, there are some common facts and concepts that will help us in this section.

After a channel has been deleted but before it is committed, all properties become read-only. However, even after a deleted Channel object is committed, it may still reside in an in-memory collection. All Channel child objects must be removed before a Channel object can be deleted. Even if they still reside in memory, Channel child objects cannot be read once the Channel object has been deleted and committed.

Historical revisions of a channel don't typically keep the value that was associated with the revision when it was the current version. Properties typically represent the value of the current revision regardless of the value when the historical revision was the current revision. Attempting to assign a value to these properties for a historical revision will result in an exception. This concept is extended to the child objects for historical revisions of a channel, including the collections (Channels, Postings, All Children, and CustomProperties), whose contents are based upon the revision date and time of the channel. Channel objects and Posting objects are only included in these collections if they have a corresponding revision date and are currently contained in the referencing Channel object. Otherwise, they are left out.

Often it is valuable to iterate through an ordered collection. But the default sequence may not be well suited for the task at hand. So, collections come with some built-in sort options. In Chapter 25, in the Working with Channel Objects section, we listed the available sort members for collections.

Each sort method can be applied successively to the Channels collection to create a multikey sort. This can be beneficial if duplicate values are expected in the collection and we want to iterate a consistent sequence of values (as is often the case in dynamically generating navigation for a site). For example, sorting the collection using SortByDisplay Name followed by SortByOwner would yield a list of channels grouped by channel owner in channel DisplayName sequence. To start the sort sequence over again, we would need to get another instance of the Channels property.

Several Posting child objects can only be used if the posting has placeholders. See the Adding Placeholders to Scratchpad sidebar for instructions on adding a couple of placeholders to our posting before we start.

Adding Placeholders to Scratchpad

Since postings in the real world will typically have placeholders, we will add two HtmlPlaceholderControls to our physical Scratchpad template file and relate them, respectively, to the two HtmlPlaceholderDefinitions already in our logical Scratchpad template. (Working with placeholders in VS.NET is covered in depth in Chapter 13.)

Although it's typically not the best programming practice, just leave the default names and properties for all four entries (Figure 26-10).

Figure 26-10. Scratchpad template file in VS.NET

graphics/26fig10.jpg

Next, let's give those two new placeholders some values in our Scratchpad posting. Build the solution and then refresh the Scratchpad posting in Internet Explorer or browse to it. (The Web Author console used in the steps that follow is covered in Chapter 5.)

While viewing the Scratchpad posting in Internet Explorer, use the following steps to complete this setup task:

  1. Click the Switch to Edit Site link in the Web Author console.

  2. Click the Edit link in the Web Author console.

  3. Enter the literal string "one" into the first placeholder (you may have to scroll down to see it).

  4. Enter the literal string "two" into the second placeholder.

  5. Click the Save and Exit link in the Web Author console.

  6. Click the Approve link in the Web Author console.

  7. Click the Switch to Live Site link in the Web Author console.

The resulting Scratchpad posting should look similar to Figure 26-11.

Figure 26-11. Placeholders with content

graphics/26fig11.gif

Since postings must exist within a channel hierarchy, it will also be very helpful to have a hierarchy to post into. Figure 25-1 in Chapter 25 shows the structure of the potentially familiar hierarchy as viewed in the CMS Site Manager. This channel hierarchy can be created using the code in the Creating and Deleting Objects in a Channel section of Chapter 25 just preceding Figure 25-3. This channel hierarchy will be used with the examples in this chapter. Initially, the only channel that has a posting in it is the Scratch channel.

Note that building the simple Scratchpad template file (illustrated earlier), populating it using the Web Author console, and running the code to create the channel hierarchy described earlier should take no more than three or four minutes to complete. But if you prefer, you can just apply the concepts discussed here to your own channels, templates, and postings.


Parent (Inherited from ChannelItem)

The Parent property of a Posting object returns the Channel object that contains it. This concept was covered in detail in Chapter 25 regarding a channel and is identical for a posting. See the Working with Channel Objects section near the end of Chapter 25 for details and a code sample.

ConnectedPostings, ConnectedTemplates

The ConnectedPostings and ConnectedTemplates collection properties of Posting and Template objects, respectively, share the same placeholder content and PlaceholderDefinitions, again respectively, as the referencing Posting object. The IsConnected property, discussed earlier, should be used to determine if this collection contains objects, because both collections' content is dependent on the current PublishingMode, the user's rights, and the state of each ConnectedPosting. In either case, an empty collection does not necessarily mean that there are no Connected Postings. The referencing Posting object or posting template, respectively, is never included in the collection. A Historical Revision Posting object will return ConnectedPostings and ConnectedTemplates that were connected when it was the Approved posting.

ConnectedPostings can be created using the Web Author console, are usually saved in different channels from the current channel, and are typically used to provide different user groups with a view of the same data. The ConnectedPosting is related to the posting template or can use a ConnectedTemplate.

ConnectedTemplates can be created using VS.NET and can be related to a unique template file (ASPX). However, they must be related to the posting template, and they are typically used to present the user with a different look and feel of the content. A common need is for a posting to be shown in a different form for printing than it is for typical viewing. A ConnectedTemplate would be one way to accommodate that need.

NOTE: Chapter 15 covers ConnectedPostings and ConnectedTemplates in depth, including a detailed code sample.


Assuming the user has sufficient rights, any posting can be presented using any of its ConnectedTemplates. This takes the place of the error-prone URLUsingAlternateTemplate (aka Template Switching) used in previous versions of CMS.

CustomProperties (Inherited from ChannelItem)

The CustomProperties collection of CustomProperty objects for a Posting object is used as a catch-all for capturing characteristics that were not thought of by Microsoft. This concept was covered in detail in Chapter 25 regarding a channel and is similar for a posting. See the Working with Channel Objects section near the end of Chapter 25 for details and a code sample.

All the concepts are the same, and, as with a Channel object, a Posting object's CustomProperty can be maintained and manipulated using the Web Author and PAPI. However, we use VS.NET instead of Site Manager to create a CustomProperty (Figure 26-12).

Figure 26-12. Custom Property Definition Collection Editor

graphics/26fig12.jpg

This means that the number of people who can physically create these is much smaller. This can be a huge disadvantage. The interface is similar to the Site Manager-based version but just different enough to be weird. The same capabilities of creating a Text-based CustomProperty or Selection-based CustomProperty with an allowed values list exist.

The only other difference is the ability to define a default value in VS.NET or in code. So, the UsesDefaultValue property will return true or false, the DefaultValue property will return the value selected in the dialog, and the ResetToDefault method will obviously reset the Value to the DefaultValue.

WorkingRevision

The WorkingRevision is either the Approved or the Unapproved version of the posting. A posting is typically referred to as a single entity; however the reality is that at any point in time there could be as many as seven concurrent conceptual types of postings (Figure 26-13):

  • An in-memory Working Revision Posting object that represents either:

    • A data-based Unapproved posting

    • A data-based Approved posting (which can coexist)

  • An in-memory Preview Posting object

  • An in-memory historical revision that represents any number of:

    • Data-based historical revisions (postings that were previously in the Approved state)

  • A ConnectedPosting fully reliant upon the referencing Posting object's placeholder content

Figure 26-13. Posting instances with valid states

graphics/26fig13.gif

The Context PublishingMode will determine which posting, if any, will occupy the in-memory Working Revision Posting object. Entering a Published Context (aka Live Site in the Web Author console) or Staging PublishingMode hydrates the Approved Committed Posting object into the Working Revision. Entering an Unpublished Context (aka Edit Site in the Web Author console) or Update PublishingMode hydrates the Unapproved Committed Posting object into the in-memory Working Revision. We realize that the Web is inherently stateless so CMS Server Memory is imprecise (more like application state); however, it seems to help people understand the concept of posting revisions, so we left it in.

A posting in the process of being initially created is the first possible in-memory Working Revision and has a State of New until it is initially committed to the database. New is never a State that is physically found in the database and once an Unapproved posting row is created in the database it has a State of Saved. Since there is not an Approved posting in the database, its logical State is None. The in-memory Working Revision now represents that Unapproved posting.

The only physical table in the database is Node, and its contents are managed through a series of indicator fields and business rules, but the logical representation of that physical structure includes Unapproved postings, Approved postings, and Past Approved postings (aka Historical Revisions). However, Working Revision is always a reference to the currently in-memory version of an Unapproved or Approved posting based upon the PublishingMode of the Context that the current user used to obtain the posting.

The user can continue with this now Saved, still Unapproved, in-memory Working Revision or abandon it. If at a future time the user enters an Unpublished Context and retrieves the posting, the Unapproved posting will again become the in-memory Working Revision. However, a subscriber user cannot enter a Published Context and view this posting, because there isn't an Approved version yet.

With the Unapproved posting represented in the in-memory Working Revision, assume the CMS Administrator marks the in-memory Working Revision as Approved and calls CommitAll on the Context. Also assume the Start and Expiry dates are such that it becomes Published. Yes, we are skipping the Submitted step and the Waiting For Approval States as well as the possibility of a Declined posting, but they all use the in-memory Working Revision in the same way any Unapproved posting uses it basically as the representation of the posting that can be manipulated in-memory until it is committed. Upon Approval however, the Unapproved posting row in the database is changed to Approved with a State of Published. There is no Unapproved posting in the database, so its logical State is None. The in-memory Working Revision now represents that Approved posting, and the CMS Context is switched to Published.

The user can continue with this now Published and Approved in-memory Working Revision or abandon it. If at a future time the user enters a Published Context and retrieves the posting, the Approved posting becomes the in-memory Working Revision. If the user enters an Unpublished Context and attempts to view this posting, they will get a New Unapproved version (based upon the Approved version) that has no associated database row until CommitAll is called. Making changes to this and saving them will create a second physical row in the database, and the process starts over again, but now there is both a current Approved version in the database and a current Unapproved version in the database. With the second still Unapproved revision of the posting represented in the in-memory Working Revision, the CMS Administrator marks the in-memory Working Revision as Approved and calls CommitAll on the Context.

The initially Approved posting row in the database becomes the first Previously Approved posting (aka Historical Revision). Aside from its state changing from Published (could have been Approved or Expired) to Historical, the ChangeDate reflecting today, the RevisionDate reflecting today, and the RevisionCause property reflecting the posting approved, its other properties remain unchanged and can never again be changed. The Unapproved posting row in the database is changed to Approved with a state of Published. Again, there is no Unapproved posting in the database so its logical state is None. The Revisions Collection of the posting (discussed next) now contains two entities (the current Approved and the single Historical Revision).

The IsWorkingRevision Posting object property will return true for any in-memory Working Revision. If at any time the user Previews a posting, the values from the in-memory Working Revision are used to hydrate the read-only in-memory Preview posting. The Web Author console is not rendered. This is not an in-memory Working Revision because it cannot be revised. This posting will display the values that were in the Working Revision for IsWorkingRevision and state, but effectively it is only allowed to have a state of New. An in-memory Working Revision and an in-memory Preview posting can both be instantiated simultaneously. Any uncommitted changes to the in-memory Working Revision are not reflected in the Preview. The IsWorkingRevision Posting object property will return false for the in-memory Preview posting

A new Historical Revision is created every time an Unapproved posting is successfully Approved. If at any time the user views a Historical Revision, the database values for the posting that existed when it became the newest Previously Approved Revision will be used to hydrate the read-only in-memory Historical Revision posting. The Web Author console is not rendered. This read-only posting is only allowed to have a state of Historical. An in-memory Working Revision and an in-memory Historical Revision Posting object can both be instantiated simultaneously. The IsWorkingRevision Posting object property will return false for the in-memory Revision History posting.

With an Unapproved posting represented in the in-memory Working Revision, assume the CMS Administrator marks the in-memory Working Revision as Deleted and calls CommitAll on the Context. Deleted is not a state that is physically found in the database except when Site Manager moves items into Deleted Items before it actually removes them from the database. The Unapproved posting row is physically removed from the table upon a successful delete. The Approved posting row and any Previously Approved posting row (aka Historical Revisions) are untouched. The in-memory Working Revision now represents the Approved posting, if any. Otherwise, the user is taken to the default page in the channel.

With an Approved posting represented in the in-memory Working Revision, the CMS Administrator marks the in-memory Working Revision as Deleted and calls CommitAll on the Context. The Approved posting row is physically removed from the table upon a successful delete. The Unapproved posting row, if any, and any Previously Approved posting rows (aka Historical Revisions) are also deleted. The in-memory Working Revision cannot be rendered, so the user is taken to the default page in the channel.

ConnectedPostings can be modeled similarly to Historical Revisions except that each ConnectedPosting can have all conceptual types of posting, whereas a Historical Revision can only be a Historical Revision. Again, see the graphical representation in Figure 26-13.

Revisions, RevisionCause, RevisionForDate

The Revisions collection property of a Posting object contains the current Approved posting and all Historical Revisions (previously Approved) versions of the posting. The property takes two optional Boolean parameters that both default to true. The first parameter specifies whether the collection should include Historical Revisions caused by a posting being Approved (most common cause for a Historical Revision) or not. The second parameter specifies whether the collection should include Historical Revisions caused by changes to shared resources.

The RevisionCause property will either return the posting or the resource that was the catalyst for the revision's creation. The RevisionForDate can be used to retrieve a Historical Revision for a specific point in time. The Historical Revision that was created closest to and/or before the date and time specified will be returned.

The Posting objects in the Revisions collection will be ordered, by default, in reverse chronological order by RevisionDate (most recent first). However, as with all collections, the default sort order can be overridden using the built-in sorts (see Chapter 25 for available sort options) that can be applied to the list.

Be cautious about overusing this functionality, because sorting is always a CPU-intensive activity, and repeatedly sorting a large list or a large number of small lists could become a resource drain. This collection is not self-updating. If new revisions are added to the Web Property or existing channels are deleted, the collection in memory will not be updated. It is good programming practice to get the property and use it swiftly. In busy sites, if some time has passed since the property was first acquired, it would typically be better to get the property again rather than use the one previously in memory.

The Channels collection has a Count property that can be used to determine whether the list contains any items. The items in the collection can be iterated using the common foreach statement or directly using the string Name for the item or its zero-based ordinal index.

There is also a Union method for the Channels collection. It can be combined with another collection to create a superset of all the objects in both collections.

The coding concepts are very similar to the code sample provided for the Channel Postings collection in Chapter 25.

Placeholders

The Placeholders collection property of a Posting object contains all the Placeholder objects. Placeholders are covered in depth in Chapter 27. This collection cannot be sorted.

Some of the concepts demonstrated in the following code sample use the modified Scratchpad posting created earlier in this chapter.

Replace the Button1_Click function of our Scratchpad template (see the Adding Placeholders to Scratchpad sidebar in this chapter and the Scratchpad sidebar in Chapter 24 for details) with the following code:

 private void Button1_Click(object sender, System.EventArgs e) {   try   {     //1. Put current Posting into variable     Posting cmsPosting = CmsHttpContext.Current.Posting;     //2. Populate the label with informational text     Label1.Text =       HttpUtility.HtmlEncode(cmsPosting.DisplayName.ToString()) +       " Placeholders";     //3. Iterate through the collection of Placeholders     foreach(Placeholder cmsPlaceholder in cmsPosting.Placeholders)     {       //4. Put the Name of each Placeholder into the ListBox       ListBox1.Items.Add(cmsPlaceholder.Name.ToString());     }   }   catch(Exception eError)   {     //5. Provide error feedback to the developer     Label1.Text = "<b>Error: </b>" + eError.Message.ToString();   } } 

Build the solution and then refresh the Scratchpad posting in Internet Explorer, or browse to it and click the Button. The page should reload and look similar to Figure 26-14.

Figure 26-14. Working with a Posting Placeholders collection

graphics/26fig14.gif

Template

The Template property provides access to the underlying Template object (aka TGI or TemplateGalleryItem) used to render the referencing Posting object. A user with sufficient rights can gain a wealth of information using this object. A TGI inherits the same members of the HierarchyItem, and they have exactly the same functionality of the Posting object members described in this chapter; these include CanDelete, CanSetProperties, CreatedBy, CreatedDate, Delete, Description, Guid, IsDeleted, IsDescendantOf, IsWorkingRevision, LastModifiedBy, LastModifiedDate, Name, OwnedBy, Path, and RevisionDate.

The following template members have very similar functionality to the similarly named Posting object members also described in this chapter: AcquireOwnership/ReleaseOwnership, CanMove (inherited from TemplateGalleryItem), CanSubmit, ChangeToken/ValidateChangeToken, ConnectedTemplates, CopyTo, GetByRelativePath (inherited from TemplateGalleryItem), GetHashCode (inherited from CmsObject), GetType (inherited from System.Object), HasInaccessibleConnectedTemplates, IsConnected, MoveTo (inherited from TemplateGalleryItem), Parent (inherited from TemplateGalleryItem), State, and Submit.

Table 26-2. Template Members

Member

Description

CreateCustomPropertyDefinition

Creates a new custom property definition for this template.

CreatePlaceholderDefinition

Creates a new placeholder definition for this template by copying a provided placeholder definition or using a provided type of PlaceholderDefinition.

CustomPropertyDefinitions

Gets a collection of CustomProperty Definition objects that have been configured for the template.

PlaceholderDefinitions

Gets a collection of PlaceholderDefinition objects that have been configured for this template.

SourceFile

Provides the file name, including the virtual path, of the template file.

UrlAsPosting

Simulates the appearance of a posting created from the template without the need to create a new posting to preview the template.

However, the template members described in Table 26-2 are unique to Template objects.

Replace the Button1_Click function of our Scratchpad template with the following code:

 private void Button1_Click(object sender, System.EventArgs e) {   try   {     //1. Put current Posting into variable     Posting cmsPosting = CmsHttpContext.Current.Posting;     //2. Populate the label with informational text     Label1.Text =       HttpUtility.HtmlEncode(cmsPosting.DisplayName.ToString()) +       " Template: " +       cmsPosting.Template.Name.ToString();     //3. Iterate through the collection of Placeholders     foreach(PlaceholderDefinition cmsDefinition               in cmsPosting.Template.PlaceholderDefinitions)     {       //4. Put the Name of each Placeholder into the ListBox       ListBox1.Items.Add(cmsDefinition.Name.ToString());     }   }   catch(Exception eError)   {     //5. Provide error feedback to the developer     Label1.Text = "<b>Error: </b>" + eError.Message.ToString();   } } 

Build the solution and then refresh the Scratchpad posting in Internet Explorer, or browse to it and click the Button. The page should reload and look similar to Figure 26-15.

Figure 26-15. Working with a posting Template property

graphics/26fig15.gif

NOTE: Figure 26-15 represents only a brief sample showing how to access the Template property of a posting. Templates are covered in depth in Chapters 9, 10, 11, 12, and 16, and make many other cameo appearances throughout the book.


Approvers

The Approvers collection property of a Posting object contains the list of users that could potentially approve the posting. If the optional parameter is passed as true, all users and the members of all NT groups that have rights to approve the referencing Posting object will be included. But if the optional parameter is passed as false or isn't passed at all, only the users and groups (not their members) will be included. Obviously, the list of editors or moderators that have rights to approve the referencing Posting object will depend on the posting's state. When a posting is in WaitingForEditorApproval state, the users from the editor rights group will populate the list. When a posting is in WaitingForModerator Approval state, the users from the moderator rights group will populate the list. Although CMS administrators, template designers, or channel managers are allowed to approve the posting, they are not included in the list.

This property is useful to proactively notify the appropriate users when a posting's state changes. To see the Approvers, the posting will need to be in a Waiting For Approvers state; otherwise, it will return an empty collection.

Replace the Button1_Click function of our Scratchpad template with the following code:

 private void Button1_Click(object sender, System.EventArgs e) {   try   {     //1. Put current Posting into variable     Posting cmsPosting = CmsHttpContext.Current.Posting;     //2. Populate the label with informational text     Label1.Text =       HttpUtility.HtmlEncode(cmsPosting.DisplayName.ToString()) +       " Placeholders";     //3. Iterate through the collection of Placeholders     foreach(Placeholder cmsPlaceholder in cmsPosting.Placeholders)     {       //4. Put the Name of each Placeholder into the ListBox       ListBox1.Items.Add(cmsPlaceholder.Name.ToString());     }   }   catch(Exception eError)   {     //5. Provide error feedback to the developer     Label1.Text = "<b>Error: </b>" + eError.Message.ToString();   } } 

Build the solution and then refresh the Scratchpad posting in Internet Explorer, or browse to it and click the Button. The page should reload and look similar to Figure 26-16.

Figure 26-16. Posting Approvers

graphics/26fig16.gif

GetByRelativePath (Inherited from ChannelItem)

The GetByRelativePath property of a posting provides a means to get a channel or posting relative to the current posting's Path. This concept was covered in detail in Chapter 25 regarding a channel and is identical for a posting. See the Working with Channel Objects section near the end of Chapter 25 for details and a code sample.



Microsoft Content Management Server 2002. A Complete Guide
Microsoft Content Management Server 2002: A Complete Guide
ISBN: 0321194446
EAN: 2147483647
Year: 2003
Pages: 298

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net