Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Getting to know Midgard

Content management API for PHP helps you work with dynamically-generated Web applications

David Seager, Software engineer, IBM, Software Group
David Seager, a software developer at IBM, has been working with Linux, PHP, and Web-based technology for more than two years. He's been running the local network gaming club's Web site using Midgard for a year and reckons PHP is the best scripting language ever (well, maybe after Perl).

Summary:  Server-side scripting languages such as PHP are great for creating dynamic, creative, and compelling Web sites. Unfortunately they have always left the mechanics of creating, rendering, and administering dynamic content to the script author -- until now. This article introduces and shows you how to use Midgard, an open-source system based on PHP that takes over the job of looking after content, allowing you to concentrate on site aesthetics and functionality.

Date:  09 Feb 2005
Level:  Introductory
Also available in:   Japanese

Activity:  6738 views
Comments:  

What is Midgard?

Midgard is described in its documentation as an application "for developing and serving... dynamically generated Web applications." It looks like a content management system, and provides distributed content ownership, separation of content from look and feel, serving of sites, and Web-based administration.

Once you've got PHP up and running and you've taken care of MySQL connectivity, the next step is to get some database-driven content working. After a good deal of hacking, you might have a news page that takes articles from a database, with a Web front-end for editing and creating these articles. If your code is like mine, it might not be very pretty or maintainable -- it could be a jumble of SQL statements and array manipulation -- but it's all yours.

On a very basic technical level, Midgard provides a content management API for PHP that makes managing such articles a whole lot easier and administering them a snap. It introduces some of its own content management concepts to help you organize articles more logically and deal with them easily. It can implement security, allowing only authorized users to update or view content, and recording personal information about users.

Midgard comes packaged with two Web sites (records in a sample MySQL database): an example site for the "Virtual Midgard Using Company" and the admin site -- a complete Web-based content management system that can be used out-of-the-box to administer Web sites.


How I use Midgard

I first started using Midgard when I was looking to set up a Web site for our network gaming club. I wanted the entire committee to be able to alter content on the Web site (add news, files, FAQ entries, and so on), and a nice straightforward way to generate the content dynamically. Having already done the PHP hacking to get a rough draft of the site working for a different project, I was faced with either rewriting it all from scratch (to get it up to the quality I wanted) or trying something different. Midgard was that something.


Installation

The easiest way to install Midgard is to get the Apache-Midgard packages from www.midgard-project.org and follow the installation guide. These packages contain the Apache Webserver and PHP with Midgard extensions. You'll also need the MySQL server from www.mysql.org. (See Resources for links to these sites.)


Midgard concepts

Midgard divides a typical Web site into pieces using its own content concepts. These are topics, articles, hosts, pages, and styles. Each type of content can be administered using the admin site. Within each type of content, each definition has a unique ID that you can use to refer to it.

Distributed content ownership can be implemented using person and group records in the Midgard database. From the admin site, the Midgard Administrator (the default user account created when Midgard is set up) can create persons and groups. Person records have a whole load of attributes such as name, address, e-mail address, homepage, and description. They can also be assigned a Midgard logon user account (when modifying the person on the admin site) so they can administer content over the Web and change their own details. Group records also have lots of details -- name, description, and so forth -- and persons listed on the system can be organized into groups (when modifying a group on the admin site). This becomes important because typically other items in the system (such as hosts, articles, and other groups) are owned by a particular group. Members of the owning group can modify these items through the admin Web site, which provides a distributed content ownership system.

For my club Web site, I created a group for the club committee ("NGS Committee") and person records for each committee member. I then added these to the committee group and finally gave each person a user account so they could log on and modify content over the Web. I also created a group for those responsible for the Web site (called "NGS Admins") and added my person record to it.


Laying out Web sites using styles

A style defines how a Web site will look and how its content will fit into it. Like other Midgard elements, a style is owned by a group; only members of that group can alter a style. A style is made up of style elements, each of which has a name and some content. A style's content is a piece of HTML that can refer to other elements to include their HTML (rather like a server-side include) as well as PHP and PHP Midgard commands. The important style element is called ROOT and is used first by Midgard when building a Web site page. Style records that are defined as "new child style" inherit style elements from their parent records.

