Inserting image into visualforce email template (without hard-coding IDs) - salesforce

The "official" solution for including images in visualforce email templates suggests hard coding IDs in your template to reference an image file stored as a document.
https://help.salesforce.com/HTViewHelpDoc?id=email_template_images.htm&language=en_US
Is there a better way that avoids hard coding instance ID and OID? I tried using the partner URL to grab the instance ID, but I got the following error
Error Error: The reference to entity "oid" must end with the ';' delimiter.
Using:
{!LEFT($Api.Partner_Server_URL_140,FIND(".com/",$Api.Partner_Server_URL_140)+3)/
to replace "https://na2.salesforce.com/"
in
"na2.salesforce.com/servlet/servlet.ImageServer?id=01540000000RVOe&oid=00Dxxxxxxxxx&lastMod=1233217920"
Should I use a static resource instead?

I've arrived here looking for an answer for this question related to hardcoded ID and OID in Visualforce e-mail templates. Well, I found a workaround for that.
First I needed to create a Visualforce Component:
<apex:component access="global" controller="LogomarcaController">
<apex:image url="{!LogoUrl}" />
</apex:component>
In the respective controller class, I've created a SFInstance property to get the correct URL Salesforce Instance, LogoUrl property to concatenate SFInstance and IDs... And Finally I've used Custom Settings (Config_Gerais__c.getInstance().ID_Documento_Logomarca__c) to configurate the ID of Image (in my case, Document Object) on Sandbox or Production:
public class LogomarcaController {
public String LogoUrl {
get {
id orgId = UserInfo.getOrganizationId();
String idDocumentoLogomarca = Config_Gerais__c.getInstance().ID_Documento_Logomarca__c;
return this.SfInstance + '/servlet/servlet.ImageServer?id=' + idDocumentoLogomarca + '&oid=' + orgId ;
}
}
public String SfInstance
{
get{
string SFInstance = URL.getSalesforceBaseUrl().toExternalForm();
list<string> Dividido = SFInstance.split('.visual', 0);//retira o restante a partir de .visual
SFInstance = dividido[0];
dividido = SFInstance.split('://',0);//retira o https://
SFInstance = dividido[1];
if(!SFInstance.contains('sybf')) //managed package prefix, if you need
{
SFInstance = 'sybf.'+ SFInstance;
}
return 'https://'+SFInstance;
}
}
}
And finally, I've added the component in Visualforce template:
<messaging:emailTemplate subject="Novo Ofício - {!relatedTo.name}" recipientType="User" relatedToType="Oficio__c" >
<messaging:htmlEmailBody >
<c:Logomarca />
</messaging:htmlEmailBody>
<messaging:plainTextEmailBody >
</messaging:plainTextEmailBody>
</messaging:emailTemplate>
PS: Some of my variables, properties and comments are in my native language (portuguese). If you have some problems understanding them, please ask me!

We ran into a similar problem and after trying various solutions, the following worked for us. In our case the image is uploaded as a content asset(https://help.salesforce.com/articleView?id=000320130&type=1&language=en_US&mode=1)
Solution:
<img src="{!LEFT($Api.Partner_Server_URL_260,FIND('/services',$Api.Partner_Server_URL_260))}/file-asset-public/<Image_Name_Here>?oid={!$Organization.Id}&height=50&width=50"/>

Related

How to find the API name of field from an label of field from a particular sobject?

How to find the API name of field from an label of field from a particular sobject.
This was pretty bad to find the field api name in salesforce, It is an indeed a trivial question which many of developer folks find out tough while working on projects.
Putting here as an code snippet for searching easily.
Here's the code snippet to find out the api name of the field based on the label of an object.
public static String getMyAPIName(String objectName, String fieldLabel ) {
SObjectType type = Schema.getGlobalDescribe().get(objectName);
Map<String,Schema.SObjectField> mfields = type.getDescribe().fields.getMap();
for(String strField : mfields.keySet())
{
SObjectField fl = mfields.get(strField);
if(fieldLabel == fl.getDescribe().getlabel())
{
return strField;
}
}
return '';
}
SELECT EntityDefinition.QualifiedApiName, QualifiedApiName, Label
FROM FieldDefinition
WHERE EntityDefinition.QualifiedApiName = 'Account' AND Label = 'Parent Account'
outputs "ParentId" just fine, no describes and loops

How can i fetch dynamic data from database based on selected language.?

Hi i am working on a project in laravel 7.0, in back-end i have a table called Posts which contains 2 text language input one in french and the other is arabic added by the back-end application.
what i am trying to do is when the user uses the French Language i want the title_fr to be displayed on the view and same thing in Arabic language the title should be title_ar.
P.S data are stored in French and Arabic
I have tried the similar solution given in an other similar question but none of it worked in my case!
Any idea how i might get this to work ?
Thanks in advance.
You can do something similar to below. We have a model Post, this model has an attribute title. I also assume that you have an attribute that will return user's language from the User model.
class Post extends Model
{
public function getTitleAttribute(): string
{
return Auth::user()->language === 'fr' ? $this->title_fr : $this->title_ar;
}
}
FYI above is just a demo on what can be done. For a full blow solution I would recommend decorator pattern.
Also it might be worth considering using morph for things like that. You can have a service provider that will initiate the morph map for you post model relevant to the language that user has, I.e.
Class ModelProvider {
Protected $models = [
‘fr’ => [
‘post’ => App/Models/Fr/Post::class,
],
‘ar’ => [
‘post’ => App/Models/Ar/Post::class,
]
];
Public function boot() {
$language = Auth::user()->Settings->language;
Relation::morphMap($This->models[$language]);
}
}
Afterwards you just need to call to Relation::getMorphModel(‘post’) to grab Post class that will return correct language.
I.e. App/Models/Fr/Post can have a an attribute title:
Public function getTitleAttribute(): string {
Return $this->title_fr;
}
For example above you would also want to utilise interfaces to make sure that all models follow the same contract, something below would do the trick:
Interface I18nPostInterface {
Public function getTitleAttribute(): string
}
Also, depending on the database you use, to store titles (and other language data) in a JSON format in the database. MySQL 8 has an improve support for JSON data, but there are limitations with that.
So I was Able to fetch data from my database based on the Language selected by the user.
Like i said before I have a table called Posts and has columns id,title_fr and title_ar. I am using laravel Localization.
Inside my PostController in the index function i added this code:
public function index()
{
//
$post = Post::all();
$Frtitle = post::get()->pluck('title_fr');
$Artitle = post::get()->pluck('title_ar');
return view('post.index',compact('post','Frtitle','Artitle'));
}
if anyone has a better way then mine please let me know, i am sure
there is a better way.

Programmatically include xhtml fragment in MyFaces

I know it is possible in MyFaces to programmatically add a xhtml fragment to the component tree, instead of using ui:include.
The snipplet I am talking about is as (in the original form):
ViewDeclarationLanguage vdl = facesContext.getApplication().getViewHandler().getViewDeclarationLanguage(facesContext, facesContext.getViewRoot().getViewId());
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put("src", "/fragmentToInclude.xhtml");
UIComponent component = vdl.createComponent(facesContext, "http://java.sun.com/jsf/facelets", "include", attributes);
The problem I am facing is I am not able to pass in parameters, that would normally be passed in via <ui:param .../> tag.
What I tried, of course, was to add params into attributes map:
attributes.put("testingParam1", "Yeah, it worked!");
But this seems not to help. Content of my testing fragment is quite simple:
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<div class="testingDiv">#{empty testingParam1 ? 'testingParam1 IS EMPTY' : testingParam1}</div>
</ui:composition>
The fragment is properly loaded, but I only get that 'is empty' message.
I have walked through multiple resources but haven't found answer there:
NullPointerException in MyFaces facelet inclusion
http://lu4242.blogspot.cz/2014/01/whats-new-in-myfaces-22.html
https://java.net/projects/javaserverfaces-spec-public/lists/jsr344-experts/archive/2014-03/message/12
https://java.net/projects/javaserverfaces-spec-public/lists/users/archive/2014-10/message/120
Please, do you know, is this even possible? Or am I missing something? Thanks for any hints.

Ideas on how to implement CMS for language specific page

I'm building a web shop and I'm implementing language selection as well as a CMS. I also have to provide an administrator of the site with the means to be able to edit a page through the CMS.
Therein doesn't lay the problem.
The problem is how I should build up my tables for these pages. I've made my database design but didn't think the web pages part through.
I already have the following table structure for the info that is equal throughout all languages for a page (called Webpages) and for language or culture specific info (called Webpages_local).
Which attributes could I add or remove so that I can easily and dynamically perform the CRUD actions?
I'm using MVC4 with razor syntax with the following url structure:
url: "{language}/{controller}/{action}/{id}"
My main concern is now that I'm not sure on how to show the language specific content of a page when a visitor presses, for example, the link to the About page.
Maybe use the controller part of the url and save it as a key in my Webpages table and filter on that as well as the selected language?
So when a visitor goes to http://example.com/nl/About, I in my AboutController I retrieve "nl" and "about", of course filter them first and then with a query to the database select the correct nl content?
How should I go about this technically?
I would use OnActionExecuting to handle the retrieve lang process, something like:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
#region set Language
var lang = string.Empty;
if (filterContext.RouteData.Values["lang"] != null && !string.IsNullOrWhiteSpace(filterContext.RouteData.Values["lang"].ToString()))
{
// set the culture from the route data (url {lang})
lang = filterContext.RouteData.Values["lang"].ToString();
switch (lang)
{
case "es":
break;
case "en":
break;
default:
lang = "es";//default language
filterContext.RouteData.Values["lang"] = lang;
filterContext.HttpContext.Response.Redirect("/");
break;
}
}
else
{
//set default language
lang = "es";
filterContext.RouteData.Values["lang"] = lang;
}
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(lang);
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang);
#endregion
base.OnActionExecuting(filterContext);
}
Then anywhere in your code you just read the Thread.CurrentThread.CurrentCulture (this will be your global lang indicator) to show the correct language.
UPDATE - know I understand your point =)
If the pages will be dynamically created then you wont have an ActionResult per page, you need just one ActionResult like:
public ActionResult ShowPage(int id,string slug)
{
//Use the slug to check for url attacks and ensure 301 redirections to the correct url
var page = db.Webpages_local.First(p=> p.id == id
&& p.culture.name == Thread.CurrentThread.CurrentCulture);
return View(page);
}
For SEO reasons i would suggest you define a route like:
routes.MapRoute(
name: "LocalizedPages",
url: "{lang}/p/{slug}/{id}",
defaults: new { controller = "Page", action = "Show", id = UrlParameter.Optional },
constraints: new { lang = #"(es|en|fr|nl)" }
);
That give you urls like:
/nl/p/about/1 //the p is just an identifier for 'page', to differentiate this routes from others
I would add a column called language or similar to your table instead of having multiple tables.
Then your controller can fetch the right page after finding the requested language key in your menu table and then it can read the content in your webpages table.

ADF - Unable to read view Id of Declarative Component from "var" of af:iterator

I am facing a weird issue where when i assign "var" of af:iterator to the view Id of declarative component, it is saying " Encountered null from the viewId expression: #{row}"
And Page is showing blank.
My JSPX code is as follows :
<af:iterator value="#{pageFlowScope.stageBean.pathList}" var="row">
<af:outputText value="#{row}" id="ot1"/>
<af:declarativeComponent viewId="#{row}"/>
</af:iterator>
And code snippet for getter in Java bean is as follows:
public List<String> getPathList()
{
List<String> pathList = new ArrayList<String>();
pathList.add("/Test.jspx");
return pathList;
}
The weird thing here is output text is printing the path /Test.jspx but declarative component is not recognizing it. Its showing blank page and in logs, error says "Encountered null from the viewId expression: #{row}"
If i remove #{row} from viewId and manually give like viewId = "/Test.jspx" , its displaying the page correctly.
Can anyone please help me solve this issue?
Regards,
Rakesh.
I remember this issue from the Oracle forums and I am not sure declarative components can be stamped (which is how af:iterator lays out its children). Can you try af:forEach?
Frank

Resources