<chapter id="dev">
<title>Developer's guide</title>
<para>
This chapter will show you more details about writing common OTRS Modules. 
</para>
<para>

</para>

<section id="dev-style">
<title>Coding Style Guide</title>
<para>
In order to preserve the consistent development of OTRS project we
have set up a few guidelines regarding style.
</para>

<section id="dev-style-format">
<title>Formatting</title>
<para>
TAB: We use 4 spaces.
</para>
<para>
Braces examles:
<programlisting>
 if ($Condition) {
     Foo();
 }
 else {
     Bar();
 }
</programlisting>
<programlisting>
 while ($Condition == 1) {
     Foo();
 }
</programlisting>
</para>
</section>
<section id="dev-style-name">
<title>Naming</title>
<para>
Names and comments are written in English.
</para>
<para>
Variables, Objects and Methods must be descriptive nouns or noun phrases with
the first letter uppercase (e. g. '@TicketIDs' or '$Output' or 'BuildQueueView()').
</para>
</section>
<section id="dev-style-header">
<title>Code header</title>
<para>
Attach the following header to each source file.
<programlisting>
# --
# (file name) - a short decription what it does.
# Copyright (C) (year) (name of author) (email of author)
# --
# $Id: developer-guide.sgml,v 1.2 2004/03/28 11:13:47 martin Exp $
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see http://www.gnu.org/licenses/gpl.txt.
</programlisting>
</para>
</section>
<section id="dev-style-misc">
<title>Misc</title>
<para>
All things depending on http://www.perl.com/CPAN-local/doc/manual/html/pod/perlstyle.html.
</para>
<para>
You can also use 'pb' the 'Perl Beautifier', http://www.arachnoid.com/lutusp/ftp/cgi/pb.txt. 
It's really nice. ;-)
</para>
</section>

</section>

<section id="dev-fw">
<title>OTRS Framework</title>
<para>
The OTRS framework is modular. The following picture shows the OTRS layer architecture.
<screenshot>
<screeninfo>OTRS Layer</screeninfo>
<graphic srccredit="OTRS Layer" scale="40" fileref="screenshots/otrs-layer.png"></graphic>
</screenshot>
</para>