Style records can be manipulated from the Layout Administration section of the admin site. For my club Web site, I defined a new top level style, called it "NGS Style," and made the NGS Admin group the owner (to do this, you have to be logged in as Midgard Administrator):


Figure 1

<html> 
<head> 
<title>
</title> 
</head> 
<body bgcolor="black" text="white"> 
<table border=0> 
  <tr> 
    <td>
</td> 
    <td><[content]></td> 
  </tr> 
</table> 
</body> 
</html> 

Notice that <(title)> appears within the <title> tags. This pulls the title field from the page being displayed and uses its contents in the HTML title. Those <td> tags are references to other style elements called navigator and content, respectively. Here's an example of a navigator style element:

<a href="/">Home page</a> 
<a href="/news/">News</a> 
<a href="/about/">About the club</a> 

The navigator can also contain references to other style elements and you can create as many of them as you need.

The content reference in the ROOT style element is a special one. This is the actual Web site content, which comes from Midgard and, in this case, the NGS Committee members. You don't need to further define a content style element.

A fairly simple style, then, can be extended to include a page header, page footer, search field, or whatever else you want. Putting each in its own style element simplifies editing the HTML and imposes some logical structure on the process.

Using multiple style elements also allows child styles to override style elements. For example, you could easily make a version of the Web site with a different footer by using a child of the original style, then adding a style element with the same name as the footer element of the parent and coding the new footer in it.


Storing dynamic content

Content management is performed using article records and topics. Article records have a title, a name, an abstract, content, an author, and other fields. Articles track modifications to themselves and can be locked by the author to prevent anyone else from making alterations. Articles are organized under topic records, each belonging to a single topic, and can be programatically retrieved through their unique ID.

Each topic has a name, description, and several other fields, and is owned by a group that controls who can add and modify the articles associated with a topic, as well as modify the topic itself. Topics can also be organized under other topics; the top-level topic forms the root of a Web site's topic tree, and subtopics and articles collected using various topics fall underneath it.

Details of a topic can be retrieved using that topic's unique ID. The articles under it can be retrieved one by one.

Article permissions work in a cumulative fashion for subtopics; the owning groups of all parent topics get permissions for a topic. To lock a particular topic down to a certain group, it's important to make sure parent topics are not owned by any other groups.


Adding content

Content can be managed from the Content Administration section of the admin site.

For my club site, I defined a new top-level topic called "NGS," gave the NGS Admins ownership, and entered a few descriptive words (logged in as Midgard Administrator):


Figure 2

To create some descriptive text for the front page that site administrators can update, I created a new article under this topic, giving it the title "Home page," the name "Home," a brief abstract, and some details in the description field:


Figure 3

Note the unique article ID assigned to this is 33, although the ID depends on how many articles are already defined and may well be different on another system.

To add some dynamic news that committee members can manage, I created a new subtopic called "News," giving the NGS Committee ownership. This lets members of the committee group alter and define news for themselves, ideally assuring a good flow of information. The topic ID on my system is 23.

Finally, I defined a test news article with a suitably catchy title, a small abstract, and a full article for the content.


Figure 4

Topics and articles help organize the dynamic content of a Web site but don't define how the information is linked together. This is what the host and page records are used for.


Defining Web sites with hosts

A host describes the Web-serving nuts and bolts of a Web site -- the host and the port it runs on, the owning group of the site, the site style, and the home page (the "root page"). Host records can be manipulated from the Host Administration section of the admin site.

For my club site, I listed port 8090, the NGS Web site style, and NGS Admins as owners. The name is the host name and domain of the Web server. Since I wanted to start from scratch, I used the [new root page] setting for the root page:


Figure 5

The Host definition and port information are closely tied to entries in the Apache Web server configuration file, httpd.conf. For a host to work, it must have a VirtualHost entry in httpd.conf. For my test site, the entries were as follows:

Listen 8090 

NameVirtualHost 127.0.0.1:8090 

