• sgkmills
  • NEWBIE
  • 100 Points
  • Member since 2007

  • Chatter
    Feed
  • 3
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 21
    Questions
  • 29
    Replies

All,

 

I have written a controller extension which is extending the standard controller of an object, say abc__c.  Within the controller extension, I have declared the class with the keyword 'without sharing'.  In the abc__c object, there is a field that only Admins can update, call it PRM__c.  Within the controller extension, I write to the the PRM__c field and then try to update the abc__c record. 

 

To test the code, I login as a standard user and click the button that kicks off the controller extension class.  When the update abc__c code executes, I get a validation error stating that the update failed.  The validation rule checks the PRM__c field == True and $Profile.Name <> "System Administrator".  When I look in the debug logs, I see that the $Profile.Name is the value of the standard user 'SU' (who I am currently logged in as), but I was expecting it to be 'System Administrator' since the APEX code should be running in System Mode. An excerpt from my log is below:

 

 

|VALIDATION_FORMULA|PRM__c = True && 
$Profile.Name <> "System Administrator"|Primary__c=1 , $Profile.Name=SU
17:59:06.150 (150752000)|VALIDATION_FAIL
17:59:06.150 (150803000)|CODE_UNIT_FINISHED|Validation:abc:a0l50000009lmGk
17:59:06.152 (152315000)|FATAL_ERROR|System.DmlException: Update failed. First exception on row 0 with id a0l50000009lmGk; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION,....

 

I also looked in the the Visual Force Developer's Guide and on Pg. 11 it states the below:

 

Because standard controllers execute in user mode, in which the permissions, field-level security, and sharing rules of the
current user are enforced, extending a standard controller allows you to build a Visualforce page that respects user permissions.
Although the extension class executes in system mode, the standard controller executes in user mode. As with custom
controllers, you can specify whether a user can execute methods in a controller extension based on the user's profile.
Note: Although custom controllers and controller extension classes execute in system mode and thereby ignore
profile-based permissions and field-level security, you can choose whether they respect a user's organization-wide
defaults, role hierarchy, and sharing rules by using the with sharing keywords in the class definition. For information,
see “Using the with sharing or without sharing Keywords” in the Force.com Apex Code Developer's Guide

 

So is the problem that even though my controller extension is set up with 'without sharing', the standard controller, abc__c, runs in user mode?  Consequently, the field PRM__c is read_only for the standard user profile (SU), therefore the update in the controller extension to the PRM__c field in the abc__c object fails!

 

If this is the case, how can I allow the controller extension to update the PRM__c field?  If it isn't, has anyone come across this situation and has a solution?

 

Thanks in advance.

I need some clarification as to why the the two scenarios below give different results. I am retrieving a record (IO Campaign, with all its children from Inventory Reservation). These are both custom objects in our organization. There are actually 561 inventory Reservations associated with the IO Campaign I am retrieving, so that is the value I am expecting in the list, invresItems.

1. The first scenario, I use one query to get data from a parent child relationship.:

public IO_Campaign__c io_campaign { get; private set;}
public List<Inventory_Reservation__c> invresItems { get; private set; }

io_campaign = [SELECT Id, Name,
(SELECT Id, Name FROM Inventory_Reservations__r ORDER BY Name) FROM IO_Campaign__c
where id = :id limit 1];
invresItems = io_campaign.Inventory_Reservations__r;
System.debug('invresItems.size()=' + invresItems.size());

 

When I debug this, the output for invresItems.size() is 499


2. The second scenario:

public IO_Campaign__c io_campaign { get; private set;}
public List<Inventory_Reservation__c> invresItems { get; private set; }

io_campaign = [SELECT Id, Name FROM IO_Campaign__c where id = :id limit 1];
invresItems = [SELECT Id, Name FROM Inventory_Reservation__c ORDER BY Name where IO_Campaign__r.Id = :io_campaign.Id];
System.debug('invresItems.size()=' + invresItems.size());

 

