How to specify composite action variables in magento dataflow xml profiles - magento

I have created some custom actions to use inside a Magento Dataflow profile. I would like to pass in composite parameter values (arrays or dictionaries) to the action, similar to the map var you can pass to the default parser actions. I.e., I would like to do something like this:
<var name="attribute_map">
<map name="sColore"><![CDATA[colore]]></map>
<map name="sMarca"><![CDATA[marca]]></map>
<map name="sFornitore"><![CDATA[fornitore]]></map>
</var>
The variable turns out as null in this case, although, upon fiddling with the xml and skimming through the code, it seems that this pattern only works with <var name="map">. Puzzling and disappointing. I also have not been able to find even the slightest hint about the relevant xml schema in any documentation whatsoever...
Any idea on this? Thanks!
(I am working with Community Edition version 1.7.0.2)

If i understand right what you ask, you could overwrite the system/convert/profile/wizard.phtml from admin and add another section similar to existing map but the form elements should have name="gui_data[attribute_map]...[]".
Then you should overwrite the _parseGuiData method from Mage_Dataflow_Model_Profile to form the correct profile actions xml.
Hope that helps.

You can't, using the core implementation.
The var elements can only contain simple text, unless the element has the attribute name="map", in which case the profile parser will search for children map elements and use them to populate a php associative array.
The relevant code is inside the importProfileXml method of the Mage_Dataflow_Model_Convert_Profile_Collection class:
if ($varNode['name'] == 'map') {
$mapData = array();
foreach ($varNode->map as $mapNode) {
$mapData[(string)$mapNode['name']] = (string)$mapNode;
}
$container->setVar((string)$varNode['name'], $mapData);
}
To extend this behavior you should override this class with a custom (sub)class through the usual magento class override methods.

Related

Sitecore MVC: pass parameters to placeholders

As we are switching to sitecore from a java platform, I have some questions regarding parameters. This is easily done in jsp but I can't find a solution for sitecore. (the implementation is done by external partners)
In my cshtml, I include other elements via the placeholder-function: #Html.Sitecore().Placeholder("Placholdername")
The elements included as a placeholder also can include other elements as placeholders.
So the question is: can I pass some parameters along with those placeholders?
Like my parent element has a certain variable set, for example "i = 5", and I want to pass this variable to the elements included as placeholders and also pass it to the elements included as placeholders in the placeholders?
Something like:
A includes B as a placeholder and passes "i=5" and B includes C as a placeholder and passes "i=5" so in C the value of "i" is "5" because "i" was set to "5" in A.
On out current coremedia platform I can simply use something like:
<cm:include self="${self}" view="asdf">
<cm:param name="i" value="5"/>
</cm:include>
Edit:
What I want to achieve is the following: For example I have the following structure: the page frame cshtml with a variable i=5, which then includes a grid as a placeholder and passes the variable to the grid. The grid then does some math like i=i+5 (which should equal 10) and then includes a teaser as a placeholder and passes the new i=10 to the teaser and so on..
You should set the value of i in the model. Then all the different views or partial views should inherit the same model.
You can assign parameters to renderings, but not to placeholders. Placeholders should be seen as a hole. You can dynamically put stuff in it but you can't assign parameters to it. There's a discussion of that here: https://sitecore.stackexchange.com/questions/2098/add-rendering-parameters-to-placeholder/2101
I can think of at least two approaches to solve your problem:
Although your question is a bit lacking in detail, it kind of looks like you don't necessarily need placeholders because you already know what you're going to render inside those spaces. If that's the case, then you can statically bind your MVC views instead of using placeholders. This is not a common practice, but it is mentioned in Sitecore's latest training material and elsewhere as a way to optimize when you don't need the flexibility of placeholders. This is normally done using the #Html.Sitecore.Rendering helper.
You could use a global variable of sorts by leveraging the good old HttpContext.Items collection.
You can add parameters to the ViewData dictionary, in a controller action method:
public ActionResult MyPage()
{
ContextService.Get().GetCurrent().ViewData.Add("MyKey", "MyValue");
return View();
}
Then, any View Renderings can access the parameter from ViewData:
#{
var value = ViewData["MyKey"].Value;
}
Or if you're using Controller Renderings, add some code to fetch the ViewData from parent pages, and add it to the current ViewData instance:
public ActionResult ChildRendering()
{
// Get any ViewData previously added to this ViewContext
var contextViewData = ContextService.Get().GetCurrent().ViewData;
contextViewData.ToList().ForEach(x => ViewData.Add(x.Key, x.Value));
return View();
}
Your ViewData contents will now be available in view files.
This is discussed in a little more detail here: https://chrisperks.co/2017/03/06/a-workaround-for-missing-viewdata-in-sitecore-mvc/

