This is an example of how to create a blog system powered by the Midgard Create web editing tool. This example follows the principles of literate programming, meaning that it is not only a human-readable document but can also be used to construct the full running blog system using the code examples inside this file.
As this blog system is an example application, we will call it net_example_blog
. This will be used as a namespace in PHP classes and global variables.
To be able to store and display blog posts we have to first define a persistent storage for them. Midgard MVC itself is not in way tied to any storage solution, but in this case we will use the Midgard2 content repository for our data persistence needs. Midgard2 is an object-oriented content store that can be accessed from various programming languages including PHP, Python and Vala.
With Midgard2, the content we want to store must be defined in MgdSchema XML files. In the MgdSchema we will describe a class of persistent object, and its properties.
Let us start with the title of a post. In this case we connect the title also to a RDF definition so that it can be understood by search engines and other semantic tools. The RDF definition we use for titles comes from Dublin Core:
<property name="title" type="string"> <description>Title of a blog post</description> <property>dcterms:title</property> </property>
Then we need to define a holder for the actual post contents. In addition to the regular field definition, we'll also specify that this property holds HTML-formatted contents. We will connect it to the definition of Content from the SIOC specification:
<property name="content" type="text"> <description>Content of the post</description> <contenttype>html</contenttype> <property>sioc:content</property> </property>
Now that we have the actual properties of a post defined, we can define the actual blog post type. We will give it a class name, and also the database table where the posts should be stored:
<?xml version="1.0" encoding="UTF-8"?> <Schema xmlns="http://www.midgard-project.org/repligard/1.4"> <type name="net_example_blog_post" table="net_example_blog_post">
As the properties contain RDF mappings, we will have to provide a list of namespaces defining them here. We also specify a RDF typeOf mapping explaining that our class follows the SIOC description of a Post:
<user_values> <typeof>http://rdfs.org/sioc/ns#Post</typeof> <namespaces>sioc:http://rdfs.org/sioc/ns#,dcterms:http://purl.org/dc/terms/</namespaces> </user_values>
Then we include our properties and a mandatory database ID, and we're done:
<property name="id" type="unsigned integer" primaryfield="id"> <description>Local non-replication-safe database identifier</description> </property> <<blog post properties>> </type> </Schema>
The most important thing in a blog is the list of new posts. The posts are displayed in a time-based order with latest entries shown first.
In order to show our listing of posts on the front page we need to register a Route. Routes are a way to connect a URL request sent by a browser to some PHP code on the server that performs the desired operation and displays the results. Route definitions are specified in the YAML format.
First we give a name to the route, and define the path this route handles:
index: path: '/'
Then we need to provide the name of the controller class, and the action method in that class used to fetch the latest posts:
controller: net_example_blog_controllers_latest action: items
The controller action code is reasonably simple PHP. First we generate a query for fetching latest items:
$qb = new midgard_query_builder('net_example_blog_post'); $qb->add_order('metadata_created', 'DESC');
We want to be able to control the amount of items shown on the front page, and to make this easy to change by configuration later. For this we introduce a new configuration key:
index_items: 6
Now we can use this configuration key to limit the amount of items we query:
$qb->set_limit(midgardmvc_core::get_instance()->configuration->index_items);
Then we need to execute our query, and set the blog items to a list accessible in the display phase:
$items = $qb->execute(); $this->data['items'] = new midgardmvc_ui_create_container(); foreach ($items as $item) { $this->data['items']->attach($item); }
The query method defined above needs to be written into a controller class in order to run:
<?php class net_example_blog_controllers_latest { public function __construct(midgardmvc_core_request $request) { $this->request = $request; } public function get_items(array $args) { <<net_example_blog_controllers_latest::get_items>> } }
The next question then is how to display the news items. For this we define a display template. The display template ought to be registered into the route that we have, through template aliasing. With this alias we tell that template alias called content
should contain the contents of our template called neb-show-latest
:
template_aliases: content: neb-show-latest
To make the template work we need to write it to file matching the template alias set earlier:
<<list of blog items>>
The actual template is defined in HTML using the TAL templating system. TAL enables us to include content set to the data
array of our controller into the generated HTML. To traverse the news items we do the following TAL. First we have a list container, with some RDFa mark-up to explain to the browser that this is a list of items:
<ol mgd:type="container" mgd:order="desc">
Then we can define how an individual item ought to be displayed, and tell TAL to repeat this definition for each item our controller returned. For templates, the data
array of the controller is accessible as a variable matching the name of our component, net_example_blog
:
<li tal:repeat="item net_example_blog/items">
Now we're ready to display an individual blog item. In this case we will wrap each item within a HTML5 article
element for clarity. The item will include RDFa attributes identifying and explaining the data within. These attributes can be hard-coded into the template, or we can use the rdfmapper
tool provided by the framework, as we do in this example:
<article tal:attributes="about item/rdfmapper/about; typeof item/rdfmapper/typeof"> <h1 tal:content="item/title" tal:attributes="property item/rdfmapper/title">Title of a news item</h1> <div tal:content="item/content" tal:attributes="property item/rdfmapper/content"> <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. </p> </div> </article>
Then we just wrap up the template by closing the list:
</li> </ol>
To make our blog installable we need to provide a manifest file explaining the dependencies and routes of the component.
routes: <<blog routes>>
- [RDF]: Resource Description Framework, a way to specify semantic content as subject-predicate-object triples
- [SIOC]: Semantically-Interlinked Online Communities