When I debug this, the output for invresItems.size() is 561. This is the expected output.

Why is the first scenario truncating the list at 499? I believe it has to do with the way Salesforce returns data in the API where you have to use the querymore function to retrieve the rest of the rows. I don't believe I can use that in Apex, so what is the correct approach. Am I missing something?


 

Also, I found an article What does the Invalid Query Locator error mean? and it explained that APEX might create a query locator when you use an inner query and the query locator will be used with a querymore when you try to retrieve the inner query data.

 

I tried to change the code to the below and it still only gave me the 499 records.

 

public IO_Campaign__c io_campaign { get; private set;}
public List<IO_Campaign__c > lst_io_campaign { get; private set;}
public List<Inventory_Reservation__c> invresItems { get; private set; }

invresItems = new List<Inventory_Reservation__c>();


lst_io_campaign = [SELECT Id, Name,
(SELECT Id, Name FROM Inventory_Reservations__r ORDER BY Name) FROM IO_Campaign__c
where id = :id limit 1];

for(IO_Campaign__c io : lst_io_campaign) // queryMore() will be used to retrieve child cases
invresItems.addAll(io.Inventory_Reservations__r);


io_campaign = lst_io_campaign[0];
System.debug('invresItems.size()=' + invresItems.size());


 

When I debug this, the output for invresItems.size() is 499


So it seems as if the inner query is only retrieving the 500 (the one IO Campaign record and the 499 Inventory Reservation records), but the For Loop should add the rest by using the query locator and the querymore function.  This isn't happening.

 

Any help will be greatly appreciated.

 

I have written a custom controller extension on a custom object and am trying to retrieve the current record/id by using the getRecord and getId methods of the StandardController class but both are coming back null. How is that possible?

part of the controller extension is below. The custom object is called SC__c:

