ObjectModel

From Request Tracker Wiki
Jump to navigation Jump to search

Introduction

NOTE: This document expects that you're using default installation directory of /opt/rt3. Relative paths are all against /opt/rt3.

Files in library

Base files

> ls lib/RT/ | grep '^Queue'
Queue_Overlay.pm
Queue.pm
Queues_Overlay.pm
Queues.pm

Queue.pm is the base file for the RT::Queue package. You can list all RT packages and their base files with command:

> find lib/RT -name '*.pm' | \
    perl -ne 'print $_ unless /Overlay|Local|Vendor/' | \
    xargs grep '^package '

lib/RT/ACE.pm:package RT::ACE;
lib/RT/ACL.pm:package RT::ACL;
lib/RT/Action/AutoOpen.pm:package RT::Action::AutoOpen;
lib/RT/Action/Autoreply.pm:package RT::Action::Autoreply;
lib/RT/Action/CreateTickets.pm:package RT::Action::CreateTickets;
...

As you can see almost all files that have no '_' character in the file name define a package.

Overlay, Local and Vendor files

> cat Queue.pm
...
       eval "require RT::Queue_Overlay";
       if ($@ && $@ !~ qr{^Can't locate RT/Queue_Overlay.pm}) {
           die $@;
       };

This code tries load the file lib/RT/Queue_Overlay.pm. If the file doesn't exist then RT will silently ignore it. On other errors RT will throw an exception. lib/RT/Queue_Overlay.pm has no package definition so all code in it loads into RT::Queue package(name-space)

If Queue_Overlay.pm defines a subroutine already present in Queue.pm Perl will override the original subroutine from Queue.pm with subroutine in Queue_Overlay.pm. Almost all base files (packages) load overrides from _Overlay.pm, _Vendor.pm and _Local.pm files. RT loads files in predefined order: the _Local.pm file is last and its subroutines have highest priority.

RT uses this technique because RT many base files (Queue.pm, Ticket.pm, etc) are generated automatically from information about data base. From the file's heading:

# Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
  # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.
  #
  # !! DO NOT EDIT THIS FILE !!
  
  

See also: CleanlyCustomizeRT

So many overlaying files where to look?

Again, on example. There is a Queues table in the DB, so Queue.pm is autogenerated from table schema and RT developers use Queue_Overlay.pm. Queue_Vendor.pm is for distributors packaging RT with extensions and fixes. Queue_Local.pm is for end-administrators for customization. If you want to know more about Queue class and its methods then you look at Queue.pm for basic list of methods to access data fields and then at Queue_Overlay.pm to get more advanced methods.

Singular vs plural file names

Table in DB is a collection of the records. RT has tickets(collection). When you search tickets you limit collection with some conditions, each item in the collection is a ticket(record). So each table is represented with two classes. One represent a record in the table, second represent the table like collection of records.

Records Collections(tables)
ACE.pm ACL.pm
Attachment.pm Attachments.pm
CachedGroupMember.pm CachedGroupMembers.pm
CustomField.pm CustomFields.pm
CustomFieldValue.pm CustomFieldValues.pm
GroupMember.pm GroupMembers.pm
Group.pm Groups.pm
Link.pm Links.pm
Principal.pm Principals.pm
Queue.pm Queues.pm
ScripAction.pm ScripActions.pm
ScripCondition.pm ScripConditions.pm
Scrip.pm Scrips.pm
Template.pm Templates.pm
TicketCustomFieldValue.pm TicketCustomFieldValues.pm
Ticket.pm Tickets.pm
Transaction.pm Transactions.pm
User.pm Users.pm

Classes listed in the left column are inherited from RT::Record class. The right column represents classes inherited from [=RT::SearchBuilder] class. Both(Record and SearchBuilder) are major classes that provide a platform (based on [=DBIx::SearchBuilder] framework) to manipulate RT's DB.

See below about records and collections.

How local folder works

In RT files hierarchy there is local folder that has special meaning, see CleanlyCustomizeRT for details.

API

RT::Base

Base class for all RT classes. Implements minor functionality that is general for all classes. Provides several methods, description below.

perldoc lib/RT/Base.pm

CurrentUser

When you construct RT objects from classes then you should define user context. Example: [=my $ticket = RT::Ticket->new( $RT::SystemUser );] with this code you create an object of RT::Ticket class in context of SystemUser(see below about SystemUser). You can do everything with the ticket now, but if you create a ticket object in context of user 'John' then some operations may fail because of right restrictions.

This sub also allows you to change user context. For example, if you get a ticket object from external code and want to execute code that shouldn't fail even if the user doesn't have some rights, then you can switch to SystemUser do what you need and then switch back. Code example:

my $old_user = $ticket->CurrentUser;
$ticket->CurrentUser( $RT::SystemUser );
...
$ticket->CurrentUser( $old_user );

If some object method returns other RT object then the returned object is also in the same user context as original object. Example:

my $queue = $ticket->QueueObj;
my $cur_user = $queue->CurrentUser; # same user as for $ticket

loc

i18n stuff, see examples in code, how RT uses it and also see [=perldoc Locale::Maketext].

RT::Record

Base class for records in tables. This class allows you to:

  • load a record that already exists by one column value or by several column values;
use RT::Ticket;
  my $TicketObj = new RT::Ticket( $RT::SystemUser );
  # loads ticket with id = 1
  $TicketObj->Load( 1 );
  
  • create new record;
use RT::Ticket;
  my $TicketObj = new RT::Ticket( $RT::SystemUser );
  # creates new ticket
  $TicketObj->Create( Queue => 1, Subject => ' ' );
  
  • after you load or create new record, you can get or set its column values;
$TicketObj->Load( 1 );
  # gets current subject
  my $subject = $TicketObj->Subject;
  # adds urgent mark to old subject and updates ticket
  $TicketObj->SetSubject("urgent: $subject");
  
  • get other objects that relates to the current.
my $transactions = $TicketObj->Transactions;

[=Set*], [=_Set] and [=__Set] methods

  • You call [=SetXxxx( $Value )] method of the RT object.
    • If perl can't find method, AUTOLOAD is called.
      • AUTOLOAD splits [=SetXxxx] into 'Set' and 'Xxxx'
      • Check is there accesible field in object? No?! Then RT will die.
      • Is field mutable or readonly. Return error if readonly.
      • Create alias: [=SetXxxx($Value) ~ _Set(Field => 'Xxxx', Value => $Value)]
      • Call alias.
    • Next time RT will find this function because of alias.
  • _Set actually comes from [=SearchBuilder], this function is specially intended for inheritance.
    • RT check user rights here and do some magic if needed.
    • If everything is allright _Set calls __Set which updates DB. __Set rare does more magic.

RT::SearchBuilder

Base class for collections of records(tables). This class has several groups of functions that alow you to:

  • limit collection from all records in table to several records that match some conditions;
  • walk through this collection and get first, last, next, prev records or by index;
  • change records order by colum values;
  • limit collection with conditions based on other tables via relationships of tables.

RT API docs

Perl supports POD(Plain Old Documentation) embeded into code. RT uses POD to describe methods of the clases. You can view this documentation with perldoc utility that comes with perl.

perldoc /www/rt3/lib/RT/CustomField_Overlay.pm

Also you can use RT::OnlineDocs module.

RT API Inspector

I wrote a small snippet that uses Class::Inspector to show which methods are available to specific RT objects.

http://www.cpan.org/authors/id/A/AH/AHARRISON/scripts/rt-class-map-1.3.pl