How to get the actual Hyperlink element inside the main document part using docx4j

So I have a case where I need to be able to work on the actual Hyperlink element inside the body of the docx, not just the target URL or the internal/externality of the link.
As a possible additional wrinkle this hyperlink wasn't present in the docx when it was opened but instead was added by the docx4j-xhtmlImporter.
I've iterated the list of relationships here: wordMLPackage.getMainDocumentPart().getRelationshipsPart().getRelationships().getRelationship()
And found the relationship ID of the hyperlink I want. I'm trying to use an XPath query: List<Object> results = wordMLPackage.getMainDocumentPart().getJAXBNodesViaXPath("//w:hyperlink[#r:id='rId11']", false);
But the list is empty. I also thought that it might need a refresh because I added the hyperlink at runtime so I tried with the refreshXMLFirst parameter set to true. On the off chance it wasn't a real node because it's an inner class of P, I also tried getJAXBAssociationsForXPath with the same parameters as above and that doesn't return anything.
Additionally, even XPath like "//w:hyperlink" fails to match anything.
I can see the hyperlinks in the XML if I unzip it after saving to a file, so I know the ID is right: <w:hyperlink r:id="rId11">
Is XPath the right way to find this? If it is, what am I doing wrong? If it's not, what should I be doing?
Thanks
XPathHyperlinkTest.java is a simple test case which works for me
You might be having problems because of JAXB, or possibly because of the specific way in which the binder is being set up in your case (do you start by opening an existing docx, or creating a new one?). Which docx4j version are you using?
Which JAXB implementation are you using? If its the Sun/Oracle implementation (the reference implementation, or the one included in their JDK/JRE), it might be this which is causing the problem, in which case you might try using MOXy instead.
An alternative to using XPath is to traverse the docx; see finders/ClassFinder.java
Try without namespace binding
List<Object> results = wordMLPackage.getMainDocumentPart().getJAXBNodesViaXPath("//*:hyperlink[#*:id='rId11']", false);

Can we dynamically set the value of "list" attribute of <apex:relatedList> component?

I am trying to design a generalized detail page for an object.
In the controller class I find the list of all child relations of that object.
I then want to create for each child relations found and for accomplishing this I will have to dynamically set the value of list attribute within it.
For example :
<apex:relatedList subject={!ObjName} list="{!relatedListName}" />
But the problem here is that list attribute only accepts String literal, so can't implement it. Please suggest a way for this requirement to be accomplished.
Yes, you can dynamically set the value of the "list" attribute on a relatedlist tag, and you do so via Dynamic Visualforce. This question has since been asked and concisely answered here on the Salesforce Stack exchange for any future browsers:
https://salesforce.stackexchange.com/questions/7531/apexrelatedlist-list-dontexistinallorgs-c-only-solveable-with-dynamic
Here is the general solution:
In a custom controller, add a function to dynamically generate the RelatedList markup. I will assume from your wording that you have already accessed the full list of child relationships in your controller, so in order to spit out all the lists in one block, I would use something like this:
public Component.Apex.OutputPanel getDynamicList()
{
Component.Apex.OutputPanel outPanel = new Component.Apex.OutputPanel();
for(String id : childNames) {
Component.Apex.RelatedList relList = new Component.Apex.RelatedList();
relList.list = id;
outPanel.childComponents.add(relList);
}
return outPanel;
}
In the middle there, you can dynamically set any string to the "List" value, and by iterating through your list of strings, you are adding related list objects over and over again. (To simply add one list, remove the for loop, and make the "id" string value whatever specific relationship you wish to display).
Then on your visualforce page, you can render this block out using a dynamic visualforce tag:
<apex:dynamicComponent componentValue="{!DynamicList}" />
(as you may know, the formulaic value field will dig up the getter automatically)
Great success!
I would suggest trying apex:dataTable or apex:repeat to build your own list display. You will likely need a wrapper class to handle passing attributes and values from the sObject to the page.

Extend a Varien Form Element for a Custom Module