<section id="dev-fw-core">
<title>Core Modules</title>
<para>
Core modules are located under $OTRS_HOME/Kernel/System/*. 
This layer is for the logical work.
This modules are to handle system routines like "lock ticket" and "create ticket". 
</para>
<para>
The main core modules are:
Log (Kernel::System::Log),
Ticket (Kernel::System::Ticket),
Auth (Kernel::System::Auth),
User (Kernel::System::User),
Email (Kernel::System::Email). For more see http://dev.otrs.org/. 
</para>
<para>
A example for an core module is this:
<programlisting>
# --
# Kernel/System/Backend.pm - a simple backend module
# Copyright (C) 2001-2004 Martin Edenhofer martin+code@otrs.org
# --
# $Id: developer-guide.sgml,v 1.2 2004/03/28 11:13:47 martin Exp $
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see http://www.gnu.org/licenses/gpl.txt.
# --

package Kernel::System::Backend;

use strict;

use vars qw($VERSION);
$VERSION = '$Revision: 1.2 $';
$VERSION =~ s/^\$.*:\W(.*)\W.+?$/$1/;

# --
sub new {
    my $Type = shift;
    my %Param = @_;

    # allocate new hash for object
    my $Self = {};
    bless ($Self, $Type);

    # get needed objects
    foreach (qw(ConfigObject LogObject)) {
        $Self->{$_} = $Param{$_} || die "Got no $_!";
    }
 
    # system variable
    $Self->{ConfigParam} = $Self->{ConfigObject}->Get('ConfigParam'); 

    return $Self;
}
# --
sub Check {
    my $Self = shift;
    my %Param = @_;
    # check needed stuff
    foreach (qw(Text)) {
        if (!$Param{$_}) {
            $Self->{LogObject}->Log(Priority => 'error', Message => "Need $_!");
            return;
        }
    }
    # do some thinks

    return 1;
}
# --
sub Convert {
    my $Self = shift;
    my %Param = @_;
    # check needed stuff
    foreach (qw(Text)) {
        if (!$Param{$_}) {
            $Self->{LogObject}->Log(Priority => 'error', Message => "Need $_!");
            return;
        }
    }
    # do some thinks

    return $Param{Text};
}
# --
1;
</programlisting>
</para>
</section>

<section id="dev-fw-web-handle">
<title>Web-Frontend-Handle</title>
<para>
This is the interface between the browser, webserver and the Web-Frontend-Modules.
A Web-Frontend-Module can be used via the http-link "http://localhost/otrs/index.pl?Action=Modul". 
</para>
</section>

<section id="dev-fw-web-module">
<title>Web-Frontend-Modules</title>
<para>
Web-Frontend-Modules are located under "$OTRS_HOME/Kernel/Modules/*.pm". There are two public functions in there. new() and Run() which are used from the Web-Frontend-Handle (e. g. index.pl).
</para>
<para>
"new()" is used to create an Web-Frontend-Module object. The Web-Frontend-Handle gives basic framwork object to the Web-Frontend-Module. 
</para>
<para>
For example 
ParamObject (to get formular params), 
DBObject (to use existing database connects), 
LayoutObject (to use templates and other html layout functions), 
ConfigObject (to access config settings),
LogObject (to use the framework log system),
UserObject (to get the user functions from the current user),
GroupObject (to get the group functions). 
</para>
<para>
For more info of this core modules see http://dev.otrs.org/.
</para>

<para>
An example of an Web-Frontend-Module could look like this:
<programlisting>
# --
# Kernel/Modules/Test.pm - a simple test module
# Copyright (C) 2001-2004 Martin Edenhofer martin+code@otrs.org
# --
# $Id: developer-guide.sgml,v 1.2 2004/03/28 11:13:47 martin Exp $
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see http://www.gnu.org/licenses/gpl.txt.
# --

package Kernel::Modules::Test;

use strict;
 
use vars qw($VERSION);
$VERSION = '$Revision: 1.2 $';
$VERSION =~ s/^\$.*:\W(.*)\W.+?$/$1/;

# --
sub new {
    my $Type = shift;
    my %Param = @_;

    # allocate new hash for object
    my $Self = {};
    bless ($Self, $Type);

    # get common opjects
    foreach (keys %Param) {
        $Self->{$_} = $Param{$_};
    }

    # check all needed objects
    foreach (qw(ParamObject DBObject LayoutObject ConfigObject LogObject)) {
        die "Got no $_" if (!$Self->{$_});
    }

    return $Self;
}
# --
sub Run {
    my $Self = shift;
    my %Param = @_;

    # get params
    $Param{TestParam} = $Self->{ParamObject}->GetParam(Param => 'TestParam');


    # get test page header
    my $Output = $Self->{LayoutObject}->Header(Title => 'Test Page');

    # get test page 
    $Output .= $Self->{LayoutObject}->Output(TemplateFile => 'Test', Data => \%Param);

    # get test page footer
    $Output .= $Self->{LayoutObject}->Footer();

    # return test page
    return $Output;
}
# --
1;
</programlisting>
This module need to be saved under "Kernel/Modules/Test.pm" and can be
used via "http://host/otrs/index.pl?Action=Test". 
</para>
<para>
There are HTML templates for header, footer and other things. The templates
are located under "Kernel/Output/HTML/$Theme/*.dtl". For example under
"Kernel/Output/HTML/Standard/*.dtl".
</para>
<para>
So it's easy to create an site. If you want to use an template use the
following in your Web-Frontend-Module:
<programlisting>
    $Output .= $Self->{LayoutObject}->Output(TemplateFile => 'Test', Data => \%Param);
</programlisting>
The "LayoutObject" is used with the "TemplateFile" (for the template file name) and the Data (in this case with the %Param hash) params.
</para>
</section>

<section id="dev-fw-cmd">
<title>CMD Frontend</title>
<para>
The CMD Frontend is like the Web-Frontend-Handle and the Web-Frontend-Module
in one (just without the LayoutObject) and is using the core modules to do some actions in the system. 
</para>
<para>
An example for an CMD Frontend is the follwoing:
<programlisting>
# --
# bin/UnlockTickets.pl - to unlock tickets
# Copyright (C) 2002-2004 Martin Edenhofer martin+code@otrs.org
# --
# $Id: developer-guide.sgml,v 1.2 2004/03/28 11:13:47 martin Exp $
# --
# 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.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# --

# use ../ as lib location
use File::Basename;
use FindBin qw($RealBin);
use lib dirname($RealBin);
use lib dirname($RealBin)."/Kernel/cpan-lib";
  
use strict;
 
use vars qw($VERSION);
$VERSION = '$Revision: 1.2 $';
$VERSION =~ s/^\$.*:\W(.*)\W.+?$/$1/;

# use Date::Pcalc
use Date::Pcalc qw(Delta_Days Add_Delta_Days Day_of_Week Day_of_Week_Abbreviation);
# use otrs backend modules
use Kernel::Config;
use Kernel::System::Log;
use Kernel::System::DB;
use Kernel::System::Ticket;
use Kernel::System::User;
use Kernel::System::State;
use Kernel::System::Lock;

my $Debug = 0;

# --
# create common objects
# --
my %CommonObject = ();
$CommonObject{ConfigObject} = Kernel::Config->new();
$CommonObject{LogObject} = Kernel::System::Log->new(
    LogPrefix => 'OTRS-UnlockTickets',
    %CommonObject,
);
$CommonObject{DBObject} = Kernel::System::DB->new(%CommonObject);
$CommonObject{TicketObject} = Kernel::System::Ticket->new(%CommonObject);
$CommonObject{UserObject} = Kernel::System::User->new(%CommonObject);
$CommonObject{StateObject} = Kernel::System::State->new(%CommonObject);
$CommonObject{LockObject} = Kernel::System::Lock->new(%CommonObject);
# --
# get system variables
# --
my @UnlockStateIDs = $CommonObject{StateObject}->StateGetStatesByType(
    Type => 'Unlock',
    Result => 'ID',
);
my @ViewableLockIDs = $CommonObject{LockObject}->LockViewableLock(Type => 'ID');
# --
# check args
# --
print "UnlockTickets.pl Revision $VERSION - unlock tickets\n";
print "Copyright (c) 2001-2004 Martin Edenhofer email\@otrs.org\n";
# --
# unlock all tickets
# --
my @TicketIDs = $CommonObject{TicketObject}->GetLockedTickets();
foreach (@Tickets) {
    print " Unlocking ticket id $_ ...";
    if ($CommonObject{TicketObject}->SetLock(
        TicketID => $_,
        Lock => 'unlock',
        UserID => 1,
    ) ) {
        print " done.\n";
    }
    else {
        print " failed.\n";
    }
}
exit (0);
</programlisting>
</para>
</section>

</section>

<!--
<section id="dev-debug">
<title>Debugging</title>
<para>
...
</para>
</section>
-->

</chapter>
