[Rt-commit] rt branch, 4.0/columnmap-cache-cf, created. rt-4.0.8-64-g15d4da6
Alex Vandiver
alexmv at bestpractical.com
Thu Nov 1 18:29:05 EDT 2012
The branch, 4.0/columnmap-cache-cf has been created
at 15d4da6fb6707f26228c301cd33cbb2210c0dd41 (commit)
- Log -----------------------------------------------------------------
commit db2a6ae274a580644ac96ed88850168c9283a4f0
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Tue Jun 12 13:57:27 2012 -0400
RT::ObjectCustomFieldValues calls LimitToEnabled by default
This cleans up an unnecessary (Disabled = 0 OR Disabled = 0)
diff --git a/lib/RT/CustomField.pm b/lib/RT/CustomField.pm
index 2002d4e..d065b7f 100644
--- a/lib/RT/CustomField.pm
+++ b/lib/RT/CustomField.pm
@@ -1656,7 +1656,6 @@ sub ValuesForObject {
$values->LimitToCustomField($self->Id);
- $values->LimitToEnabled();
$values->LimitToObject($object);
return ($values);
commit 3d91316bfc2e0e7690c2cecef549e7d8dda1b85e
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Tue Jun 12 16:30:27 2012 -0400
Move "global or queue" logic to LoadCustomFieldByIdentifier
The logic for attempting to load a queue-specific queue, and then the
global one, was on the CustomFieldValues method. Move the logic to
LoadCustomFieldByIdentifier, which is called by
RT::Record->CustomFieldValues, rather than overriding CustomFieldValues
directly; this allows other methods to simple call
->LoadCustomFieldByIdentifier and gain the queue-or-global
functionality.
This change also causes ->CustomFieldValues (and thus both
->FirstCustomFieldValue and ->CustomFieldValuesAsString), when called on
tickets with an invalid CF name, to warn. This makes it consistent with
->CustomFieldValues called on other types of objects, and may provide
useful feedback when a CF name is improperly specified.
diff --git a/lib/RT/Ticket.pm b/lib/RT/Ticket.pm
index 2109d71..f9c587a 100644
--- a/lib/RT/Ticket.pm
+++ b/lib/RT/Ticket.pm
@@ -3710,37 +3710,29 @@ sub TransactionCustomFields {
}
+=head2 LoadCustomFieldByIdentifier
-=head2 CustomFieldValues
-
-# Do name => id mapping (if needed) before falling back to
-# RT::Record's CustomFieldValues
-
-See L<RT::Record>
+Finds and returns the custom field of the given name for the ticket,
+overriding L<RT::Record/LoadCustomFieldByIdentifier> to look for
+queue-specific CFs before global ones.
=cut
-sub CustomFieldValues {
+sub LoadCustomFieldByIdentifier {
my $self = shift;
my $field = shift;
- return $self->SUPER::CustomFieldValues( $field ) if !$field || $field =~ /^\d+$/;
+ return $self->SUPER::LoadCustomFieldByIdentifier($field)
+ if ref $field or $field =~ /^\d+$/;
my $cf = RT::CustomField->new( $self->CurrentUser );
$cf->SetContextObject( $self );
$cf->LoadByNameAndQueue( Name => $field, Queue => $self->Queue );
- unless ( $cf->id ) {
- $cf->LoadByNameAndQueue( Name => $field, Queue => 0 );
- }
-
- # If we didn't find a valid cfid, give up.
- return RT::ObjectCustomFieldValues->new( $self->CurrentUser ) unless $cf->id;
-
- return $self->SUPER::CustomFieldValues( $cf->id );
+ $cf->LoadByNameAndQueue( Name => $field, Queue => 0 ) unless $cf->id;
+ return $cf;
}
-
=head2 CustomFieldLookupType
Returns the RT::Ticket lookup type, which can be passed to
diff --git a/lib/RT/Transaction.pm b/lib/RT/Transaction.pm
index e01b257..b1e818c 100644
--- a/lib/RT/Transaction.pm
+++ b/lib/RT/Transaction.pm
@@ -1180,37 +1180,31 @@ sub UpdateCustomFields {
}
}
+=head2 LoadCustomFieldByIdentifier
-
-=head2 CustomFieldValues
-
- Do name => id mapping (if needed) before falling back to RT::Record's CustomFieldValues
-
- See L<RT::Record>
+Finds and returns the custom field of the given name for the
+transaction, overriding L<RT::Record/LoadCustomFieldByIdentifier> to
+look for queue-specific CFs before global ones.
=cut
-sub CustomFieldValues {
+sub LoadCustomFieldByIdentifier {
my $self = shift;
my $field = shift;
- if ( UNIVERSAL::can( $self->Object, 'QueueObj' ) ) {
-
- # XXX: $field could be undef when we want fetch values for all CFs
- # do we want to cover this situation somehow here?
- unless ( defined $field && $field =~ /^\d+$/o ) {
- my $CFs = RT::CustomFields->new( $self->CurrentUser );
- $CFs->SetContextObject( $self->Object );
- $CFs->Limit( FIELD => 'Name', VALUE => $field );
- $CFs->LimitToLookupType($self->CustomFieldLookupType);
- $CFs->LimitToGlobalOrObjectId($self->Object->QueueObj->id);
- $field = $CFs->First->id if $CFs->First;
- }
- }
- return $self->SUPER::CustomFieldValues($field);
-}
+ return $self->SUPER::LoadCustomFieldByIdentifier($field)
+ if ref $field or $field =~ /^\d+$/;
+ return $self->SUPER::LoadCustomFieldByIdentifier($field)
+ unless UNIVERSAL::can( $self->Object, 'QueueObj' );
+ my $CFs = RT::CustomFields->new( $self->CurrentUser );
+ $CFs->SetContextObject( $self->Object );
+ $CFs->Limit( FIELD => 'Name', VALUE => $field );
+ $CFs->LimitToLookupType($self->CustomFieldLookupType);
+ $CFs->LimitToGlobalOrObjectId($self->Object->QueueObj->id);
+ return $CFs->First || RT::CustomField->new( $self->CurrentUser );
+}
=head2 CustomFieldLookupType
diff --git a/t/customfields/api.t b/t/customfields/api.t
index d739a57..228693f 100644
--- a/t/customfields/api.t
+++ b/t/customfields/api.t
@@ -3,7 +3,8 @@
use strict;
use warnings FATAL => 'all';
-use RT::Test nodata => 1, tests => 139;
+use RT::Test nodata => 1, tests => 145;
+use Test::Warn;
# Before we get going, ditch all object_cfs; this will remove
# all custom fields systemwide;
@@ -69,13 +70,21 @@ is( $cfvs->Count, 0 );
is( $ticket->FirstCustomFieldValue, undef );
# CF with ID -1 shouldnt exist at all
-$cfvs = $ticket->CustomFieldValues( -1 );
+warning_like {
+ $cfvs = $ticket->CustomFieldValues( -1 );
+} qr{Couldn't load custom field};
is( $cfvs->Count, 0 );
-is( $ticket->FirstCustomFieldValue( -1 ), undef );
+warning_like {
+ is( $ticket->FirstCustomFieldValue( -1 ), undef );
+} qr{Couldn't load custom field};
-$cfvs = $ticket->CustomFieldValues( 'SomeUnexpedCustomFieldName' );
+warning_like {
+ $cfvs = $ticket->CustomFieldValues( 'SomeUnexpedCustomFieldName' );
+} qr{Couldn't load custom field};
is( $cfvs->Count, 0 );
-is( $ticket->FirstCustomFieldValue( 'SomeUnexpedCustomFieldName' ), undef );
+warning_like {
+ is( $ticket->FirstCustomFieldValue( 'SomeUnexpedCustomFieldName' ), undef );
+} qr{Couldn't load custom field};
for (@custom_fields) {
$cfvs = $ticket->CustomFieldValues( $_->id );
@@ -183,9 +192,13 @@ $test_add_delete_cycle->( sub { return $_[0] } );
$ticket->AddCustomFieldValue( Field => $local_cf2->id , Value => 'Baz' );
$ticket->AddCustomFieldValue( Field => $global_cf3->id , Value => 'Baz' );
# now if we ask for cf values on RecordCustomFields4 we should not get any
-$cfvs = $ticket->CustomFieldValues( 'RecordCustomFields4' );
+warning_like {
+ $cfvs = $ticket->CustomFieldValues( 'RecordCustomFields4' );
+} qr{Couldn't load custom field};
is( $cfvs->Count, 0, "No custom field values for non-Queue cf" );
-is( $ticket->FirstCustomFieldValue( 'RecordCustomFields4' ), undef, "No first custom field value for non-Queue cf" );
+warning_like {
+ is( $ticket->FirstCustomFieldValue( 'RecordCustomFields4' ), undef, "No first custom field value for non-Queue cf" );
+} qr{Couldn't load custom field};
{
my $cfname = $global_cf3->Name;
commit a64a16d1cf32a0fc2d9ca298e7323891759ae739
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Thu Nov 1 18:20:42 2012 -0400
Promote _LookupId to a public method, and optimize slightly
diff --git a/lib/RT/Record.pm b/lib/RT/Record.pm
index 8e4ce0e..6d0a55b 100644
--- a/lib/RT/Record.pm
+++ b/lib/RT/Record.pm
@@ -1563,29 +1563,32 @@ sub CustomFields {
$cfs->SetContextObject( $self );
# XXX handle multiple types properly
$cfs->LimitToLookupType( $self->CustomFieldLookupType );
- $cfs->LimitToGlobalOrObjectId(
- $self->_LookupId( $self->CustomFieldLookupType )
- );
+ $cfs->LimitToGlobalOrObjectId( $self->CustomFieldLookupId );
$cfs->ApplySortOrder;
return $cfs;
}
-# TODO: This _only_ works for RT::Class classes. it doesn't work, for example,
-# for RT::IR classes.
+# TODO: This _only_ works for RT::Foo classes. it doesn't work, for
+# example, for RT::IR::Foo classes.
-sub _LookupId {
+sub CustomFieldLookupId {
my $self = shift;
- my $lookup = shift;
+ my $lookup = shift || $self->CustomFieldLookupType;
my @classes = ($lookup =~ /RT::(\w+)-/g);
+ # Work on "RT::Queue", for instance
+ return $self->Id unless @classes;
+
my $object = $self;
+ # Save a ->Load call by not calling ->FooObj->Id, just ->Foo
+ my $final = shift @classes;
foreach my $class (reverse @classes) {
my $method = "${class}Obj";
$object = $object->$method;
}
- return $object->Id;
+ return $object->$final;
}
commit da1736e54204ec7dd09edf444a8cc03737058ed5
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Thu Nov 1 18:24:04 2012 -0400
Remove unnecessary RT::Class::_LookupId
It was previously required because the class was RT::FM::Foo, and hence
the generic method in RT::Record did not work (as noted in the comment
there). With the merge of RTFM into core, and the rename of
RT::FM::Class -> RT::Class, this method is no longer necessary.
diff --git a/lib/RT/Article.pm b/lib/RT/Article.pm
index 678aa11..58dd94b 100644
--- a/lib/RT/Article.pm
+++ b/lib/RT/Article.pm
@@ -611,15 +611,6 @@ sub CustomFieldLookupType {
"RT::Class-RT::Article";
}
-# _LookupId is the id of the toplevel type object the customfield is joined to
-# in this case, that's an RT::Class.
-
-sub _LookupId {
- my $self = shift;
- return $self->ClassObj->id;
-
-}
-
=head2 LoadByInclude Field Value
Takes the name of a form field from "Include Article"
commit 15d4da6fb6707f26228c301cd33cbb2210c0dd41
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Tue Jun 12 16:41:38 2012 -0400
Cache CFs in ColumnMap on a per-request basis
When displaying /n/ rows of search results with /m/ columns of global CF
values displayed, custom field queries accounted for /n/ * /m/ * 3
queries; one to try to load the queue-specific CF with the column name,
one to load the global CF with that name, and one to load the OCFV for
that CF and ticket. With sufficient CFs in a search result format,
these account for a significant performance impact, despite being
relatively well-indexed.
Cache the CF objects in the per-request $m->notes() cache to eliminate
the CF loads, which account for ½ to â
of those queries, depending on
the prevalence of global CFs. The cache key must also include the
lookup id (queue id, in most cases) -- as a single search may include
results from multiple queues, each of which may resolve a CF name
differently. It must also include the lookup type, such that a ticket
CF and a transaction CF with the same name can be differentiated.
diff --git a/share/html/Elements/ColumnMap b/share/html/Elements/ColumnMap
index 7295e3f..fbe6a9d 100644
--- a/share/html/Elements/ColumnMap
+++ b/share/html/Elements/ColumnMap
@@ -96,13 +96,25 @@ my $COLUMN_MAP = {
attribute => sub { return shift @_ },
title => sub { return pop @_ },
value => sub {
+ # Cache the CF object on a per-request basis, to avoid
+ # having to load it for every row
+ my $key = join("-","CF",
+ $_[0]->CustomFieldLookupType,
+ $_[0]->CustomFieldLookupId,
+ $_[-1]);
+
+ my $cf = $m->notes($key);
+ unless ($cf) {
+ $cf = $_[0]->LoadCustomFieldByIdentifier($_[-1]);
+ $m->notes($key, $cf);
+ }
+
# Display custom field contents, separated by newlines.
# For Image custom fields we also show a thumbnail here.
-
- my $values = $_[0]->CustomFieldValues( $_[-1] );
+ my $values = $cf->ValuesForObject( $_[0] );
my @values = map {
(
- ($_->CustomFieldObj->Type eq 'Image')
+ ($cf->Type eq 'Image')
? \($m->scomp( '/Elements/ShowCustomFieldImage', Object => $_ ))
: $_->Content
),
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list