Practical Module Functions (pmf) – an overview

pmf is a Library for Website Baker CMS to create modules with ease — or at least, to avoid the most annoying tasks.

pmf is hosted on launchpad.

pmf is not released, yet!

What are the most annoying tasks in module programming?

Template handling

The old way

Here is a typical phplib-Template to create a <select>-Button:

phplib-Template

<tr>
    <td class="setting_name">{SORT_THUMBS_STR}:</td>
    <td><select name="sort_thumbs" size="1" style="width: 160px" title="{SORT_THUMBS_TITLE}">
    <!-- BEGIN Sort_Thumbs -->
        <option value="{SORT_THUMBS_VALUE}" {SORT_THUMBS_SELECTED}>{SORT_THUMBS_TEXT}</option>
    <!-- END Sort_Thumbs -->
    </select></td>
</tr>


The PHP-code to fill that template may look like this:

php code for the above template

$t = new Template(dirname(__FILE__).'/htt', 'keep');
$t->set_file('settings', 'settings.htt');
 
$t->set_var(array(
    'SORT_THUMBS_STR' => $MOD_ECARD['SORT_THUMBS_STR'],
    'SORT_THUMBS_TITLE' => $MOD_ECARD['SORT_THUMBS_TITLE']
));
$t->set_block('settings', 'Sort_Thumbs', 'SORT_THUMBS');
foreach($sort as $v=>$text) {
    if($settings['sort_thumbs']==$v)
        $t->set_var('SORT_THUMBS_SELECTED', 'selected="selected"');
    else $t->set_var('SORT_THUMBS_SELECTED', '');
    $t->set_var(array(
        'SORT_THUMBS_VALUE' => $v,
        'SORT_THUMBS_TEXT' => $text
    ));
    $t->parse('SORT_THUMBS','Sort_Thumbs', TRUE);
}
 
$t->pparse('output', 'settings');

Phew! - that sucks!

And to make things worse, phplib is one of the slowest template-engines available. See this link.

pmf's new way

pmf-Template

<tr>
    <td class="setting_name">{{+'Sorting'}}:</td>
    <td><select name="sort_thumbs" size="1" style="width: 160px" title="{{+'Sorting sequence'}}">
    {{foreach($tpl_sort_thumbs as $v=>$text):}}
        <option value="{{_$v}}" {{if($tpl_sort_thumbs_selected==$v):}} selected="selected" {{endif;}}>{{_$text}}</option>
    {{endforeach;}}
    </select></td>
</tr>

php code for the above template

$id = pmf_tpl_create($sh, dirname(__FILE__).'/templates/settings.htt');
 
pmf_tpl_setvar($sh, $id, array(
    'sort_thumbs' => $sort,
    'sort_thumbs_selected' => $settings['sort_thumbs']
));
 
pmf_tpl_echo($sh, $id);

You will notice that from programmer's point of view this is really practical.

As web designer you may argue that it will bring another “programming-language” into effect - but if you look carefully at the template's code, you will notice that it's just plain PHP (alternative syntax)! And - I bet - you know enough PHP to handle this PHP-based Template gracefully. There is no need to learn another “programming-language”, as most template-engines demand to do.

