From 423fa639fa9a9ce9756468db15ec93b245eba05d Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 10 Feb 2005 14:18:51 +0000 Subject: [PATCH] updated dependencies --- etemplate/doc/etemplate.html | 462 +++++++++++++++++++++++++++++++++++ 1 file changed, 462 insertions(+) create mode 100644 etemplate/doc/etemplate.html diff --git a/etemplate/doc/etemplate.html b/etemplate/doc/etemplate.html new file mode 100644 index 0000000000..902ff20255 --- /dev/null +++ b/etemplate/doc/etemplate.html @@ -0,0 +1,462 @@ + + + + + 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 phpgw- and setup(3)-compatible app.

+
+

Introduction - The concept of the eTemplates

+The eTemplates + + +
+

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).

+ +

1. Creating a new phpgw 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:

+ + + +
    +
  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 +
+ +

4. creating an eTemplates for the edit-dialog

+

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:

    +

+ + +

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.

+ +

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');
+
+	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
+/**************************************************************************\
+* eGroupWare - eTemplates - Tutoria Example - a simple MediaDB           *
+* http://www.eGroupWare.org                                              *
+* 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 $ */
+
+include_once(PHPGW_INCLUDE_ROOT . '/etemplate/inc/class.so_sql.inc.php');
+$GLOBALS['phpgw_info']['flags']['included_classes']['so_sql'] = True;
+
+ +

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
+{
+	var $types = array(
+		'' => 'Select one ...',
+		'cd' => 'Compact Disc',
+		'dvd' => 'DVD',
+		'book' => 'Book',
+		'video' => 'Video Tape'
+	);
+
+ +

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().

+ +
+	function et_media()
+	{
+		$this->tmpl = CreateObject('etemplate.etemplate','et_media.edit');
+
+		$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
+
+		$this->public_functions += array(	// this function can be called external, eg. by /index.php?menuaction=...
+			'edit' => True,
+			'writeLangFile' => True
+		);
+	}
+
+ +

This is the contructor of the class, it does the following for us: +

    +
  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: writeing !!!');
+			}
+			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):
+

    +
  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:

+ +

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

+

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

+ + + +

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:

+
    +
  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));
+				}
+			}
+
+ +
    +
  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();
+			}
+
+
+		$no_button = array(	// no delete button if id == 0 --> entry not saved
+			'delete' => !$this->data[$this->db_key_cols[$this->autoinc_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 ;-).

+ +

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:

+
    +
  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.

+ +

10. further information

+
    +
  1. the referenz-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: +
      +
    • class.uietemplate.inc.php for the exec function +
    • class.boetemplate.inc.php for the variable replacement in names and about the autorepeat rows and columns +
    • class.soetemplate.inc.php for writeLangFile and all functions to read, store and dump an eTemplate +
    +
  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

+ + +