diff --git a/etemplate/doc/db_tools.gif b/etemplate/doc/db_tools.gif deleted file mode 100644 index 4bc440e7cd..0000000000 Binary files a/etemplate/doc/db_tools.gif and /dev/null differ diff --git a/etemplate/doc/editor.gif b/etemplate/doc/editor.gif deleted file mode 100644 index 95a1ac669e..0000000000 Binary files a/etemplate/doc/editor.gif and /dev/null differ diff --git a/etemplate/doc/etemplate.html b/etemplate/doc/etemplate.html index 981ab47c4a..59816897ef 100644 --- a/etemplate/doc/etemplate.html +++ b/etemplate/doc/etemplate.html @@ -1,461 +1,703 @@ - - - - - eGroupWare: eTemplates - Templates and Dialog-Editor - - - + + + eGroupWare: eTemplates - Templates and Dialog-Editor + + + + + + + + +

eTemplate - Templates and Dialog-Editor for eGroupWare

-

by Ralf Becker RalfBecker AT outdoor-training DOT de

-

A developers tutorial how to write an application with the new eTemplates.
-It is also an introduction how to write a eGW- and setup(3)-compatible app.

+

by Ralf Becker RalfBecker +AT outdoor-training DOT de

+

Updated by Raphael Alla >raphael AT olineopensolutions +DOT com

+

A developers tutorial how to write an application with the new +eTemplates.
It is also an introduction how to write a eGW- and +setup(3)-compatible app.


Introduction - The concept of the eTemplates

-The eTemplates +

The eTemplates +