<VirtualHost 127.0.0.1:8090> 
ServerName ngs.domain.com 
DocumentRoot "/home/djs/ngs" 
Port 8090 
</VirtualHost> 

Tip: Although most of your content will naturally come from Midgard, you'll want to store things like images and downloadable files within the traditional file system. The DocumentRoot in the VirtualHost definition determines where URLs not recognized by Midgard come from. For example, all the images for my site are in /home/djs/ngs/images, which I can then access using the URL http://ngs.domain.com/images/.

Defining a host using the Midgard admin site creates an entry in the host table in the midgard database like the following:

mysql> USE midgard; SELECT * FROM host WHERE port='8090'; 
| id | name                  | root | style | info | owner | port | online | prefix | 
|  5 | ngs.domain.com |   41 |    3 |          |     3     | 8090 |      0 |        | 


Taking sites up and down

With the Host Admin part of the admin site, a Web site can be taken offline (users trying to access the site will get a 403 Forbidden response) or put online. The Web site and the root page can be switched to any other available style, making those necessary site look-and-feel transitions easy.

When I created the new host, Midgard created a new page for me, which can be managed from the Page Admin section on the admin site. This page is linked to when the host record is viewed.


Building a Web site with pages

Page records define the structure of the Web site, specifically the URLs used to access the different parts of the site, the content that appears on each, and which parts are static and which dynamic. Each page has a name, a title, a style (which can be inherited so the overall host style is preserved across Web site pages), an author, and some content. Whether or not authentication is required can also be set per page or inherited. Each page has a type that determines whether it can read the rest of the URL specified after its location as input parameters (for the page "news," loading /news/10.html makes the 10.html bit available as a parameter to the script, for example) or whether it's just a plain page. The former is an active page and the latter a static one, although static pages can use PHP and be fairly dynamic.

Pages can have subpages and page elements. Making a subpage creates a page that can be accessed using the URL /<parent page name>/<subpage name>/, so for example when put under the root page, a subpage can be accessed as /<subpage name>/. For a URL such as /news/extra/, you would create a subpage under the news subpage called "extra." A page element is very much like a style element; it's a piece of HTML that can be included in a page's content using the <[element name]> syntax.

A page's content will typically contain PHP code that retrieves an article and uses its contents to write out some HTML, or a collection of articles under a topic to create a list of items (such as news articles) for visitors to choose from. The root page is the page used as the Web site root (such as /).


Structuring pages

I gave the club root page the name "NGS," the title "Network Gaming Subsection," made it static, and added some PHP code to the content that gets the article I created for the home page text:

<? $article = mgd_get_article(33); ?> 
<h2>&(article.title);</h2> 

<p> 
&(article.abstract); 

&(article.content:h); 

This demonstrates two concepts that are useful when writing Midgard code. First, I used the mgd_get_article function, which takes the unique ID of the article and returns a handle to the article. Along with every other Midgard PHP function this one begins with mgd_. Second, to actually write out the fields of the article I used the format &(<article handle>.<field>); in ordinary HTML. For example, &(article.title); writes out the title field of the article. I can also specify how the field content is written out: The :h in &(article.content:h); tells Midgard to render the content field as HTML, which will do things like put <br> and <p> tags in, replace list-like structures with HTML lists, and so on.

You can find a full list of format modifiers in the Midgard documentation under "Formatting Engine" (see Resources for a link).

Below that, I added some code to retrieve articles from my news topic and display the title and abstract of the first three, with links to the news page to read the full article:

<? 
 $article = mgd_list_topic_articles_all(23); 
  if($article) 
  { 
    // show first 3 news articles 
    for($i = 0; $i < 3 && $article->fetch(); $i++) 
    { ?> 
<p> 
<strong><a href="/news/&(article.id);.html">&(article.title);</a></strong> 
<br>&(article.abstract);<br> 
</p> 
<?   } 
    } 
?> 

The first line uses the unique ID of the news topic to retrieve a cursor object, the handle of which is stored in the $article variable. This describes the articles under the given topic. If this is set (that is, there is at least one news article), the method fetch() retrieves the first article and subsequent article each time it is called. To limit the number of articles to the first three, the code puts the fetch() in a for loop. By default, the mgd_list_topic_articles_all function will sort based on the creation date, with the newest articles first, exactly what we want for news. Other sorting options can be used, however, such as by article name, score, or reverse name.

