New doc for using admin/config.php. This should probably go somewhere else...

This commit is contained in:
Miles Lott 2001-12-23 00:02:44 +00:00
parent 6c2caba4ba
commit cbd35e90eb
6 changed files with 1446 additions and 0 deletions

BIN
admin/doc/adminconfig.dvi Normal file

Binary file not shown.

413
admin/doc/adminconfig.lyx Normal file
View File

@ -0,0 +1,413 @@
#LyX 1.1 created this file. For more info see http://www.lyx.org/
\lyxformat 218
\textclass docbook
\language english
\inputencoding auto
\fontscheme default
\graphics default
\paperfontsize default
\spacing single
\papersize Default
\paperpackage a4
\use_geometry 0
\use_amsmath 0
\paperorientation portrait
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\defskip medskip
\quotes_language english
\quotes_times 2
\papercolumns 1
\papersides 1
\paperpagestyle default
\layout Title
phpGroupWare admin/config.php
\layout Abstract
A brief introduction to writing hooks and templates for any application
to use this admin interface, by
\layout Abstract
Miles Lott <milosch@phpgroupware.org> Dec 22, 2001.
\layout Section
Files
\layout Subsection
config.tpl (required)
\layout Standard
In your application/templates/default directory, create a new template file
named 'config.tpl'.
This will be included by config.php and used to draw the page.
This template should include a POST method form.
The following template tags may be used:
\layout Enumerate
{action_url} - A phpgw->link to config.php will be inserted.
\layout Enumerate
{title} - This will be parsed to display 'Site Configuration'.
\layout Enumerate
{th_bg},{th_text},{row_on},{row_off} - Replaced with the current theme colors.
\layout Standard
and the following special types:
\layout Enumerate
{lang_XXX} - Filled with lang('XXX').
\layout Enumerate
{value_XXX} - Filled with the current value of config item 'XXX'.
\layout Enumerate
{selected_XXX} - set to '', or ' selected' if an option value is current.
\layout Enumerate
{hook_XXX} - Calls a function named XXX (will be discussed later).
\layout Standard
Following is an example from the addressbook application:
\layout Code
<form method="POST" action="{action_url}">
\layout Code
<table border="0" align="center">
\layout Code
<tr bgcolor="{th_bg}">
\layout Code
<td colspan="2"><font color="{th_text}">&nbsp;<b>{title}</b></font></td>
\layout Code
</tr> <tr bgcolor="{th_err}">
\layout Code
<td colspan="2">&nbsp;<b>{error}</b></font></td>
\layout Code
</tr>
\layout Code
<!-- END header -->
\layout Code
<!-- BEGIN body -->
\layout Code
<tr bgcolor="{row_on}">
\layout Code
<td colspan="2">&nbsp;</td>
\layout Code
</tr>
\layout Code
<tr bgcolor="{row_off}">
\layout Code
<td colspan="2">&nbsp;<b>{lang_Addressbook}/{lang_Contact_Settings}</b></font>
\layout Code
</td>
\layout Code
</tr>
\layout Code
<tr bgcolor="{row_on}">
\layout Code
<td>{lang_Contact_application}:</td>
\layout Code
<td><input name="newsettings[contact_application]" value="{value_contact_appli
cation}"></td>
\layout Code
</tr>
\layout Code
...
\layout Standard
Note the fieldname, newsettings[contact_application].
This array name must be used for the form values.
Next, note the value setting for this form element, {value_contact_application}.
This indicates that we want the current value of the config setting, 'contact_a
pplication', to be set and displayed on the form.
Lastly, look at the template element, {lang_Contact_application}.
Here, the value from the lang db table will be inserted if available.
\layout Standard
Let's take a look at part of the preferences/default/config.tpl:
\layout Code
<tr bgcolor="{row_on}">
\layout Code
<td>{lang_Country_Selection} ({lang_Text_Entry}/{lang_SelectBox}):</td>
\layout Code
<td>
\layout Code
<select name="newsettings[countrylist]">
\layout Code
{hook_country_set}
\layout Code
</select>
\layout Code
</td>
\layout Code
</tr>
\layout Standard
Here, we are adding a new element, {hook_country_set}.
This brings up the next file we will need to parse this value...
\layout Subsection
hook_config.inc.php (optional)
\layout Standard
At each invocation of config.php, a call to the common class function hook_single
() is made.
It attempts to include a file, hook_config.inc.php as a set of code for config.php
to use.
In the case of the preferences example above, using hook_country_set, here
is the corresponding function in preferences/inc/hook_config.inc.php:
\layout Code
function country_set($config)
\layout Code
{
\layout Code
$country = array( 'user_choice' => 'Users Choice', 'force_select' =>
'Force Selectbox' );
\layout Code
while (list ($key, $value) = each ($country))
\layout Code
{
\layout Code
if ($config['countrylist'] == $key)
\layout Code
{
\layout Code
$selected = ' selected';
\layout Code
}
\layout Code
else
\layout Code
{
\layout Code
$selected = '';
\layout Code
}
\layout Code
$descr = lang($value);
\layout Code
$out .= '<option value="' .
$key .
'"' .
$selected .
'>' .
$descr .
'</option>' .
"
\backslash
n";
\layout Code
}
\layout Code
return $out;
\layout Code
}
\layout Standard
Note again the template value we used earlier, {hook_country_set}.
This causes config.php to look for a function named country_set().
Since we included the file with this function via the hook_single() call,
this function is executed.
It's return is a string, and the function prints nothing itself.
\layout Subsection
hook_config_validate.inc.php (optional)
\layout Standard
Once the admin clicks the submit button to post the form, we can optionally
validate their input using one or many different functions.
This is done by first making another call to hook_single() in the API common
class.
This time, the name config_validate is used, so common tries to include
'application/inc/hook_config_validate.inc.php'.
\layout Standard
If this file exists, it sets a var to tell config.php it was found.
Following then are functions named after each config we want to validate.
The following example is for addressbook:
\layout Code
$GLOBALS['phpgw_info']['server']['found_validation_hook'] = True;
\layout Code
\layout Code
/* Check a specific setting.
Name must match the setting.
*/
\layout Code
function ldap_contact_context($value='')
\layout Code
{
\layout Code
if($value == $GLOBALS['phpgw_info']['server']['ldap_context'])
\layout Code
{
\layout Code
$GLOBALS['config_error'] = 'Contact context for ldap must be
different from the context used for accounts';
\layout Code
}
\layout Code
elseif($value == $GLOBALS['phpgw_info']['server']['ldap_group_context'])
\layout Code
{
\layout Code
$GLOBALS['config_error'] = 'Contact context for ldap must be
different from the context used for groups';
\layout Code
}
\layout Code
else
\layout Code
{
\layout Code
$GLOBALS['config_error'] = '';
\layout Code
}
\layout Code
}
\layout Standard
Here we created a function to check the entered value for the config item,
ldap_contact_context.
We want to make sure the admin did not set this value to one which would
conflict with another config item, used for accounts or groups in phpGroupWare.
\layout Standard
config.php calls this function, sending it the POSTed value.
config.php continues, adding all other config items from the POSTed values.
\layout Standard
The variable $GLOBALS['config_error'] is parsed through lang(), then appended
to the local variable, $error.
If this has any value after the POSTed variables are checked, the form
then has its {error} tag filled with this result.
The form is displayed again, with the error.
If $error has no value, config.php redirects to admin/index.php.
\layout Standard
However, there is one more function that may be included in hook_config_validate.
inc.php:
\layout Code
/* Check all settings to validate input.
Name must be 'final_validation' */
\layout Code
function final_validation($value='')
\layout Code
{
\layout Code
if($value['contact_repository'] == 'ldap' && !$value['ldap_contact_dn'])
\layout Code
{
\layout Code
$GLOBALS['config_error'] = 'Contact dn must be set';
\layout Code
}
\layout Code
elseif($value['contact_repository'] == 'ldap' && !$value['ldap_contact_c
ontext'])
\layout Code
{
\layout Code
$GLOBALS['config_error'] = 'Contact context must be set';
\layout Code
}
\layout Code
else
\layout Code
{
\layout Code
$GLOBALS['config_error'] = '';
\layout Code
}
\layout Code
}
\layout Standard
config.php checks for the existence of the function 'final_validation()'.
This function can be used to check all form values at once.
It gets sent the entire $newsettings array POSTed from the form.
As with the other functions in this file, final_validation() should set
$GLOBALS['config_error'] if there is a problem.
\the_end

BIN
admin/doc/adminconfig.pdf Normal file

Binary file not shown.

534
admin/doc/adminconfig.ps Normal file
View File

@ -0,0 +1,534 @@
%!PS-Adobe-2.0
%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software
%%Title: adminconfig.dvi
%%Pages: 6
%%PageOrder: Ascend
%%BoundingBox: 0 0 612 792
%%DocumentFonts: Helvetica-Bold Times-Roman Courier Times-Italic
%%EndComments
%DVIPSWebPage: (www.radicaleye.com)
%DVIPSCommandLine: dvips -t letter -o adminconfig.ps adminconfig.dvi
%DVIPSParameters: dpi=600, compressed
%DVIPSSource: TeX output 2001.12.22:1805
%%BeginProcSet: texc.pro
%!
/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
(LaserWriter 16/600)]{A length product length le{A length product exch 0
exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
%%EndProcSet
%%BeginProcSet: 8r.enc
% @@psencodingfile@{
% author = "S. Rahtz, P. MacKay, Alan Jeffrey, B. Horn, K. Berry",
% version = "0.6",
% date = "22 June 1996",
% filename = "8r.enc",
% email = "kb@@mail.tug.org",
% address = "135 Center Hill Rd. // Plymouth, MA 02360",
% codetable = "ISO/ASCII",
% checksum = "119 662 4424",
% docstring = "Encoding for TrueType or Type 1 fonts to be used with TeX."
% @}
%
% Idea is to have all the characters normally included in Type 1 fonts
% available for typesetting. This is effectively the characters in Adobe
% Standard Encoding + ISO Latin 1 + extra characters from Lucida.
%
% Character code assignments were made as follows:
%
% (1) the Windows ANSI characters are almost all in their Windows ANSI
% positions, because some Windows users cannot easily reencode the
% fonts, and it makes no difference on other systems. The only Windows
% ANSI characters not available are those that make no sense for
% typesetting -- rubout (127 decimal), nobreakspace (160), softhyphen
% (173). quotesingle and grave are moved just because it's such an
% irritation not having them in TeX positions.
%
% (2) Remaining characters are assigned arbitrarily to the lower part
% of the range, avoiding 0, 10 and 13 in case we meet dumb software.
%
% (3) Y&Y Lucida Bright includes some extra text characters; in the
% hopes that other PostScript fonts, perhaps created for public
% consumption, will include them, they are included starting at 0x12.
%
% (4) Remaining positions left undefined are for use in (hopefully)
% upward-compatible revisions, if someday more characters are generally
% available.
%
% (5) hyphen appears twice for compatibility with both ASCII and Windows.
%
/TeXBase1Encoding [
% 0x00 (encoded characters from Adobe Standard not in Windows 3.1)
/.notdef /dotaccent /fi /fl
/fraction /hungarumlaut /Lslash /lslash
/ogonek /ring /.notdef
/breve /minus /.notdef
% These are the only two remaining unencoded characters, so may as
% well include them.
/Zcaron /zcaron
% 0x10
/caron /dotlessi
% (unusual TeX characters available in, e.g., Lucida Bright)
/dotlessj /ff /ffi /ffl
/.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef
% very contentious; it's so painful not having quoteleft and quoteright
% at 96 and 145 that we move the things normally found there down to here.
/grave /quotesingle
% 0x20 (ASCII begins)
/space /exclam /quotedbl /numbersign
/dollar /percent /ampersand /quoteright
/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash
% 0x30
/zero /one /two /three /four /five /six /seven
/eight /nine /colon /semicolon /less /equal /greater /question
% 0x40
/at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O
% 0x50
/P /Q /R /S /T /U /V /W
/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
% 0x60
/quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o
% 0x70
/p /q /r /s /t /u /v /w
/x /y /z /braceleft /bar /braceright /asciitilde
/.notdef % rubout; ASCII ends
% 0x80
/.notdef /.notdef /quotesinglbase /florin
/quotedblbase /ellipsis /dagger /daggerdbl
/circumflex /perthousand /Scaron /guilsinglleft
/OE /.notdef /.notdef /.notdef
% 0x90
/.notdef /.notdef /.notdef /quotedblleft
/quotedblright /bullet /endash /emdash
/tilde /trademark /scaron /guilsinglright
/oe /.notdef /.notdef /Ydieresis
% 0xA0
/.notdef % nobreakspace
/exclamdown /cent /sterling
/currency /yen /brokenbar /section
/dieresis /copyright /ordfeminine /guillemotleft
/logicalnot
/hyphen % Y&Y (also at 45); Windows' softhyphen
/registered
/macron
% 0xD0
/degree /plusminus /twosuperior /threesuperior
/acute /mu /paragraph /periodcentered
/cedilla /onesuperior /ordmasculine /guillemotright
/onequarter /onehalf /threequarters /questiondown
% 0xC0
/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla
/Egrave /Eacute /Ecircumflex /Edieresis
/Igrave /Iacute /Icircumflex /Idieresis
% 0xD0
/Eth /Ntilde /Ograve /Oacute
/Ocircumflex /Otilde /Odieresis /multiply
/Oslash /Ugrave /Uacute /Ucircumflex
/Udieresis /Yacute /Thorn /germandbls
% 0xE0
/agrave /aacute /acircumflex /atilde
/adieresis /aring /ae /ccedilla
/egrave /eacute /ecircumflex /edieresis
/igrave /iacute /icircumflex /idieresis
% 0xF0
/eth /ntilde /ograve /oacute
/ocircumflex /otilde /odieresis /divide
/oslash /ugrave /uacute /ucircumflex
/udieresis /yacute /thorn /ydieresis
] def
%%EndProcSet
%%BeginProcSet: texps.pro
%!
TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2
index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll
exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]/Metrics
exch def dict begin Encoding{exch dup type/integertype ne{pop pop 1 sub
dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def}
ifelse}forall Metrics/Metrics currentdict end def[2 index currentdict
end definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{
dup sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1
roll mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def
dup[exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}
if}forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}
def end
%%EndProcSet
%%BeginProcSet: special.pro
%!
TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N
/vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N
/rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N
/@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{
/hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho
X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B
/@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{
/urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known
{userdict/md get type/dicttype eq{userdict begin md length 10 add md
maxlength ge{/md md dup length 20 add dict copy def}if end md begin
/letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S
atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{
itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll
transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll
curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf
pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}
if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1
-1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3
get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip
yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub
neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{
noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop
90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get
neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr
1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr
2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4
-1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S
TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{
Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale
}if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState
save N userdict maxlength dict begin/magscale true def normalscale
currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts
/psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x
psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx
psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub
TR/showpage{}N/erasepage{}N/copypage{}N/p 3 def @MacSetUp}N/doclip{
psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2
roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath
moveto}N/endTexFig{end psf$SavedState restore}N/@beginspecial{SDict
begin/SpecialSave save N gsave normalscale currentpoint TR
@SpecialDefaults count/ocount X/dcount countdictstack N}N/@setspecial{
CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto
closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx
sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR
}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse
CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury
lineto closepath clip}if/showpage{}N/erasepage{}N/copypage{}N newpath}N
/@endspecial{count ocount sub{pop}repeat countdictstack dcount sub{end}
repeat grestore SpecialSave restore end}N/@defspecial{SDict begin}N
/@fedspecial{end}B/li{lineto}B/rl{rlineto}B/rc{rcurveto}B/np{/SaveX
currentpoint/SaveY X N 1 setlinecap newpath}N/st{stroke SaveX SaveY
moveto}N/fil{fill SaveX SaveY moveto}N/ellipse{/endangle X/startangle X
/yrad X/xrad X/savematrix matrix currentmatrix N TR xrad yrad scale 0 0
1 startangle endangle arc savematrix setmatrix}N end
%%EndProcSet
%%BeginProcSet: color.pro
%!
TeXDict begin/setcmykcolor where{pop}{/setcmykcolor{dup 10 eq{pop
setrgbcolor}{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll
}repeat setrgbcolor pop}ifelse}B}ifelse/TeXcolorcmyk{setcmykcolor}def
/TeXcolorrgb{setrgbcolor}def/TeXcolorgrey{setgray}def/TeXcolorgray{
setgray}def/TeXcolorhsb{sethsbcolor}def/currentcmykcolor where{pop}{
/currentcmykcolor{currentrgbcolor 10}B}ifelse/DC{exch dup userdict exch
known{pop pop}{X}ifelse}B/GreenYellow{0.15 0 0.69 0 setcmykcolor}DC
/Yellow{0 0 1 0 setcmykcolor}DC/Goldenrod{0 0.10 0.84 0 setcmykcolor}DC
/Dandelion{0 0.29 0.84 0 setcmykcolor}DC/Apricot{0 0.32 0.52 0
setcmykcolor}DC/Peach{0 0.50 0.70 0 setcmykcolor}DC/Melon{0 0.46 0.50 0
setcmykcolor}DC/YellowOrange{0 0.42 1 0 setcmykcolor}DC/Orange{0 0.61
0.87 0 setcmykcolor}DC/BurntOrange{0 0.51 1 0 setcmykcolor}DC
/Bittersweet{0 0.75 1 0.24 setcmykcolor}DC/RedOrange{0 0.77 0.87 0
setcmykcolor}DC/Mahogany{0 0.85 0.87 0.35 setcmykcolor}DC/Maroon{0 0.87
0.68 0.32 setcmykcolor}DC/BrickRed{0 0.89 0.94 0.28 setcmykcolor}DC/Red{
0 1 1 0 setcmykcolor}DC/OrangeRed{0 1 0.50 0 setcmykcolor}DC/RubineRed{
0 1 0.13 0 setcmykcolor}DC/WildStrawberry{0 0.96 0.39 0 setcmykcolor}DC
/Salmon{0 0.53 0.38 0 setcmykcolor}DC/CarnationPink{0 0.63 0 0
setcmykcolor}DC/Magenta{0 1 0 0 setcmykcolor}DC/VioletRed{0 0.81 0 0
setcmykcolor}DC/Rhodamine{0 0.82 0 0 setcmykcolor}DC/Mulberry{0.34 0.90
0 0.02 setcmykcolor}DC/RedViolet{0.07 0.90 0 0.34 setcmykcolor}DC
/Fuchsia{0.47 0.91 0 0.08 setcmykcolor}DC/Lavender{0 0.48 0 0
setcmykcolor}DC/Thistle{0.12 0.59 0 0 setcmykcolor}DC/Orchid{0.32 0.64 0
0 setcmykcolor}DC/DarkOrchid{0.40 0.80 0.20 0 setcmykcolor}DC/Purple{
0.45 0.86 0 0 setcmykcolor}DC/Plum{0.50 1 0 0 setcmykcolor}DC/Violet{
0.79 0.88 0 0 setcmykcolor}DC/RoyalPurple{0.75 0.90 0 0 setcmykcolor}DC
/BlueViolet{0.86 0.91 0 0.04 setcmykcolor}DC/Periwinkle{0.57 0.55 0 0
setcmykcolor}DC/CadetBlue{0.62 0.57 0.23 0 setcmykcolor}DC
/CornflowerBlue{0.65 0.13 0 0 setcmykcolor}DC/MidnightBlue{0.98 0.13 0
0.43 setcmykcolor}DC/NavyBlue{0.94 0.54 0 0 setcmykcolor}DC/RoyalBlue{1
0.50 0 0 setcmykcolor}DC/Blue{1 1 0 0 setcmykcolor}DC/Cerulean{0.94 0.11
0 0 setcmykcolor}DC/Cyan{1 0 0 0 setcmykcolor}DC/ProcessBlue{0.96 0 0 0
setcmykcolor}DC/SkyBlue{0.62 0 0.12 0 setcmykcolor}DC/Turquoise{0.85 0
0.20 0 setcmykcolor}DC/TealBlue{0.86 0 0.34 0.02 setcmykcolor}DC
/Aquamarine{0.82 0 0.30 0 setcmykcolor}DC/BlueGreen{0.85 0 0.33 0
setcmykcolor}DC/Emerald{1 0 0.50 0 setcmykcolor}DC/JungleGreen{0.99 0
0.52 0 setcmykcolor}DC/SeaGreen{0.69 0 0.50 0 setcmykcolor}DC/Green{1 0
1 0 setcmykcolor}DC/ForestGreen{0.91 0 0.88 0.12 setcmykcolor}DC
/PineGreen{0.92 0 0.59 0.25 setcmykcolor}DC/LimeGreen{0.50 0 1 0
setcmykcolor}DC/YellowGreen{0.44 0 0.74 0 setcmykcolor}DC/SpringGreen{
0.26 0 0.76 0 setcmykcolor}DC/OliveGreen{0.64 0 0.95 0.40 setcmykcolor}
DC/RawSienna{0 0.72 1 0.45 setcmykcolor}DC/Sepia{0 0.83 1 0.70
setcmykcolor}DC/Brown{0 0.81 1 0.60 setcmykcolor}DC/Tan{0.14 0.42 0.56 0
setcmykcolor}DC/Gray{0 0 0 0.50 setcmykcolor}DC/Black{0 0 0 1
setcmykcolor}DC/White{0 0 0 0 setcmykcolor}DC end
%%EndProcSet
TeXDict begin 40258431 52099146 1000 600 600 (adminconfig.dvi)
@start /Fa 138[42 2[32 1[42 42 42 60 3[23 42 42 1[37
42 37 1[42 9[69 15[60 16[42 42 42 42 42 42 1[23 21 43[42
2[{TeXBase1Encoding ReEncodeFont}24 83.022 /Times-Italic
rf /Fb 107[45 22[45 1[45 1[45 45 45 45 45 45 45 45 1[45
45 45 45 45 45 1[45 45 45 45 45 45 45 45 45 1[45 1[45
45 45 5[45 45 45 2[45 45 45 1[45 2[45 1[45 45 45 45 45
45 45 2[45 45 45 45 45 7[45 1[45 45 45 45 45 1[45 45
45 45 45 1[45 1[45 45 33[{TeXBase1Encoding ReEncodeFont}64
74.7198 /Courier rf /Fc 137[66 73 40 1[47 73 73 73 73
1[33 66 1[33 73 73 1[66 73 66 1[66 1[66 43[66 66 66 2[33
4[40 40 37[73 2[{TeXBase1Encoding ReEncodeFont}25 119.552
/Helvetica-Bold rf /Fd 140[80 6[40 2[40 3[80 30[88 20[80
2[40 46[{TeXBase1Encoding ReEncodeFont}7 143.462 /Helvetica-Bold
rf /Fe 107[37 22[40 1[40 1[42 42 60 42 42 23 32 28 1[42
42 42 65 23 42 1[23 42 42 28 37 42 37 42 37 1[42 1[28
1[28 2[60 78 2[51 46 55 1[46 60 60 74 51 2[28 60 60 46
1[60 55 55 60 76 1[47 1[47 1[23 5[42 42 42 42 42 23 21
28 21 2[28 28 28 2[42 32[46 46 2[{TeXBase1Encoding ReEncodeFont}66
83.022 /Times-Roman rf /Ff 138[126 2[80 1[126 126 126
184 3[57 126 126 1[115 126 115 1[115 9[195 15[161 23[57
57 43[126 2[{TeXBase1Encoding ReEncodeFont}18 206.584
/Helvetica-Bold rf end
%%EndProlog
%%BeginSetup
%%Feature: *Resolution 600dpi
TeXDict begin
%%BeginPaperSize: Letter
letter
%%EndPaperSize
%%EndSetup
%%Page: 1 1
1 0 bop Black 0 TeXcolorgray Black Black 505 647 a Ff(phpGr)l(oupW)-8
b(are)58 b(admin/con\002g.php)695 879 y Fe(A)21 b(brief)e(introduction)
f(to)i(writing)g(hooks)f(and)h(templates)g(for)f(an)o(y)h(application)e
(to)j(use)f(this)695 987 y(admin)f(interf)o(ace,)h(by)695
1136 y(Miles)h(Lott)f(<milosch@phpgroupw)o(are.or)o(g)o(>)15
b(Dec)20 b(22,)g(2001.)-2 1854 y Fd(1.)39 b(Files)-2
2182 y Fc(1.1.)34 b(con\002g.tpl)h(\(required\))396 2350
y Fe(In)20 b(your)f(application/templates/def)o(ault)e(directory)-5
b(,)18 b(create)i(a)g(ne)n(w)g(template)g(\002le)h(named)e
('con\002g.tpl'.)f(This)i(will)396 2458 y(be)g(included)f(by)h
(con\002g.php)d(and)j(used)g(to)g(dra)o(w)g(the)g(page.)f(This)i
(template)e(should)h(include)f(a)h(POST)h(method)396
2566 y(form.)e(The)h(follo)n(wing)f(template)g(tags)i(may)e(be)i(used:)
p Black 463 2798 a(1.)p Black 40 w({action_url})e(-)h(A)h(phpgw->link)c
(to)j(con\002g.php)e(will)j(be)f(inserted.)p Black 463
2947 a(2.)p Black 40 w({title})h(-)f(This)h(will)g(be)f(parsed)f(to)i
(display)e('Site)i(Con\002guration'.)p Black 463 3097
a(3.)p Black 40 w({th_bg},{th_te)o(xt},{ro)n(w_on)o(},{r)o(o)n(w_)o(of)
m(f})15 b(-)20 b(Replaced)g(with)g(the)g(current)f(theme)h(colors.)396
3246 y(and)g(the)g(follo)n(wing)f(special)h(types:)p
Black 463 3479 a(1.)p Black 40 w({lang_XXX})f(-)i(Filled)f(with)h
(lang\('XXX'\).)p Black 463 3628 a(2.)p Black 40 w({v)n(alue_XXX})e(-)h
(Filled)h(with)f(the)g(current)f(v)n(alue)h(of)g(con\002g)f(item)h
('XXX'.)p Black 463 3778 a(3.)p Black 40 w({selected_XXX})g(-)g(set)h
(to)f(\224,)h(or)f(')g(selected')g(if)g(an)h(option)d(v)n(alue)i(is)h
(current.)p Black 463 3927 a(4.)p Black 40 w({hook_XXX})d(-)j(Calls)g
(a)g(function)d(named)h(XXX)i(\(will)f(be)h(discussed)f(later\).)396
4077 y(F)o(ollo)n(wing)f(is)i(an)f(e)o(xample)f(from)g(the)h
(addressbook)e(application:)396 4257 y Fb(<form)44 b(method="POST")f
(action="{action_url}">)396 4354 y(<table)h(border="0")f
(align="center">)441 4451 y(<tr)h(bgcolor="{th_bg}">)486
4548 y(<td)g(colspan="2"><font)e
(color="{th_text}">&nbsp;<b>{title}</b></f)o(ont><)o(/td>)441
4645 y(</tr>)i(<tr)g(bgcolor="{th_err}">)486 4742 y(<td)g
(colspan="2">&nbsp;<b>{error}</b></font></)o(td>)441
4840 y(</tr>)p Black 3842 5278 a Fa(1)p Black eop
%%Page: 2 2
2 1 bop Black 0 TeXcolorgray Black 2778 67 a Fa(phpGr)l(oupW)-8
b(ar)m(e)19 b(admin/con\002g)o(.php)p Black 396 579 a
Fb(<!--)44 b(END)h(header)f(-->)396 676 y(<!--)g(BEGIN)g(body)h(-->)441
773 y(<tr)f(bgcolor="{row_on}">)486 870 y(<td)g
(colspan="2">&nbsp;</td>)441 967 y(</tr>)441 1065 y(<tr)g
(bgcolor="{row_off}">)486 1162 y(<td)g
(colspan="2">&nbsp;<b>{lang_Addressbook}/{)o(lang_C)o(ontact)o(_Setti)o
(ngs}<)o(/b></f)o(ont>)396 1259 y(</td>)441 1356 y(</tr>)441
1453 y(<tr)g(bgcolor="{row_on}">)486 1550 y
(<td>{lang_Contact_application}:</td>)486 1647 y(<td><input)f
(name="newsettings[contact_application]")38 b
(value="{value_contact_application}"></td>)441 1745 y(</tr>)396
1842 y(...)396 2130 y Fe(Note)20 b(the)h(\002eldname,)e(ne)n
(wsettings[contact_application].)c(This)20 b(array)f(name)h(must)g(be)g
(used)g(for)g(the)g(form)f(v)n(alues.)396 2238 y(Ne)o(xt,)h(note)g(the)
g(v)n(alue)f(setting)i(for)e(this)i(form)e(element,)g({v)n
(alue_contact_application}.)c(This)20 b(indicates)g(that)h(we)396
2346 y(w)o(ant)g(the)f(current)f(v)n(alue)g(of)h(the)g(con\002g)g
(setting,)g('contact_application',)c(to)k(be)g(set)h(and)f(displayed)f
(on)g(the)i(form.)396 2454 y(Lastly)-5 b(,)20 b(look)f(at)i(the)f
(template)g(element,)f({lang_Contact_application}.)d(Here,)j(the)i(v)n
(alue)e(from)g(the)i(lang)e(db)h(table)396 2561 y(will)h(be)f(inserted)
g(if)g(a)n(v)n(ailable.)396 2711 y(Let')-5 b(s)21 b(tak)o(e)f(a)h(look)
e(at)i(part)f(of)g(the)g(preferences/def)o(ault/con\002g.tpl:)441
2891 y Fb(<tr)44 b(bgcolor="{row_on}">)486 2988 y
(<td>{lang_Country_Selection})c
(\({lang_Text_Entry}/{lang_SelectBox}\):</)o(td>)486
3085 y(<td>)531 3182 y(<select)j(name="newsettings[countrylist]">)396
3280 y({hook_country_set})531 3377 y(</select>)486 3474
y(</td>)441 3571 y(</tr>)396 3859 y Fe(Here,)20 b(we)h(are)f(adding)f
(a)h(ne)n(w)g(element,)f({hook_country_set}.)d(This)k(brings)f(up)h
(the)g(ne)o(xt)g(\002le)h(we)f(will)h(need)f(to)396 3967
y(parse)g(this)h(v)n(alue...)-2 4337 y Fc(1.2.)34 b
(hook_con\002g.inc.php)j(\(optional\))396 4504 y Fe(At)21
b(each)f(in)m(v)n(ocation)e(of)i(con\002g.php,)d(a)k(call)g(to)f(the)g
(common)f(class)i(function)d(hook_single\(\))f(is)k(made.)f(It)g
(attempts)396 4612 y(to)h(include)e(a)h(\002le,)h
(hook_con\002g.inc.php)14 b(as)21 b(a)g(set)g(of)f(code)f(for)h
(con\002g.php)d(to)k(use.)f(In)g(the)g(case)h(of)f(the)g(preferences)
396 4720 y(e)o(xample)f(abo)o(v)o(e,)f(using)i(hook_country_set,)15
b(here)20 b(is)h(the)f(corresponding)d(function)i(in)396
4828 y(preferences/inc/hook_con\002g.)o(inc.p)o(hp)o(:)p
Black 3842 5278 a Fa(2)p Black eop
%%Page: 3 3
3 2 bop Black 0 TeXcolorgray Black 2778 67 a Fa(phpGr)l(oupW)-8
b(ar)m(e)19 b(admin/con\002g)o(.php)p Black 396 579 a
Fb(function)44 b(country_set\($config\))396 676 y({)576
773 y($country)f(=)i(array\()f('user_choice')e(=>)j('Users)f(Choice',)f
('force_select')f(=>)j('Force)f(Se-)396 870 y(lectbox')g(\);)576
967 y(while)g(\(list)g(\($key,)f($value\))h(=)h(each)f(\($country\)\))
576 1065 y({)755 1162 y(if)g(\($config['countrylist'])d(==)k($key\))755
1259 y({)934 1356 y($selected)f(=)g(')h(selected';)755
1453 y(})755 1550 y(else)755 1647 y({)934 1745 y($selected)f(=)g(\224;)
755 1842 y(})755 1939 y($descr)g(=)g(lang\($value\);)755
2036 y($out)g(.=)h('<option)e(value="')h(.)g($key)g(.)h('"')f(.)h
($selected)e(.)i('>')f(.)h($descr)f(.)g('</option>')f(.)i("\\n";)576
2133 y(})576 2230 y(return)e($out;)396 2327 y(})396 2615
y Fe(Note)20 b(again)g(the)g(template)f(v)n(alue)h(we)h(used)e(earlier)
m(,)h({hook_country_set}.)15 b(This)20 b(causes)h(con\002g.php)c(to)k
(look)e(for)h(a)396 2723 y(function)f(named)g(country_set\(\).)e(Since)
j(we)h(included)d(the)j(\002le)g(with)f(this)h(function)d(via)i(the)g
(hook_single\(\))d(call,)396 2831 y(this)k(function)d(is)k(e)o(x)o
(ecuted.)c(It')-5 b(s)21 b(return)e(is)i(a)f(string,)g(and)g(the)g
(function)e(prints)i(nothing)f(itself.)-2 3201 y Fc(1.3.)34
b(hook_con\002g_v)n(alidate)r(.inc.php)39 b(\(optional\))396
3369 y Fe(Once)20 b(the)g(admin)g(clicks)g(the)g(submit)g(b)n(utton)f
(to)i(post)f(the)g(form,)f(we)i(can)f(optionally)e(v)n(alidate)i(their)
g(input)f(using)396 3477 y(one)h(or)g(man)o(y)f(dif)n(ferent)f
(functions.)h(This)h(is)h(done)e(by)h(\002rst)h(making)e(another)g
(call)h(to)h(hook_single\(\))c(in)j(the)g(API)396 3584
y(common)f(class.)h(This)h(time,)f(the)g(name)g(con\002g_v)n(alidate)d
(is)k(used,)f(so)h(common)d(tries)j(to)f(include)396
3692 y('application/inc/hook_con\002g_)o(v)n(a)o(lidate.in)o(c.p)o(hp)o
('.)396 3842 y(If)g(this)h(\002le)g(e)o(xists,)f(it)h(sets)g(a)g(v)n
(ar)f(to)g(tell)h(con\002g.php)d(it)i(w)o(as)i(found.)c(F)o(ollo)n
(wing)h(then)g(are)h(functions)f(named)g(after)396 3950
y(each)h(con\002g)f(we)i(w)o(ant)f(to)h(v)n(alidate.)e(The)h(follo)n
(wing)e(e)o(xample)h(is)i(for)f(addressbook:)576 4130
y Fb($GLOBALS['phpgw_info']['server']['fou)o(nd_val)o(idatio)o(n_hook)o
('])39 b(=)45 b(True;)576 4227 y(/*)f(Check)g(a)h(specific)e(setting.)h
(Name)g(must)g(match)g(the)g(setting.)g(*/)576 4324 y(function)f
(ldap_contact_context\($value=\224\))576 4421 y({)755
4518 y(if\($value)g(==)i($GLOBALS['phpgw_info']['server']['ldap)o
(_conte)o(xt']\))755 4616 y({)934 4713 y($GLOBALS['config_error'])c(=)k
('Contact)e(context)h(for)g(ldap)g(must)g(be)h(differ-)396
4810 y(ent)g(from)f(the)g(context)g(used)g(for)g(accounts';)p
Black 3842 5278 a Fa(3)p Black eop
%%Page: 4 4
4 3 bop Black 0 TeXcolorgray Black 2778 67 a Fa(phpGr)l(oupW)-8
b(ar)m(e)19 b(admin/con\002g)o(.php)p Black 755 579 a
Fb(})755 676 y(elseif\($value)43 b(==)h
($GLOBALS['phpgw_info']['server']['ldap_g)o(roup_)o(contex)o(t']\))755
773 y({)934 870 y($GLOBALS['config_error'])d(=)k('Contact)e(context)h
(for)g(ldap)g(must)g(be)h(differ-)396 967 y(ent)g(from)f(the)g(context)
g(used)g(for)g(groups';)755 1065 y(})755 1162 y(else)755
1259 y({)934 1356 y($GLOBALS['config_error'])d(=)k(\224;)755
1453 y(})576 1550 y(})396 1838 y Fe(Here)20 b(we)f(created)g(a)h
(function)e(to)i(check)e(the)i(entered)e(v)n(alue)h(for)g(the)g
(con\002g)g(item,)g(ldap_contact_conte)o(xt.)c(W)-7 b(e)21
b(w)o(ant)396 1946 y(to)g(mak)o(e)e(sure)h(the)h(admin)e(did)h(not)g
(set)h(this)f(v)n(alue)g(to)g(one)g(which)g(w)o(ould)f(con\003ict)h
(with)g(another)f(con\002g)g(item,)h(used)396 2054 y(for)g(accounts)f
(or)h(groups)f(in)h(phpGroupW)-7 b(are.)396 2204 y(con\002g.php)18
b(calls)j(this)g(function,)d(sending)h(it)i(the)f(POST)-6
b(ed)20 b(v)n(alue.)f(con\002g.php)f(continues,)h(adding)g(all)h(other)
g(con\002g)396 2312 y(items)h(from)e(the)h(POST)-6 b(ed)21
b(v)n(alues.)396 2461 y(The)f(v)n(ariable)f($GLOB)m
(ALS['con\002g_error'])c(is)21 b(parsed)f(through)e(lang\(\),)h(then)g
(appended)f(to)j(the)f(local)g(v)n(ariable,)396 2569
y($error)-5 b(.)19 b(If)h(this)h(has)f(an)o(y)g(v)n(alue)f(after)h(the)
g(POST)-6 b(ed)20 b(v)n(ariables)g(are)g(check)o(ed,)f(the)h(form)f
(then)h(has)g(its)h({error})e(tag)396 2677 y(\002lled)i(with)f(this)h
(result.)f(The)g(form)f(is)i(displayed)e(again,)g(with)h(the)g(error)-5
b(.)20 b(If)g($error)e(has)j(no)e(v)n(alue,)h(con\002g.php)396
2785 y(redirects)g(to)g(admin/inde)o(x.php.)396 2934
y(Ho)n(we)n(v)o(er)m(,)e(there)i(is)h(one)f(more)f(function)g(that)h
(may)g(be)g(included)e(in)j(hook_con\002g_v)n(alidate.inc)o(.ph)o(p:)
576 3114 y Fb(/*)44 b(Check)g(all)g(settings)g(to)g(validate)g(input.)g
(Name)g(must)g(be)h('final_validation')c(*/)576 3212
y(function)i(final_validation\($value=\224\))576 3309
y({)755 3406 y(if\($value['contact_repository'])d(==)k('ldap')g(&&)g
(!$value['ldap_contact_dn']\))755 3503 y({)934 3600 y
($GLOBALS['config_error'])d(=)k('Contact)e(dn)i(must)f(be)g(set';)755
3697 y(})755 3794 y(elseif\($value['contact_repository'])39
b(==)44 b('ldap')g(&&)h(!$value['ldap_contact_context']\))755
3891 y({)934 3989 y($GLOBALS['config_error'])c(=)k('Contact)e(context)h
(must)g(be)h(set';)755 4086 y(})755 4183 y(else)755 4280
y({)934 4377 y($GLOBALS['config_error'])c(=)k(\224;)755
4474 y(})576 4571 y(})p Black 3842 5278 a Fa(4)p Black
eop
%%Page: 5 5
5 4 bop Black 0 TeXcolorgray Black 2778 67 a Fa(phpGr)l(oupW)-8
b(ar)m(e)19 b(admin/con\002g)o(.php)p Black 396 579 a
Fe(con\002g.php)f(checks)i(for)f(the)h(e)o(xistence)g(of)g(the)g
(function)e('\002nal_v)n(alidation\(\)'.)f(This)j(function)e(can)i(be)g
(used)g(to)396 687 y(check)g(all)g(form)g(v)n(alues)f(at)i(once.)e(It)i
(gets)f(sent)h(the)f(entire)g($ne)n(wsettings)f(array)g(POST)-6
b(ed)21 b(from)e(the)h(form.)f(As)i(with)396 795 y(the)f(other)g
(functions)f(in)h(this)h(\002le,)f(\002nal_v)n(alidation\(\))d(should)j
(set)h($GLOB)m(ALS['con\002g_error'])15 b(if)20 b(there)g(is)h(a)396
903 y(problem.)p Black 3842 5278 a Fa(5)p Black eop
%%Page: 6 6
6 5 bop Black 0 TeXcolorgray Black 2778 67 a Fa(phpGr)l(oupW)-8
b(ar)m(e)19 b(admin/con\002g)o(.php)p Black Black 3840
5278 a(6)p Black eop
%%Trailer
end
userdict /end-hook known{end-hook}if
%%EOF

216
admin/doc/adminconfig.sgml Normal file
View File

@ -0,0 +1,216 @@
<!doctype article public "-//OASIS//DTD DocBook V3.1//EN">
<article lang="en">
<!-- DocBook file was created by LyX 1.1
See http://www.lyx.org/ for more information -->
<artheader>
<title>
phpGroupWare admin/config.php
</title>
<abstract>
<para>
A brief introduction to writing hooks and templates for any application to use this admin interface, by
</para>
<para>
Miles Lott &lt;milosch@phpgroupware.org&gt; Dec 22, 2001.
</para>
</abstract>
</artheader>
<sect1>
<title>
Files
</title>
<sect2>
<title>
config.tpl (required)
</title>
<para>
In your application/templates/default directory, create a new template file named 'config.tpl'. This will be included by config.php and used to draw the page. This template should include a POST method form. The following template tags may be used:
</para>
<orderedlist>
<listitem>
<para>
&lcub;action_url&rcub; - A phpgw-&gt;link to config.php will be inserted.
</para>
</listitem>
<listitem>
<para>
&lcub;title&rcub; - This will be parsed to display 'Site Configuration'.
</para>
</listitem>
<listitem>
<para>
&lcub;th_bg&rcub;,&lcub;th_text&rcub;,&lcub;row_on&rcub;,&lcub;row_off&rcub; - Replaced with the current theme colors.
</para>
</listitem>
</orderedlist>
<para>
and the following special types:
</para>
<orderedlist>
<listitem>
<para>
&lcub;lang_XXX&rcub; - Filled with lang('XXX').
</para>
</listitem>
<listitem>
<para>
&lcub;value_XXX&rcub; - Filled with the current value of config item 'XXX'.
</para>
</listitem>
<listitem>
<para>
&lcub;selected_XXX&rcub; - set to '', or ' selected' if an option value is current.
</para>
</listitem>
<listitem>
<para>
&lcub;hook_XXX&rcub; - Calls a function named XXX (will be discussed later).
</para>
</listitem>
</orderedlist>
<para>
Following is an example from the addressbook application:
</para>
<programlisting>
<![ CDATA [<form method="POST" action="{action_url}">
]]><![ CDATA [<table border="0" align="center">
]]><![ CDATA [ <tr bgcolor="{th_bg}">
]]><![ CDATA [ <td colspan="2"><font color="{th_text}">&nbsp;<b>{title}</b></font></td>
]]><![ CDATA [ </tr> <tr bgcolor="{th_err}">
]]><![ CDATA [ <td colspan="2">&nbsp;<b>{error}</b></font></td>
]]><![ CDATA [ </tr>
]]><![ CDATA [<!-- END header -->
]]><![ CDATA [<!-- BEGIN body -->
]]><![ CDATA [ <tr bgcolor="{row_on}">
]]><![ CDATA [ <td colspan="2">&nbsp;</td>
]]><![ CDATA [ </tr>
]]><![ CDATA [ <tr bgcolor="{row_off}">
]]><![ CDATA [ <td colspan="2">&nbsp;<b>{lang_Addressbook}/{lang_Contact_Settings}</b></font>
]]><![ CDATA [</td>
]]><![ CDATA [ </tr>
]]><![ CDATA [ <tr bgcolor="{row_on}">
]]><![ CDATA [ <td>{lang_Contact_application}:</td>
]]><![ CDATA [ <td><input name="newsettings[contact_application]" value="{value_contact_application}"></td>
]]><![ CDATA [ </tr>
]]><![ CDATA [...
]]> </programlisting>
<para>
Note the fieldname, newsettings&lsqb;contact_application&rsqb;. This array name must be used for the form values. Next, note the value setting for this form element, &lcub;value_contact_application&rcub;. This indicates that we want the current value of the config setting, 'contact_application', to be set and displayed on the form. Lastly, look at the template element, &lcub;lang_Contact_application&rcub;. Here, the value from the lang db table will be inserted if available.
</para>
<para>
Let's take a look at part of the preferences/default/config.tpl:
</para>
<programlisting>
<![ CDATA [ <tr bgcolor="{row_on}">
]]><![ CDATA [ <td>{lang_Country_Selection} ({lang_Text_Entry}/{lang_SelectBox}):</td>
]]><![ CDATA [ <td>
]]><![ CDATA [ <select name="newsettings[countrylist]">
]]><![ CDATA [{hook_country_set}
]]><![ CDATA [ </select>
]]><![ CDATA [ </td>
]]><![ CDATA [ </tr>
]]> </programlisting>
<para>
Here, we are adding a new element, &lcub;hook_country_set&rcub;. This brings up the next file we will need to parse this value...
</para>
</sect2>
<sect2>
<title>
hook_config.inc.php (optional)
</title>
<para>
At each invocation of config.php, a call to the common class function hook_single() is made. It attempts to include a file, hook_config.inc.php as a set of code for config.php to use. In the case of the preferences example above, using hook_country_set, here is the corresponding function in preferences/inc/hook_config.inc.php:
</para>
<programlisting>
<![ CDATA [function country_set($config)
]]><![ CDATA [{
]]><![ CDATA [ $country = array( 'user_choice' => 'Users Choice', 'force_select' => 'Force Selectbox' );
]]><![ CDATA [ while (list ($key, $value) = each ($country))
]]><![ CDATA [ {
]]><![ CDATA [ if ($config['countrylist'] == $key)
]]><![ CDATA [ {
]]><![ CDATA [ $selected = ' selected';
]]><![ CDATA [ }
]]><![ CDATA [ else
]]><![ CDATA [ {
]]><![ CDATA [ $selected = '';
]]><![ CDATA [ }
]]><![ CDATA [ $descr = lang($value);
]]><![ CDATA [ $out .= '<option value="' . $key . '"' . $selected . '>' . $descr . '</option>' . "\n";
]]><![ CDATA [ }
]]><![ CDATA [ return $out;
]]><![ CDATA [}
]]> </programlisting>
<para>
Note again the template value we used earlier, &lcub;hook_country_set&rcub;. This causes config.php to look for a function named country_set(). Since we included the file with this function via the hook_single() call, this function is executed. It's return is a string, and the function prints nothing itself.
</para>
</sect2>
<sect2>
<title>
hook_config_validate.inc.php (optional)
</title>
<para>
Once the admin clicks the submit button to post the form, we can optionally validate their input using one or many different functions. This is done by first making another call to hook_single() in the API common class. This time, the name config_validate is used, so common tries to include 'application/inc/hook_config_validate.inc.php'.
</para>
<para>
If this file exists, it sets a var to tell config.php it was found. Following then are functions named after each config we want to validate. The following example is for addressbook:
</para>
<programlisting>
<![ CDATA [ $GLOBALS['phpgw_info']['server']['found_validation_hook'] = True;
]]><![ CDATA [
]]><![ CDATA [ /* Check a specific setting. Name must match the setting. */
]]><![ CDATA [ function ldap_contact_context($value='')
]]><![ CDATA [ {
]]><![ CDATA [ if($value == $GLOBALS['phpgw_info']['server']['ldap_context'])
]]><![ CDATA [ {
]]><![ CDATA [ $GLOBALS['config_error'] = 'Contact context for ldap must be different from the context used for accounts';
]]><![ CDATA [ }
]]><![ CDATA [ elseif($value == $GLOBALS['phpgw_info']['server']['ldap_group_context'])
]]><![ CDATA [ {
]]><![ CDATA [ $GLOBALS['config_error'] = 'Contact context for ldap must be different from the context used for groups';
]]><![ CDATA [ }
]]><![ CDATA [ else
]]><![ CDATA [ {
]]><![ CDATA [ $GLOBALS['config_error'] = '';
]]><![ CDATA [ }
]]><![ CDATA [ }
]]> </programlisting>
<para>
Here we created a function to check the entered value for the config item, ldap_contact_context. We want to make sure the admin did not set this value to one which would conflict with another config item, used for accounts or groups in phpGroupWare.
</para>
<para>
config.php calls this function, sending it the POSTed value. config.php continues, adding all other config items from the POSTed values.
</para>
<para>
The variable &dollar;GLOBALS&lsqb;'config_error'&rsqb; is parsed through lang(), then appended to the local variable, &dollar;error. If this has any value after the POSTed variables are checked, the form then has its &lcub;error&rcub; tag filled with this result. The form is displayed again, with the error. If &dollar;error has no value, config.php redirects to admin/index.php.
</para>
<para>
However, there is one more function that may be included in hook_config_validate.inc.php:
</para>
<programlisting>
<![ CDATA [ /* Check all settings to validate input. Name must be 'final_validation' */
]]><![ CDATA [ function final_validation($value='')
]]><![ CDATA [ {
]]><![ CDATA [ if($value['contact_repository'] == 'ldap' && !$value['ldap_contact_dn'])
]]><![ CDATA [ {
]]><![ CDATA [ $GLOBALS['config_error'] = 'Contact dn must be set';
]]><![ CDATA [ }
]]><![ CDATA [ elseif($value['contact_repository'] == 'ldap' && !$value['ldap_contact_context'])
]]><![ CDATA [ {
]]><![ CDATA [ $GLOBALS['config_error'] = 'Contact context must be set';
]]><![ CDATA [ }
]]><![ CDATA [ else
]]><![ CDATA [ {
]]><![ CDATA [ $GLOBALS['config_error'] = '';
]]><![ CDATA [ }
]]><![ CDATA [ }
]]> </programlisting>
<para>
config.php checks for the existence of the function 'final_validation()'. This function can be used to check all form values at once. It gets sent the entire &dollar;newsettings array POSTed from the form. As with the other functions in this file, final_validation() should set &dollar;GLOBALS&lsqb;'config_error'&rsqb; if there is a problem.
</para>
</sect2>
</sect1>
</article>

283
admin/doc/adminconfig.txt Normal file
View File

@ -0,0 +1,283 @@
phpGroupWare admin/config.php
Abstract
A brief introduction to writing hooks and templates for any
application to use this admin interface, by
Abstract
Miles Lott <milosch@phpgroupware.org> Dec 22, 2001.
1 Files
1.1 config.tpl (required)
In your application/templates/default directory, create a
new template file named 'config.tpl'. This will be included
by config.php and used to draw the page. This template should
include a POST method form. The following template tags
may be used:
1. {action_url} - A phpgw->link to config.php will be inserted.
2. {title} - This will be parsed to display 'Site Configuration'.
3. {th_bg},{th_text},{row_on},{row_off} - Replaced with the
current theme colors.
and the following special types:
1. {lang_XXX} - Filled with lang('XXX').
2. {value_XXX} - Filled with the current value of config item
'XXX'.
3. {selected_XXX} - set to '', or ' selected' if an option
value is current.
4. {hook_XXX} - Calls a function named XXX (will be discussed
later).
Following is an example from the addressbook application:
<form method="POST" action="{action_url}">
<table border="0" align="center">
<tr bgcolor="{th_bg}">
<td colspan="2"><font color="{th_text}">&nbsp;<b>{title}</b></font></td>
</tr> <tr bgcolor="{th_err}">
<td colspan="2">&nbsp;<b>{error}</b></font></td>
</tr>
<!-- END header -->
<!-- BEGIN body -->
<tr bgcolor="{row_on}">
<td colspan="2">&nbsp;</td>
</tr>
<tr bgcolor="{row_off}">
<td colspan="2">&nbsp;<b>{lang_Addressbook}/{lang_Contact_Settings}</b></font>
</td>
</tr>
<tr bgcolor="{row_on}">
<td>{lang_Contact_application}:</td>
<td><input name="newsettings[contact_application]" value="{value_contact_application}"></td>
</tr>
...
Note the fieldname, newsettings[contact_application]. This
array name must be used for the form values. Next, note
the value setting for this form element, {value_contact_application}.
This indicates that we want the current value of the config
setting, 'contact_application', to be set and displayed
on the form. Lastly, look at the template element, {lang_Contact_application}.
Here, the value from the lang db table will be inserted
if available.
Let's take a look at part of the preferences/default/config.tpl:
<tr bgcolor="{row_on}">
<td>{lang_Country_Selection} ({lang_Text_Entry}/{lang_SelectBox}):</td>
<td>
<select name="newsettings[countrylist]">
{hook_country_set}
</select>
</td>
</tr>
Here, we are adding a new element, {hook_country_set}. This
brings up the next file we will need to parse this value...
1.2 hook_config.inc.php (optional)
At each invocation of config.php, a call to the common class
function hook_single() is made. It attempts to include a
file, hook_config.inc.php as a set of code for config.php
to use. In the case of the preferences example above, using
hook_country_set, here is the corresponding function in
preferences/inc/hook_config.inc.php:
function country_set($config)
{
$country = array( 'user_choice' => 'Users Choice', 'force_select'
=> 'Force Selectbox' );
while (list ($key, $value) = each ($country))
{
if ($config['countrylist'] == $key)
{
$selected = ' selected';
}
else
{
$selected = '';
}
$descr = lang($value);
$out .= '<option value="' . $key . '"' . $selected
. '>' . $descr . '</option>' . "\n";
}
return $out;
}
Note again the template value we used earlier, {hook_country_set}.
This causes config.php to look for a function named country_set().
Since we included the file with this function via the hook_single()
call, this function is executed. It's return is a string,
and the function prints nothing itself.
1.3 hook_config_validate.inc.php (optional)
Once the admin clicks the submit button to post the form,
we can optionally validate their input using one or many
different functions. This is done by first making another
call to hook_single() in the API common class. This time,
the name config_validate is used, so common tries to include
'application/inc/hook_config_validate.inc.php'.
If this file exists, it sets a var to tell config.php it
was found. Following then are functions named after each
config we want to validate. The following example is for
addressbook:
$GLOBALS['phpgw_info']['server']['found_validation_hook']
= True;
/* Check a specific setting. Name must match the setting.
*/
function ldap_contact_context($value='')
{
if($value == $GLOBALS['phpgw_info']['server']['ldap_context'])
{
$GLOBALS['config_error'] = 'Contact context for
ldap must be different from the context used for accounts';
}
elseif($value == $GLOBALS['phpgw_info']['server']['ldap_group_context'])
{
$GLOBALS['config_error'] = 'Contact context for
ldap must be different from the context used for groups';
}
else
{
$GLOBALS['config_error'] = '';
}
}
Here we created a function to check the entered value for
the config item, ldap_contact_context. We want to make sure
the admin did not set this value to one which would conflict
with another config item, used for accounts or groups in
phpGroupWare.
config.php calls this function, sending it the POSTed value.
config.php continues, adding all other config items from
the POSTed values.
The variable $GLOBALS['config_error'] is parsed through lang(),
then appended to the local variable, $error. If this has
any value after the POSTed variables are checked, the form
then has its {error} tag filled with this result. The form
is displayed again, with the error. If $error has no value,
config.php redirects to admin/index.php.
However, there is one more function that may be included
in hook_config_validate.inc.php:
/* Check all settings to validate input. Name must be
'final_validation' */
function final_validation($value='')
{
if($value['contact_repository'] == 'ldap' && !$value['ldap_contact_dn'])
{
$GLOBALS['config_error'] = 'Contact dn must be
set';
}
elseif($value['contact_repository'] == 'ldap' &&
!$value['ldap_contact_context'])
{
$GLOBALS['config_error'] = 'Contact context must
be set';
}
else
{
$GLOBALS['config_error'] = '';
}
}
config.php checks for the existence of the function 'final_validation()'.
This function can be used to check all form values at once.
It gets sent the entire $newsettings array POSTed from the
form. As with the other functions in this file, final_validation()
should set $GLOBALS['config_error'] if there is a problem.