public SC_Controller_Ext (ApexPages.StandardController stdController) {
// this will kickoff you main page
controller = stdController;
system.debug('stdController=' + stdController + ', stdController.getRecord()=' + stdController.getRecord() + ', stdController.getId()=' + stdController.getId());

 

The system.debug shows the getRecord and the getId are null.  The controller extension gets kicked off from an overwritten button on a Standard Page.  The button that is overwritten is the 'new' button of the custom object.  

 

I don't understand how the standardcontroller object can be null because I am viewing the record and then just clicking the edit button, of the custom object.  This button is not overwitten, it is using the default Salesforce action.  Then I click the 'Save and New' button from the 'edit' screen and the controller isn't initialized.

 

Any info/ideas will be greatly appreciated.

Hi All,

 

I have a custom object (XYZ__c) under Opportunities as a related list (master-detail).

 

I had to pre-populate few fields in XYZ record when user clicks on 'NEW XYZ' button under the opportunity.

 

So, I used a custom button and replaced the standard NEW XYZ button in the page layout (of opportunity) passing values in the URL.

 

.........&Name=Auto+Number&RecordType=****************&saveURL=/{!XYZ__c.Id}&retURL=/{!XYZ__c.Id}

 

Everything is fine. But when users click on Save and New, these values are not prepolating, instead it re-directs user to record type selection page !!!!!!!! Becoz, after save its going to the standard NEW button in the XYZ object, which I haven't overriden.  I just replaced the new button in the pagelayout (of opportunity). 

 

I cannot over-write the standard NEW button of XYZ object with URL. I dont have any VF pages. I just need couple of fields to be pre-populated hence i am using URL to override. 

 

Any help would be highly appreciated!

 

Please help.

Winter '11 was supposed to include the much-improved system log, and we got an email blast saying that with Winter '11, the Help & Training minisite was getting an overhaul.  We've had Winter '11 implemented already, but these features are missing.

I created a visualforce page and a button that calls the visual force page to do some behind the scenes processing.  The processing basically clones a custom object record and its children, doing some other unique things.  The button is displayed on the standard detail record screen of the custom object and when clicked it will call the visual force page below, call it 'CLONE':

 

 

 

<apex:page standardController="custom_object__c" action="{!autoRun_Version}" extensions="custom_Controller_Ext" title="Cloning Custom object record"> <apex:sectionHeader title="Cloning of Custom object record"/> <apex:messages /> <apex:outputPanel > Click <apex:outputLink value="/{!$CurrentPage.parameters.id}"> Here </apex:outputLink> to return to the Custom object record </apex:outputPanel> </apex:page>

 

The code in the controller does all the processing and it works fine.  The issue is I want to display any error messages on the page where the button is clicked, but this is a standard page created by Salesforce and the company doesn't want to change it.  So I currently display the messages in the Visual force page, 'CLONE' above.  I would prefer to display the errors on the standard page where the button is clicked, if possible.  But, if it isn't, I want to display them on a Generic Error Page.  The error page will have the errors and then a link to go back to the standard detail page where the button is on.

 

The main part of the controller code is displayed, I didn't include everything because it would just complicate the matter:

 

 

public with sharing class custom_Controller_Ext { *** all the stuff such as constructors and private variables set above *** public PageReference autoRun_Version() { .... // *** all the stuff in autoRun_Version that wasn't pertinent has been left out *** .... if (Campaign_Inactive__c != true) { vIO(); vInv(); } else { System.debug('SKM-IO Campaign is Inactive'); PageReference pageRef = Page.ErrorPg; pageRef.getParameters().put('id', custom_object__c.id); System.debug('SKM- (INACTIVE) Page Reference =' + pageRef); pageRef.setRedirect(true); ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.ERROR, 'ERROR: \'INACTIVE\' '); ApexPages.addMessage(myMsg); return pageRef; } } }

 

Lastly, the  visualforce page, ErrorPg, is attached.  This is my generic error page. As you see below, I have the <apex:messages /> code in the visual force page, but the message I added above int the controller doesn't get displayed.   I believe it has to do with the fact that the button exists on a standard detail page, which calls a visualforce page and then gets redirected to another visualforce page to display the message.  Is this permissable

 

BTW, I can see the error messages if I change the 'return pageRef' to 'return null'.  This basically shows the errors in the 'CLONE' visualforce page, not the generic error visualforce page.

 

 

<apex:page standardController="custom_object__c"> <apex:sectionHeader title="Generic Error Page"/> <apex:messages /> <apex:outputPanel > Click <apex:outputLink value="/{!$CurrentPage.parameters.id}"> Here </apex:outputLink> to return to the Campaign </apex:outputPanel> </apex:page>

 

 Any help will be appreciated.

 

Thanks

 

 

 

When developing a Visualforce page for overiding view page for any object, one problem that creeps up is to display the History details of a record. The standard related list Component doesn't works for History.

 

With the help of some code from Community ( I now can't find the link to it :( ), I wrote my own code  then to display the history of an object. It mimics the standard list as far as possible.  

 

Heres the code. It is for the Case object but it can be used for any other object.

 1.Component Code

 

<apex:component controller="CaseHistoriesComponentController">
<!-- Attribute Definition -->
<apex:attribute name="CaseId" description="Salesforce Id of the Case whose Case History needs to be rendered" type="Id" required="true" assignTo="{!caseId}" />

<!-- Case History Related List -->
<apex:pageBlock title="Case History">
<apex:pageBlockTable value="{!histories}" var="History" >
<apex:column headerValue="Date" value="{!History.thedate}"/>
<apex:column headerValue="User"> <apex:outputLink value="/{!History.userId}"> {!History.who} </apex:outputLink></apex:column>
<apex:column headerValue="Action"><apex:outputText escape="false" value="{!History.action}"/></apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:component>

 

 

 

 

2. Apex Code

 

public class CaseHistoriesComponentController {

public Id caseId {get; set;}
public cHistories[] histories;

// Variables
public Static final Map<String, Schema.SObjectField> CaseFieldmap = Schema.SObjectType.Case.fields.getMap();
public Static final List<Schema.PicklistEntry> fieldPicklistValues = CaseHistory.Field.getDescribe().getPicklistValues();

public List<cHistories> getHistories()
{
list<cHistories> histories = new list<cHistories>();
String prevDate = '';
for(CaseHistory cHistory : [Select CreatedDate, CreatedBy.Name, CreatedBy.Id, Field, NewValue, OldValue from CaseHistory where CaseId = :caseId order by CreatedDate desc])
{
if((cHistory.newValue == null && cHistory.oldValue == null)
|| (cHistory.newValue != null && !(string.valueOf(cHistory.newValue).startsWith('005') || string.valueOf(cHistory.newValue).startsWith('00G')))
|| (cHistory.oldValue != null && !(string.valueOf(cHistory.oldValue).startsWith('005') || string.valueOf(cHistory.oldValue).startsWith('00G'))))
{
cHistories tempHistory = new cHistories();
// Set the Date and who performed the action
if(String.valueOf(cHistory.CreatedDate) != prevDate)
{
tempHistory.theDate = String.valueOf(cHistory.CreatedDate);
tempHistory.who = cHistory.CreatedBy.Name;
tempHistory.userId = cHistory.CreatedBy.Id;
}
else
{
tempHistory.theDate = '';
tempHistory.who = '';
tempHistory.userId = cHistory.CreatedBy.Id;
}
prevDate = String.valueOf(cHistory.CreatedDate);

// Get the field label
String fieldLabel = CaseHistoriesComponentController.returnFieldLabel(String.valueOf(cHistory.Field));

// Set the Action value
if (String.valueOf(cHistory.Field) == 'created') { // on Creation
tempHistory.action = 'Created.';
}
else if(cHistory.OldValue != null && cHistory.NewValue == null){ // when deleting a value from a field
// Format the Date and if there's an error, catch it and re
try {
tempHistory.action = 'Deleted ' + Date.valueOf(cHistory.OldValue).format() + ' in <b>' + fieldLabel + '</b>.';
} catch (Exception e){
tempHistory.action = 'Deleted ' + String.valueOf(cHistory.OldValue) + ' in <b>' + fieldLabel + '</b>.';
}
}
else{ // all other scenarios
String fromText = '';
if (cHistory.OldValue != null) {
try {
fromText = ' from ' + Date.valueOf(cHistory.OldValue).format();
} catch (Exception e) {
fromText = ' from ' + String.valueOf(cHistory.OldValue);
}
}

String toText = '';
if (cHistory.OldValue != null) {
try {
toText = Date.valueOf(cHistory.NewValue).format();
} catch (Exception e) {
toText = String.valueOf(cHistory.NewValue);
}
}
if(toText != '')
tempHistory.action = 'Changed <b>' + fieldLabel + '</b>' + fromText + ' to <b>' + toText + '</b>.';
else
tempHistory.action = 'Changed <b>' + fieldLabel;
}

// Add to the list
histories.add(tempHistory);
}
}

return histories;
}

// Function to return Field Label of a Case field given a Field API name
public Static String returnFieldLabel(String fieldName)
{
if(CaseHistoriesComponentController.CaseFieldmap.containsKey(fieldName))
return CaseHistoriesComponentController.CaseFieldmap.get(fieldName).getDescribe().getLabel();
else
{
for(Schema.PicklistEntry pickList : fieldPicklistValues)
{
if(pickList.getValue() == fieldName)
{
if(pickList.getLabel() != null)
return pickList.getLabel();
else
return pickList.getValue();
}
}
}
return '';
}
// Inner Class to store the detail of the case histories
public class cHistories {

public String theDate {get; set;}
public String who {get; set;}
public Id userId {get; set;}
public String action {get; set;}
}
}

  Let me know your views on the code or if you have any questions

 

I am trying to use the method EncodingUtil.urlEncode as shown below to encode a string passed into my method 'checkProduct'.  For example, if I call checkProduct('Jelly Beans'), I am expecting that the econdedURL would equal https://somewhere.com/something/Jelly%20Beans.  I am not getting that.  I am getting https://somewhere.com/something/Jelly++Beans.

 

What I need is for any of the spaces to be converted to %20.  I thought this is what the urlEncode method would do?  Any help would be appreciated.

 

public String checkProduct(String target) { String URL = 'https://somewhere.com/something/'; String encodedURL; System.debug('URL= ' + URL); encodedURL = URL + EncodingUtil.urlEncode(target, 'UTF-8'); System.debug('encodedURL= ' + encodedURL); )

 

I am trying to do a callout that logon's to a webservice and then returns an xml file.  I am trying to set the response header's content-type to be application-xml, but only see a setHeader method on the HttpRequest object.  

 

I am having a problem setting the Content-Type header with the below code.  When I check the Content-Type of the HttpResponse object, the value isn't 'application/xml' as I expected. 

 

Is this the correct approach?

 

 

Http http = new Http(); HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setHeader('Content-Type', 'application/xml'); req.setEndpoint('https://something./rest/clientauth/authenticate?account=xxx&password=xxx&source=xxx'); try { //Execute web service call here HTTPResponse res = http.send(req); //Helpful debug messages System.debug(res.toString()); System.debug('STATUS:'+res.getStatus()); System.debug('STATUS_CODE:'+res.getStatusCode()); System.debug('Content-Type:'+ res.getHeader('Content-Type')); } catch (System.CalloutException e) { system.debug('SKM-CalloutException occurred'); }

 

 

 

 

I have a trigger that calls a asynchronous method and it hits the 'Too Many DML rows' exception.  Basically the trigger creates a bunch of records in a child table which is used to do statistics.  Is there any way that I can create these records at a later date, for instance schedule a job, or write a class to do the creation after the trigger completes.

 

I had a solution, but it entails in making numerous calls to the asynchrounous method.  When I do that, I hit the barrier of 'Too many Future Calls'

 

So my main question is how can I break the process up so I can load the DML rows into the child table.  BTW, the code is already batching the records and I have optimized the code for bulk operation.

 

Any ideas/help will be appreciated.

 

Thanks

I have written a C# application that forces territory rules to run on a scheduled time period by running the salesforce generated URL.  So I am trying to write a trigger that runs the territory rules when an Opportunity is either created or updated!  The problem is that I don't see a way to force the territory rules to run! 

Does any one have a practical solution?  BTW, I tried to update the account associated with the opportunity.  If I do it via Salesforce, the account page layout forces the territory rules to run.  This is due to the checkbox 'Run territory Assignment Rules on save by default' on the account page layout.  But, it seems this doesn't work via the API.

Any information on this matter would be greatly appreciated!
I have the following trigger on a user object, but I am not getting any debugging information within the sandobx environment.  I have selected my 'Log Category' to be 'Apex Code' and 'Log Level' to be 'Debug'.

Nothing is being displayed?  Is there another setting or area where I must view the debug information for the trigger?

Code:
trigger NewUserTrigger on User(before insert, before update, after insert, after update) {

 Account temp_acc;
 String TestAcct = 'New User Trigger - do not delete or modify'; //Test Account
  System.Debug('Starting NewUserTrigger');

 try {
     System.Debug('SKM-NewUserTrigger');
  
  if (Trigger.isBefore) {     
     for (User u : Trigger.new) {
        System.Debug('Update--SKM-isBefore: ' + u.Full_Name__c );
     }
  } else if (Trigger.isAfter) {
        for (User u : Trigger.new) {
            System.Debug('Update--SKM-isAfter ' + u.Full_Name__c );
        }
  }
 }
 finally
 {
 }
}