SlideShare une entreprise Scribd logo
1  sur  93
Good Morning
An Introduction to
Module Development
An Introduction to
Module Development
Or: How To Create Modules Without Becoming a
           Bitter, Angry Little Man
What is a module?


• adds functions or capabilities to CMSMS
• allows more complexity than a plug-in or
  user-defined tag (UDT)
Why a module instead
of a plug-in or UDT?
• multi-language
• install / uninstall / upgrade
• trigger / handle events
• provide infrastructure and functions for
  other modules
What else does the
   module API offer?
• database abstraction (ADODB)
• templating system (Smarty)
• user-input sanitizing
• persistent preferences
• access to CMS configurations
• dependencies management
Module API, cont.

• admin-side permission system
• admin-side tools for tabbed interfaces
• form utilities
• ... and more ...
Types of modules
• plug-ins (e.g., News, Search, FormBuilder)
• content-type modules (e.g., Cataloger)
• infrastructure module support (e.g.,
  CMSMailer, nuSOAP)
• administrative (e.g., ModuleManager)
• event handlers (e.g., UserWarning*)
• filters (e.g., RegTM*)
Types of modules
    • plug-ins (e.g., News, Search, FormBuilder)
    • content-type modules (e.g., Cataloger)
    • infrastructure module support (e.g.,
       CMSMailer, nuSOAP)
    • administrative (e.g., ModuleManager)
    • event handlers (e.g., UserWarning*)
    • filters (e.g., RegTM*)
* modules written for this presentation, source in appendix
Ready? Let’s go!

• “Hello World” module
• create the directory:
  $CMSROOT/modules/HelloWorld
• create the initial module file:
  HelloWorld.module.php
HelloWorld.module.php
<?php

class   HelloWorld extends CMSModule

       {


       function GetName()

       
   {

       
   return 'HelloWorld';

       
   }

        function IsPluginModule()
           {
           return true;
           }

       

       function DoAction($action, $id, $params, $returnid=-1)

       
    {

       
    echo 'Hello World!';

       
    }

       }
?>
Congratulations!
• you’re done!
• next steps:
 • publish Hello World on the Developer’s
    Forge
 • check in to svn or git
 • mention the new module in the Forum
 • wait for fame and fortune to roll in
Uh-oh!
• our first Bitter Angry Little Man alert!
• 3 people filed bug reports / feature requests:
 • “why English only?”
 • “Capitalizing ‘World’ is grammatically
    incorrect.”
  • “I want to use this module in German!”
Solving problems