Once the code has fetched an article it again uses the &(<handle>.<field>); syntax to display the title and abstract of the article. It also links the article title to the URL /news/<article ID>.html. This refers the link to an active subpage called "news," which takes the article ID as a parameter.


Making a dynamic news Web page

active

<? 
  if($argc == 1) 
  { 
    $id = $argv[0]; 
  } 
  if($id) 
  { 
    $article = mgd_get_article($id); 
  } 
  if($article) 
  { 
?> <[article]> <? 
  } 

For an active page, the parameters, which are obtained from the extra part of the URL, are passed in using the familiar $argv array with the $argc variable specifying the length. Midgard is a little clever when getting these parameters, though; it will strip the .html from the end, so the URL /news/10.html will result in one parameter in the argv array with the value 10. You can specify further parameters by separating them with slashes (/news/sports/10/, for example), but I'm only using one here, which represents the unique ID of the article to be displayed. If an article has been specified, the code retrieves it and uses the article page element to render it.

  else 
  { 
?> 
<h3>News</h3> 
<? 
  $article = mgd_list_topic_articles_all(23); 
  if($article) 
  { 
    while($article->fetch()) 
    { 
      ?> 
<p> 
<strong><a href="&(article.id);.html">&(article.title);</a></strong> 
   <font size=-1>&(article.adate);</font>
&(article.abstract);
</p> 
<?  } 
  } 
  } 
?> 


Rendering an article's content

This outputs the article title in a nice header, the date in a smaller font, and the article content as HTML. It also puts a small link back to the news page at the bottom of the article. Of course the content of the article page element could have been embedded into the news page if I'd wanted to, but separating them out keeps things kinda neat and tidy.

code-init$id

'code-init' page element content: 
<? 
  if($argc == 1) 
  { 
    $id = $argv[0]; 
  } 
  if($id) 
  { 
    $article = mgd_get_article($id); 
  } 
?> 

$article

<P>Partial style element content: 
<title><? 
if($article) 
{ 
  ?>NGS - &(article.title);<? 
} 
else 
{ 
  ?><(title)><? 
} 
?></title> 

To finish off the site I added an /about page by creating a static subpage of the Root page called "about" and writing some informative content.


Listing the members of a group

Just as article records can be retrieved from a Topic ID, person records can be accessed from a Group ID.

3mgd_list_membersuid$personmgd_get_personmgd_list_members

<? 
  $person = mgd_list_members(3); 
  if($person) 
  { 
    while($person->fetch()) 
    { 
      $persondetails = mgd_get_person($person->uid); 
      ?> 
<p> 
<strong>&(persondetails.name);</strong>
&(persondetails.extra); 
<? 
  if($persondetails->email) 
  { 
?> 
<a href="mailto:&(persondetails.email);"><font size=-1>&(persondetails.email);</font></a> 
<? 
  } 
?> 
</p> 
<?  } 
  } 
  else 
  { 
?> 
There are no committee members! =) 
<? 
  } 
?> 

The code outputs the name, extra, and e-mail fields of the person records that use the same &(<variable>.<field>); syntax I used for articles, but checks to see if there's anything in the e-mail field (if there's nothing in this field, the code won't output an e-mail link).


Conclusion

The site I created is only a very simple example of what is possible with Midgard. My NGS Committee members can now log on to the server and create news articles. As a member of the NGS Admins, I can alter the descriptive text on the home page as well as the style and pages. Midgard provides a load of PHP functions that can be used to extend the functionality of your Web site; for a good example check out the source to the admin site -- which is, of course, a Midgard site!


Resources

About the author

David Seager, a software developer at IBM, has been working with Linux, PHP, and Web-based technology for more than two years. He's been running the local network gaming club's Web site using Midgard for a year and reckons PHP is the best scripting language ever (well, maybe after Perl).

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=11479
ArticleTitle=Getting to know Midgard
publish-date=02092005
author1-email=
author1-email-cc=