Improving on this question:
Is it good practice to add own file in lib/Varien/Data/Form/Element folder
The accepted answer shows how to extend a Varien form element, but this will not work if you want to package it into a custom module.
What would be the proper method of extending the Varien form element in a module? A simple XML setting I'm hoping?
Update:
Thanks Vinai for the response. Although that does work, I was hoping to extend the form element somehow. My extension is using the base File form element to allow administrators to upload files to categories. So, I'm not directly adding the form elements to the fieldset myself.
I suppose it's possible to to check for the file input on my category block on the backend: Mage_Adminhtml_Block_Catalog_Category_Tab_Attributes , and then change the form element if it is 'file' to 'mycompany_file' -- but this seems like a workaround.
Is there an easier way? Thanks again Vinai.
On the Varien_Data_Form instance you can specify custom element types like this:
$fieldset->addType('custom', 'Your_Module_Model_Form_Element_Custom');
Then, add your element with
$fieldset->addField('the_name', 'custom', $optionsArray);
If you are using a form without fieldsets you can do the same on the Varien_Data_Forminstance, too.
EDIT: Expand answer because of new additional details in the question.
In the class Mage_Adminhtml_Block_Widget_Form::_setFieldset() there is the following code:
$rendererClass = $attribute->getFrontend()->getInputRendererClass();
if (!empty($rendererClass)) {
$fieldType = $inputType . '_' . $attribute->getAttributeCode();
$fieldset->addType($fieldType, $rendererClass);
}
Because of this the attribute frontend_input_renderer on the attributes can be used to specify custom element classes.
This property can be found in the table catalog_eav_attribute, and luckily enough it isn't set for any of the category image attributes.
Given this, there are several ways to apply customizaton.
One option is to simply set the element class in the table using an upgrade script.
Another would be using an observer for the eav_entity_attribute_load_after event and setting the input renderer on the fly if the entity_type_id and the input type matches.
So it is a little more involved then just regular class rewrites in Magento, but it is quite possible.
You don't necessarily need to have a file in the lib/Varien/ directory in order to extend it. If you needed to add an element to that collection, you should be able to extend one of the Elements in your app/code/local module. The answer to the question you referenced seems to also indicate this is the case. I would create your custom field, extending its highest-level function set (i.e., lib/Varien/Data/Form/Element/File.php).
If you want to override the Mage_Adminhtml_Block_Catalog_Category_Tab_Attributes block, then you should extend that block in your module and then reference the new one. You may wish to extend the block using an event observer rather than an XML rewrite, for compatibility purposes.

Is it possible to pass argument from visualforce apex tag?

I have a function searchWorkByName that takes "key" as an argument and use SQOL to retrieve the data.
In visualforce side, I have a link that calls searchWorkByName but would like to be able to pass argument such as character 'a'
example, (this throws an error)
<apex:commandLink value="search!" action="{!searchWorkByName('aaa')}" />
Is it possible to do so if not what is the alternatives?
apex class
public class SearchWorkTest {
public PageReference searchWorkByName(String key) {
//find record of work names starting from provided key character
workNames = [select name from work__c where work__c.name like 'key%'];
return Page.searchResult;
}
}
visualforce
<apex:page standardController="work__c" extenstions="SearchWorkTest">
<!-- Is it possible to pass argument like 'foo' ? -->
<apex:commandLink value="search!" action="{!searchWorkByName}" />
</apex:page>
You can pass in parameters from a page into a function like this:
<apex:commandLink value="search!" action="{!searchWorkByName}">
<apex:param name="key" value="val"/>
</apex:commandLink>
Obviously, the value of the parameter in this case is fixed. If you want something dynamic (i.e. user types something and that is passed to the function), I'm not 100% sure how you'd do that, but I think it might be possible. However, the solution already posted skins the cat for you, but I thought I'd follow up with an alternative in case it's any use.
No, you cannot pass arguments to actions like that.
1 option is to make this variable a normal form field that user can type text/select from dropdown/whatever - if you'll use same name for a variable in Apex (and make it publicly visible by setters/getters), this will work without problems. Check out my answer at How do I integrate Salesforce with Google Maps? to get started.
Second option - if this search must be somehow done programatically without user having to click anything, if the data for example comes from page itself (i.e. is read in <apex:repeat> tag)... you could make a small helper page & controller and call them as components. There is no problem with passing data to components. Check documentation for <apex:component> and <apex:componentBody>. But I think first answer os most useful for you.
Good luck!

Resources