9

Filing the content

Create site20 by copying site19.

  1. /cms
    1. ...
    2. site19
    3. site20

In this chapter, we are going to organize nodes in threads.

To test the result online, enter http://www.frasq.org/cms/site20/en/thread/1 in the address bar of your navigator. The site displays the content of thread 1 in English. Enter http://www.frasq.org/cms/site20/fr/fil/1 to display its translation in French.

A thread has a title, a name, an abstract and a cloud of words associated to it. A thread contains an ordered list of nodes. Click on the link Legal information to display node 1.

Start the command processor of MySQL and enter in the site's DB:

$ mysql -u root -p
mysql> use frasqdb2;

NOTE: Use phpMyAdmin for more comfort.

Add the table thread then the table thread_locale to the DB of the site:

CREATE TABLE thread (
  thread_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  user_id INT(10) NOT NULL DEFAULT '1',
  thread_type enum('thread') NOT NULL DEFAULT 'thread',
  created datetime NOT NULL,
  modified datetime NOT NULL,
  PRIMARY KEY (thread_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

thread contains the properties of a node which are in common for all languages: its identifier, the identifier of the user who has modified it for the last time, the type of the thread, its creation and modification dates. The type of a thread will allow a particular interpretation of its contents - book, blog, forum, wiki etc. The primary key of a thread is its identifier.

CREATE TABLE thread_locale (
  thread_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  locale enum('fr','en') NOT NULL DEFAULT 'fr',
  name VARCHAR(100) NOT NULL,
  title VARCHAR(100) NOT NULL,
  abstract text,
  cloud text,
  PRIMARY KEY (thread_id,locale)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

A thread_locale contains the properties of a thread which depend on a language: the designation of language of the content, the name of the thread, its title, the abstract and the list of words associated to the thread. The identifier of a thread_locale matches the identifier of a thread. The designations of the languages must match the languages listed by the configuration parameter $supported_languages defined in the file includes/config.inc. The primary key of a thread_locale is its identifier and the designation of the language of its content.

The link between a thread and the nodes it contains is done by the table thread_node:

CREATE TABLE thread_node (
  thread_id INT(10) UNSIGNED NOT NULL,
  node_id INT(10) UNSIGNED NOT NULL,
  `number` INT(4) UNSIGNED NOT NULL,
  PRIMARY KEY (thread_id,node_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

A thread_node lists and orders the nodes of a thread. The identifier thread_id matches the identifier of a thread. node_id matches the identifier of a node in node. The primary key of a thread_node is the identifier of a thread and the identifier of a node.

Create a first thread:

INSERT INTO thread (thread_id, user_id, `type`, created, modified) VALUES
(1, 1, 'thread', NOW(), NOW());

Thread 1 is created by the user 1, the administrator of the site. Check in the table user.

Add a content in English:

INSERT INTO thread_locale (thread_id, locale, name, title, abstract, cloud) VALUES
(1, 'en', 'folder', 'Folder', 'Articles, notes and various pages.', 'articles notes information');

Add the version en French:

INSERT INTO thread_locale (thread_id, locale, name, title, abstract, cloud) VALUES
(1, 'fr', 'classeur', 'Classeur', 'Articles, notes et pages diverses.', 'articles notes informations');

Associate node 1 to thread 1 and place it at position 1:

INSERT INTO thread_node VALUES(1, 1, 1);

Try a few requests on the DB:

SELECT thread_id FROM thread WHERE thread_id=1 LIMIT 1;

Checks that thread 1 has been created.

SELECT thread_id FROM thread_locale WHERE name='folder' LIMIT 1;

Checks the name of thread 1 in English.

SELECT tn.node_id AS node_id FROM thread_node tn WHERE tn.thread_id=1 AND tn.node_id=1 LIMIT 1;

Checks that node 1 belongs to thread 1.

SELECT tn.node_id AS node_id FROM thread_node tn JOIN node_locale nl ON nl.node_id=tn.node_id WHERE tn.thread_id=1 AND nl.name='legal-information' LIMIT 1;

Returns the identifier of the node of thread 1 according to its name in English.

SELECT tn.node_id, `tn.number` AS node_number, nl.name AS node_name, nl.title AS node_title, nl.abstract AS node_abstract, nl.cloud AS node_cloud FROM thread_node tn JOIN node_locale nl ON nl.node_id=tn.node_id AND nl.locale='en' WHERE tn.thread_id=1 ORDER BY `tn.number`

Returns all the properties of all the nodes of thread 1 in English.

Add the file thread.inc in the folder models with the following content:

  1. function thread_id($thread) {
  2.     if (is_numeric($thread)) {
  3.         $tabthread=db_prefix_table('thread');
  4.  
  5.         $sql="SELECT thread_id FROM $tabthread WHERE thread_id=$thread LIMIT 1";
  6.     }
  7.     else {
  8.         $sqlname=db_sql_arg($thread, true);
  9.  
  10.         $tabthreadlocale=db_prefix_table('thread_locale');
  11.  
  12.         $sql="SELECT thread_id FROM $tabthreadlocale WHERE name=$sqlname LIMIT 1";
  13.     }
  14.  
  15.     $r = db_query($sql);
  16.  
  17.     return $r ? $r[0]['thread_id'] : false;
  18. }

thread_id returns the thread_id of the thread whose identifier or name is $thread, or false if a thread with thread_id or thread_name set to $thread doesn't exist.

  1. function thread_node_id($thread_id, $node) {
  2.     if (is_numeric($node)) {
  3.         $tabthreadnode=db_prefix_table('thread_node');
  4.  
  5.         $sql="SELECT tn.node_id AS node_id FROM $tabthreadnode tn WHERE tn.thread_id=$thread_id AND tn.node_id=$node LIMIT 1";
  6.     }
  7.     else {
  8.         $sqlname = db_sql_arg($node, true);
  9.  
  10.         $tabthreadnode=db_prefix_table('thread_node');
  11.         $tabnodelocale=db_prefix_table('node_locale');
  12.  
  13.         $sql="SELECT tn.node_id AS node_id FROM $tabthreadnode tn JOIN $tabnodelocale nl ON nl.node_id=tn.node_id WHERE tn.thread_id=$thread_id AND nl.name=$sqlname LIMIT 1";
  14.     }
  15.  
  16.     $r = db_query($sql);
  17.  
  18.     return $r ? $r[0]['node_id'] : false;
  19. }

thread_node_id returns the node_id of the node contained in the thread $thread_id whose identifier or name is $node, or false if thread $thread_id doesn't contain a node with node_id or node_name set to $node.

  1. function thread_get($lang, $thread_id) {
  2.     $sqllang=db_sql_arg($lang, false);
  3.  
  4.     $tabthread=db_prefix_table('thread');
  5.     $tabthreadlocale=db_prefix_table('thread_locale');
  6.  
  7.     $sql="SELECT tloc.name AS thread_name, tloc.title AS thread_title, tloc.abstract AS thread_abstract, tloc.cloud AS thread_cloud, t.thread_type AS thread_type, UNIX_TIMESTAMP(t.created) AS thread_created, UNIX_TIMESTAMP(t.modified) AS thread_modified FROM $tabthread t JOIN $tabthreadlocale tloc ON tloc.thread_id=t.thread_id AND tloc.locale=$sqllang WHERE t.thread_id=$thread_id LIMIT 1";
  8.  
  9.     $r = db_query($sql);
  10.  
  11.     return $r ? $r[0] : false;
  12. }

thread_get returns all the attributes for the language $lang of the thread whose identifier is $thread_id, or false in case of error. Notice that the fields thread_created and thread_modified are converted to a Unix time.

  1. function thread_get_contents($lang, $thread_id) {
  2.     $sqllang=db_sql_arg($lang, false);
  3.  
  4.     $tabthreadnode=db_prefix_table('thread_node');
  5.     $tabnodelocale=db_prefix_table('node_locale');
  6.  
  7.     $sql="SELECT tn.node_id, tn.number AS node_number, nl.name AS node_name, nl.title AS node_title, nl.abstract AS node_abstract, nl.cloud AS node_cloud FROM $tabthreadnode tn LEFT JOIN $tabnodelocale nl ON nl.node_id=tn.node_id AND nl.locale=$sqllang WHERE tn.thread_id=$thread_id ORDER BY tn.number";
  8.  
  9.     $r = db_query($sql);
  10.  
  11.     return $r;
  12. }

thread_get_contents returns the content of the thread $thread_id for the language $lang, or false in case of error.

Create the action thread by adding the file thread.php then the file threadsummary.php in the folder actions with the following contents:

  1. /cms/site20
    1. actions
      1. thread.php
      2. threadsummary.php
  1. function thread($lang, $arglist=false) {
  2.     $thread=false;
  3.  
  4.     if (is_array($arglist)) {
  5.         if (isset($arglist[0])) {
  6.             $thread=$arglist[0];
  7.         }
  8.     }
  9.  
  10.     if (!$thread) {
  11.         return run('error/notfound', $lang);
  12.     }
  13.  
  14.     require_once 'actions/threadsummary.php';
  15.  
  16.     return threadsummary($lang, $thread);
  17. }
  1. require_once 'models/thread.inc';
  2.  
  3. function threadsummary($lang, $thread) {
  4.     $thread_id = thread_id($thread);
  5.     if (!$thread_id) {
  6.         return run('error/notfound', $lang);
  7.     }
  8.  
  9.     $r = thread_get($lang, $thread_id);
  10.     if (!$r) {
  11.         return run('error/notfound', $lang);
  12.     }
  13.     extract($r); /* thread_name thread_title thread_abstract thread_cloud */
  14.  
  15.     head('title', $thread_title);
  16.     head('description', $thread_abstract);
  17.     head('keywords', $thread_cloud);
  18.  
  19.     $validate=url('thread', $lang) . '/'. $thread_name;
  20.     $banner = build('banner', $lang, compact('validate'));
  21.  
  22.     $r = thread_get_contents($lang, $thread_id);
  23.  
  24.     $thread_contents = array();
  25.  
  26.     if ($r) {
  27.         $node_uri = url('node', $lang);
  28.         foreach ($r as $c) {
  29.             extract($c);    /* node_id node_name node_title node_number */
  30.             $node_url = $node_uri . '/' . $node_id;
  31.             $thread_contents[] = compact('node_title' , 'node_url');
  32.         }
  33.     }
  34.  
  35.     $content = view('threadsummary', $lang, compact('thread_title', 'thread_abstract', 'thread_cloud', 'thread_contents'));
  36.  
  37.     $output = layout('standard', compact('banner', 'content'));
  38.  
  39.     return $output;
  40. }

To give access to the thread action, add an alias for each language in the file includes/aliases.inc:

  1.         'thread'                => 'thread',
  1.         'fil'                   => 'thread',

Add the view of the summary of a thread in the folders views/en for the English version and views/fr for the version in French:

  1. /cms/site20
    1. views
      1. en
        1. threadsummary.phtml
      2. fr
        1. threadsummary.phtml
  1. <h3><?php echo htmlspecialchars($thread_title, ENT_COMPAT, 'UTF-8'); ?></h3>
  2. <?php if ($thread_abstract): ?>
  3. <h5>Abstract</h5>
  4. <p><?php echo htmlspecialchars($thread_abstract, ENT_COMPAT, 'UTF-8'); ?></p>
  5. <?php endif; ?>
  6. <?php if ($thread_cloud): ?>
  7. <h6>Cloud</h6>
  8. <p class="smaller"><?php echo htmlspecialchars($thread_cloud, ENT_COMPAT, 'UTF-8'); ?></p>
  9. <?php endif; ?>
  10. <h4>Contents</h4>
  11. <ol>
  12. <?php foreach ($thread_contents as $c): ?>
  13. <?php extract($c)/* node_title node_url */ ?>
  14. <li><a href="<?php echo $node_url; ?>"><?php echo htmlspecialchars($node_title, ENT_COMPAT, 'UTF-8'); ?></a></li>
  15. <?php endforeach; ?>
  16. </ol>
  1. <h3><?php echo htmlspecialchars($thread_title, ENT_COMPAT, 'UTF-8'); ?></h3>
  2. <?php if ($thread_abstract): ?>
  3. <h5>Extrait</h5>
  4. <p><?php echo htmlspecialchars($thread_abstract, ENT_COMPAT, 'UTF-8'); ?></p>
  5. <?php endif; ?>
  6. <?php if ($thread_cloud): ?>
  7. <h6>Nuage</h6>
  8. <p class="smaller"><?php echo htmlspecialchars($thread_cloud, ENT_COMPAT, 'UTF-8'); ?></p>
  9. <?php endif; ?>
  10. <h4>Contenu</h4>
  11. <ol>
  12. <?php foreach ($thread_contents as $c): ?>
  13. <?php extract($c)/* node_title node_url */ ?>
  14. <li><a href="<?php echo $node_url; ?>"><?php echo htmlspecialchars($node_title, ENT_COMPAT, 'UTF-8'); ?></a></li>
  15. <?php endforeach; ?>
  16. </ol>

Enter http://localhost/cms/site20/en/thread/1 then http://localhost/cms/site20/fr/fil/1 in the address bar of your navigator.

Comments

To add a comment, click here.