ObjectModel
Introduction
NOTE: This documents 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 );
- [=$RT::SystemUser] is described in GlobalObjects page
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. - Next time RT will find this function because of alias.
- If perl can't find method,
_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