-
ChatterFeed
-
3Best Answers
-
0Likes Received
-
0Likes Given
-
21Questions
-
29Replies
Controller Extension seems to be running in user mode not system mode
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.
- sgkmills
- December 01, 2011
- Like
- 0
- Continue reading or reply
Query not returning all rows in APEX code
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.
- sgkmills
- October 13, 2011
- Like
- 0
- Continue reading or reply
Standard Controller is not being initialized
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.
- sgkmills
- August 09, 2011
- Like
- 0
- Continue reading or reply
How to use Asynchronous Callout to process XML Data
- sgkmills
- October 07, 2010
- Like
- 0
- Continue reading or reply
Detect if user logged in via API or web browser
I have an excel app I wrote with the excel connector, that allows users to login and do some inserts/deletes for some custom objects. I would like to write some validation rules that detect when the user is logged in via this APP which will allow them to edit certain fields. If they are logged in via the browser, they shouldn't be able to edit those same fields.
Is there a field/flag that allows me to detect that the login came from the API as opposed to the Web Browser?
Thanks in advance
- sgkmills
- February 04, 2010
- Like
- 0
- Continue reading or reply
Displaying ApexPages.Messages on Redirected VisualForce Page via custom Controller
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
- sgkmills
- January 07, 2010
- Like
- 0
- Continue reading or reply
EncodingUtil.urlEncode method not returning what I expected
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); )
- sgkmills
- July 01, 2009
- Like
- 0
- Continue reading or reply
How to Set the HttpResponse object Content-Type?
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'); }
- sgkmills
- June 29, 2009
- Like
- 0
- Continue reading or reply
Write a future call (async method) to avoid the System Exception Too many DML rows issue
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
- sgkmills
- May 15, 2009
- Like
- 0
- Continue reading or reply
Triggers failing after activating Spring 09 Critical Updates
I have a trigger on the opportunity object that gets called on the 'After Insert' event. The code in this trigger creates a record in a custom s-object that I created, call it "SC__c".
trigger CreateSCTrigger on Opportunity (after insert) {
if (Trigger.isInsert) {
for (Opportunity o : Trigger.new) {
//Code to create new SC
temp_SC = new SC__c(Opportunity__c=o.Id, Sales_Rep__c=o.OwnerID, CPct__c=100);
insert temp_SC;
}
}
}
I also have a trigger on "SC__c" that gets called on the 'Before Insert' event. The code for this trigger just changes a field value
trigger UpdateSCTrigger on SC__c (before insert) {
if (Trigger.isInsert) {
if (Trigger.new.size() >=1) {
for (SC__c sc : Trigger.new) {
sc.Sales_Goal__c = sc.SalesGoalID__c;
}
}
}
}
So the 'insert temp_SC' line in the CreateSCTrigger, causes the UpdateSCTrigger to fire.
This used to work fine, but with the Spring09 changes to the behavior of workflow rules and roll-up summary field evaluations, the 2nd trigger is causing a 'INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id:' error.
Why would this be? Any help will be greatly appreciated.
Thanks in advance.
- sgkmills
- April 08, 2009
- Like
- 0
- Continue reading or reply
A Trigger fired from another Trigger
Hi,
I have 2 custom objects, once is called 'res' and the other called 'res_mt', which has a lookup relationship to 'res'. I have a trigger on the 'res' object that creates 48 'res_mt' records upon 'afterinsert'. This trigger works fine.
I then added a new object called 'res_d', which has a lookup relationship to 'res_mt'. I created a trigger on the 'res_mt' object that would create 31 'res_d' records upon 'afterinsert'.
I try to add a 'res' record and get a Too Many DML Rows error. When looking in the 'System Log', I see the trigger on 'res' gets fired and the 48 records are created. But, the 2nd trigger that creates the 31 'res_d' records, doesn't get fired for each of the 48 records! I thought that for each of the 48 'res_mt' records, I would see the 2nd trigger fire in between, like a nested trigger. That doesn't seem to be the case, it seems that the first trigger must complete before the 2nd starts.
Does anyone have any suggestions for me?
When looking at the System Log, I see that
- sgkmills
- April 01, 2009
- Like
- 0
- Continue reading or reply
Update the same Opportunity in a batch multiple times via Data Loader
I have a custom object, call it MDP, that is associated with an opportunity. There can be many MDP records for each opportunity. I have written a trigger that updates fields in the Opportunity when certain fields in a MDP record is modified.
The problem is that the data loader does not seem to be updating the same opportunity if two MDP records associated to the same Opportunity is updated. What I would need is each time the MDP record is updated, the Opportunity is updated. Regardless if it is the same opportunity in a batch update via dataloader. Is it possible?
- sgkmills
- November 20, 2008
- Like
- 0
- Continue reading or reply
Redirect Apex Trigger Email
Is there a way to send the email for an 'unhandled trigger exception' to another admin in Salesforce?
- sgkmills
- October 27, 2008
- Like
- 0
- Continue reading or reply
Test Code Coverage for OpportunityShare
I have the below code in a trigger:
temp_opp_share = new OpportunityShare(OpportunityAccessLevel='Edit', UserOrGroupId=o.Channel_Specialist__c, OpportunityId=o.Id); insert temp_opp_share;
How would I do this?
- sgkmills
- June 17, 2008
- Like
- 0
- Continue reading or reply
Salesforce Global Server variable
Currently, I have the following code:
var saveURL ="https://tapp0.salesforce.com/"+ newOppId;
But, I don't want to hardcode the URL, so how can I get the salesforce server name that I am currently connected to.
I was trying to use the URLFOR function, but I still need a target value and didn't know what I could put.
Thanks in advance
- sgkmills
- April 25, 2008
- Like
- 0
- Continue reading or reply
Force 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!
- sgkmills
- February 19, 2008
- Like
- 0
- Continue reading or reply
Debug Output not displaying in Salesforce
Nothing is being displayed? Is there another setting or area where I must view the debug information for the trigger?
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 { } }
- sgkmills
- February 19, 2008
- Like
- 0
- Continue reading or reply
Apex Code not ablet to reference the Account Name field
I create an array of accounts and try to access the Name field, but I get a null value. The problem is I can reference the name field by displaying accts[0].Name, (where accts is my array of accounts returned from a SOQL query) but not reference it by doing the 'for (Account a1 : accts)' and then displaying a1.Name. a1.Name shows as Null.
Below is the code for the trigger:
if (Trigger.isAfter) { /* Once the insert/update trigger is completed, the cascading phase is as follows: 1. Get the Acct Id of the record that was just inserted/updated 2. Do a search to see which records have their ParentId the same as the Acct Id found in 1. 3. Update the new Parent Name for all those records in 2. */ for (Account a : Trigger.new) { System.Debug('isAfter-a: ' + a); Account[] accts = [select id, ParentId, Name from Account where ParentId = :a.Id]; System.Debug('SKM-Acct.Size: ' + accts.size()); if (accts.size() > 0) { System.Debug('accts[0]: ' + accts[0].Name); for (Account a1 : accts) { a1.Name = a.Parent_Account_Name__c; System.Debug('a1= ' + a1 + ', acct.Name= ' + a1.Name + ', a.Parent_Account.Name= ' + a.Parent_Account_Name__c); } } }
Partial print of the debug code is below:
20080219162042.523:Trigger.ParentNameUpdateTrigger: line 6, column 3: Starting ParentNameUpdate 20080219162042.523:Trigger.ParentNameUpdateTrigger: line 51, column 10: isAfter-a: Account:{SystemModstamp=Tue Feb 19 16:20:42 GMT 2008, Type=Master Customer, Parent_ID_Confirm__c=1, RecordTypeId=0125000000097vkAAA, OwnerId=00550000000s4qAAAQ, IsExcludedFromRealign=false, IsLocked=false, LastModifiedById=00550000000s4qAAAQ, MayEdit=false, IsDeleted=false, Master_Customer_Level__c=SKM-Tes1a, CreatedDate=Tue Feb 19 16:20:38 GMT 2008, LastModifiedDate=Tue Feb 19 16:20:42 GMT 2008, Account_ID_Display__c=001S0000002f8AY, Name=SKM-Tes1a, Id=001S0000002f8AYIAY, CreatedById=00550000000s4qAAAQ} 20080219162042.523:Trigger.ParentNameUpdateTrigger: line 53, column 10: SKM-Acct.Size: 2 20080219162042.523:Trigger.ParentNameUpdateTrigger: line 55, column 13: accts[0]: SKM-Test2 20080219162042.523:Trigger.ParentNameUpdateTrigger: line 58, column 17: a1= Account:{ParentId=001S0000002f8AYIAY, Name=null, Id=001S0000002f8AZIAY}, acct.Name= null, a.Parent_Account.Name= null 20080219162042.523:Trigger.ParentNameUpdateTrigger: line 58, column 17: a1= Account:{ParentId=001S0000002f8AYIAY, Name=null, Id=001S0000002f8AaIAI}, acct.Name= null, a.Parent_Account.Name= null
- sgkmills
- February 19, 2008
- Like
- 0
- Continue reading or reply
Setting Fields within an edit Page *** Solution ***
I took the liberty to show my solution, which actually sets fields defined as read-only and editable fields on a specific page layout.
Below, I create a variable called "options". This variable holds all the fieldnames and values I want to set within the field. For example, opp7 is the fieldname for amount and the fields starting with "00N" are custom fields. BTW, you can find the fieldname of the custom field by going to the Setup | Customize area in Salesforce and then going into the Fields area for the object that you are setting values in. In my case it was Opportunity.
The next step, I created a "newURL" variable, which uses the URLFOR function to build the URL that I will redirect the browser to. As you see, I append the "options" variable to the end of the created URL.
Then I just use the window.parent.location.replace function to redirect the browser to the newly created URL.
As I stated above, some of these fields are not editable on the layout, but still get changed and then they are viewed as read-only.
var options = "&opp7=0&opp11=Development&00N5000000xxxxx=0&00N3000000xxxxx=0&00N5000000xxxxx=" + "&RecordType=012300000000xxxxxx&opp5; var newURL = "{!URLFOR( $Action.Opportunity.Edit, Opportunity.Id, [retURL=$Request.retURL] ,true)}"+options; window.parent.location.replace(newURL);
- sgkmills
- December 07, 2007
- Like
- 0
- Continue reading or reply
Cloned Opportunity returning to edit page without parameters when validation fails
BTW, Deliverables, is our name for Opportunity LineItems.
The code below works fine if validation is passed on all fields when the user clicks "Save". The Opportunity Line Items are also cloned. As stated, the problem is if the user makes an error or doesn't put in a required field on the cloned opportunity and then they try to save it, then Salesfoce redirects them to the following URL https://na3.salesforce.com/006/e. All my variables that I added to the URL are stripped!
How can I get the same variables I passed when I clicked the "Clone" button to show up if validation fails when the user clicks the "Save" button in the newly created cloned opportunity?
Note: The "options" variable below are the parameters I pass to the URL and the newURL variable is the actual URL that gets called.
var options = "&opp7=0&opp11=&00N50000001TsuZ=0&00N300000018Fd8=0&00N50000001gfzh=&00N50000001TsuZ=0&00N50000001QPD1=0&00N50000001hD8t=0&00N50000001hD8Z=0&retURL=/" + "{!Opportunity.Id}" ;
var newURL ="https://na3.salesforce.com/"+ "{!Opportunity.Id}" + "/e—clone=1" + options + "&nooverride=1&cloneli=1";
window.parent.location.replace(newURL);
- sgkmills
- December 06, 2007
- Like
- 0
- Continue reading or reply
Controller Extension seems to be running in user mode not system mode
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.
- sgkmills
- December 01, 2011
- Like
- 0
- Continue reading or reply
Query not returning all rows in APEX code
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.
- sgkmills
- October 13, 2011
- Like
- 0
- Continue reading or reply
Standard Controller is not being initialized
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.
- sgkmills
- August 09, 2011
- Like
- 0
- Continue reading or reply
Override Save & new button
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.
- community
- May 30, 2011
- Like
- 0
- Continue reading or reply
Where's the new system log and the new support site?
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.
- paul-lmi
- October 15, 2010
- Like
- 0
- Continue reading or reply
Displaying ApexPages.Messages on Redirected VisualForce Page via custom Controller
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
- sgkmills
- January 07, 2010
- Like
- 0
- Continue reading or reply
History related List using Visualforce
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
- Rajesh Shah
- October 16, 2009
- Like
- 1
- Continue reading or reply
EncodingUtil.urlEncode method not returning what I expected
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); )
- sgkmills
- July 01, 2009
- Like
- 0
- Continue reading or reply
How to Set the HttpResponse object Content-Type?
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'); }
- sgkmills
- June 29, 2009
- Like
- 0
- Continue reading or reply
Write a future call (async method) to avoid the System Exception Too many DML rows issue
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
- sgkmills
- May 15, 2009
- Like
- 0
- Continue reading or reply
Force 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!
- sgkmills
- February 19, 2008
- Like
- 0
- Continue reading or reply
Debug Output not displaying in Salesforce
Nothing is being displayed? Is there another setting or area where I must view the debug information for the trigger?
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 { } }
- sgkmills
- February 19, 2008
- Like
- 0
- Continue reading or reply