{{ }} is just a shortcut for <?php ?>. {{_ is a shortcut to apply htmlspecialchars() to text automatically.
{{+ is a shortcut to translate the supplied string automatically (if language is available).

caching

Each template is cached (i.e. it is translated to real PHP only once and stored for faster retrieval).

Read more ...


Language-file maintenance

The way WB uses language-files is really annoying: After adding a new language-string you have to alter every single existing language-file, over and over again!

The old way

language-file (DE)

$MOD_ECARD['NO_JS'] = 'Ohne Javascript kann die eCard nicht versendet werden!';
$MOD_ECARD['HEADING'] = 'eCard &Uuml;bersicht';
$MOD_ECARD['HEADING_SETTINGS'] = 'eCard Einstellungen';
...

usage of language-strings

if(!file_exists(WB_PATH .'/modules/news/languages/'.LANGUAGE .'.php')) {
    require_once(WB_PATH .'/modules/news/languages/EN.php');
} else {
    require_once(WB_PATH .'/modules/news/languages/'.LANGUAGE .'.php');
}
 
echo $MOD_ECARD['NO_JS'];


To add a new string, you have to open each existing language file and add that new string.
In case you miss one language-file, or a user uses a private self-translated language-file, those non-existing strings may display nothing, or - in worst case - an error-message.

pmf's new way

pmf uses a gettext-inspired method to generate language-files automatically!
Instead of using cryptic placeholders in your source code, just use English text:

usage of language-strings inside php-code

echo pmf_t($sh, 'Javascript must be enabled to be able to send the eCard');

In Templates, one can use a handy abbreviation:

usage of language-strings inside templates

<h1>{{+'eCard Settings'}}</h1>
<p>
  <strong>{{+'eCard Overview'}}</strong>
</p>
...
<b>{{+'Javascript must be enabled to be able to send the eCard'}}</b>
...


pmf_t() is a function-call to output either the translated string (if present) or the original string.

To add new language-files, just create some empty files inside languages/ named XX_pmf.php. Substitute XX by the language-code to create, e.g. DE_pmf_php.
In the following examples we use the Linux console, but you may use the Explorer instead.

using Linux console

thorn@xen:~$ touch languages/DE_pmf.php
thorn@xen:~$ touch languages/NL_pmf.php
thorn@xen:~$ la languages
drwxr-xr-x 2 thorn thorn 4096 20. Dez 17:19 .
drwxr-xr-x 9 thorn thorn 4096 20. Dez 03:17 ..
-rw-r--r-- 1 thorn thorn    0 20. Dez 17:19 DE_pmf.php
-rw-r--r-- 1 thorn thorn  949 19. Dez 21:13 index.php
-rw-r--r-- 1 thorn thorn    0 20. Dez 17:19 NL_pmf.php

After creation of some empty language-files, we have to call the file update_languages.php. Again we use the Linux console - you may use Firefox instead.

using Linux console

thorn@xen:~$ php update_languages.php

languages/DE_pmf.php
Unique language strings: 3 | Added: 3 | Removed: 0 | Context: 0

languages/NL_pmf.php
Unique language strings: 3 | Added: 3 | Removed: 0 | Context: 0

thorn@xen:~$ la languages
drwxr-xr-x 2 thorn thorn 4096 20. Dez 17:33 .
drwxr-xr-x 9 thorn thorn 4096 20. Dez 03:17 ..
-rw-r--r-- 1 thorn thorn   96 20. Dez 17:33 DE.php
-rw-r--r-- 1 thorn thorn  476 20. Dez 17:33 DE_pmf.php
-rw-r--r-- 1 thorn thorn    0 20. Dez 17:33 DE_pmf.php.bak
-rw-r--r-- 1 thorn thorn  949 19. Dez 21:13 index.php
-rw-r--r-- 1 thorn thorn   96 20. Dez 17:33 NL.php
-rw-r--r-- 1 thorn thorn  476 20. Dez 17:33 NL_pmf.php
-rw-r--r-- 1 thorn thorn    0 20. Dez 17:33 NL_pmf.php.bak

The XX.php-files (e.g. DE.php) are just created for compatibility reasons.
The XX_pmf.php.bak-files are backups.

The file languages/DE_pmf.php now contains:

content of created language-file

$trans['Javascript must be enabled to be able to send the eCard'] = 'Javascript must be enabled to be able to send the eCard'; // translation missing
$trans['eCard Settings'] = 'eCard Settings'; // translation missing
$trans['eCard Overview'] = 'eCard Overview'; // translation missing

Now, (let) translate that file as usual…

content of translated language-file

$trans['Javascript must be enabled to be able to send the eCard'] = 'Ohne Javascript kann die eCard nicht versendet werden!';
$trans['eCard Settings'] = 'eCard Einstellungen';
$trans['eCard Overview'] = 'eCard &Uuml;bersicht';

After changing the language-settings to DE, you will see the German strings automatically. There is no need to include() language-files in your php.code!
In case there is no language-file for the chosen language, or a string is missing in an old language-file, you will just see the original English strings.

After adding more language-strings to your module's source-code, just call update_languages.php again. That will update all existing language-files, but it will keep the already translated strings. – That's really practical!

Read more ...


Database retrieval

The old way

I really dislike WB's method to fetch data from mySQL:

retrieval of a single value

if($query_page = $database->query("SELECT link FROM ".TABLE_PREFIX."pages WHERE page_id = '$page_id'")) {
    if($query_page->numRows() > 0) {
        $page = $query_page->fetchRow();
        echo $page['link'];
    }
}

retrieval of several rows

if($query_post = $database->query("SELECT * FROM ".TABLE_PREFIX."mod_news_posts WHERE active = '1'")) {
    if($query_post->numRows() > 0) {
        while($post = $query_post->fetchRow()) {
            echo $post['title'];
        }
    }
}

Every time these boring if($query→numRows()>0) and while($res=$query→fetchRow()) lines, that's really annoying.

pmf's new way

retrieval of a single value

if($link = pmf_db_query_vars($sh, "SELECT link FROM {TP}pages WHERE page_id = '$page_id'")) {
    echo $link;
}

retrieval of several rows

if($posts = pmf_db_query($sh, "SELECT * FROM {TP}mod_news_posts WHERE active = '1'")) {
    foreach($posts as $post) {
        echo $post['title'];
    }
}

Just do the query. Either there's a result … or not. It's that simple! And practical, isn't it?


Furthermore pmf_db_query_vars() and pmf_db_query() can apply mysql_real_escape_string() to all variables automatically, using printf-syntax:

mysql_real_escape_string() is applied automatically

pmf_db_query($sh, "DELETE FROM `{TP}mod_{MD}_cache`
                   WHERE `identifier`='%s' AND `section_id`=%d", $identifier, $section_id);

{TP} is a shortcut for TABLE_PREFIX. {MD} is a shortcut for $module_directory.
%s inserts the variable's value as string. %d inserts the variable's value as integer.

Read more ...


Settings handling

pmf will ease settings-handling by providing easy to use functions to access your module's settings automatically. The module has to stick to WB's standard method for the settings-table, i.e. the table has to be called mod_moduledirectory_settings, to make this work.

Read more ...


Additional noticeable features

  • Module generator – generates a module-skeleton based on few simple questions. Read more ...
  • Caching – storing of computed Data into the database for faster retrieval. Read more ...
  • Session storage – storing of user-related Data into the Session. Read more ...
  • Debugging – comprehensive debug-system. Read more ...



Back to projects main page

 
projects/practical_module_functions/intro_en.txt · Last modified: 2010-04-30 11:42 by Thomas "thorn" Hornik
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki