Kniblet Tutorial Part 9
From n² wiki
<< Part 8 | Index | Part 10 >>
Adding Topics
As we add more and more articles we're going to need a way to organise them. There are various possibilities such as tagging or categorisation. We're going to try something a little bit different and group articles into topics. Each topic will have its own page that can list relevant articles and, conversely, each article can be associated with multiple topics if necessary. This gives us flexibility for the future for people to express an interest in a particular topic or even rate their level of expertise within a topic. As we add other types of resource to Kniblet beyond simple articles we might expect the topics to become hubs of knowledge.
First, as always, we want to design the URI structure for our topics. Like we did for articles we'll use the list/item pattern. So, for the list of topics we'll choose to use:
http://kniblet.com/topics
and each individual topic will have URIs following this pattern:
http://kniblet.com/topics/{topic-name}
The different formats are accesible using URIs like:
http://kniblet.com/topics/{topic-name}/{format-name}
class Topic { var $graph; var $uri; function __construct($uri = null, $graph = null) { $this->uri = $uri; if (null == $graph) { $this->graph = new SimpleGraph(); } else { $this->graph = $graph; } } function get_vars() { $vars = Array('title'=>'', 'body'=>''); if ( null != $this->uri) { $vars['title'] = $this->graph->get_first_literal($this->uri, DC_TITLE, ''); } return $vars; } function calculate_changeset($vars, $creator_name, $change_reason) { $new = new SimpleGraph(); if ( null != $this->uri) { $new->add_resource_triple( $this->uri, RDF_TYPE, 'http://schemas.talis.com/kniblet/Topic' ); $new->add_literal_triple( $this->uri, DC_TITLE, $vars['title'] ); } $changeset = new Changeset(array( 'subjectOfChange'=>$this->uri, 'before_rdfxml' => $this->graph->to_rdfxml(), 'after_rdfxml' => $new->to_rdfxml(), 'creatorName' => $creator_name, 'changeReason' => $change_reason, 'createdDate' => gmdate(DATE_W3C, time()), )); return $changeset; } }
class TopicController extends k_Controller { function describe_topic() { $uri = $this->url(); $store = new Store(STORE_URI); $meta = $store->get_metabox(); $desc = $meta->describe_to_simple_graph($uri); return $desc; } function generate_response($type, $content) { $response = new k_http_Response(200); $response->setHeader("Content-type", $type); $response->setContent($content); throw $response; } function forward($name) { if ($name == 'rdf') { $desc = $this->describe_topic(); $this->generate_response("application/rdf+xml", $desc->to_rdfxml() ); } else if ($name == 'turtle') { $desc = $this->describe_topic(); $this->generate_response("text/plain", $desc->to_turtle() ); } else if ($name == 'json') { $desc = $this->describe_topic(); $this->generate_response("application/json", $desc->to_json() ); } else if ($name == 'edit') { $vars = $this->get_vars_from_topic(); return $this->render("templates/articleedit.tpl.php", $vars); } else { $response = new k_http_Response(404); $response->setHeader("Content-type", "text/html"); $response->setContent("<html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1></body></html>"); throw $response; } } function get_vars_from_topic() { $uri = $this->url(); $desc = $this->describe_topic(); $topic = new Topic($uri, $desc); return $topic->get_vars(); } function GET() { $vars = $this->get_vars_from_topic(); return $this->render("templates/topic.tpl.php", $vars); } }
prefix dc: <http://purl.org/dc/elements/1.1/>
prefix k: <http://schemas.talis.com/kniblet/>
select ?topic ?title
where {
?topic a k:Topic ;
dc:title ?title .
}
order by ?title
class TopicListController extends k_Controller { function forward($name) { if ($name) { if ($name == 'new') { $new_topic = new Topic(); $vars = $new_topic->get_vars(); return $this->render("templates/topicedit.tpl.php", $vars); } else { $next_controller = new TopicController($this, $name); return $next_controller->handleRequest() ; } } else { return $this->GET(); } } function GET() { $vars = array( 'results' => null, 'q' => '' ); $query = "prefix dc: <http://purl.org/dc/elements/1.1/> prefix k: <http://schemas.talis.com/kniblet/> select ?topic ?title where { ?topic a k:Topic ; dc:title ?title . } order by ?title"; $store = new Store(STORE_URI); $sparql = $store->get_sparql_service(); $vars['topics'] = $sparql->select_to_array($query); return $this->render("templates/topiclist.tpl.php", $vars); } function POST() { $title = $this->POST['title']; $uri = 'http://' . $_SERVER["HTTP_HOST"] . '/topics/' . $this->make_slug($title, 28); $article = new Topic($uri); $changeset = $article->calculate_changeset( Array('title' => $title), 'Anonymous Kniblet user', 'Anonymous edit'); $store = new Store(STORE_URI, new Credentials("knibletapp", "rkgm5gqz")); $meta = $store->get_metabox(); $response = $meta->apply_changeset($changeset); $redirect = new k_http_Response(303); $redirect->setHeader("Location", $uri); throw $redirect; } function make_slug($input, $max_length) { $stoplist = Array("a", "an", "and", "as", "at", "before", "but", "by", "for", "from", "is", "in", "into", "like", "of", "off", "on", "onto", "per", "since", "than", "the", "this", "that", "to", "up", "via", "with"); $input = preg_replace("/\\b(" . implode('|', $stoplist) . ")\\b/i", '', $input); $input = preg_replace("/[^-A-Z0-9\s]/i", '', $input); $input = trim($input); $input = preg_replace("/[\s]+/i", '-', $input); $input = strtolower($input); return substr($input, 0, $max_length); } }
<p><a href="/topics/new">Create a new topic</a></p> <?php if (count($topics) > 0) { echo '<h2>Browse Topics</h2>'; echo '<ul>'; foreach ($topics as $item) { echo '<li>'; echo '<a href="' . htmlspecialchars($item['topic']['value']) . '">'; echo htmlspecialchars($item['title']['value']); echo '</a>'; echo '</li>'; } echo '</ul>'; } ?>
<< Part 8 | Index | Part 10 >>

