COLDFUSION: Component [Document] has no accessible Member with name [FILENAME] - coldfusion

i am trying to save a document (image in article). i use article uid as document filename. what i want to save in document is:
-caption (string text consists of the description of the image).
-fileName (string text consists of the article uid)
-fileHref (path to image location).
here is my code:
Document Handler:
function save (event, rc, prc) localmode="modern" {
prc.article = articleService.findWhere({"uid"=rc.fileName});
try {
if (prc.article.hasDocument()) {
response = {
"status" = "error",
"message" = "Article already have an image.",
"data" = {}
};
} else {
structUpdate(rc,"fileName", #rc.fileName#&".jpg");
prc.document = documentService.new(rc);
documentService.save(prc.document);
prc.article.addDocument(prc.document);
articleService.save(prc.article);
response = {
"status" = "success",
"message" = "",
"data" = prc.document// Include newly uploaded image info. in struct
};
}
} catch(e) {
response = {
"status" = "error",
"message" = e.message,
"data" = {}
};
log.fatal("Failed to create image file.", e.message);
}
event.renderData(type="json", data=response);
}
Document bean:
component entityname="Document" persistent="true" extends="BaseEntity" {
// primary key
// secondary key
property name="uid" ormtype="string" unique="true";
// non-relational columns
property name="fileName" ormtype="string" unique="true";
property name="caption" ormtype="string";
// one-to-one
// one-to-many
// many-to-one
property name="article" fieldtype="many-to-one" cfc="Article" fkcolumn="articleId" fetch="join";
// many-to-many
// calculated properties
property name="fileHref" ormtype="string" persistent="false";
// non-persistent
// object constraints
this.constraints = {
"caption" = { required=true, requiredMessage="Please enter Document caption." },
"fileName" = { required=true, requiredMessage="Please enter Document file." }
};
// methods
function init() localmode="modern" {
if(isNull(variables.uid)){
variables.uid = lCase(right(createUUID(), 16));
}
return this;
}
function onDIComplete() localmode="modern" {
variables.fileHref = "/docs/article/" & variables.fileName;
}
}
as you can see i already have set the fileName in my bean. but system can access that fileName property.
sorry i am not fluent in english.

i called the wrong bean in the handler so this is happen.

Related

Refresh rows in table, which are created from factory function (SAPUI5)

How can I "refresh" the data in rows inside a table? I know, that the table is refreshed, when the model is getting changed. But the problem is, that the rows are created by a factory method. The code for the rows looks like this:
formatter : function(text, id) {
if (text != null && id != null) {
if (this.getProperty("showId")) {
return text + " ( " + id + " )";
} else {
return text;
}
}
return "";
So, when I click on a button "hide ID" the property is getting changed and the table should be refreshed so that the content is built new. How can I do this? I checked the method .refresh() but this didn't work.
EDIT:
This is my column with the factory function:
columns : [ new sap.ui.table.Column({
label : "XYZ( ID )",
filterProperty : "SHORT_TEXT",
template : new sap.m.Label().bindProperty("text", {
parts : [ {
path : "SHORT_TEXT",
type : new sap.ui.model.type.String()
}, {
path : "ID",
type : new sap.ui.model.type.String()
} ],
formatter : function(text, id) {
if (text != null && id != null) {
if (this.getProperty("showId")) {
return text + " ( " + id + " )";
} else {
return text;
}
}
return "";
}.bind(this)
})
})
This is the method, which changes the property:
onShowHideIdRequest : function(oControlEvent) {
if (oControlEvent.getParameter("pressed")) {
this.setProperty("showId", true);
sap.ui.getCore().byId("oShowHideIdButton").setIcon("sap-icon://show");
} else {
this.setProperty("showId", false);
sap.ui.getCore().byId("oShowHideIdButton").setIcon("sap-icon://hide");
}
sap.ui.getCore().byId("oTreeTable").rerender();
},
And the the property looks like this inside my component:
metadata : {
properties : {
showId : {
type : "boolean",
defaultValue : true
}
},
The "oTreeTable" ID refers to a sap.ui.tableTreeTable
I thought for a few days this all works fine, I don't know what's no wrong ...
First of all, the method you have written is formatter not the factory method. There is a difference between formatter and factory method. Formatter is used to return the value of a property of ui5 control based on some conditions or evaluation where as factory method is used to bind aggregations

Display items in bucket with Sitecore Data Provider

Hej Guys
I have a rather large problem, I've been tasked with creating a Custom Data Provider for extracting Stock Keeping Units(SKUs) from a SOLR database into sitecore, without actually populating the database with items.
I've created a data provider, which succesfully pulls data from the SOLR database a "creates" the items in sitecore, by using the following code:
public class SkuDataProvider : DataProvider, ISkuDataProvider
{
private readonly string _targetDatabaseName = "master";
private readonly string _idTablePrefix = "Skus";
private readonly ID _skuTemplateId = new ID("{F806B403-BDAF-4C60-959D-E706A82FC1DC}");
private readonly ID _skuRootTemplateId = new ID("{9767BC47-0A95-40E9-A2DE-3766FF241411}");
private readonly IEnumerable<SkuItemInfo> _skus;
public SkuDataProvider(/*IProductPageService productPageService*/)
{
_skus = new MockDataForSkuDataProvider().GetSimpleSkuCollection();
}
public override ItemDefinition GetItemDefinition(ID itemId, CallContext context)
{
Assert.ArgumentNotNull(itemId, "itemID");
// Retrieve the sku id from Sitecore's IDTable
var skuId = GetSkuIdFromIdTable(itemId);
if (!string.IsNullOrEmpty(skuId))
{
// Retrieve the sku data from the skus collection
var sku = _skus.FirstOrDefault(o => o.SkuId == skuId);
if (sku != null)
{
// Ensure the sku item name is valid for the Sitecore content tree
var itemName = ItemUtil.ProposeValidItemName($"{sku.SkuId}_{sku.Name}");
// Return a Sitecore item definition for the sku using the sku template
return new ItemDefinition(itemId, itemName, ID.Parse(_skuTemplateId), ID.Null);
}
}
return null;
}
private string GetSkuIdFromIdTable(ID itemId)
{
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemId);
if (idTableEntries.Any())
return idTableEntries[0].Key.ToString();
return null;
}
public override IDList GetChildIDs(ItemDefinition parentItem, CallContext context)
{
if (CanProcessParent(parentItem.ID))
{
var itemIdList = new IDList();
foreach (var sku in _skus)
{
var skuId = sku.SkuId;
// Retrieve the Sitecore item ID mapped to his sku
IDTableEntry mappedId = IDTable.GetID(_idTablePrefix, skuId) ??
IDTable.GetNewID(_idTablePrefix, skuId, parentItem.ID);
itemIdList.Add(mappedId.ID);
}
context.DataManager.Database.Caches.DataCache.Clear();
return itemIdList;
}
return base.GetChildIDs(parentItem, context);
}
private bool CanProcessParent(ID id)
{
var item = Factory.GetDatabase(_targetDatabaseName).Items[id];
bool canProcess = item.Paths.IsContentItem && item.TemplateID == _skuRootTemplateId && item.ID == new ID("{F37753A0-BC79-4FF7-B975-A8F142AACD76}");
return canProcess;
}
public override ID GetParentID(ItemDefinition itemDefinition, CallContext context)
{
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemDefinition.ID);
if (idTableEntries.Any())
{
return idTableEntries.First().ParentID;
}
return base.GetParentID(itemDefinition, context);
}
public override FieldList GetItemFields(ItemDefinition itemDefinition, VersionUri version, CallContext context)
{
var fields = new FieldList();
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemDefinition.ID);
if (idTableEntries.Any())
{
if (context.DataManager.DataSource.ItemExists(itemDefinition.ID))
{
ReflectionUtil.CallMethod(typeof(ItemCache), CacheManager.GetItemCache(context.DataManager.Database), "RemoveItem", true, true, new object[] { itemDefinition.ID });
}
var template = TemplateManager.GetTemplate(_skuTemplateId, Factory.GetDatabase(_targetDatabaseName));
if (template != null)
{
var skuId = GetSkuIdFromIdTable(itemDefinition.ID);
if (!string.IsNullOrEmpty(skuId))
{
var sku = _skus.FirstOrDefault(o => o.SkuId == skuId);
if (sku != null)
{
foreach (var field in GetDataFields(template))
{
fields.Add(field.ID, GetFieldValue(field, sku));
}
}
}
}
}
return fields;
}
protected virtual IEnumerable<TemplateField> GetDataFields(Template template)
{
return template.GetFields().Where(ItemUtil.IsDataField);
}
private string GetFieldValue(TemplateField field, SkuItemInfo sku)
{
string fieldValue = string.Empty;
switch (field.Name)
{
case "Name":
fieldValue = sku.Name;
break;
case "SkuId":
fieldValue = sku.SkuId;
break;
default:
break;
}
return fieldValue;
}
}
}
The problem emerges when accessing the Sitecore backend, where all items appears below the bucket item in a hierarchly-way.
I've checked that the Root item is set a bucket and that the template used is bucketable.
Furthermore when inserting manually in the backend, the item is correctly inserted in the bucket.
Do anyone got an idea for me, on how to fix this issue?
Best Regards
Nicolai
You need to set the Is Bucketable flag on the standard values of the template item rather than the template item itself.
Also, the way that items get "bucketed" is via events when the item is being created or saved. Sitecore then creates the bucket folders to store the items in. In your case as you have virtual items, you will need to handle their path via the data provider.
If you just want them hidden in the same way that they are in a standard bucket, then I would suggest creating a bucket folder under your SKU Root folder and using that item as the parent for all SKU virtual items. That way the bucket folder will be hidden by sitecore and you will get the same view as a standard bucket.
This is the template to use:

Programmatically add a new field in a template in sitecore

In Sitecore is it possible to programmatically add a new field in a template?
I have a template "DictionaryName", in this template I want to add a field "Newname" with its type "Single-Line Text".
I wrote and tested this code for you - it worked out perfect on my machine and created new single line field within template specified. Here is the method:
private void AddFieldToTemplate(string fieldName, string tempatePath)
{
const string templateOftemplateFieldId = "{455A3E98-A627-4B40-8035-E683A0331AC7}";
// this will do on your "master" database, consider Sitecore.Context.Database if you need "web"
var templateItem = Sitecore.Configuration.Factory.GetDatabase("master").GetItem(tempatePath);
if (templateItem != null)
{
var templateSection = templateItem.Children.FirstOrDefault(i => i.Template.Name == "Template section");
if (templateSection != null)
{
var newField = templateSection.Add(fieldName, new TemplateID(new ID(templateOftemplateFieldId)));
using (new EditContext(newField))
{
newField["Type"] = "Text"; // text stands for single-line lext field type
}
}
{
// there are no template sections here, you may need to create one. template has only inherited fields if any
}
}
}
And below is the usage - first string parameter is the name of your new field, the second is string value for template path within the database you are using:
AddFieldToTemplate("New Single Line Field", "/sitecore/templates/Sample/Sample Item");
Replace "Sample Item" template with your template path and set desired field name to add. Also do not forget usings for namespaces:
using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
Hope this helps!
You can access programmatically a template from the item and then add a an item to this template. The template is a usual item childrens.
Wrote this Example for you.
Want to find out more https://doc.sitecore.com/legacy-docs/SC71/data-definition-api-cookbook-sc70-a4.pdf
public JsonResult CreateTemplate()
{
try
{
using(new SecurityDisabler())
{
///Get Database
Database master = Sitecore.Configuration.Factory.GetDatabase("master");
/// Every node in content tree ia an Item. Ex- Templates,Field, Item, etc.
/// Template: /sitecore/templates/System/Templates/Template -{AB86861A-6030-46C5-B394-E8F99E8B87DB}
var templateId = master.GetTemplate(new ID("{AB86861A-6030-46C5-B394-E8F99E8B87DB}"));
/// parentItem is the item/ Template folder where you want to create your template.
/// ParentItem: /sitecore/templates/[new folder {Guid}]
Item parentItem = master.GetItem(new ID("{3C7516ED-7E3E-4442-8124-26691599596E}"));
Item newItem = parentItem.Add("HelloTemplate", templateId);
// adding Field in Templates.
TemplateItem exampleTemplate = master.Templates[new ID(newItem.ID.ToString())];
TemplateSectionItem data = exampleTemplate?.GetSection("data");
if( data == null || data.InnerItem.Parent.ID != exampleTemplate.ID)
{
data = exampleTemplate.AddSection("Data", false);
}
TemplateFieldItem title = data?.GetField("title");
if(title == null)
{
TemplateFieldItem field = data.AddField("Title");
}
}
return Json(new { Result = "item created" }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(new { Result = "item not created " + ex.Message+"\n"+ex.StackTrace } , JsonRequestBehavior.AllowGet);
}
}

How to enable VersionCountDisabler for Glass Mapper in Sitecore for SitecoreQuery and SitecoreChildren attributes

The glass mapper will return null object or (no items) for SitecoreQuery and SitecoreChildren attribute that are placed on the GlassModels. These attributes don't take any such parameter where I can specify them to return items if they don't exist in the the context lanaguge. The items e.g. exist in EN but don't exist in en-ES. I need to put a lot of null check in my views to avoid Null exception and makes the views or controller very messy. It is lot of boiler plate code that one has to write to make it work.
In Page Editor the SitecoreChildren returns item and content authors can create items in that langauge version by editing any field on the item. This automatically creates the item in that langauge. However the same code will fail in Preview mode as SitecoreChidren will return null and you see null pointer exception.
SitecoreQuery doesn't return any items in page editor and then Content Authors wont be able to create items in Page editor.
To make the experience good if we can pass a parameter to SiteocreQuery attribute so it disable VsersionCount and returns the items if they dont exist in that langauge.
This is actually not possible. There is an issue on GitHub which would make it easy to create a custom attribute to handle this very easy. Currently you need to create a new type mapper and copy all the code from the SitecoreQueryMapper. I have written a blog post here about how you can create a custom type mapper. You need to create the following classes (example for the SitecoreQuery).
New configuration:
public class SitecoreSharedQueryConfiguration : SitecoreQueryConfiguration
{
}
New attribute:
public class SitecoreSharedQueryAttribute : SitecoreQueryAttribute
{
public SitecoreSharedQueryAttribute(string query) : base(query)
{
}
public override AbstractPropertyConfiguration Configure(PropertyInfo propertyInfo)
{
var config = new SitecoreSharedQueryConfiguration();
this.Configure(propertyInfo, config);
return config;
}
}
New type mapper:
public class SitecoreSharedQueryTypeMapper : SitecoreQueryMapper
{
public SitecoreSharedQueryTypeMapper(IEnumerable<ISitecoreQueryParameter> parameters)
: base(parameters)
{
}
public override object MapToProperty(AbstractDataMappingContext mappingContext)
{
var scConfig = Configuration as SitecoreQueryConfiguration;
var scContext = mappingContext as SitecoreDataMappingContext;
using (new VersionCountDisabler())
{
if (scConfig != null && scContext != null)
{
string query = this.ParseQuery(scConfig.Query, scContext.Item);
if (scConfig.PropertyInfo.PropertyType.IsGenericType)
{
Type outerType = Glass.Mapper.Sc.Utilities.GetGenericOuter(scConfig.PropertyInfo.PropertyType);
if (typeof(IEnumerable<>) == outerType)
{
Type genericType = Utilities.GetGenericArgument(scConfig.PropertyInfo.PropertyType);
Func<IEnumerable<Item>> getItems;
if (scConfig.IsRelative)
{
getItems = () =>
{
try
{
return scContext.Item.Axes.SelectItems(query);
}
catch (Exception ex)
{
throw new MapperException("Failed to perform query {0}".Formatted(query), ex);
}
};
}
else
{
getItems = () =>
{
if (scConfig.UseQueryContext)
{
var conQuery = new Query(query);
var queryContext = new QueryContext(scContext.Item.Database.DataManager);
object obj = conQuery.Execute(queryContext);
var contextArray = obj as QueryContext[];
var context = obj as QueryContext;
if (contextArray == null)
contextArray = new[] { context };
return contextArray.Select(x => scContext.Item.Database.GetItem(x.ID));
}
return scContext.Item.Database.SelectItems(query);
};
}
return Glass.Mapper.Sc.Utilities.CreateGenericType(typeof(ItemEnumerable<>), new[] { genericType }, getItems, scConfig.IsLazy, scConfig.InferType, scContext.Service);
}
throw new NotSupportedException("Generic type not supported {0}. Must be IEnumerable<>.".Formatted(outerType.FullName));
}
{
Item result;
if (scConfig.IsRelative)
{
result = scContext.Item.Axes.SelectSingleItem(query);
}
else
{
result = scContext.Item.Database.SelectSingleItem(query);
}
return scContext.Service.CreateType(scConfig.PropertyInfo.PropertyType, result, scConfig.IsLazy, scConfig.InferType, null);
}
}
}
return null;
}
public override bool CanHandle(AbstractPropertyConfiguration configuration, Context context)
{
return configuration is SitecoreSharedQueryConfiguration;
}
}
And configure the new type mapper in your glass config (mapper and parameters for the constructor):
container.Register(Component.For<AbstractDataMapper>().ImplementedBy<SitecoreSharedQueryTypeMapper>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemPathParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemIdParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemIdNoBracketsParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemEscapedPathParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemDateNowParameter>>().LifeStyle.Transient);
You can then simply change the SitecoreQuery attribute on your model to SitecoreSharedQuery:
[SitecoreSharedQuery("./*")]
public virtual IEnumerable<YourModel> YourItems { get; set; }
For the children you could either use the shared query mapper and querying the children or create the same classes for a new SitecoreSharedChildren query.
Edit: Added bindings for IEnumerable<ISitecoreQueryParameter> as they are missing and therefor it threw an error.

using a viewmodel to assign values from a soap web service to a dropdownlist

I need some advice on getting values from a soap web service to display in a dropdownlist using a viewmodel, I currently receive the data for the various dropdownlists from a service class found in a service class library project (n-tier application).
The code for the dropdownlist service follows a similar format to the code below:
public IEnumerable<SelectListItem> getValuesAsSelectItems(string selected)
{
var items = new List<SelectListItem>();
items.Add(new SelectListItem { Text = "Please Select", Value = string.Empty, Selected = (selected == string.Empty) });
foreach (var value in this.getValues())
{
items.Add(new SelectListItem { Text = value.Value, Value = value.Value, Selected = (selected == value.Value) });
}
return new SelectList(items, "Value", "Text");
}
I need a way of passing the values from this service to the viewmodel I have then created 7 controllers for each of the dropdownlist which will all link to partial views that I can reuse throughout the application, dropdownlists include titles, countries, states and others.
An approach you could take is to extract the drop down list values into a viewmodel of their own. So:
Step 1: Create a view model (ItemsViewModel) that encapsulates the drop down list items:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Models
{
public class DropDownListItem
{
public string Text { get; set; }
public string Value { get; set; }
}
public class ItemsViewModel
{
private readonly List<DropDownListItem> _items;
// The selected item:
public string SelectedItem { get; set; }
// The items:
public IEnumerable<SelectListItem> Items
{
get
{
var allItems = _items.Select(i => new SelectListItem
{
Value = i.Value,
Text = i.Text
});
return DefaultItem.Concat(allItems);
}
}
// Default item (i.e. the "select" text) if none selected
public IEnumerable<SelectListItem> DefaultItem
{
get
{
return Enumerable.Repeat(new SelectListItem
{
Value = "-1",
Text = "Select an item"
}, count: 1);
}
}
public ItemsViewModel()
{
}
// Constructor taking in items from service and selected item string:
public ItemsViewModel(List<DropDownListItem> items, string selected)
{
_items = items;
SelectedItem = selected;
}
}
}
Step 2: Create a partial view in the Views folder that binds to the ItemsViewModel:
#model Models.ItemsViewModel
#Html.DropDownListFor(m => m.SelectedItem, Model.Items)
Step 3: In the appropriate controller (e.g. HomeController), place the child action that pulls the data from the service, the view model and the partial view together:
[ChildActionOnly]
public ActionResult DropDownList(string type, string selected)
{
// If you need to call different services based on the type (e.g. Country), then pass through "type" and base the call on that
var items = new ItemsViewModel(
(from g in _service.getTitles() select new DropDownListItem { Text = g.Text, Value = g.Value }).ToList(),
selected);
return PartialView("DropDownPartial", items);
}
Step 4: Drop this line of code into the view where you need the drop down list:
#Html.Action("DropDownList", "Home", new { selected = "2", type = "country" })
Note that selected and type are to be determined whichever way you see fit and are optional.
Hopefully this gives you some inspiration.