• reject issue about `World’ capitalization
  (“works for me!”)
• solve other problem by using language files:
 • create directory HelloWorld/lang
 • create initial language file: en_US.php
modules/HelloWorld/lang/en_US.php
<?php

/* CMSROOT/modules/HelloWorld/lang/en_US.php */

$lang['hello_world_string'] = 'Hello World!';

?>
HelloWorld.module.php
<?php

class   HelloWorld extends CMSModule

       {


       function GetName()

       
   {

       
   return 'HelloWorld';

       
   }

       

       function IsPluginModule()

       
   {

       
   return true;

       
   }

       

       function DoAction($action, $id, $params, $returnid=-1)

       
   {

       
   echo $this->Lang('hello_world_string');

       
   }

       }
?>
Translation
• by adding module to Translation Center, it
   can be translated into any language
• add by setting up externals in svn
• instructions at
  http://forum.cmsmadesimple.org/index.php/topic,2639.0.html

• results in lang/ext directory containing
   translation files
HelloWorld/lang/ext/de_DE.php
<?php

$lang['hello_world_string'] = 'Hallo Welt! Grüße!';

?>
Success!

• localized version of the module is available
 • checked into the repository and published
    on the Forge
  • downloaded all over the world
• surely, fame and fortune must follow
Uh-Oh!
• another Bitter Angry Little Man alert!
• more bug reports / feature requests:
 • “I want the message in <h2> tags”
 • “text should be in <p> tags!”
 • “I also want ‘goodbye world’ as an
    option!”
Solutions

• output should use a template to allow
  different formatting
• module should use the DoAction method to
  provide alternate functionality
Templates
• create
  CMSROOT/modules/HelloWorld/templates
  directory
• create your template: hello.tpl
• templates use the Smarty markup language
• you will learn to read and love the Smarty
  manual at http://www.smarty.net/manual/en/
HelloWorld/templates/hello.tpl
{*
smarty template.
CMSROOT/modules/HelloWorld/templates/hello.tpl
*}

<h2>{$mod->Lang('hello_world_string')}</h2>
Changes to HelloWorld.module.php

   function DoAction($action, $id, $params, $returnid=-1)

   
   {

   
   $this->smarty->assign_by_ref('mod',$this);

   
   $this->ProcessTemplate('hello.tpl');

   
   }
Where we’re at

• output is now templated. Site developer
  could edit the hello.tpl to make it output the
  message in any way they wanted
• we still have only one action - the module
  will only display the “hello world” string
Multiple actions


• build out the DoAction method
• initially, we’ll implement it in-line in the
   module
DoAction in HelloWorld.module.php

    function DoAction($action, $id, $params, $returnid=-1)

    
   {

    
   switch ($action)

    
   
   {

    
   
   case 'default':

    
   
   case 'hello':

    
   
   
   {

    
   
   
   $this->_do_hello($id, $params, $returnid);

    
   
   
   break;

    
       
             }

    
   
   case 'goodbye':

    
   
   
   {

    
   
   
   $this->_do_goodbye($id, $params, $returnid);

    
   
   
   break;

    
   
   
   }

    
   
   }

    
   }
DoAction


• special action: default
• we’ll see another special action later
• other parameters will be explained later
Adds to HelloWorld.module.php

   function _do_hello($id, $params, $returnid)

   
   {

   
   $this->smarty->assign_by_ref('mod',$this);

   
   echo $this->ProcessTemplate('hello.tpl');

   
   }

   

   function _do_goodbye($id, $params, $returnid)

   
   {

   
   $this->smarty->assign_by_ref('mod',$this);

   
   echo $this->ProcessTemplate('goodbye.tpl');

   
   }
HelloWorld/templates/goodbye.tpl
{* smarty template.
CMSROOT/modules/HelloWorld/templates/goodbye.tpl *}

<h2>{$mod->Lang('goodbye_world_string')}</h2>
Update lang file
<?php

/* CMSROOT/modules/HelloWorld/lang/en_US.php */

$lang['hello_world_string'] = 'Hello World!';
$lang['goodbye_world_string'] = 'Goodbye you cruel old planet.';

?>
Take a breath

• what we’ve covered so far:
 • basic module file
 • localization
 • templates
 • multiple actions
Oh Noes!
• another Bitter Angry Little Man alert!
• 12 people filed bug reports:
 • “I have one installation that accepts the
    ‘hello’ and ‘goodbye’ actions, and another
    that’s the older version, and I’m confused.”
  • “I have different versions on my sites and
    can’t tell them apart easily.”
Solutions

• we should have the module report its
  version
 • this opens up a can of worms: module
    installation, upgrades, uninstallation
   • which opens up another can of worms:
      separating files
Reporting version

• module method “GetVersion”
• version-related module methods
 • install
 • upgrade
 • uninstall
Adds to module
function GetVersion()

     {

     return '1.0';

     }

     
function Install()

     {
       $this->Audit( 0,$this->GetName(),$this->Lang('installed',
       $this->GetVersion()) );

     }

     
function Uninstall()

     {

     $this->Audit( 0,$this->GetName(),$this->Lang('uninstalled') );

     }

     
function Upgrade($oldversion, $newversion)

     {
       $this->Audit( 0,$this->GetName(),$this->Lang('upgraded',
       $newversion) );

     }
update lang file
<?php

/* CMSROOT/modules/HelloWorld/lang/en_US.php */

$lang['hello_world_string'] = 'Hello World!';
$lang['goodbye_world_string'] = 'Goodbye you cruel old planet.';
$lang['installed'] = 'Hello World version %s installed.';
$lang['uninstalled'] = 'Hello World has been uninstalled.';
$lang['upgraded'] = 'Hello World upgraded to version %s.';

?>
Working backwards

• separate files
 • method.install.php
 • method.upgrade.php
 • method.uninstall.php
Separate file features

• global handle to CMS is defined: $gCms
• security tip: test for the global, so people
  can’t call the file directly and cause trouble
• other variables pre-defined based on
  method that’s been split out
method.install.php
<?php

// security measure
if (!isset($gCms)) exit;

$this->CreatePreference('use_random_phrase','y');

// entry in admin log
$this->Audit( 0,$this->GetName(),

     $this->Lang('installed', $this->GetVersion()) );
?>
method.upgrade.php
<?php

// safety measure
if (!isset($gCms)) exit;

switch($oldversion)
{
 case "0.0.0.1":
  $this->CreatePreference('use_random_phrase','y');
}

$this->Audit( 0, $this->GetName(),

     $this->Lang('upgraded', $newversion));
?>
method.unistall.php
<?php

// safety measure
if (!isset($gCms)) exit;

$this->RemovePreference('use_random_phrase');

$this->Audit( 0,$this->GetName(),

     $this->Lang('uninstalled', $this->GetVersion()) );
?>
Separate actions

• DoAction can also be split into multiple files
• this keeps memory footprint smaller, code
  organization more logical
• each file is called action.action_name.php
• these files also have special pre-set variables
action.action_name.php

• has $gCms defined
• has $id, $params, and $returnid defined
  (more on these later)
• has $smarty defined
action.default.php
<?php

// safety first
if (!isset($gCms)) exit;

$this->_do_hello($id, $params, $returnid)

?>
action.goodbye.php
<?php

// safety first
if (!isset($gCms)) exit;

$this->_do_goodbye($id, $params, $returnid)

?>
Wha??

• where’s our “Hello World?”
• action “hello” is not the same as action
  “default”
• we can either implement action “hello” by
  creating action.hello.php, or change our
  model such that this is the default.
Another deep breath
• what we’ve accomplished:
 • keeping track of module versions
 • providing a clean approach to module
    upgrades and uninstalls
 • breaking module into separate files for
    better memory management
 • set preferences, logged to the admin log
Uh-Oh!
• Bitter Angry Little Man alert!
• 16 people filed feature requests:
 • “I should be able to load in multiple
    messages, not just ‘hello’ and ‘goodbye’!”
  • “Yeah, and they should have the option of
    displaying randomly according to that new
    preference you created!”
The database

• handle to database available via GetDb()
  method
• supports ADODB functionality
• hides a lot of the complexity for table
  creation. see
  http://phplens.com/lens/adodb/docs-datadict.htm
Adds to method.install.php
// get database handle
$db = &$this->GetDb();

// mysql-specific, but ignored by other database
$taboptarray = array( 'mysql' => 'TYPE=MyISAM' );

// database-independent table creation
$dict = NewDataDictionary( $db );
$flds = "phrase_id I KEY AUTO,

       phrase C(255)";

$sqlarray = $dict->CreateTableSQL( cms_db_prefix().
   'module_hello', $flds, $taboptarray);

$dict->ExecuteSQLArray($sqlarray);

$db->Execute('insert into '.cms_db_prefix().
  'module_hello (phrase) values (?)',
  array($this->Lang('hello_world_string') ));
Don’t forget!

• implement similar code in the
  method.upgrade.php
• bump the module’s version number to 1.1
• and implement code that uses the phrases
  from the database
Revised function
function _do_hello($id, $params, $returnid)
  {
  $db = &$this->GetDb();
  if ($this->GetPreference('use_random_phrase','y') == 'y')
      {

       $count = $db->GetOne('select count(phrase) from '.

       
    
    cms_db_prefix().'module_hello');

       $rand_line = rand(1,$count) - 1;

       $res = $db->SelectLimit('select phrase from '.

       
    
    cms_db_prefix().'module_hello',1,$rand_line);

       if ($res && $row=$res->FetchRow())

       
    {

       
    $phrase = $row['phrase'];

       
    }

       }
  else

       {

       $phrase = $db->GetOne('select phrase from '.cms_db_prefix().

       
    
    'module_hello where phrase_id=1');

       }
  $this->smarty->assign('phrase',$phrase);
  echo $this->ProcessTemplate('hello.tpl');
  }
Revised template/hello.tpl
{* smarty template.
CMSROOT/modules/HelloWorld/templates/hello.tpl *}

<h2>{$phrase}</h2>
Fear & loathing

• Angry bitter little man alert!
 • 23 users complained about not being able
    to change the preference
 • 47 users complained about the lack of a
    form to add phrases
Solution


• need to create an admin area for the module
• and need to create an input form
Creating an admin


• HasAdmin() method returns true
• our other magic action: defaultadmin
• separated file: action.defaultadmin.php
Additions to HelloWorld.module.php
function HasAdmin()
  {
  return true;
  }

function VisibleToAdminUser()
  {
  return $this->CheckPermission('Manage All Content');
  }
action.defaultadmin.php
<?php
if (!isset($gCms)) exit;

if (! $this->CheckPermission('Manage All Content')) exit;

if (isset($params['random']) && !empty($params['random']))

       {

       $this->SetPreference('use_random_phrase',$params['random']);

       $smarty->assign('message',$this->Lang('preference_set'));

       }

$smarty->assign('start_form',
   $this->CreateFormStart($id, 'defaultadmin', $returnid));

$smarty->assign('input_pref',$this->CreateInputHidden($id,'random','n').

     $this->CreateInputCheckbox($id, 'random', 'y',

     $this->GetPreference('use_random_phrase','y')).

     $this->Lang('title_use_random_phrase'));

$smarty->assign('submit', $this->CreateInputSubmit($id, 'submit',
   lang('submit')));

echo $this->ProcessTemplate('adminpanel.tpl');
?>
templates/adminpanel.tpl
{if isset($message)}<p class="pagemessage">{$message}</p>{/if}
{$start_form}

       <div class="pageoverflow">

       
   <p class="pagetext">{$input_pref}</p>

       
   <p class="pageinput">{$submit}</p>

       </div>
</form>
Create a user-side form


• very much like the admin side
action.add.php
<?php
if (!isset($gCms)) exit;

if (isset($params['phrase']) && !empty($params['phrase']))

       {

       $db = &$this->GetDb();

       $db->Execute('insert into '.cms_db_prefix().
            'module_hello (phrase) values (?)',

       
    array($params['phrase']));

       $smarty->assign('message',$this->Lang('phrase_added'));

       }

$smarty->assign('start_form',
  $this->CreateFormStart($id, 'add', $returnid));
$smarty->assign('input_phrase',
  $this->CreateInputText($id,'phrase',
     $this->Lang('add_phrase_here'),40,255));
$smarty->assign('submit',
  $this->CreateInputSubmit($id, 'submit', $this->Lang('submit')));
$smarty->assign_by_ref('mod',$this);

echo $this->ProcessTemplate('add.tpl');
?>
add.tpl
{if isset($message)}<p class="pagemessage">{$message}</p>{/if}
{$start_form}

       <fieldset><legend>{$mod->Lang('add_a_phrase')}</legend>

       <div>

       
   <p>{$input_phrase}</p>

       <div>

       <div>

       
   <p>{$submit}</p>

       </div>

       </fieldset>
</form>
What we’ve covered
   API Covered               API Not Covered



                       10%




                 90%
Resources

• the Wiki
  http://wiki.cmsmadesimple.org/index.php/Developers

• Skeleton module
  http://dev.cmsmadesimple.org/projects/skeleton

• IRC
  freenode.net #cms
Bitter, angry little man

• hitting a moving target; keeping up to date
• lots of complaints about the flavors of free
  ice cream available
• give an inch, they’ll ask for a mile
• using module for what it was never meant to
  do
Preparing for CMSMS 2.0
• beware of direct access to API class
  variables! e.g., use $this->GetDb(), don’t use
  $this->db
• no more PHP 4.x-isms
• callbacks are going away! use the event
  system.
• lots more – ORM, etc, so beware!
Calguy’s cardinal rules
• Do not use members of the module object,
  use accessors
• Split everything up into logical classes
• No separate entry points, use actions
• Use the permissions model liberally
• Use separate files for actions, tabs, install/
  upgrade/uninstall actions
Calguy’s rules, cont.
• Cache data where practical data may be read
  (if it's feasible/expected that the
  more than one time in a request).

• Use DEFINES or class constants rather than
  hardcoded strings
• Separate logic from display... use Smarty
• Provide the data to Smarty, let Smarty
  display it.
Calguy’s rules, cont.

• Use ADODB’s parameter cleansing stuff,
  don't build in all the params yourself.
• Keep your code clean.
• Get off my lawn, you kids!
Closing
Closing


• Thanks for your attention
Closing


• Thanks for your attention
• Goodbye cruel world...
Appendix


• module directory structure
• source listings
• random notes
Module directory structure
RegTM Module source
<?php
# extremely simple filter module; adds registered trademark symbol to your company's name

class RegTM extends CMSModule
{

    var $company_name = 'CMS Made Simple';

    function GetName()
    {
      return 'RegTM';
    }

    function GetFriendlyName()
    {
      return 'RegTM';
    }

    function GetVersion()
    {
      return '0.1';
    }

    function GetAuthor()
    {
      return 'SjG';
    }

    function GetAuthorEmail()
RegTM Module source, cont.
    function MinimumCMSVersion()
    {
      return "1.6";
    }

 function SetParameters()
 
{

 $this->AddEventHandler( 'Core', 'ContentPostRender', true );

 }

    function DoEvent( $originator, $eventname, &$params )

    {

    if ($originator == 'Core' && $eventname == 'ContentPostRender')

    
      {

    
      $params['content'] = str_replace($this->company_name,

    
      
     $this->company_name.'<sup>&reg;</sup>',

    
      
     $params['content']);

    
      }

    }
}

// end
?>
User Warning Module source
<?php
# extremely simple event-handler module; sends email to admins giving them warning when a user is deleted.

class UserWarning extends CMSModule
{

 function GetName()
 {
   return 'UserWarning';
 }

 function GetFriendlyName()
 {
   return 'UserWarning';
 }

 function GetVersion()
 {
   return '0.1';
 }

 function GetAuthor()
 {
   return 'SjG';
 }

 function GetAuthorEmail()
 {
   return 'sjg@cmsmodules.com';
User Warning Module source, cont.
function MinimumCMSVersion()
{
  return "1.6";
}

function GetDependencies()
{
  return array('CMSMailer'=>'1.73');
}

function SetParameters()
{
  $this->AddEventHandler( 'Core', 'DeleteUserPre', true );
}
User Warning Module source, cont.
 function DoEvent( $originator, $eventname, &$params )

{

 if ($originator == 'Core' && $eventname == 'DeleteUserPre')


     {


     $db = $this->GetDB();


     $user = $params['user'];


     $result = $db->Execute('select * from '.cms_db_prefix().'users where user_id <>?',
           array($user->id));


     if ($result)


     
     {


     
     $mail =& $this->GetModuleInstance('CMSMailer');


     
     if ($mail != FALSE)


     
     
    {


     
     
    $mail->reset();


     
     
    $mail->SetSubject('Admin User Deleted');


     
     
    $mail->SetBody('FYI: CMS admin user "'.$user->firstname.' '.$user->lastname.


     
     
    
    '" ('.$user->username.') has been terminated.');


     
     
    }


     
     while ($row = $result->FetchRow())


     
     
    {


     
     
    $mail->AddAddress($row['email'],$row['first_name'].' '.$row['last_name']);


     
     
    }


     
     $sent = $mail->Send();


     
     }


     }

}
}

// end
Contact me


• sjg@cmsmodules.com
• drop by next time you’re in L.A.

Contenu connexe

Dernier

New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 

Dernier (20)

New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 

En vedette

PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at WorkGetSmarter
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...DevGAMM Conference
 
Barbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationErica Santiago
 

En vedette (20)

PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 
More than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike RoutesMore than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike Routes
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
 
Barbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy Presentation
 

Geek Moot '09 -- Introduction to CMS Module Development

  • 3. An Introduction to Module Development Or: How To Create Modules Without Becoming a Bitter, Angry Little Man
  • 4. What is a module? • adds functions or capabilities to CMSMS • allows more complexity than a plug-in or user-defined tag (UDT)
  • 5. Why a module instead of a plug-in or UDT? • multi-language • install / uninstall / upgrade • trigger / handle events • provide infrastructure and functions for other modules
  • 6. What else does the module API offer? • database abstraction (ADODB) • templating system (Smarty) • user-input sanitizing • persistent preferences • access to CMS configurations • dependencies management
  • 7. Module API, cont. • admin-side permission system • admin-side tools for tabbed interfaces • form utilities • ... and more ...
  • 8. Types of modules • plug-ins (e.g., News, Search, FormBuilder) • content-type modules (e.g., Cataloger) • infrastructure module support (e.g., CMSMailer, nuSOAP) • administrative (e.g., ModuleManager) • event handlers (e.g., UserWarning*) • filters (e.g., RegTM*)
  • 9. Types of modules • plug-ins (e.g., News, Search, FormBuilder) • content-type modules (e.g., Cataloger) • infrastructure module support (e.g., CMSMailer, nuSOAP) • administrative (e.g., ModuleManager) • event handlers (e.g., UserWarning*) • filters (e.g., RegTM*) * modules written for this presentation, source in appendix
  • 10. Ready? Let’s go! • “Hello World” module • create the directory: $CMSROOT/modules/HelloWorld • create the initial module file: HelloWorld.module.php
  • 11. HelloWorld.module.php <?php class HelloWorld extends CMSModule { function GetName() { return 'HelloWorld'; } function IsPluginModule() { return true; } function DoAction($action, $id, $params, $returnid=-1) { echo 'Hello World!'; } } ?>
  • 12.
  • 13.
  • 14.
  • 15. Congratulations! • you’re done! • next steps: • publish Hello World on the Developer’s Forge • check in to svn or git • mention the new module in the Forum • wait for fame and fortune to roll in
  • 16. Uh-oh! • our first Bitter Angry Little Man alert! • 3 people filed bug reports / feature requests: • “why English only?” • “Capitalizing ‘World’ is grammatically incorrect.” • “I want to use this module in German!”
  • 17. Solving problems • reject issue about `World’ capitalization (“works for me!”) • solve other problem by using language files: • create directory HelloWorld/lang • create initial language file: en_US.php
  • 19. HelloWorld.module.php <?php class HelloWorld extends CMSModule { function GetName() { return 'HelloWorld'; } function IsPluginModule() { return true; } function DoAction($action, $id, $params, $returnid=-1) { echo $this->Lang('hello_world_string'); } } ?>
  • 20. Translation • by adding module to Translation Center, it can be translated into any language • add by setting up externals in svn • instructions at http://forum.cmsmadesimple.org/index.php/topic,2639.0.html • results in lang/ext directory containing translation files
  • 22. Success! • localized version of the module is available • checked into the repository and published on the Forge • downloaded all over the world • surely, fame and fortune must follow
  • 23. Uh-Oh! • another Bitter Angry Little Man alert! • more bug reports / feature requests: • “I want the message in <h2> tags” • “text should be in <p> tags!” • “I also want ‘goodbye world’ as an option!”
  • 24. Solutions • output should use a template to allow different formatting • module should use the DoAction method to provide alternate functionality
  • 25. Templates • create CMSROOT/modules/HelloWorld/templates directory • create your template: hello.tpl • templates use the Smarty markup language • you will learn to read and love the Smarty manual at http://www.smarty.net/manual/en/
  • 27. Changes to HelloWorld.module.php function DoAction($action, $id, $params, $returnid=-1) { $this->smarty->assign_by_ref('mod',$this); $this->ProcessTemplate('hello.tpl'); }
  • 28. Where we’re at • output is now templated. Site developer could edit the hello.tpl to make it output the message in any way they wanted • we still have only one action - the module will only display the “hello world” string
  • 29. Multiple actions • build out the DoAction method • initially, we’ll implement it in-line in the module
  • 30. DoAction in HelloWorld.module.php function DoAction($action, $id, $params, $returnid=-1) { switch ($action) { case 'default': case 'hello': { $this->_do_hello($id, $params, $returnid); break; } case 'goodbye': { $this->_do_goodbye($id, $params, $returnid); break; } } }
  • 31. DoAction • special action: default • we’ll see another special action later • other parameters will be explained later
  • 32. Adds to HelloWorld.module.php function _do_hello($id, $params, $returnid) { $this->smarty->assign_by_ref('mod',$this); echo $this->ProcessTemplate('hello.tpl'); } function _do_goodbye($id, $params, $returnid) { $this->smarty->assign_by_ref('mod',$this); echo $this->ProcessTemplate('goodbye.tpl'); }
  • 34.
  • 35.
  • 36. Update lang file <?php /* CMSROOT/modules/HelloWorld/lang/en_US.php */ $lang['hello_world_string'] = 'Hello World!'; $lang['goodbye_world_string'] = 'Goodbye you cruel old planet.'; ?>
  • 37.
  • 38. Take a breath • what we’ve covered so far: • basic module file • localization • templates • multiple actions
  • 39. Oh Noes! • another Bitter Angry Little Man alert! • 12 people filed bug reports: • “I have one installation that accepts the ‘hello’ and ‘goodbye’ actions, and another that’s the older version, and I’m confused.” • “I have different versions on my sites and can’t tell them apart easily.”
  • 40. Solutions • we should have the module report its version • this opens up a can of worms: module installation, upgrades, uninstallation • which opens up another can of worms: separating files
  • 41. Reporting version • module method “GetVersion” • version-related module methods • install • upgrade • uninstall
  • 42. Adds to module function GetVersion() { return '1.0'; } function Install() { $this->Audit( 0,$this->GetName(),$this->Lang('installed', $this->GetVersion()) ); } function Uninstall() { $this->Audit( 0,$this->GetName(),$this->Lang('uninstalled') ); } function Upgrade($oldversion, $newversion) { $this->Audit( 0,$this->GetName(),$this->Lang('upgraded', $newversion) ); }
  • 43. update lang file <?php /* CMSROOT/modules/HelloWorld/lang/en_US.php */ $lang['hello_world_string'] = 'Hello World!'; $lang['goodbye_world_string'] = 'Goodbye you cruel old planet.'; $lang['installed'] = 'Hello World version %s installed.'; $lang['uninstalled'] = 'Hello World has been uninstalled.'; $lang['upgraded'] = 'Hello World upgraded to version %s.'; ?>
  • 44. Working backwards • separate files • method.install.php • method.upgrade.php • method.uninstall.php
  • 45. Separate file features • global handle to CMS is defined: $gCms • security tip: test for the global, so people can’t call the file directly and cause trouble • other variables pre-defined based on method that’s been split out
  • 46. method.install.php <?php // security measure if (!isset($gCms)) exit; $this->CreatePreference('use_random_phrase','y'); // entry in admin log $this->Audit( 0,$this->GetName(), $this->Lang('installed', $this->GetVersion()) ); ?>
  • 47. method.upgrade.php <?php // safety measure if (!isset($gCms)) exit; switch($oldversion) { case "0.0.0.1": $this->CreatePreference('use_random_phrase','y'); } $this->Audit( 0, $this->GetName(), $this->Lang('upgraded', $newversion)); ?>
  • 48. method.unistall.php <?php // safety measure if (!isset($gCms)) exit; $this->RemovePreference('use_random_phrase'); $this->Audit( 0,$this->GetName(), $this->Lang('uninstalled', $this->GetVersion()) ); ?>
  • 49.
  • 50. Separate actions • DoAction can also be split into multiple files • this keeps memory footprint smaller, code organization more logical • each file is called action.action_name.php • these files also have special pre-set variables
  • 51. action.action_name.php • has $gCms defined • has $id, $params, and $returnid defined (more on these later) • has $smarty defined
  • 52. action.default.php <?php // safety first if (!isset($gCms)) exit; $this->_do_hello($id, $params, $returnid) ?>
  • 53. action.goodbye.php <?php // safety first if (!isset($gCms)) exit; $this->_do_goodbye($id, $params, $returnid) ?>
  • 54.
  • 55. Wha?? • where’s our “Hello World?” • action “hello” is not the same as action “default” • we can either implement action “hello” by creating action.hello.php, or change our model such that this is the default.
  • 56. Another deep breath • what we’ve accomplished: • keeping track of module versions • providing a clean approach to module upgrades and uninstalls • breaking module into separate files for better memory management • set preferences, logged to the admin log
  • 57. Uh-Oh! • Bitter Angry Little Man alert! • 16 people filed feature requests: • “I should be able to load in multiple messages, not just ‘hello’ and ‘goodbye’!” • “Yeah, and they should have the option of displaying randomly according to that new preference you created!”
  • 58. The database • handle to database available via GetDb() method • supports ADODB functionality • hides a lot of the complexity for table creation. see http://phplens.com/lens/adodb/docs-datadict.htm
  • 59. Adds to method.install.php // get database handle $db = &$this->GetDb(); // mysql-specific, but ignored by other database $taboptarray = array( 'mysql' => 'TYPE=MyISAM' ); // database-independent table creation $dict = NewDataDictionary( $db ); $flds = "phrase_id I KEY AUTO, phrase C(255)"; $sqlarray = $dict->CreateTableSQL( cms_db_prefix(). 'module_hello', $flds, $taboptarray); $dict->ExecuteSQLArray($sqlarray); $db->Execute('insert into '.cms_db_prefix(). 'module_hello (phrase) values (?)', array($this->Lang('hello_world_string') ));
  • 60. Don’t forget! • implement similar code in the method.upgrade.php • bump the module’s version number to 1.1 • and implement code that uses the phrases from the database
  • 61. Revised function function _do_hello($id, $params, $returnid) { $db = &$this->GetDb(); if ($this->GetPreference('use_random_phrase','y') == 'y') { $count = $db->GetOne('select count(phrase) from '. cms_db_prefix().'module_hello'); $rand_line = rand(1,$count) - 1; $res = $db->SelectLimit('select phrase from '. cms_db_prefix().'module_hello',1,$rand_line); if ($res && $row=$res->FetchRow()) { $phrase = $row['phrase']; } } else { $phrase = $db->GetOne('select phrase from '.cms_db_prefix(). 'module_hello where phrase_id=1'); } $this->smarty->assign('phrase',$phrase); echo $this->ProcessTemplate('hello.tpl'); }
  • 62. Revised template/hello.tpl {* smarty template. CMSROOT/modules/HelloWorld/templates/hello.tpl *} <h2>{$phrase}</h2>
  • 63.
  • 64. Fear & loathing • Angry bitter little man alert! • 23 users complained about not being able to change the preference • 47 users complained about the lack of a form to add phrases
  • 65. Solution • need to create an admin area for the module • and need to create an input form
  • 66. Creating an admin • HasAdmin() method returns true • our other magic action: defaultadmin • separated file: action.defaultadmin.php
  • 67. Additions to HelloWorld.module.php function HasAdmin() { return true; } function VisibleToAdminUser() { return $this->CheckPermission('Manage All Content'); }
  • 68. action.defaultadmin.php <?php if (!isset($gCms)) exit; if (! $this->CheckPermission('Manage All Content')) exit; if (isset($params['random']) && !empty($params['random'])) { $this->SetPreference('use_random_phrase',$params['random']); $smarty->assign('message',$this->Lang('preference_set')); } $smarty->assign('start_form', $this->CreateFormStart($id, 'defaultadmin', $returnid)); $smarty->assign('input_pref',$this->CreateInputHidden($id,'random','n'). $this->CreateInputCheckbox($id, 'random', 'y', $this->GetPreference('use_random_phrase','y')). $this->Lang('title_use_random_phrase')); $smarty->assign('submit', $this->CreateInputSubmit($id, 'submit', lang('submit'))); echo $this->ProcessTemplate('adminpanel.tpl'); ?>
  • 69. templates/adminpanel.tpl {if isset($message)}<p class="pagemessage">{$message}</p>{/if} {$start_form} <div class="pageoverflow"> <p class="pagetext">{$input_pref}</p> <p class="pageinput">{$submit}</p> </div> </form>
  • 70.
  • 71. Create a user-side form • very much like the admin side
  • 72. action.add.php <?php if (!isset($gCms)) exit; if (isset($params['phrase']) && !empty($params['phrase'])) { $db = &$this->GetDb(); $db->Execute('insert into '.cms_db_prefix(). 'module_hello (phrase) values (?)', array($params['phrase'])); $smarty->assign('message',$this->Lang('phrase_added')); } $smarty->assign('start_form', $this->CreateFormStart($id, 'add', $returnid)); $smarty->assign('input_phrase', $this->CreateInputText($id,'phrase', $this->Lang('add_phrase_here'),40,255)); $smarty->assign('submit', $this->CreateInputSubmit($id, 'submit', $this->Lang('submit'))); $smarty->assign_by_ref('mod',$this); echo $this->ProcessTemplate('add.tpl'); ?>
  • 73. add.tpl {if isset($message)}<p class="pagemessage">{$message}</p>{/if} {$start_form} <fieldset><legend>{$mod->Lang('add_a_phrase')}</legend> <div> <p>{$input_phrase}</p> <div> <div> <p>{$submit}</p> </div> </fieldset> </form>
  • 74.
  • 75.
  • 76. What we’ve covered API Covered API Not Covered 10% 90%
  • 77. Resources • the Wiki http://wiki.cmsmadesimple.org/index.php/Developers • Skeleton module http://dev.cmsmadesimple.org/projects/skeleton • IRC freenode.net #cms
  • 78. Bitter, angry little man • hitting a moving target; keeping up to date • lots of complaints about the flavors of free ice cream available • give an inch, they’ll ask for a mile • using module for what it was never meant to do
  • 79. Preparing for CMSMS 2.0 • beware of direct access to API class variables! e.g., use $this->GetDb(), don’t use $this->db • no more PHP 4.x-isms • callbacks are going away! use the event system. • lots more – ORM, etc, so beware!
  • 80. Calguy’s cardinal rules • Do not use members of the module object, use accessors • Split everything up into logical classes • No separate entry points, use actions • Use the permissions model liberally • Use separate files for actions, tabs, install/ upgrade/uninstall actions
  • 81. Calguy’s rules, cont. • Cache data where practical data may be read (if it's feasible/expected that the more than one time in a request). • Use DEFINES or class constants rather than hardcoded strings • Separate logic from display... use Smarty • Provide the data to Smarty, let Smarty display it.
  • 82. Calguy’s rules, cont. • Use ADODB’s parameter cleansing stuff, don't build in all the params yourself. • Keep your code clean. • Get off my lawn, you kids!
  • 84. Closing • Thanks for your attention
  • 85. Closing • Thanks for your attention • Goodbye cruel world...
  • 86. Appendix • module directory structure • source listings • random notes
  • 88. RegTM Module source <?php # extremely simple filter module; adds registered trademark symbol to your company's name class RegTM extends CMSModule { var $company_name = 'CMS Made Simple'; function GetName() { return 'RegTM'; } function GetFriendlyName() { return 'RegTM'; } function GetVersion() { return '0.1'; } function GetAuthor() { return 'SjG'; } function GetAuthorEmail()
  • 89. RegTM Module source, cont. function MinimumCMSVersion() { return "1.6"; } function SetParameters() { $this->AddEventHandler( 'Core', 'ContentPostRender', true ); } function DoEvent( $originator, $eventname, &$params ) { if ($originator == 'Core' && $eventname == 'ContentPostRender') { $params['content'] = str_replace($this->company_name, $this->company_name.'<sup>&reg;</sup>', $params['content']); } } } // end ?>
  • 90. User Warning Module source <?php # extremely simple event-handler module; sends email to admins giving them warning when a user is deleted. class UserWarning extends CMSModule { function GetName() { return 'UserWarning'; } function GetFriendlyName() { return 'UserWarning'; } function GetVersion() { return '0.1'; } function GetAuthor() { return 'SjG'; } function GetAuthorEmail() { return 'sjg@cmsmodules.com';
  • 91. User Warning Module source, cont. function MinimumCMSVersion() { return "1.6"; } function GetDependencies() { return array('CMSMailer'=>'1.73'); } function SetParameters() { $this->AddEventHandler( 'Core', 'DeleteUserPre', true ); }
  • 92. User Warning Module source, cont. function DoEvent( $originator, $eventname, &$params ) { if ($originator == 'Core' && $eventname == 'DeleteUserPre') { $db = $this->GetDB(); $user = $params['user']; $result = $db->Execute('select * from '.cms_db_prefix().'users where user_id <>?', array($user->id)); if ($result) { $mail =& $this->GetModuleInstance('CMSMailer'); if ($mail != FALSE) { $mail->reset(); $mail->SetSubject('Admin User Deleted'); $mail->SetBody('FYI: CMS admin user "'.$user->firstname.' '.$user->lastname. '" ('.$user->username.') has been terminated.'); } while ($row = $result->FetchRow()) { $mail->AddAddress($row['email'],$row['first_name'].' '.$row['last_name']); } $sent = $mail->Send(); } } } } // end
  • 93. Contact me • sjg@cmsmodules.com • drop by next time you’re in L.A.