- +
  • group: the id of a group if the + template is just for that group (that allows admin to show differnt + views to each group) +

    +
  • lang: the 2 or 5 letter language + code (or empty for a non-language specific template) +

    +
  • template set: they belong too (if + the template-set key is empty it is an default-template) +

    +
  • version: version number like: + '0.9.15.001' +

    +
  • +
  • they are stored in an array and in + serialized form in the db-table 'phpgw_etemplate' +

    +
  • the dialog editor can dump all + templates of an app for distribution (so they can be in the CVS too) +

    +
  • they encapsulate differnt UI (User Interface) types from the + app: at the moment only a HTML one is ready, but a GTK one (using + php-gtk, running + as native app under linux and win32) and XUL is under + development.
    Here is a first screenshot of the DB-Tools as native + Linux Application: +

    +
  • +

    +


    Tutorial / Example: a simple media database

    -

    As an example we will run now through the necessary steps to create a simple media database using eTemplates and -other tools and classes from the eTemplate app: db-tools and class.so_sql.inc.php.

    -

    Out media database should have the usual fields: name, author, description, type: BOOK, CD, VIDEO and should be able -to edit records and search for them.

    -

    As a preaquistion you need to get / checkout the etemplate app, install the app via setup/manage applications and -enable your account for using the app (Admin/User account: check eTemplates).

    - +

    As an example we will run now through the necessary steps to +create a simple media database using eTemplates and other tools and +classes from the eTemplate app: db-tools and class.so_sql.inc.php.

    +

    Out media database should have the usual fields: name, author, +description, type: BOOK, CD, VIDEO and should be able to edit records +and search for them.

    +

    As a preaquistion you need to get / checkout the etemplate app, +install the app via setup/manage applications and enable your account +for using the app (Admin/User account: check eTemplates).

    1. Creating a new eGW app directory

    -

    Each app need a name, eg. 'et_media'. We now need to create the following directory structur above the eGroupWare dir: -

    -et_media				that has to be identical to our app-name
    -	+ setup				files necessary for the setup Programm, give the webserver write-permission to that dir
    -	+ inc				class-files
    -	+ templates			templates, still needed to store the images and get around a lot of complains from the api
    -		+ default
    -			+ images	here goes our images / icons
    -
    - -

    2. creating et_media/setup/setup.inc.php

    -

    That files contains the necessary information for setup to install the app.

    -
    -<?php
    -	$setup_info['et_media']['name']      = 'et_media';
    -	$setup_info['et_media']['title']     = 'eT-Media';
    -	$setup_info['et_media']['version']   = '0.9.15.001';
    -	$setup_info['et_media']['app_order'] = 100;		// at the end
    -	$setup_info['et_media']['tables']    = array('phpgw_et_media');
    -	$setup_info['et_media']['enable']    = 1;
    -
    -	/* Dependencies for this app to work */
    -	$setup_info['et_media']['depends'][] = array(
    -		 'appname' => 'phpgwapi',
    -		 'versions' => Array('0.9.14','0.9.15','0.9.16','1.0.0','1.0.1')
    -	);
    -	$setup_info['et_media']['depends'][] = array(	// this is only necessary as long the etemplate-class is not in the api
    -		 'appname' => 'etemplate',
    -		 'versions' => Array('0.9.14','0.9.15','0.9.16','1.0.0')
    -	);
    -
    - -

    3. setting up the db-table with the db_tools and setup

    -

    To enable setup to create a db-table for us and to supply the so_sql-class with the necessary information, we need to define -the type and size of the fields / columns in our db-table.
    -We can use the db-Tools from the etemplate app to create the file for us:

    - - +

    Each app need a name, eg. 'et_media'. We now need to create the +following directory structur above the eGroupWare dir: +

    +
    et_media                                that has to be identical to our app-name
    +        + setup                         files necessary for the setup Programm, give the webserver write-permission to that dir
    +        + inc                           class-files
    +        + templates                     templates, still needed to store the images and get around a lot of complains from the api
    +                + default
    +                        + images        here goes our images / icons

    +2. creating et_media/setup/setup.inc.php

    +

    That files contains the necessary information for setup to install +the app. +

    +
    <?php
    +        $setup_info['et_media']['name']      = 'et_media';
    +        $setup_info['et_media']['title']     = 'eT-Media';
    +        $setup_info['et_media']['version']   = '0.9.15.001';
    +        $setup_info['et_media']['app_order'] = 100;             // at the end
    +        $setup_info['et_media']['tables']    = array('phpgw_et_media');
    +        $setup_info['et_media']['enable']    = 1;
     
    +        /* Dependencies for this app to work */
    +        $setup_info['et_media']['depends'][] = array(
    +                 'appname' => 'phpgwapi',
    +                 'versions' => Array('1.2.005','1.2.006')
    +        );
    +        $setup_info['et_media']['depends'][] = array(   // this is only necessary as long the etemplate-class is not in the api
    +                 'appname' => 'etemplate',
    +                 'versions' => Array('1.2')
    +        );

    +3. setting up the db-table with the db_tools and setup

    +

    To enable setup to create a db-table for us and to supply the +so_sql-class with the necessary information, we need to define +the type and size of the fields / columns in our db-table.

    +



    +

    +



    We +can use the db-Tools from the etemplate application to create the +file for us: +

      -
    1. start the etemplate app and click on the button up, right which says db-Tools -
    2. select Application: eT-Media -
    3. type 'phpgw_et_media' in the field in front of the [Add Table] button and click on the button -
    4. now use [Add Column] to create the necessary fields as shown on the screenshot -
    5. Click on [Write Table] (If you get the error-message like in the screenshot, you need to give the webserver write-permission - to the setup-dir of et_media, leave the write-permission as it is necessary later on too, click on write again) -
    6. log out and log into setup and start manage applications -
    7. eT-Media is shown as not installed and only install is offerd, check it and submit -
    8. you can now log out from setup, the db-table is now created -
    - +
  • start the etemplate app and click + on the button up, right which says db-Tools +

    +
  • select Application: eT-Media +

    +
  • type 'egw_et_media' in the field + in front of the [Add Table] button and click on the button +

    +
  • now use [Add Column] to create the + necessary fields as shown on the screenshot +

    +
  • Click on [Write Table] (you need + to give the webserver write-permission to the setup-dir of et_media + or you will get an error message, leave the write-permission as it + is necessary later on too, click on write again) +

    +
  • log out and log into setup and + start manage applications +

    +
  • eT-Media is shown as not installed + and only install is offerd, check it and submit +

    +
  • you can now log out from setup, the db-table is now created +

    +
  • In order to be able to use your eT-Media application, do not + forget to give yourself access to it (Admin/User account: check + eT-Media)

    +
  • 4. creating an eTemplates for the edit-dialog

    -

    Now we need a nice edit dialog and use the eTemplate editor to set it up:

    - - - +

    Now we need a nice edit dialog and use the eTemplate editor to set +it up: +

      -
    1. start the etemplate app and type 'et_media.edit' in the name field -
    2. enter the field-types and other data as shown above -
    3. click on the [+] in the first column of the last row to add more rows -
    4. click on [Save] to save the dialog / template -
    5. you can use [Show (no save)] to have a look at it:

      -

    +
  • start the etemplate app and type + 'et_media.edit' in the name field. Save the template in order + to create it

    +
  • an empty template is displayed. An + eTemplate can be thought off as a “grid”. The first cell may be + a bit tricky to find, but will be highlighted when moving the mouse + over it. On my computer this cell appears in pink as illustrated + below:

    +

  • Double + click on the pink spot will bring the following dialog:

    +

  • The + top row allows you to add column and rows to the template. We will + need 2 columns and 6 rows

    +
  • Create the following label in the + first top left cell:

    +
  • +



    +

    +


    +

    +
      +
    1. In the top right cell, we will create a user entry and call + it “name”: this is the same name as thee column in our + egw_et_media table. This is important as those fields will be + populated automatically for us by eGroupWare:

      +

    2. Complete + the template as follows. The widget used for “type” is a + Selectbox, the one used for “description” is a textarea. Note + that the name of the input is “descr” and not description, as + this is the name of the column in the table. Finally on the last row + we have two widgets of type “Submitbutton” of names “read” + and “save” and of corresponding label.

      +


      +
    +

    Then before moving to the next stage save the template as an XML +file by clicking on “Export XML”. Once again the server must have +write permissions on the directory.

    +

    5. Setting up the index page

    +

    The index page is only used if someone clicks on the navbar icon +(or on the black cross as we haven't supplied one so far).
    Create +the file /et_media/index.php with the following content:

    +
    <?php
    +        $GLOBALS['phpgw_info']['flags'] = array(
    +                'currentapp'    => 'et_media',
    +                'noheader'      => True,
    +                'nonavbar'      => True
    +        );
    +        include('../header.inc.php');
    +        $GLOBALS['egw']->redirect_link('/index.php', 'menuaction=raphatest.ui_et_media.edit');
    +       

    +6. The code for our application

    +

    An eGroupWare application is organised around 3 application +layers:

    +
      +
    1. the storage layer, managed by a “Storage Object” (so). + This object is responsible for handling all access to the storage + engine

      +
    2. the business layer, managed by a “Business Ojbect” (bo). + This object is responsible for all the business logic

      +
    3. the user interface layer, managed by a “User Interface” + (ui) object. This object is responsible for all interaction with the + user, including displaying and gathering data to and from the user

      +
    +

    For this, we create 3 files in the “inc” directory, called +class.so.et_media.inc.php, class.bo_et_media.inc.php, +class.ui_et_media.inc.php. In this simple application, the bo and so +layers will be fairly minimal, this said it is a good idea to create +the application using the right standards from the start.

    +

    Here is the file /et_media/inc/class.so_et_media.inc.php:

    +
    <?php
    +  include_once(PHPGW_INCLUDE_ROOT . '/etemplate/inc/class.so_sql.inc.php');
     
    -
    -

    As you see above i added an application titel, a horizontal rule after it and some space (empty label's). Do so if you want.

    + /** + * General storage class for et_media + */ + class so_et_media extends so_sql + { + function so_et_media() + { + $this->so_sql('et_media','egw_et_media'); + $this->empty_on_write = "''"; + } + }

    +

    +

    +

    The file /et_media/inc/class.bo_et_media.inc.php:

    +
    <?php
    + /**
    +  * Business Object for et_media
    +  */
    +  class bo_et_media
    +  {
    +     var $types = array(
    +         ''      => 'Select one ...',
    +         'cd'    => 'Compact Disc',
    +         'dvd'   => 'DVD',
    +         'book'  => 'Book',
    +         'video' => 'Video Tape'
    +     );
     
    -

    5. setting up the index page

    -

    The index page is only used if someone clicks on the navbar icon (or on the black cross as we haven't supplied one so far).
    -Create the file /et_media/index.php with the following content:

    + function bo_et_media() + { + $this->so =& CreateObject('et_media.so_et_media'); + } + + function save($content) + { + $this->so->save($content); + } -
    -<?php
    -	$GLOBALS['phpgw_info']['flags'] = array(
    -		'currentapp'	=> 'et_media',
    -		'noheader'	=> True,
    -		'nonavbar'	=> True
    -	);
    -	include('../header.inc.php');
    -
    -	header('Location: '.$GLOBALS['phpgw']->link('/index.php','menuaction=et_media.et_media.edit'));
    -	$GLOBALS['phpgw_info']['flags']['nodisplay'] = True;
    -	exit;
    -
    - -

    6. the code of class.et_media.inc.php

    -

    As a first step, we only save new entries. The code of the app is in /et_media/inc/class.et_media.inc.php:

    - -
    -<?php
    -/**************************************************************************\
    +    function read($content)
    +    {
    +      $this->so->search($content);
    +    }
    +  }

    +

    +

    +

    And finally the start of the +/et_media/inc/class.ui_et_media.inc.php:

    +
    <?php
    +/**************************************************************************\
     * eGroupWare - eTemplates - Tutoria Example - a simple MediaDB           *
     * http://www.eGroupWare.org                                              *
    -* Written by Ralf Becker <RalfBecker AT outdoor-training DOT de>           *
    +* Written by Ralf Becker <RalfBecker AT outdoor-training DOT de>           *
     * --------------------------------------------                             *
     *  This program is free software; you can redistribute it and/or modify it *
     *  under the terms of the GNU General Public License as published by the   *
     *  Free Software Foundation; either version 2 of the License, or (at your  *
     *  option) any later version.                                              *
    -\**************************************************************************/
    +\**************************************************************************/
     
    -/* $ Id: class.et_media.inc.php,v 1.2 2002/10/19 11:11:03 ralfbecker Exp $ */
    +/* $ Id: class.et_media.inc.php,v 1.2 2002/10/19 11:11:03 ralfbecker Exp $ */
     
    -include_once(PHPGW_INCLUDE_ROOT . '/etemplate/inc/class.so_sql.inc.php');
    -
    - -

    This loads the class so_sql, in a way that more than one class may use it (would be nice if we had an api-function for that).

    - -
    -class et_media extends so_sql
    +class ui_et_media
     {
    -	var $types = array(
    -		'' => 'Select one ...',
    -		'cd' => 'Compact Disc',
    -		'dvd' => 'DVD',
    -		'book' => 'Book',
    -		'video' => 'Video Tape'
    -	);
    -
    + var $public_functions = array( + "edit" => True, + "writeLangFile" => True + );

    +The $public_functions array defines which public functions can be +accessed by the user.

    +

    The constructor initialises the template engine and the Business +Object:

    +
        function ui_et_media()
    +    {
    +      $this->tmpl =& CreateObject('etemplate.etemplate', 'et_media.edit');
    +      $this->bo   =& CreateObject('et_media.bo_et_media');
    +      $this->html =& $GLOBALS['egw']->html;
    +                
    +      if(!@is_object($GLOBALS['egw']->js))
    +      {
    +           $GLOBALS['egw']->js =& CreateObject('phpgwapi.javascript');
    +      }
     
    -

    These are a few messages to show the user what happend, we show it via 'msg' in content in the first Label-field after the app-title.
    -As one of the messages contain a %s to be used with sprintf, we have to run them manualy through lang().

    + }

    +

    +

    +

    Finally, the edit function is the one which does all the work from +a user perspective.

    +
    function edit($content='') 
    +{
    +        if (is_array($content)) // we are called as a call back
    +        {
    +                $r_id = $content['id'];
    +                if ($r_id>0) // if we have an id -> read the entry
    +                {
    +                        $content = $this->bo->read($content['id']);
    +                }
     
    -
    -	function et_media()
    -	{
    -		$this->tmpl = CreateObject('etemplate.etemplate','et_media.edit');
    +                if (isset($content['save']))
    +                {
    +                        unset($content['save']);
    +                        $msg .= (!$this->bo->save($content))?lang('Entry Saved'):lang('Error: while saving');
    +                }
    +                elseif (isset($content['read']))
    +                {
    +                        unset($content['id']);
    +                        unset($content['read']);
    +                        $found = $this->bo->so->search($content, False, 'name, author');
     
    -		$this->so_sql('et_media','phpgw_et_media');	// sets up our storage layer using the table 'phpgw_et_media'
    -		$this->empty_on_write = "''";		// what to write in the db, if a column is empty, the default is NULL
    +                        if (!$found)
    +                        {
    +                                $msg .= lang('Nothing matched the search criteria');
    +                        }
    +                        else
    +                        {
    +                                $content = $found[0];
    +                        }
    +                }
    +        }
    +        else
    +        {
    +                $content = array();
    +        }
     
    -		$this->public_functions += array(	// this function can be called external, eg. by /index.php?menuaction=...
    -			'edit' => True,
    -			'writeLangFile' => True
    -		);
    -	}
    -
    + //now we fill the content array for the next call to etemplate.exec -

    This is the contructor of the class, it does the following for us: + $content = $content + array ( + 'msg' => $msg + ); + + $sel_options = array( + 'type' => $this->bo->types + ); + + $no_button = array( + ); + $preserv = array( + 'id' => $this->data['id'] + ); + + $this->tmpl->exec( + 'et_media.ui_et_media.edit', // setting this function as the callback + $content,$sel_options, $no_button,$preserv + ); + } + }

    +The edit function is called from our index.php file or as callback +for this form / dialog. In that case $content is an array with the +content the user put into the fields of the dialog.

    +

    Let first have a look what happend if we called the first time (or +what we do to show the dialog again with the changed data):

      -
    1. creates a eTemplate object and load direct our 'et_media.show' template via the constructor -
    2. set up our storage-layer, this is the so_sql class we are extending.
      - so_sql provides basic functions to read, write, delete and search records in a sql-database. - It get's the information it needs about the structure of our table from the tables_current-file we created with the db-tools. -
    3. set up / extends from so_sql the public_functions array, all functions called which should be called by links or as methode, - like our callbacks, need to be listed here. -
    - -
    -	function edit($content='',$msg = '')
    -	{
    -		if (is_array($content))	// we are called as callback for the dialog / form
    -		{
    -			if ($content['id'] > 0)		// if we have an id --> read the entry
    -			{
    -				$this->read($content);
    -			}
    -			$this->data_merge($content);	// merge content with our internal data-array ($this->data)
    -
    -			if (isset($content['save']))	// save the entry ($this->data)
    -			{
    -				$msg .= !$this->save() ? lang('Entry saved') : lang('Error: while saving !!!');
    -			}
    -			elseif (isset($content['read']))
    -			{
    -				unset($content['id']);					// not set by user, so dont use for seach
    -				$found = $this->search($content,False,'name,author');	// searches by using the no-empty fields
    -
    -				if (!$found)			// search returned empty
    -				{
    -					$msg .= lang('Nothing matched search criteria !!!');
    -				}
    -				else
    -				{
    -					$this->init($found[0]);	// set data-array with the content of the first match
    -				}
    -			}
    -		}
    -
    -		// now we filling the content array for the next call to etemplate.exec
    -
    -		$content = $this->data + array(	// the content to be merged in the template
    -			'msg' => $msg
    -		);
    -		$sel_options = array(		// the options for our type selectbox
    -			'type' => $this->types
    -		);
    -		$no_button = array(		// button not to show
    -		);
    -		$preserv = array(		// this data is preserved over the exec-call (like a hidden input-field in form)
    -				'id' => $this->data['id']
    -		);
    -		$this->tmpl->exec(
    -			'et_media.et_media.edit',	// setting this function as callback for the dialog
    -			$content,$sel_options,$no_button,$preserv
    -		);
    -	}
    -}
    -
    - -

    The edit function is called from our index.php file or as callback for this form / dialog. In that case $content is an array -with the content the user put into the fields of the dialog.

    -

    Let first have a look what happend if we called the first time (or what we do to show the dialog again with the changed data):
    +

  • the $content array is set up with + our internal data-array (which is empty on the first call) and the + message +

    +
  • $sel_options has the options for + our selectbox: the options are an array where the keys are the + values returned by the selectbox and the values are what the + selectbox shows to the user. As we can have more than one selectbox + in a dialog, the key in $sel_options need to be the same as the name + of the selectbox. +

    +
  • $readonlys: if a fieldname is set + in $readonlys to True, its content is showed readonly (for regular + fields like type Text) or left out for buttons (we use this later to + show the delete-button only when an entry is loaded) +

    +
  • the array $preserv is preserved, + which means its stored in the app's session-data and is delivered + back like the content of the fields to the callback-function. We use + it here to store the id of the entry. This is similar to use a + hidden input-field in a form, but it does not need to be serialized + by the app and is NOT transmitted to the user and back. +

    +
  • at last we call etemplate::exec to show the template with the + content from $content and set the function itself as callback for + the dialog / form. +

    +
  • +

    Now let's have a look what happens if the user submits the form +and our callback is called: +

      -
    1. the $content array is set up with our internal data-array (which is empty on the first call) and the message -
    2. $sel_options has the options for our selectbox: the options are an array where the keys are the values returned by the selectbox - and the values are what the selectbox shows to the user. As we can have more than one selectbox in a dialog, the key in - $sel_options need to be the same as the name of the selectbox. -
    3. $readonlys: if a fieldname is set in $readonlys to True, its content is showed readonly (for regular fields like type Text) - or left out for buttons (we use this later to show the delete-button only when an entry is loaded) -
    4. the array $preserv is preserved, which means its stored in the app's session-data and is delivered back like the content of the - fields to the callback-function. We use it here to store the id of the entry. This is similar to use a hidden input-field in a - form, but it does not need to be serialized by the app and is NOT transmitted to the user and back. -
    5. at last we call etemplate::exec to show the template with the content from $content and set the function itself as callback - for the dialog / form. -
    -

    Now let's have a look what happens if the user submits the form and our callback is called: -

      -
    1. the callback (this function) is not the submit-address of the form, the form get's always submitted to the function - process_exec of the etemplate class. This function changes for some field-types the content (eg. a date-field consists - of 3 single fields, process_exec takes care that it is delivered back as timestamp, as we set it in content before). It can - even submit the form back to the user if for a address-selection a search for a pattern has to be performed and the matches - are shown to the user. In this case the callback is NOT called. The same is true if an int field contains letters or is not - within the minimum or maximum set. Not all of the is allready working, it will follow in the next days/weeks.
      - For the specialist process_exec uses $_POST and ignores $_GET set as query in the url. -
    2. the so_sql function data_merge, copies all values from $content, which are columns in the db-table, in our internal data array. - Values which are not real data, like buttons pressed are not copied (!). -
    3. if $content['save'] is set, the [Save] button has been pressed ('save' is the name NOT the label of the save button), in that - case we use so_sql's save function to save the content of our internal data-array to the db. -
    4. the same check is used for the [Read]: we uses the content of all fields to search db for matching entries. The user can use - wildcards to perform a search on all field. The wildcards are '*' and '?', so_sql translates them into sql-wildcards. -
    5. if the search return False we just set our message var. -
    6. if something is found we use so_sql's init-function to set the data of the first match. Lateron we will show a list if - more than one entry is found. -
    7. after that the content array is filled again as discriped above. -
    - -

    Now we are able to store entries in the db and retrive them by searching the database for patterns in the different fields.
    -We are only lacking some way to show if we get more than one match on a search, that's what we are going to implement next:

    - +
  • the callback (this function) is + not the submit-address of the form, the form get's always submitted + to the function process_exec of the etemplate class. This + function changes for some field-types the content (eg. a date-field + consists of 3 single fields, process_exec takes care that it is + delivered back as timestamp, as we set it in content before). It can + even submit the form back to the user if for a address-selection a + search for a pattern has to be performed and the matches are shown + to the user. In this case the callback is NOT called. The same is + true if an int field contains letters or is not within the minimum + or maximum set. Not all of the is allready working, it will + follow in the next days/weeks.
    For the specialist + process_exec uses $_POST and ignores $_GET set as query in the url. +

    +
  • the so_sql function data_merge, + copies all values from $content, which are columns in the db-table, + in our internal data array. Values which are not real data, like + buttons pressed are not copied (!). +

    +
  • if $content['save'] is set, the + [Save] button has been pressed ('save' is the name NOT the label of + the save button), in that case we use so_sql's save function to save + the content of our internal data-array to the db. +

    +
  • the same check is used for the + [Read]: we uses the content of all fields to search db for matching + entries. The user can use wildcards to perform a search on all + field. The wildcards are '*' and '?', so_sql translates them into + sql-wildcards. +

    +
  • if the search return False we just + set our message var. +

    +
  • if something is found we use + so_sql's init-function to set the data of the first match. Lateron + we will show a list if more than one entry is found. +

    +
  • after that the content array is filled again as discriped + above. +

    +
  • +

    Now we are able to store entries in the db and retrive them by +searching the database for patterns in the different fields. You can +try your new application now. You can create new records and save +them. By just entering the name or author, the database will find the +corresponding match and populate the form for you.

    +


    We are only lacking some way to show if we get more than one +match on a search, that's what we are going to implement next:

    7. adding a list-dialog for the search-function

    -

    First we need to create an other eTemplate to show the list: 'et_media.show'

    +

    First we need to create an other eTemplate to show the list: +'et_media.show' as follows. This is made of a label of name +“msg” (to display messages), an HorizontalRule widget, and a +Template widget: we will use a “sub template” called +et_media.show.rows to display the rows of the search function. I have +set the option of the template widget to “entry” as this is the +name we will use to access to the data in the sub-template. +

    +




    +

    +

    The 'et_media.show.rows' template is +created as a 3x2 table. On the header row, two labels “Name” and +“Author” and one empty cell.

    +

    On the second row, two labels of +name ${row}[name] and ${row}[author]. In the last cell a +submitButton of label “Edit” and of name “edit[$row_cont[$id]]” +

    +




    +

    +

    The class of the header row is “nmh” and the class of the +content row is “nmr”. eTemplate will automatically vary the +colors of the “nmr” class to provide a nice visual effect.

    +

    Here is a view of the et_media.show template once the two +templates have been created:

    +




    +

    +

    We need some code / a function in the class to call the template +and fill the content:

    +
            function show($found)
    +        {
    +                if (!is_array($found) || !count($found))
    +                {
    +                        $this->edit();
    +                        return;
    +                }
    +                reset($found);          // create array with all matches, indexes starting with 1
    +                for ($row=1; list($key,$data) = each($found); ++$row)
    +                {
    +                        $entry[$row] = $data;
    +                }
    +                $content = array(
    +                        'msg' => lang('%d matches on search criteria',count($found)),
    +                        'entry' => $entry               // et_media.show.rows uses this, as we put 'entry' in the Options-field
    +                );
    +                $this->tmpl->read('et_media.show');     // read the show-template
     
    -
    -
    -

    As you see the templates includes an other template: 'et_media.show.rows'

    - - - -

    We need some code / a function in the class to call the template and fill the content:

    - -
    -	function show($found)
    -	{
    -		if (!is_array($found) || !count($found))
    -		{
    -			$this->edit();
    -			return;
    -		}
    -		reset($found);		// create array with all matches, indexes starting with 1
    -		for ($row=1; list($key,$data) = each($found); ++$row)
    -		{
    -			$entry[$row] = $data;
    -		}
    -		$content = array(
    -			'msg' => lang('%d matches on search criteria',count($found)),
    -			'entry' => $entry		// et_media.show.rows uses this, as we put 'entry' in the Options-field
    -		);
    -		$this->tmpl->read('et_media.show'); 	// read the show-template
    -
    -		$this->tmpl->exec('et_media.et_media.edit',$content);	// exec it with the edit-function as callback
    -	}
    -
    - -

    This function is called by edit with the matches of a search:

    + $this->tmpl->exec('et_media.ui_et_media.edit',$content); // exec it with the edit-function as callback + }

    +This function is called by edit with the matches of a search:

      -
    1. We build an array with all the matches, the index in that array is the row-number starting with 1 (!) - ($entry = array('empty') + $found; would do the same).
      - The names in the data-row (last row) of 'et_media.show.rows' are like '${row}[name]'. Variable expansion is performed on each - name and expands that for the first row to '1[name]' which addresses the name in the first match. -
    2. $content contains again 'msg' which we set to the number of entris found and the above array with the data of all rows under - the key 'entry', as we put that in Options for the field loading the sub-template 'et_media.show.rows'. It not necessary to - put something in Options-field / use a sub-array for a sub-template, but it can be very helpful to organize a complex content-array. - (As an exercice you can remove 'entry' from the Options-field and change the function arrcordingly). -
    3. we now explizitly read the template 'et_media.show' (the constructor reed 'et_media.edit') and execute it again with - the edit function as callback (because of that, show does NOT need to be listed in public_functions) -
    4. as 'et_media.show.rows' contains only one data-row, but fieldnames with variables to expand, that row is autorepeated - for as many data we put into the content array (or the sub-array if we used the Options-field). -
    - -

    To call the show function, we need to make some changes to the edit-function too:

    - -
    -			elseif (isset($content['read']))
    -			{
    -				unset($content['id']);					// not set by user, so dont use for seach
    -				$found = $this->search($content,False,'name,author');	// searches by using the no-empty fields
    -
    -				if (!$found)	// search returned empty
    -				{
    -					$msg .= lang('Nothing matched search criteria !!!');
    -				}
    -				elseif (count($found) == 1)		// only one match --> show it in the editor
    -				{
    -					$this->init($found[0]);
    -				}
    -				else					// multiple matches --> use the show function/template
    -				{
    -					$this->show($found);
    -					return;
    -				}
    -			}
    -			elseif (isset($content['entry']['edit']))	// the callback from for the show function/template
    -			{						// the id is set via the button name of '$row_cont[id]'
    -				list($id) = each($content['entry']['edit']);	// note its not only ['edit'] !!!
    -				if ($id > 0)
    -				{
    -					$this->read(array('id' => $id));
    -				}
    -			}
    -
    +
  • We build an array with all the + matches, the index in that array is the row-number starting with 1 + (!) ($entry = array('empty') + $found; would do the same).
    The + names in the data-row (last row) of 'et_media.show.rows' are like + '${row}[name]'. Variable expansion is performed on each name and + expands that for the first row to '1[name]' which addresses the name + in the first match. +

    +
  • $content contains again 'msg' + which we set to the number of entris found and the above array with + the data of all rows under the key 'entry', as we put that in + Options for the field loading the sub-template 'et_media.show.rows'. + It not necessary to put something in Options-field / use a sub-array + for a sub-template, but it can be very helpful to organize a complex + content-array. (As an exercice you can remove 'entry' from the + Options-field and change the function arrcordingly). +

    +
  • we now explizitly read the + template 'et_media.show' (the constructor reed 'et_media.edit') and + execute it again with the edit function as callback (because of + that, show does NOT need to be listed in public_functions) +

    +
  • as 'et_media.show.rows' contains only one data-row, but + fieldnames with variables to expand, that row is autorepeated for as + many data we put into the content array (or the sub-array if we used + the Options-field). +

    +
  • +

    To call the show function, we need to make some changes to the +edit-function too:

    +
                            elseif (isset($content['read']))
    +                        {
    +                                unset($content['id']);                                  // not set by user, so dont use for seach
    +                                $found = $this->search($content,False,'name,author');   // searches by using the no-empty fields
     
    +                                if (!$found)    // search returned empty
    +                                {
    +                                        $msg .= lang('Nothing matched search criteria !!!');
    +                                }
    +                                elseif (count($found) == 1)             // only one match --> show it in the editor
    +                                {
    +                                        $this->init($found[0]);
    +                                }
    +                                else                                    // multiple matches --> use the show function/template
    +                                {
    +                                        $this->show($found);
    +                                        return;
    +                                }
    +                        }
    +                        elseif (isset($content['entry']['edit']))       // the callback from for the show function/template
    +                        {                                               // the id is set via the button name of '$row_cont[id]'
    +                                list($id) = each($content['entry']['edit']);    // note its not only ['edit'] !!!
    +                                if ($id > 0)
    +                                {
    +                                        $content = $this->bo->so->read(array('id' => $id));
    +                                }
    +                        }
      -
    1. the first part should be self-explaining, we call show with $found if it contain more than one entry. -
    2. The show function uses edit as callback, the [Edit] buttons in each row has 'edit[$row_cont[id]]' as name. If an [Edit] button is - pressed $content['entry']['edit'] is set to the id of the entry of that row. We use that id to read the whole entry. -
    - -

    While makeing this changes we can add a [Cancel] and [Delete] button too:

    - -
    -			elseif (isset($content['cancel']))
    -			{
    -				$this->init();
    -			}
    -			elseif (isset($content['delete']))
    -			{
    -				$this->delete();
    -				$this->init();
    -			}
    +	
  • the first part should be + self-explaining, we call show with $found if it contain more than + one entry. +

    +
  • The show function uses edit as callback, the [Edit] buttons + in each row has 'edit[$row_cont[id]]' as name. If an [Edit] button + is pressed $content['entry']['edit'] is set to the id of the entry + of that row. We use that id to read the whole entry. +

    +
  • +

    This is what the new “show” template looks like:

    +




    +

    +

    While makeing this changes we can add a [Cancel] and [Delete] +button too:

    +
                            elseif (isset($content['cancel']))
    +                        {
    +                                $content = array(); // clear the contents
    +                        }
    +                        elseif (isset($content['delete']))
    +                        {
    +                                $this->bo->so->delete($r_id);
    +                                $content = array(); // clear the content
    +                        }
     
     
    -		$no_button = array(	// no delete button if id == 0 --> entry not saved
    -			'delete' => !$this->data[$this->db_key_cols[$this->autoinc_id]]
    -		);
    -
    - + $no_button = array( // no delete button if id == 0 --> entry not saved + 'delete' => !$this->content['id']; + );
      -
    1. on cancel we just clear the internal data-array with so_sql's init function. -
    2. on delete we have to call so_sql's delete before (it deletes the db-row coresponding with our internal data-array) -
    3. the last block checks if the id field is set (it can only be set by a read or save) and disables the [Delete] button if not - ($this->db_key_cols[$this->autoinc_id] == 'id'). -
    - -

    Of course we have to add this buttons to the template 'et_media.edit'. I trust you can add 2 Submitbuttons with the names -'cancel' and 'delete', a Label and a nice helpmessages by now without looking at a screenshot ;-).

    - +
  • on cancel we just clear the + internal data-array with so_sql's init function. +

    +
  • on delete we have to call so_sql's + delete before (it deletes the db-row coresponding with our internal + data-array) +

    +
  • the last block checks if the id field is set (it can only be + set by a read or save) and disables the [Delete] button if not + ($this->db_key_cols[$this->autoinc_id] == 'id'). +

    +
  • +

    Of course we have to add this buttons to the template +'et_media.edit'. I trust you can add 2 Submitbuttons with the names +'cancel' and 'delete', a Label and a nice helpmessages by now without +looking at a screenshot ;-).

    8. creating the english lang-file

    -

    To get rid of the stars '*' behind each Label and to be able to translate the app in other languages we need to create a lang-file
    -There are 2 possibilties to create it automaticaly:

    +

    To get rid of the stars '*' behind each Label and to be able to +translate the app in other languages we need to create a +lang-file
    There are 2 possibilties to create it automaticaly:

      -
    1. Use the [Write Langfile] button in the eTemplate editor (put the app-name 'et_media' in the name-field first)
      - That will omitt our own messages in the class!!! -
    2. We use a function in our class to call etemplate::writeLangFile('et_media','en',$extra) and can so supply some extra strings.
      - If we add this function to the public_functions-array in our class, we can just call this function via the browser:
      - http://ourDomain/eGroupWare/index.php?menuaction=et_media.et_media.writeLangFile (the errormsg can be savely ignored)
      - This is the function (don't forget to add it like the edit-function to public_functions): -
    -

    Anyway we have to use the TranslationTools to find and write the lang()-messages of our code!

    - -
    -	/*!
    -	@function writeLangFile
    -	@abstract writes langfile with all templates registered here
    -	@discussion can be called via [write Langfile] in eTemplate editor
    -	*/
    -	function writeLangFile()
    -	{
    -		return $this->tmpl->writeLangFile('et_media','en',$this->types);
    -	}
    -
    - -

    9. dumping the eTemplate to a file for distribution

    -

    To be able to put the eTemplates in CVS and to ship them with your app, you need to dump them in a file first. -

    This is done in the eTemplate editor by putting the app-name or an template-name in the Name field and clicking on the button -[Dump4Setup]. This creates the file et_media/setup/etemplates.inc.php. The etemplate-class loads this file whenever it finds -a new version automaticaly.

    - +
  • Use the [Write Langfile] button in + the eTemplate editor (put the app-name 'et_media' in the name-field + first)
    That will omitt our own messages in the class!!! +

    +
  • We use a function in our class to call + etemplate::writeLangFile('et_media','en',$extra) and can so supply + some extra strings.
    If we add this function to the + public_functions-array in our class, we can just call this function + via the + browser:
    http://ourDomain/eGroupWare/index.php?menuaction=et_media.et_media.writeLangFile + (the errormsg can be savely ignored)
    This is the function (don't + forget to add it like the edit-function to public_functions): +

    +
  • +

    Anyway we have to use the TranslationTools to find and write the +lang()-messages of our code!

    +
            /*!
    +        @function writeLangFile
    +        @abstract writes langfile with all templates registered here
    +        @discussion can be called via [write Langfile] in eTemplate editor
    +        */
    +        function writeLangFile()
    +        {
    +                return $this->tmpl->writeLangFile('et_media','en',$this->types);
    +        }

    +9. dumping the eTemplate to a file for distribution

    +

    To be able to put the eTemplates in CVS and to ship them with your +app, you need to dump them in a file first. +

    +

    This is done in the eTemplate editor by putting the app-name or an +template-name in the Name field and clicking on the button +[Dump4Setup]. This creates the file +et_media/setup/etemplates.inc.php. The etemplate-class loads +this file whenever it finds a new version automaticaly.

    10. further information

      -
    1. the reference-documentation of the eTemplates -
    2. for all functions and parameters of the etemplate-class look in the comments (yes there are comments) of the files: - -
    3. for all functions and parameters of the so_sql-class look in the comments of the file class.so_sql.inc.php -
    4. for setup, the necessary files of an app or the format of tables_current.inc.php look at the exelent - docu of setup3 in the doc-dir of the setup app. -
    - -

    That's it - please contact me if you have further questions or comments about the tutorial

    - - - +
  • the reference-documentation + of the eTemplates +

    +
  • for all functions and parameters + of the etemplate-class look in the comments (yes there are + comments) of the files: +

    + +
  • for all functions and parameters + of the so_sql-class look in the comments of the file + class.so_sql.inc.php +

    +
  • for setup, the necessary files of an app or the format of + tables_current.inc.php look at the exelent docu + of setup3 in the doc-dir of the setup app. +

    +
  • +

    That's it - please contact +me if you have further questions or comments about the tutorial

    + \ No newline at end of file diff --git a/etemplate/doc/list.gif b/etemplate/doc/list.gif deleted file mode 100644 index 9f14d8fb04..0000000000 Binary files a/etemplate/doc/list.gif and /dev/null differ diff --git a/etemplate/doc/rows.gif b/etemplate/doc/rows.gif deleted file mode 100644 index 773e4582ce..0000000000 Binary files a/etemplate/doc/rows.gif and /dev/null differ diff --git a/etemplate/doc/show.gif b/etemplate/doc/show.gif deleted file mode 100644 index eed89b13d8..0000000000 Binary files a/etemplate/doc/show.gif and /dev/null differ