pnForm
[ class tree: pnForm ] [ index: pnForm ] [ all elements ]

Source for file pnForm.php

Documentation is available at pnForm.php

  1. <?php
  2. /**
  3.  * Base classes for pnForm system
  4.  *
  5.  * @copyright (c) 2006, Zikula Development Team
  6.  * @link http://www.zikula.org
  7.  * @version $Id: $
  8.  * @license GNU/GPL - http://www.gnu.org/copyleft/gpl.html
  9.  * @author Jorn Wildt
  10.  * @package pnForm
  11.  * @subpackage Base
  12.  */
  13.  
  14.  
  15. /**
  16.  * User interaction handler for pnForm system
  17.  *
  18.  * This class is the main entry point for using the pnForm system. It is expected to be used in Zikula's
  19.  * user files, such as "pnuser.php", like this:
  20.  * <code>
  21.  * function modname_user_new($args)
  22.  * {
  23.  *   // Create instance of pnFormRender class
  24.  *   $render = FormUtil::newpnForm('howtopnforms');
  25.  *
  26.  *   // Execute form using supplied template and event handler
  27.  *   return $render->pnFormExecute('modname_user_new.html', new modname_user_newHandler());
  28.  * }
  29.  * </code>
  30.  * See tutorials elsewhere for general introduction to pnForm.
  31.  *
  32.  * @package pnForm
  33.  * @subpackage Base
  34.  */
  35. class pnFormRender extends pnRender
  36. {
  37.     /** 
  38.      * Variable saving all required state information
  39.      * @internal
  40.      */
  41.     var $pnFormState;
  42.  
  43.     /**
  44.      * List of included files required to recreate plugins (Smarty function.xxx.php files)
  45.      * @internal
  46.      */
  47.     var $pnFormIncludes;
  48.  
  49.     /**
  50.      * List of instantiated plugins
  51.      * @internal
  52.      */
  53.     var $pnFormPlugins;
  54.  
  55.     /**
  56.      * Stack with all instantiated blocks (push when starting block, pop when ending block)
  57.      * @internal
  58.      */
  59.     var $pnFormBlockStack;
  60.  
  61.     /**
  62.      * List of validators on page
  63.      * @internal
  64.      */
  65.     var $pnFormValidators;
  66.  
  67.     /**
  68.      * Flag indicating if validation has been done or not
  69.      * @internal
  70.      */
  71.  
  72.     /**
  73.      * Indicates whether page is valid or not
  74.      * @internal
  75.      */
  76.     var $_pnFormIsValid;
  77.  
  78.     /**
  79.      * Current ID count - used to assign automatic ID's to all items
  80.      * @internal
  81.      */
  82.     var $pnFormIdCount;
  83.  
  84.     /**
  85.      * Reference to the main user code event handler
  86.      * @internal
  87.      */
  88.     var $pnFormEventHandler;
  89.  
  90.     /**
  91.      * Error message has been set
  92.      * @internal
  93.      */
  94.     var $pnFormErrorMsgSet;
  95.  
  96.     /**
  97.      * Set to true if pnFormRedirect was called. Means no HTML output should be returned.
  98.      * @internal
  99.      */
  100.     var $pnFormRedirected;
  101.  
  102.  
  103.     /**
  104.      * Constructor
  105.      * 
  106.      * Use FormUtil::newpnForm() instead of instantiating pnFormRender directly.
  107.      * @internal
  108.      */
  109.     function pnFormRender($module)
  110.     {
  111.         // Construct and make normal Smarty use possible
  112.         $this->pnRender($modulefalse);
  113.         array_push($this->plugins_dir"system/pnForm/plugins");
  114.  
  115.         // Setup
  116.         $this->pnFormIdCount = 1;
  117.         $this->pnFormErrorMsgSet = false;
  118.         $this->pnFormPlugins = array();
  119.         $this->pnFormBlockStack = array();
  120.         $this->pnFormRedirected = false;
  121.  
  122.         $this->pnFormValidators = array();
  123.         $this->pnFormValidationChecked = false;
  124.         $this->_pnFormIsValid = null;
  125.  
  126.         $this->pnFormInitializeState();
  127.         $this->pnFormInitializeIncludes();
  128.     }
  129.  
  130.  
  131.     /** Main event loop handler
  132.       *
  133.       * This is the function to call instead of the normal $render->fetch(...)
  134.       * @param bool $template Name of template file
  135.       * @param pnFormHandler $eventHandler Instance of object that inherits from pnFormHandler
  136.       * @return mixed False on errors, true on redirects, and otherwise it returns the HTML output for the page.
  137.       */
  138.     function pnFormExecute($template&$eventHandler)
  139.     {
  140.         // Save handler for later use
  141.         $this->pnFormEventHandler = &$eventHandler;
  142.  
  143.         if ($this->pnFormIsPostBack())
  144.         {
  145.             if (!SecurityUtil::confirmAuthKey())
  146.                 return LogUtil::registerAuthidError();
  147.  
  148.             $this->pnFormDecodeIncludes();
  149.             $this->pnFormDecodeState();
  150.             $this->pnFormDecodeEventHandler();
  151.  
  152.             if ($eventHandler->initialize($this=== false)
  153.                 return $this->pnFormGetErrorMsg();
  154.  
  155.             // (no create event)
  156.             $this->pnFormInitializePlugins();    // initialize event
  157.             $this->pnFormDecodePlugins();        // decode event
  158.             $this->pnFormDecodePostBackEvent();  // Execute optional postback after plugins have read their values
  159.         }
  160.         else
  161.         {
  162.             if ($eventHandler->initialize($this=== false)
  163.                 return $this->pnFormGetErrorMsg();
  164.         }
  165.  
  166.         // render event (calls registerPlugin)
  167.         $output $this->fetch($template);
  168.  
  169.         if ($this->pnFormHasError())
  170.             return $this->pnFormGetErrorMsg();
  171.  
  172.         // Check redirection at this point, ignore any generated HTML if redirected is required.
  173.         // We cannot skip HTML generation entirely in case of pnRedirect since there might be
  174.         // some relevant code to execute in the plugins.
  175.         if ($this->pnFormRedirected)
  176.             return true;
  177.  
  178.         return $output;
  179.     }
  180.  
  181.  
  182.     /** 
  183.      * Register a plugin
  184.      * 
  185.      * This method registers a plugin used in a template. Plugins must beregistered to be used in pnForm
  186.      * (unlike Smarty plugins). The register call must be done inside the Smarty plugin function in a
  187.      * Smarty plugin file. Use like this:
  188.      * <code>
  189.      * // In file "function.myplugin.php"
  190.      *
  191.      * // pnForm plugin class
  192.      * class MyPlugin extends pnFormPlugin
  193.      * { ... }
  194.      * 
  195.      * // Smarty plugin function
  196.      * function smarty_function_myplugin($params, &$render)
  197.      * {
  198.      *   return $render->pnFormRegisterPlugin('MyPlugin', $params);
  199.      * }
  200.      * </code>
  201.      * Registering a plugin ensures it is included in the plugin hierarchy of the current page, so that it's
  202.      * various event handlers can be called by the framework.
  203.      *
  204.      * Do dot use this function for registering Smarty blocks (the $isBlock parameter is for internal use).
  205.      * Use pnFormRegisterBlock instead.
  206.      *
  207.      * See also all the function.pnformXXX.php plugins for examples.
  208.      *
  209.      * @param string $pluginName Full class name of the plugin to register.
  210.      * @param array &$params Parameters passed from the Smarty plugin function
  211.      * @param bool $isBlock Indicates whether the plugin is a Smarty block or a Smarty function (internal)
  212.      * @return string Returns what the render() method of the plugin returns
  213.     */
  214.     function pnFormRegisterPlugin($pluginName&$params$isBlock=false)
  215.     {
  216.         // Make sure we have a suitable ID for the plugin
  217.         $id $this->pnFormGetPluginId($params);
  218.  
  219.         $stackCount count($this->pnFormBlockStack);
  220.  
  221.         // A volatile block is a block that cannot be restored through view state
  222.         // This is the case for pnForm plugins inside <!--[if]--> and <!--[foreach]--> tags.
  223.         // So create new plugins for these blocks instead of relying on the existing plugins.
  224.  
  225.         if (!$this->pnFormIsPostBack()  ||  $stackCount>&& $this->pnFormBlockStack[$stackCount-1]->volatile)
  226.         {
  227.             $plugin new $pluginName($this$params);
  228.  
  229.             // Make sure to store ID and render reference in plugin
  230.             $plugin->id $id;
  231.  
  232.             if ($stackCount 0)
  233.             {
  234.                 $plugin->parentPlugin &$this->pnFormBlockStack[$stackCount-1];
  235.                 $this->pnFormBlockStack[$stackCount-1]->registerPlugin($this$plugin);
  236.             }
  237.             else
  238.             {
  239.                 // Store plugin for later reference
  240.                 $this->pnFormPlugins[&$plugin;
  241.             }
  242.  
  243.             // Copy parameters to member variables and attribute set
  244.             $plugin->readParameters($this$params);
  245.             $plugin->create($this$params);
  246.             $plugin->load($this$params);
  247.  
  248.             // Remember which file this plugin came from in order to be able to restore it.
  249.             $this->pnFormIncludes[$plugin->getFilename()1;
  250.         }
  251.         else
  252.         {
  253.             // Fetch plugin instance by ID
  254.             // It has already got it's initialize and decode event at this point
  255.             $plugin $this->pnFormGetPluginById($id);
  256.  
  257.             // Kill existing plugins beneath a volatile block
  258.             if (isset($plugin->volatile&& $plugin->volatile)
  259.             {
  260.               $plugin->plugins null;
  261.             }
  262.         }
  263.  
  264.         $plugin->dataBound($this$params);
  265.  
  266.         if ($isBlock)
  267.         {
  268.             $this->pnFormBlockStack[&$plugin;
  269.         }
  270.  
  271.         // Ask plugin to render itself
  272.         $output '';
  273.         if ($isBlock)
  274.         {
  275.             if ($plugin->visible)
  276.                 $output $plugin->renderBegin($this);
  277.         }
  278.         else
  279.         {
  280.             if ($plugin->visible)
  281.                 $output $plugin->render($this);
  282.         }
  283.  
  284.         return $output;
  285.     }
  286.  
  287.  
  288.     /**
  289.      * Regiser a block plugin
  290.      *
  291.      * Use this like {@link pnFormRegisterPlugin} but for Smarty blocks instead of Smarty plugins.
  292.      * <code>
  293.      * // In file "block.myblock.php"
  294.      *
  295.      * // pnForm plugin class (also used for blocks)
  296.      * class MyBlock extends pnFormPlugin
  297.      * { ... }
  298.      * 
  299.      * // Smarty block function
  300.      * function smarty_block_myblock($params, $content, &$render)
  301.      * {
  302.      *   return return $render->pnFormRegisterBlock('MyBlock', $params, $content);
  303.      * }
  304.      * </code>
  305.      * @param string $pluginName Full class name of the plugin to register.
  306.      * @param array &$params Parameters passed from the Smarty block function
  307.      * @param string &$content Content passed from the Smarty block function
  308.      */
  309.     function pnFormRegisterBlock($pluginName&$params&$content)
  310.     {
  311.         if (!$content)
  312.           return $this->pnFormRegisterBlockBegin($pluginName$params);
  313.         else
  314.           return $this->pnFormRegisterBlockEnd($pluginName$params$content);
  315.     }
  316.  
  317.  
  318.     /**
  319.      * pnFormRegisterBlockBegin
  320.      * @internal
  321.      */
  322.     function pnFormRegisterBlockBegin($pluginName&$params)
  323.     {
  324.         $output $this->pnFormRegisterPlugin($pluginName$paramstrue);
  325.         $plugin &$this->pnFormBlockStack[count($this->pnFormBlockStack)-1];
  326.         $plugin->blockBeginOutput $output;
  327.     }
  328.  
  329.  
  330.     /**
  331.      * pnFormRegisterBlockEnd
  332.      * @internal
  333.      */
  334.     function pnFormRegisterBlockEnd($pluginName&$params$content)
  335.     {
  336.         $plugin &$this->pnFormBlockStack[count($this->pnFormBlockStack)-1];
  337.         array_pop($this->pnFormBlockStack);
  338.  
  339.         if ($plugin->visible)
  340.            $output $plugin->blockBeginOutput $plugin->renderContent($this$content$plugin->renderEnd($this);
  341.  
  342.         $plugin->blockBeginOutput null;
  343.  
  344.         return $output;
  345.     }
  346.  
  347.  
  348.     /**
  349.      * pnFormGetPluginId
  350.      * @internal
  351.      */
  352.     function pnFormGetPluginId(&$params)
  353.     {
  354.         if (!isset($params['id']))
  355.         {
  356.             return 'plg' ($this->pnFormIdCount++);
  357.         }
  358.  
  359.         return $params['id'];
  360.     }
  361.  
  362.  
  363.     function pnFormGetPluginById($id)
  364.     {
  365.         $lim count($this->pnFormPlugins);
  366.         for ($i=0$i<$lim++$i)
  367.         {
  368.             $plugin $this->pnFormGetPluginById_rec($this->pnFormPlugins[$i]$id);
  369.             if ($plugin != null{
  370.                 return $plugin;
  371.             }
  372.         }
  373.  
  374.         $null null;
  375.         return $null;
  376.     }
  377.  
  378.  
  379.     function pnFormGetPluginById_rec(&$plugin$id)
  380.     {
  381.         if ($plugin->id == $id)
  382.             return $plugin;
  383.  
  384.         $lim count($plugin->plugins);
  385.         for ($i=0$i<$lim++$i)
  386.         {
  387.             $subPlugin $this->pnFormGetPluginById_rec($plugin->plugins[$i]$id);
  388.             if ($subPlugin != null{
  389.                 return $subPlugin;
  390.             }
  391.         }
  392.  
  393.         $null null;
  394.         return $null;
  395.     }
  396.  
  397.  
  398.     function pnFormIsPostBack()
  399.     {
  400.         return isset($_POST['__pnFormSTATE']);
  401.     }
  402.  
  403.  
  404.     function pnFormDie($msg)
  405.     {
  406.         echo ($msg);
  407.         pnShutDown(0);
  408.     }
  409.  
  410.  
  411.     function pnFormTranslateForDisplay($txt$doEncode true)
  412.     {
  413.         $txt (strlen($txt0  &&  $txt[0== '_' && defined($txtconstant($txt$txt);
  414.         if ($doEncode{
  415.             $txt DataUtil::formatForDisplay($txt);
  416.         }
  417.         return $txt;
  418.     }
  419.  
  420.  
  421.     /* --- Validation --- */
  422.  
  423.     function pnFormAddValidator(&$validator)
  424.     {
  425.         $this->pnFormValidators[&$validator;
  426.     }
  427.  
  428.  
  429.     function pnFormIsValid()
  430.     {
  431.         if (!$this->pnFormValidationChecked)
  432.             $this->pnFormValidate();
  433.  
  434.         return $this->_pnFormIsValid;
  435.     }
  436.  
  437.  
  438.     function pnFormGetValidators()
  439.     {
  440.         return $this->pnFormValidators;
  441.     }
  442.  
  443.  
  444.     function pnFormValidate()
  445.     {
  446.         $this->_pnFormIsValid = true;
  447.  
  448.         $lim count($this->pnFormValidators);
  449.         for ($i=0$i<$lim++$i)
  450.         {
  451.             $this->pnFormValidators[$i]->validate($this);
  452.             $this->_pnFormIsValid = $this->_pnFormIsValid  &&  $this->pnFormValidators[$i]->isValid;
  453.         }
  454.  
  455.         $this->pnFormValidationChecked = true;
  456.     }
  457.  
  458.  
  459.     function pnFormClearValidation()
  460.     {
  461.         $this->_pnFormIsValid = true;
  462.  
  463.         $lim count($this->pnFormValidators);
  464.         for ($i=0$i<$lim++$i)
  465.         {
  466.             $this->pnFormValidators[$i]->clearValidation($this);
  467.         }
  468.     }
  469.  
  470.  
  471.     /* --- Public state management --- */
  472.  
  473.     function pnFormSetState($region$varName&$varValue)
  474.     {
  475.         if (!isset($this->pnFormState[$region])) {
  476.             $this->pnFormState[$regionarray();
  477.         }
  478.  
  479.         $this->pnFormState[$region][$varName&$varValue;
  480.     }
  481.  
  482.  
  483.     function pnFormGetState($region$varName)
  484.     {
  485.         return $this->pnFormState[$region][$varName];
  486.     }
  487.  
  488.  
  489.     /* --- Error handling --- */
  490.  
  491.     /**
  492.      * Register an error
  493.      *
  494.      * Example:
  495.      * <code>
  496.      * function handleCommand(...)
  497.      * {
  498.      *   if (... it did not work ...)
  499.      *     return $render->pnFormRegisterError('Operation X failed due to Y');
  500.      * }
  501.      * </code>
  502.      */
  503.     function pnFormSetErrorMsg($msg)
  504.     {
  505.         LogUtil::registerError($msg);
  506.         $this->pnFormErrorMsgSet = true;
  507.         return false;
  508.     }
  509.  
  510.  
  511.     function pnFormGetErrorMsg()
  512.     {
  513.         if ($this->pnFormErrorMsgSet)
  514.         {
  515.             include_once 'system/pnRender/plugins/function.pngetstatusmsg.php';
  516.             $args array();
  517.             return smarty_function_pngetstatusmsg($args$this);
  518.         }
  519.         else 
  520.             return '';
  521.     }
  522.  
  523.  
  524.     function pnFormHasError()
  525.     {
  526.         return $this->pnFormErrorMsgSet;
  527.     }
  528.  
  529.  
  530.     /**
  531.      * Register that we have used LogUtil::registerError() to set an error.
  532.      *
  533.      * Example:
  534.      * <code>
  535.      * function initialize(&$render)
  536.      * {
  537.      *   if (... not has access ...)
  538.      *     return $render->pnFormRegisterError(LogUtil::registerPermissionError());
  539.      * }
  540.      * </code>
  541.      */
  542.     function pnFormRegisterError($dummy)
  543.     {
  544.         $this->pnFormErrorMsgSet = true;
  545.         return false;
  546.     }
  547.  
  548.  
  549.     /* --- Redirection --- */
  550.  
  551.     function pnFormRedirect($url)
  552.     {
  553.         pnRedirect($url);
  554.         $this->pnFormRedirected = true;
  555.     }
  556.  
  557.  
  558.     /* --- Event handling --- */
  559.  
  560.     /**
  561.      * Get postback reference
  562.      * 
  563.      * Call this method to get a piece of code that will generate a postback event. The returned JavaScript code can
  564.      * be called at any time to generate the postback. The plugin that receives the postback must implement
  565.      * a function "raisePostBackEvent(&$render, $eventArgument)" that will handle the event.
  566.      *
  567.      * Example (taken from the {@link pnFormContextMenuItem} plugin):
  568.      * <code>
  569.      * function render(&$render)
  570.      * {
  571.      *   $click = $render->pnFormGetPostBackEventReference($this, $this->commandName);
  572.      *   $url = 'javascript:' . $click;
  573.      *   $title = $render->pnFormTranslateForDisplay($this->title);
  574.      *   $html = "<li><a href=\"$url\">$title</a></li>";
  575.      *
  576.      *   return $html;
  577.      * }
  578.      *
  579.      * function raisePostBackEvent(&$render, $eventArgument)
  580.      * {
  581.      *   $args = array('commandName' => $eventArgument, 'commandArgument' => null);
  582.      *   $render->pnFormRaiseEvent($this->onCommand == null ? 'handleCommand' : $this->onCommand, $args);
  583.      * }
  584.      * </code>
  585.      *
  586.      * @param plugin object Reference to the plugin that should receive the postback event
  587.      * @param commandName string Command name to pass to the event handler
  588.      */
  589.     function pnFormGetPostBackEventReference(&$plugin$commandName)
  590.     {
  591.       return "pnFormDoPostBack('$plugin->id', '$commandName');";
  592.     }
  593.  
  594.  
  595.     /// Raise event in the main user event handler
  596.     /// This method raises an event in the main user event handler. It is usually called from a plugin to signal
  597.     /// that something in that plugin needs attention.
  598.     function pnFormRaiseEvent($eventHandlerName$args)
  599.     {
  600.         $handlerClass $this->pnFormEventHandler;
  601.  
  602.         if (method_exists($handlerClass$eventHandlerName)) {
  603.             if ($handlerClass->$eventHandlerName($this$args=== false{
  604.                 return false;
  605.             }
  606.         }
  607.  
  608.         return true;
  609.     }
  610.  
  611.  
  612.     /* --- Private --- */
  613.  
  614.  
  615.     /* --- Include list --- */
  616.  
  617.     function pnFormInitializeIncludes()
  618.     {
  619.         $this->pnFormIncludes = array();
  620.     }
  621.  
  622.     function pnFormGetIncludesText()
  623.     {
  624.         $bytes serialize($this->pnFormIncludes);
  625.         $bytes SecurityUtil::signData($bytes);
  626.         $base64 base64_encode($bytes);
  627.  
  628.         return $base64;
  629.     }
  630.  
  631.  
  632.     function pnFormGetIncludesHTML()
  633.     {
  634.         $base64 $this->pnFormGetIncludesText();
  635.  
  636.         return "<input type=\"hidden\" name=\"__pnFormINCLUDES\" value=\"$base64\"/>";
  637.     }
  638.  
  639.  
  640.     function pnFormDecodeIncludes()
  641.     {
  642.         $base64 $_POST['__pnFormINCLUDES'];
  643.         $bytes base64_decode($base64);
  644.         $bytes SecurityUtil::checkSignedData($bytes);
  645.         if (!$bytes{
  646.             return// error handler required - drak
  647.         }
  648.  
  649.         $this->pnFormIncludes = unserialize($bytes);
  650.  
  651.         foreach ($this->pnFormIncludes as $includeFilename => $dummy)
  652.         {
  653.             require_once $includeFilename;
  654.         }
  655.     }
  656.  
  657.  
  658.     /* --- Authentication key --- */
  659.  
  660.     function pnFormGetAuthKeyHTML()
  661.     {
  662.         $key SecurityUtil::generateAuthKey();
  663.         $html "<input type=\"hidden\" name=\"authid\" value=\"$key\" id=\"pnFormAuthid\"/>";
  664.         return $html;
  665.     }
  666.  
  667.  
  668.     /* --- State management --- */
  669.  
  670.  
  671.     function pnFormInitializeState()
  672.     {
  673.         $this->pnFormState = array();
  674.     }
  675.  
  676.  
  677.     function pnFormGetStateText()
  678.     {
  679.         $this->pnFormSetState('pnFormRender''eventHandler'$this->pnFormEventHandler);
  680.  
  681.         $pluginState $this->pnFormGetPluginState();
  682.         $this->pnFormSetState('pnFormRender''plugins'$pluginState);
  683.  
  684.         $bytes serialize($this->pnFormState);
  685.         $bytes SecurityUtil::signData($bytes);
  686.         $base64 base64_encode($bytes);
  687.  
  688.         return $base64;
  689.     }
  690.  
  691.  
  692.     function pnFormGetPluginState()
  693.     {
  694.         //$this->dumpPlugins("Encode state", $this->pnFormPlugins);
  695.         $state $this->pnFormGetPluginState_rec($this->pnFormPlugins);
  696.         return $state;
  697.     }
  698.  
  699.  
  700.     function pnFormGetPluginState_rec(&$plugins)
  701.     {
  702.         $state array();
  703.  
  704.         $lim count($plugins);
  705.         for ($i=0$i<$lim++$i)
  706.         {
  707.             $plugin $plugins[$i];
  708.  
  709.             // Handle sub-plugins special and clear stuff not to be serialized
  710.             $plugin->parentPlugin null;
  711.             $subPlugins $plugin->plugins;
  712.             $plugin->plugins null;
  713.  
  714.             $varInfo get_class_vars(get_class($plugin));
  715.  
  716.             $pluginState array();
  717.             foreach ($varInfo as $name => $value)
  718.             {
  719.                 $pluginState[$plugin->$name;
  720.             }
  721.  
  722.             $state[array(get_class($plugin)$pluginState$this->pnFormGetPluginState_rec($subPlugins));
  723.  
  724.             $plugin->plugins $subPlugins;
  725.         }
  726.  
  727.         return $state;
  728.     }
  729.  
  730.  
  731.     function pnFormGetStateHTML()
  732.     {
  733.         $base64 $this->pnFormGetStateText();
  734.  
  735.         return "<input type=\"hidden\" name=\"__pnFormSTATE\" value=\"$base64\"/>";
  736.     }
  737.  
  738.  
  739.     function pnFormDecodeState()
  740.     {
  741.         $base64 $_POST['__pnFormSTATE'];
  742.         $bytes base64_decode($base64);
  743.         $bytes SecurityUtil::checkSignedData($bytes);
  744.         if (!$bytes{
  745.             return// FIXME: error handler required - drak
  746.         }
  747.  
  748.         $this->pnFormState = unserialize($bytes);
  749.         $this->pnFormPlugins = $this->pnFormDecodePluginState();
  750.  
  751.         //$this->dumpPlugins("Decoded state", $this->pnFormPlugins);
  752.     }
  753.  
  754.  
  755.     function pnFormDecodePluginState()
  756.     {
  757.         $state $this->pnFormGetState('pnFormRender''plugins');
  758.         $decodedState $this->pnFormDecodePluginState_rec($state);
  759.         return $decodedState;
  760.     }
  761.  
  762.  
  763.     function pnFormDecodePluginState_rec(&$state)
  764.     {
  765.         $plugins array();
  766.  
  767.         foreach ($state as $pluginInfo)
  768.         {
  769.             $pluginType $pluginInfo[0];
  770.             $pluginState &$pluginInfo[1];
  771.             $subState &$pluginInfo[2];
  772.  
  773.             $dummy array();
  774.             $plugin new $pluginType($this,$dummy);
  775.  
  776.             $vars array_keys(get_class_vars(get_class($plugin)));
  777.  
  778.             $varCount count($vars);
  779.             if ($varCount != count($pluginState)) {
  780.                 return pn_exit("Cannot restore pnForm plugin of type '$pluginType' since stored and actual number of member vars differ");
  781.             }
  782.  
  783.             for ($i=0$i<$varCount++$i)
  784.             {
  785.                 $var $vars[$i];
  786.                 $plugin->$var $pluginState[$i];
  787.             }
  788.  
  789.             $plugin->plugins $this->pnFormDecodePluginState_rec($subState);
  790.             $plugins[&$plugin;
  791.  
  792.             $lim count($plugin->plugins);
  793.             for ($i=0$i<$lim++$i)
  794.               $plugin->plugins[$i]->parentPlugin &$plugins[count($plugins)-1];
  795.         }
  796.  
  797.         return $plugins;
  798.     }
  799.  
  800.  
  801.     function pnFormDecodeEventHandler()
  802.     {
  803.         $storedHandler $this->pnFormGetState('pnFormRender''eventHandler');
  804.         $currentHandler $this->pnFormEventHandler;
  805.  
  806.         // Copy saved data into event handler (this is where form handler variables are restored)
  807.  
  808.         $varInfo get_class_vars(get_class($storedHandler));
  809.  
  810.         foreach ($varInfo as $name => $value)
  811.         {
  812.             $currentHandler->$name $storedHandler->$name;
  813.         }
  814.     }
  815.  
  816.  
  817.     /* --- plugin event generators --- */
  818.  
  819.     function pnFormInitializePlugins()
  820.     {
  821.         $this->pnFormInitializePlugins_rec($this->pnFormPlugins);
  822.  
  823.         return true;
  824.     }
  825.  
  826.  
  827.     function pnFormInitializePlugins_rec(&$plugins)
  828.     {
  829.         $lim count($plugins);
  830.         for ($i=0$i<$lim++$i)
  831.         {
  832.             $this->pnFormInitializePlugins_rec($plugins[$i]->plugins);
  833.             $plugins[$i]->initialize($this);
  834.         }
  835.     }
  836.  
  837.  
  838.     function pnFormDecodePlugins()
  839.     {
  840.         $this->pnFormDecodePlugins_rec($this->pnFormPlugins);
  841.  
  842.         return true;
  843.     }
  844.  
  845.  
  846.     function pnFormDecodePlugins_rec(&$plugins)
  847.     {
  848.         for ($i=0,$lim=count($plugins)$i<$lim++$i)
  849.         {
  850.             $this->pnFormDecodePlugins_rec($plugins[$i]->plugins);
  851.             $plugins[$i]->decode($this);
  852.         }
  853.     }
  854.  
  855.  
  856.     function pnFormDecodePostBackEvent()
  857.     {
  858.         $eventTarget FormUtil::getPassedValue('pnFormEventTarget'null'POST');
  859.         $eventArgument FormUtil::getPassedValue('pnFormEventArgument'null'POST');
  860.  
  861.         if ($eventTarget != '')
  862.         {
  863.             $targetPlugin $this->pnFormGetPluginById($eventTarget);
  864.             if ($targetPlugin != null)
  865.             {
  866.                 $targetPlugin->raisePostBackEvent($this$eventArgument);
  867.             }
  868.         }
  869.  
  870.         $this->pnFormDecodePostBackEvent_rec($this->pnFormPlugins);
  871.     }
  872.  
  873.  
  874.     function pnFormDecodePostBackEvent_rec(&$plugins)
  875.     {
  876.         for ($i=0,$lim=count($plugins)$i<$lim++$i)
  877.         {
  878.             $this->pnFormDecodePostBackEvent_rec($plugins[$i]->plugins);
  879.             $plugins[$i]->decodePostBackEvent($this);
  880.         }
  881.     }
  882.  
  883.  
  884.     function pnFormPostRender()
  885.     {
  886.         $this->pnFormPostRender_rec($this->pnFormPlugins);
  887.  
  888.         return true;
  889.     }
  890.  
  891.  
  892.     function pnFormPostRender_rec(&$plugins)
  893.     {
  894.         $lim count($plugins);
  895.         for ($i=0$i<$lim++$i)
  896.         {
  897.             $this->pnFormPostRender_rec($plugins[$i]->plugins);
  898.             $plugins[$i]->postRender($this);
  899.         }
  900.     }
  901.  
  902.  
  903.     /* --- Reading and settings submitted values --- */
  904.  
  905.     /**
  906.      * Read all values from form
  907.      *
  908.      * Use this function to read the values send by the browser on postback. The return
  909.      * value is an associative array of input names mapping to the posted values.
  910.      * For instance the data:
  911.      *
  912.      * <code>
  913.      * array('title'    => 'The posted title',
  914.      *       'text'     => 'The posted text',
  915.      *       'servings' => 4)
  916.      * </code>
  917.      *
  918.      * Most input plugins supports grouping of posted data. These inputs allows you to
  919.      * write something similar to what you do on the pnformtextinput plugin:
  920.      *
  921.      * <code>
  922.      *   <!--[pnformtextinput id="title" group="A"]--><br/>
  923.      *   <!--[pnformtextinput id="text" textMode=multiline group="A"]-->
  924.      *   <!--[pnformintinput id="servings"]--><br/>
  925.      * </code>
  926.      *
  927.      * Grouped data is combined into associative arrays with all the values in the group.
  928.      * The above example would give the data set:
  929.      *
  930.      * <code>
  931.      * array('A' => array('title'    => 'The posted title',
  932.      *                    'text'     => 'The posted text'),
  933.      *       'servings' => 4)
  934.      * </code>
  935.      *
  936.      */
  937.     function pnFormGetValues()
  938.     {
  939.         $result array();
  940.  
  941.         $this->pnFormGetValues_rec($this->pnFormPlugins$result);
  942.  
  943.         return $result;
  944.     }
  945.  
  946.  
  947.     function pnFormGetValues_rec(&$plugins&$result)
  948.     {
  949.         $lim count($plugins);
  950.         for ($i=0,$cou=$lim$i<$cou++$i)
  951.         {
  952.             $plugin &$plugins[$i];
  953.  
  954.             $this->pnFormGetValues_rec($plugin->plugins$result);
  955.  
  956.             if (method_exists($plugin'saveValue'))
  957.             {
  958.                 $plugin->saveValue($this$result);
  959.             }
  960.         }
  961.     }
  962.  
  963.  
  964.     function pnFormSetValues(&$values$group=null)
  965.     {
  966.         $empty null;
  967.         return $this->pnFormSetValues2($values$group$empty);
  968.     }
  969.  
  970.  
  971.     function pnFormSetValues2(&$values$group=null&$plugins)
  972.     {
  973.         if ($plugins == null)
  974.           $this->pnFormSetValues_rec($values$group$this->pnFormPlugins);
  975.         else
  976.           $this->pnFormSetValues_rec($values$group$plugins);
  977.  
  978.         return true;
  979.     }
  980.  
  981.  
  982.     function pnFormSetValues_rec(&$values$group&$plugins)
  983.     {
  984.         $lim count($plugins);
  985.         for ($i=0,$cou=$lim$i<$cou++$i)
  986.         {
  987.             $plugin &$plugins[$i];
  988.  
  989.             $this->pnFormSetValues_rec($values$group$plugin->plugins);
  990.  
  991.             if (method_exists($plugin'loadValue'))
  992.                 $plugin->loadValue($this$values);
  993.         }
  994.     }
  995.  
  996.  
  997.     function dumpPlugins($msg&$plugins)
  998.     {
  999.         echo "<pre style=\"background-color: #CFC; text-align: left;\">\n";
  1000.         echo "** $msg **\n";
  1001.         $this->dumpPlugins_rec($this->pnFormPlugins);
  1002.         echo "</pre>";
  1003.     }
  1004.  
  1005.  
  1006.     function dumpPlugins_rec(&$plugins)
  1007.     {
  1008.         $lim count($plugins);
  1009.         for ($i=0,$cou=$lim$i<$cou++$i)
  1010.         {
  1011.           $p &$plugins[$i];
  1012.           echo "\n(\n{$p->id}: {$p->parentPlugin}";
  1013.           $this->dumpPlugins_rec($p->plugins);
  1014.           echo "\n)\n";
  1015.         }
  1016.     }
  1017. }
  1018.  
  1019.  
  1020. /**
  1021.  * Base form handler class
  1022.  *
  1023.  * This is the base class to inherit from when creating your own form handlers.
  1024.  *
  1025.  * Member variables in a form handler object is persisted accross different page requests. This means
  1026.  * a member variable $this->X can be set on one request and on the next request it will still contain
  1027.  * the same value.
  1028.  *
  1029.  * A form handler will be notified of various events that happens during it's life-cycle.
  1030.  * When a specific event occurs then the corresponding event handler (class method) will be executed. Handlers
  1031.  * are named exactly like their events - this is how the framework knows which methods to call.
  1032.  *
  1033.  * The list of events is:
  1034.  *
  1035.  * - <b>initialize</b>: this event fires before any of the events for the plugins and can be used to setup
  1036.  *   the form handler. The event handler typically takes care of reading URL variables, access control
  1037.  *   and reading of data from the database.
  1038.  *
  1039.  * - <b>handleCommand</b>: this event is fired by various plugins on the page. Typically it is done by the
  1040.  *   pnFormButton plugin to signal that the user activated a button.
  1041.  *
  1042.  * @package pnForm
  1043.  * @subpackage Base
  1044.  */
  1045. {
  1046.     /**
  1047.      * Initialize form handler
  1048.      *
  1049.      * Typical use:
  1050.      * <code>
  1051.      * function initialize(&$render)
  1052.      * {
  1053.      *   if (!HasAccess) // your access check here
  1054.      *      return $render->pnFormSetErrorMsg('No access');
  1055.      *
  1056.      *   $id = FormUtil::getPassedValue('id');
  1057.      *
  1058.      *  $data = pnModAPIFunc('MyModule', 'user', 'get',
  1059.      *                       array('id' => $id));
  1060.      *   if (count($data) == 0)
  1061.      *     return $render->pnFormSetErrorMsg('Unknown data');
  1062.      *
  1063.      *   $render->assign($data);
  1064.      *
  1065.      *   return true;
  1066.      * }
  1067.      * </code>
  1068.      *
  1069.      * @return bool False in case of initialization errors, otherwise true. If false is returned then the
  1070.      *  framework assumes that {@link pnFormRender::pnFormSetErrorMsg()} has been called with a suitable
  1071.      *  error message.
  1072.      */
  1073.     function initialize(&$render)
  1074.     {
  1075.     }
  1076.  
  1077.  
  1078.     /**
  1079.      * Command event handler
  1080.      *
  1081.      * This event handler is called when a command is issued by the user. Commands are typically something
  1082.      * that originates from a {@link pnFormButton} plugin. The passed args contains different properties
  1083.      * depending on the command source, but you should at least find a <var>$args['commandName']</var>
  1084.      * value indicating the name of the command. The command name is normally specified by the plugin
  1085.      * that initiated the command.
  1086.      * @see pnFormButton
  1087.      * @see pnFormImageButton
  1088.      */
  1089.     function handleCommand(&$render&$args)
  1090.     {
  1091.     }
  1092. }
  1093.  
  1094.  
  1095. /**
  1096.  * Base plugin class
  1097.  *
  1098.  * This is the base class to inherit from when creating new plugins for the pnForm framework.
  1099.  * Every pnForm plugin is normally created in a Smarty plugin function file and registered in
  1100.  * the pnForm framewith with the use of {@link pnFormRender::pnFormRegisterPlugin()}.
  1101.  *
  1102.  * Member variables in a plugin object is persisted accross different page requests. This means
  1103.  * a member variable $this->X can be set on one request and on the next request it will still contain
  1104.  * the same value. This probably removes 99% of the use of hidden HTML variables in your web forms.
  1105.  * A member variable <i>must</i> be declared in order to be persisted:
  1106.  * <code>
  1107.  * class MyPlugin inherits pnFormPlugin
  1108.  * {
  1109.  *    var $X;
  1110.  * }
  1111.  * </code>
  1112.  *
  1113.  * Member variables in a plugin will be assigned automatically from Smarty parameters when the variable
  1114.  * and parameter names match. So assume you have a plugin like this:
  1115.  * <code>
  1116.  * class MyPlugin inherits pnFormPlugin
  1117.  * {
  1118.  *    var $X;
  1119.  * }
  1120.  * </code>
  1121.  *
  1122.  * Then X will be set to 1234 through this template declaration:
  1123.  *
  1124.  * <code>
  1125.  * <!--[MyPlugin X="1234"]-->
  1126.  * </code>
  1127.  *
  1128.  * A registered plugin will be notified of various events that happens during it's life-cycle.
  1129.  * When a specific event occurs then the corresponding event handler (class method) will be executed. Handlers
  1130.  * are named exactly like their events - this is how the framework knows which methods to call.
  1131.  *
  1132.  * The list of events is:
  1133.  * - <b>create</b>: Similar to a constructor since it is called directly after the plugin has been created.
  1134.  *   In this event handler you should set the various member variables your plugin requires. You can access
  1135.  *   Smarty parameters through the $params object. The automatic setting of member variables from Smarty
  1136.  *   parameters happens <i>after</i> the create event.
  1137.  *   This event is only fired the first time the plugin is instantiated,
  1138.  *   but not when restored from saved state.
  1139.  *
  1140.  * - <b>load</b>: Called immediately after member variables has been set from their Smarty parameters. So
  1141.  *   the plugin is assumed to be fully initialized when the load event is fired. During the load event the plugin
  1142.  *   is expected to load values from the render object.
  1143.  *
  1144.  *   A typical load event handler will just call the loadValue
  1145.  *   handler and pass it the values of the render object (to improve reuse). The loadValue method will then take care of the rest.
  1146.  *   This is also the place where validators should be added to the list of validators.
  1147.  *   Example:
  1148.  *   <code>
  1149.  *   function load(&$render, &$params)
  1150.  *   {
  1151.  *     $this->loadValue($render, $render->get_template_vars());
  1152.  *     $render->pnFormAddValidator($this);
  1153.  *   }
  1154.  *   </code>
  1155.  *   This event is only fired the first time the plugin is instantiated,
  1156.  *   but not when restored from saved state.
  1157.  *
  1158.  * - <b>initialize</b>: this event is the opposite of the create/load event pair. It fires when a plugin
  1159.  *   has been restored from a postback (and before then decode event).
  1160.  *
  1161.  * - <b>decode</b>: this event is fired on postback in order to let the plugin decode the HTTP POST values
  1162.  *   sent by the browser. It is left to the plugin to decide where to store the decode data.
  1163.  *
  1164.  * - <b>dataBound</b>: this event is fired when plugin is loaded and ready - both on postback and the
  1165.  *   initial page display.
  1166.  *
  1167.  * - <b>render</b>: this event is fired when the plugin is required to render itself based on the data
  1168.  *   it got through the previous events. This function is only called on Smarty function plugins.
  1169.  *   The event handler is supposed to return the rendered output.
  1170.  *
  1171.  * - <b>renderBegin</b>: this event is for Smarty block plugins only. It is fired in order to allow
  1172.  *   the plugin to render something before the plugins contained within it.
  1173.  *
  1174.  * - <b>renderContent</b>: this event is for Smarty block plugins only. It is fired in order to allow
  1175.  *   the plugin to modify content renderes by the plugins contained within it.
  1176.  *
  1177.  * - <b>renderEnd</b>: this event is for Smarty block plugins only. It is fired in order to allow
  1178.  *   the plugin to render something after the plugins contained within it.
  1179.  *
  1180.  * - <b>postRender</b>: this event is fired after all rendering is done <i>for all plugins on the page</i>.
  1181.  *   In this event handler you can use {@link pnFormRender::pnFormGetPluginById()} to fetch other plugins
  1182.  *   and read/modify their data.
  1183.  * 
  1184.  * Most events on one plugin happens before the next plugin is loaded (except the postRender event). So for two
  1185.  * plugins A and B you would get the event sequence (assuming B is placed after A in the Smarty template):
  1186.  * - A::create
  1187.  * - A::load
  1188.  * - ...
  1189.  * - A:render
  1190.  * - B::create
  1191.  * - B::load
  1192.  * - ...
  1193.  * - B:render
  1194.  * - A::postRender
  1195.  * - B::postRender
  1196.  *
  1197.  *
  1198.  * @package pnForm
  1199.  * @subpackage Base
  1200.  */
  1201. {
  1202.     /**
  1203.      * Plugin identifier
  1204.      *
  1205.      * This contains the identifier for the plugin. You can use this ID in {@link pnFormRender::pnFormGetPluginById()}
  1206.      * as well as in JavaScript where it should be set on the HTML elements (this does although depend on the plugin
  1207.      * implementation).
  1208.      *
  1209.      * Do <i>not</i> change this variable!
  1210.      *
  1211.      * @var string 
  1212.      */
  1213.     var $id;
  1214.  
  1215.     /**
  1216.      * Specifies whether or not a plugin should be rendered
  1217.      *
  1218.      * @var bool 
  1219.      */
  1220.     var $visible;
  1221.  
  1222.     /**
  1223.      * Reference to parent plugin if used inside a block
  1224.      *
  1225.      * @var &pnFormHandler 
  1226.      */
  1227.     var $parentPlugin;
  1228.  
  1229.     /**
  1230.      * HTML attributes
  1231.      *
  1232.      * Associative array of attributes to add to the plugin. For instance:
  1233.      * array('title' => 'A tooltip title', onclick => 'doSomething()')
  1234.      *
  1235.      * @var array 
  1236.      */
  1237.     var $attributes;
  1238.  
  1239.     /**
  1240.      * Name of function to call in form event handler when plugin is loaded
  1241.      *
  1242.      * If you need to notify the form event handler when the plugin has been loaded then
  1243.      * specify the name of this handler here. The prototype of the function must be:
  1244.      * function MyOnLoadHandler(&$render, &$plugin, $params) where $render is the form render,
  1245.      * $plugin is this plugin, and $params are the Smarty parameters passed to the plugin.
  1246.      *
  1247.      * The data bound handler is called both on postback and first page render.
  1248.      *
  1249.      * Example:
  1250.      * <code>
  1251.      * class MyPlugin extends pnFormPlugin
  1252.      * {
  1253.      *   function MyPlugin()
  1254.      *   {
  1255.      *      $this->onDataBound = 'MyLoadHandler';
  1256.      *   }
  1257.      * }
  1258.      *
  1259.      * class MyFormHandler extends pnFormHandler
  1260.      * {
  1261.      *   function MyLoadHandler(&$render, &$plugin, $params)
  1262.      *   {
  1263.      *     // Do stuff here
  1264.      *   }
  1265.      * }
  1266.      * </code>
  1267.      *
  1268.      * The name "dataBound" was chosen to avoid clashes with the "load" event.
  1269.      */
  1270.     var $onDataBound;
  1271.  
  1272.     /**
  1273.      * Reference to sub-plugins
  1274.      *
  1275.      * This variable contains an array of references to sub-plugins when this plugin is
  1276.      * a block plugin containing other plugins.
  1277.      * @var array 
  1278.      */
  1279.     var $plugins;
  1280.  
  1281.     /**
  1282.      * Temporary storage of the output from renderBegin in blocks
  1283.      * @internal
  1284.      */
  1285.     var $blockBeginOutput;
  1286.  
  1287.     /**
  1288.      * Volatile indicator (disables state management in sub-plugins)
  1289.      * @internal
  1290.      * @var bool 
  1291.      */
  1292.     var $volatile;
  1293.  
  1294.  
  1295.     /**
  1296.      * Constructor
  1297.      */
  1298.     function pnFormPlugin(&$render&$params)
  1299.     {
  1300.         $this->plugins = array();
  1301.         $this->attributes = array();
  1302.         $this->visible = true;
  1303.     }
  1304.  
  1305.  
  1306.     /**
  1307.      * Read Smarty plugin parameters
  1308.      *
  1309.      * This is the function that takes care of reading smarty parameters and storing them in the member variables
  1310.      * or attributes (all unknown parameters go into the "attribues" array).
  1311.      * You can override this for special situations.
  1312.      * @return void 
  1313.      */
  1314.     function readParameters(&$render&$params)
  1315.     {
  1316.         $varInfo get_class_vars(get_class($this));
  1317.  
  1318.         // Iterate through all params: place known params in member variables and the rest in the attributes set
  1319.         foreach ($params as $name => $value)
  1320.         {
  1321.             if (array_key_exists($name,$varInfo))
  1322.                 $this->$name $value;
  1323.             else
  1324.                 $this->attributes[$name$value;
  1325.         }
  1326.     }
  1327.  
  1328.  
  1329.     /**
  1330.      * Create event handler
  1331.      *
  1332.      * Default action is to do nothing.
  1333.      *
  1334.      * @see pnFormPlugin
  1335.      * @param pnFormRender &$render Reference to pnForm render object
  1336.      * @param array &$params Parameters passed from the Smarty plugin function
  1337.      * @return void 
  1338.      */
  1339.     function create(&$render&$params)
  1340.     {
  1341.     }
  1342.  
  1343.  
  1344.     /**
  1345.      * Load event handler
  1346.      *
  1347.      * Default action is to do nothing.
  1348.      *
  1349.      * @see pnFormPlugin
  1350.      * @param pnFormRender &$render Reference to pnForm render object
  1351.      * @param array &$params Parameters passed from the Smarty plugin function
  1352.      * @return void 
  1353.      */
  1354.     function load(&$render&$params)
  1355.     {
  1356.     }
  1357.  
  1358.  
  1359.     /**
  1360.      * Initialize event handler
  1361.      *
  1362.      * Default action is to do nothing. Typically used to add self as validator.
  1363.      *
  1364.      * @see pnFormPlugin
  1365.      * @param pnFormRender &$render Reference to pnForm render object
  1366.      * @return void 
  1367.      */
  1368.     function initialize(&$render)
  1369.     {
  1370.     }
  1371.  
  1372.  
  1373.     /**
  1374.      * Decode event handler
  1375.      *
  1376.      * Default action is to do nothing
  1377.      *
  1378.      * @see pnFormPlugin
  1379.      * @param pnFormRender &$render Reference to pnForm render object
  1380.      * @param array &$params Parameters passed from the Smarty plugin function
  1381.      * @return void 
  1382.      */
  1383.     function decode(&$render)
  1384.     {
  1385.     }
  1386.  
  1387.  
  1388.     /**
  1389.      * Decode event handler for actions that generate a postback event
  1390.      *
  1391.      * Default action is to do nothing. Usefull for buttons that should generate events
  1392.      * after the plugins have decoded their normal values.
  1393.      *
  1394.      * @param pnFormRender &$render Reference to pnForm render object
  1395.      * @param array &$params Parameters passed from the Smarty plugin function
  1396.      * @return void 
  1397.      */
  1398.     function decodePostBackEvent(&$render)
  1399.     {
  1400.     }
  1401.  
  1402.  
  1403.     /**
  1404.      * DataBound event handler
  1405.      *
  1406.      * Default action is to call onDataBound handler in form event handler.
  1407.      *
  1408.      * @see pnFormPlugin
  1409.      * @param pnFormRender &$render Reference to pnForm render object
  1410.      * @param array &$params Parameters passed from the Smarty plugin function
  1411.      * @return void 
  1412.      */
  1413.     function dataBound(&$render&$params)
  1414.     {
  1415.         if ($this->onDataBound != null)
  1416.         {
  1417.             $dataBoundHandlerName $this->onDataBound;
  1418.             $render->pnFormEventHandler->$dataBoundHandlerName($render$this$params);
  1419.         }
  1420.     }
  1421.  
  1422.  
  1423.     function renderAttributes(&$render)
  1424.     {
  1425.         $attr '';
  1426.         foreach ($this->attributes as $name => $value)
  1427.         {
  1428.             $attr .= " $name=\"$value\"";
  1429.         }
  1430.  
  1431.         return $attr;
  1432.     }
  1433.  
  1434.  
  1435.     /**
  1436.      * Render event handler
  1437.      *
  1438.      * Default action is to return an empty string.
  1439.      *
  1440.      * @see pnFormPlugin
  1441.      * @param pnFormRender &$render Reference to pnForm render object
  1442.      * @param array &$params Parameters passed from the Smarty plugin function
  1443.      * @return string The rendered output
  1444.      */
  1445.     function render(&$render)
  1446.     {
  1447.         return '';
  1448.     }
  1449.  
  1450.  
  1451.     /**
  1452.      * RenderBegin event handler
  1453.      *
  1454.      * Default action is to return an empty string.
  1455.      *
  1456.      * @see pnFormPlugin
  1457.      * @param pnFormRender &$render Reference to pnForm render object
  1458.      * @return string The rendered output
  1459.      */
  1460.     function renderBegin(&$render)
  1461.     {
  1462.         return '';
  1463.     }
  1464.  
  1465.  
  1466.     /**
  1467.      * RenderContent event handler
  1468.      *
  1469.      * Default action is to return the content unmodified.
  1470.      *
  1471.      * @see pnFormPlugin
  1472.      * @param pnFormRender &$render Reference to pnForm render object
  1473.      *
  1474.      * @return string The (optionally) modified content
  1475.      */
  1476.     function renderContent(&$render$content)
  1477.     {
  1478.         return $content;
  1479.     }
  1480.  
  1481.  
  1482.     /**
  1483.      * RenderEnd event handler
  1484.      *
  1485.      * Default action is to return an empty string.
  1486.      *
  1487.      * @see pnFormPlugin
  1488.      * @param pnFormRender &$render Reference to pnForm render object
  1489.      * @return string The rendered output
  1490.      */
  1491.     function renderEnd(&$render)
  1492.     {
  1493.         return '';
  1494.     }
  1495.  
  1496.  
  1497.     /**
  1498.      * PostRender event handler
  1499.      *
  1500.      * Default action is to do nothing.
  1501.      *
  1502.      * @see pnFormPlugin
  1503.      * @param pnFormRender &$render Reference to pnForm render object
  1504.      * @return void 
  1505.      */
  1506.     function postRender(&$render)
  1507.     {
  1508.     }
  1509.  
  1510.  
  1511.     function registerPlugin(&$render&$plugin)
  1512.     {
  1513.       $this->plugins[&$plugin;
  1514.     }
  1515.  
  1516.  
  1517.     /**
  1518.      * Utility function to generate HTML for ID attribute
  1519.      * 
  1520.      * Generate id="..." for use in the plugin's render methods.
  1521.      *
  1522.      * This function ignores automatically created IDs (those named "plgNNN") and will
  1523.      * return an empty string for these.
  1524.      *
  1525.      * @return string 
  1526.      */
  1527.     function getIdHtml($id=null)
  1528.     {
  1529.         if ($id == null)
  1530.             $id $this->id;
  1531.  
  1532.         if (preg_match('/^plg[0-9]+$/'$id)) {
  1533.             return '';
  1534.         }
  1535.         return " id=\"$id\"";
  1536.     }
  1537. }
  1538.  
  1539.  
  1540. /**
  1541.  * Base plugin class for plugins that uses CSS styling
  1542.  *
  1543.  * This plugin adds attributes like "color", "back_groundcolor" and "font_weight" to plugins that extends it.
  1544.  * The extending plugin must call {@link pnFormPlugin::renderAttributes()} to use the added CSS features.
  1545.  * See also {@link pnFormTextInput} for an example implementation.
  1546.  *
  1547.  * The support CSS styles are listed in the $styleElements array. Please use this as a reference. Underscores
  1548.  * are converted to hyphens in the resulting output to match the correct CSS styles. When you need to use unsupported
  1549.  * CSS styles then just write them directly in the style parameter of the plugin:
  1550.  * <code>
  1551.  * <!--[pnformtextinput id="title" maxLength="100" width="30em" style="border-left: 1px solid red;"]-->
  1552.  * </code>
  1553.  *
  1554.  * You can also add styling in the code by adding key/value pairs to $styleAttributes. Example:
  1555.  * <code>
  1556.  * $this->styleAttributes['border-right'] = '1px solid green';
  1557.  * </code>
  1558.  *
  1559.  * @package pnForm
  1560.  * @subpackage Base
  1561.  */
  1562. {
  1563.     /**
  1564.      * Styles added programatically
  1565.      *
  1566.      * @var array 
  1567.      */
  1568.     var $styleAttributes = array();
  1569.  
  1570.  
  1571.     function renderAttributes(&$render)
  1572.     {
  1573.         static $styleElements array
  1574.           ('width''height''color''background_color'
  1575.            'border''padding''margin',
  1576.            'float''display''position''visibility''overflow''clip',
  1577.            'font''font_family''font_style''font_weight''font_size');
  1578.  
  1579.         $attr '';
  1580.         $style '';
  1581.         foreach ($this->attributes as $name => $value)
  1582.         {
  1583.             if ($name == 'style')
  1584.                 $style $value;
  1585.             else if (in_array($name$styleElements))
  1586.                 $this->styleAttributes[$name$value;
  1587.             else
  1588.                 $attr .= $name=\"$value\"";
  1589.         }
  1590.  
  1591.         $style trim($style);
  1592.         if (count($this->styleAttributes0  &&  strlen($style0  &&  $style[strlen($style)-1!= ';')
  1593.             $style .= ';';
  1594.  
  1595.         foreach ($this->styleAttributes as $name => $value)
  1596.         {
  1597.             $style .= str_replace('_''-'$name":$value;";
  1598.         }
  1599.         if (!empty($style))
  1600.             $attr .= " style=\"$style\"";
  1601.  
  1602.         return $attr;
  1603.     }
  1604. }

Documentation generated on Fri, 18 Jul 2008 21:52:54 +0200 by phpDocumentor 1.4.1