Sitecore: Glass Mapper Code First - sitecore

It is possible to automatically generate Sitecore templates just coding models? I'm using Sitecore 8.0 and I saw Glass Mapper Code First approach but I cant find more information about that.

Not sure why there isn't much info about it, but you can definitely model/code first!. I do it alot using the attribute configuration approach like so:
[SitecoreType(true, "{generated guid}")]
public class ExampleModel
{
[SitecoreField("{generated guid}", SitecoreFieldType.SingleLineText)]
public virtual string Title { get; set; }
}
Now how this works. The SitecoreType 'true' value for the first parameter indicates it may be used for codefirst. There is a GlassCodeFirstDataprovider which has an Initialize method, executed in Sitecore's Initialize pipeline. This method will collect all configurations marked for codefirst and create it in the sql dataprovider. The sections and fields are stored in memory. It also takes inheritance into account (base templates).
I think you first need to uncomment some code in the GlassMapperScCustom class you get when you install the project via Nuget. The PostLoad method contains the few lines that execute the Initialize method of each CodeFirstDataprovider.
var dbs = global::Sitecore.Configuration.Factory.GetDatabases();
foreach (var db in dbs)
{
var provider = db.GetDataProviders().FirstOrDefault(x => x is GlassDataProvider) as GlassDataProvider;
if (provider != null)
{
using (new SecurityDisabler())
{
provider.Initialise(db);
}
}
}
Furthermore I would advise to use code first on development only. You can create packages or serialize the templates as usual and deploy them to other environment so you dont need the dataprovider (and potential risks) there.

You can. But it's not going to be Glass related.
Code first is exactly what Sitecore.PathFinder is looking to achieve. There's not a lot of info publicly available on this yet however.
Get started here: https://github.com/JakobChristensen/Sitecore.Pathfinder

Related

Trouble using M2Doc core generation API and SiriusServices

I am trying to generate documentation using the core generation API (as described here https://www.m2doc.org/ref-doc/3.1.0/index.html#core-generation-api). But I have the following error:
Couldn't find the 'isRepresentationDescriptionName()' service.
(It works fine when I use the genconf not programmatically).
I tried to add the SiriusServices using SiriusServiceConfigurator, but didn't manage to solve this issue.
Or maybe is it because I didn't add the SiriusSession option that refers to the .aird file?
I have looked at how new services are added in the newEnvironmentWithDefaultServices work but it is seems not applicable for SiriusServices.
final IQueryEnvironment queryEnvironment = org.eclipse.acceleo.query.runtime.Query
.newEnvironmentWithDefaultServices(null);
final Monitor monitor = new BasicMonitor.Printing(System.out);
final ResourceSet resourceSetForModels = session.getTransactionalEditingDomain().getResourceSet();
resourceSetForModels.createResource(modelUri);
try (DocumentTemplate template = M2DocUtils.parse(resourceSetForModels.getURIConverter(), templateURI,
queryEnvironment, classProvider, monitor)) {
final Map<String, Object> variable = new HashMap<>();
M2DocUtils.generate(template, queryEnvironment, variable, resourceSetForModels, outputURI, monitor);
...
Thanks
The Sirius related services need the Sirius Session. The Session is initialized using the SiriusSession option in the .genconf file. It should be set to an URI referencing the .aird file. In the class M2DocUtils you have several methods to create an IQueryEnvironment that take a Map of String where you can add the SiriusSession option, for instance:
M2DocUtils.getQueryEnvironment(ResourceSet, URI, Map<String, String>)
Note that your code needs to be ran inside of Eclipse, not a standalone java program.

Acumatica - Problem with data displaying in custom field even though saved to database

I created a custom date field in the opportunity screen. The field shows up just as expected. I enter a date save the record, go out, go back in and the date is no longer there. However, when I query the database, the column is there and there is a data in the column. So, even though the date is being stored in the database it is not displaying it in the screen or when I added that value to the generic inquiry it is also blank. I am not a programmer but it seems like that should’ve been an easy thing to do. I found some references on the web of this type of problem but was hoping there was a more straightforward fix than what those appeared, as they were more programming than I am comfortable at this point.
I found many web pages explaining how to do this seemingly simple thing using the customization tools. Not sure what I'm missing.
I am running fairly recent version of 2019R1.
Any help would be appreciated!
Response from an Acumatica support person.. Evidently they changed some things with 2018R1. See comments/answers below from support. Image of the change I made in the customization tool is also below. After making this change the custom field worked as desired.
After reviewing it into more details, it sounds that it could be related to the new implementation of PXProjection on that DAC.
Unlike ver. 2017 R2, some DAC like the PX.Objects.CR.CROpportunity DAC were implemented as a regular Data Access Class:
[System.SerializableAttribute()]
[PXCacheName(Messages.Opportunity)]
[PXPrimaryGraph(typeof(OpportunityMaint))]
[CREmailContactsView(typeof(Select2<Contact,
LeftJoin<BAccount, On<BAccount.bAccountID, Equal<Contact.bAccountID>>>,
Where2<Where<Optional<CROpportunity.bAccountID>, IsNull, And<Contact.contactID, Equal<Optional<CROpportunity.contactID>>>>,
Or2<Where<Optional<CROpportunity.bAccountID>, IsNotNull, And<Contact.bAccountID, Equal<Optional<CROpportunity.bAccountID>>>>,
Or<Contact.contactType, Equal<ContactTypesAttribute.employee>>>>>))]
[PXEMailSource]//NOTE: for assignment map
public partial class CROpportunity : PX.Data.IBqlTable, IAssign, IPXSelectable
{
...
}
In version 2018 R1(and later) the PX.Objects.CR.CROpportunity DAC is a projection over the PX.Objects.CR.Standalone.CROpportunity and PX.Objects.CR.Standalone.CROpportunityRevision DACs:
[System.SerializableAttribute()]
[PXCacheName(Messages.Opportunity)]
[PXPrimaryGraph(typeof(OpportunityMaint))]
[CREmailContactsView(typeof(Select2<Contact,
LeftJoin<BAccount, On<BAccount.bAccountID, Equal<Contact.bAccountID>>>,
Where2<Where<Optional<CROpportunity.bAccountID>, IsNull, And<Contact.contactID, Equal<Optional<CROpportunity.contactID>>>>,
Or2<Where<Optional<CROpportunity.bAccountID>, IsNotNull, And<Contact.bAccountID, Equal<Optional<CROpportunity.bAccountID>>>>,
Or<Contact.contactType, Equal<ContactTypesAttribute.employee>>>>>))]
[PXEMailSource]//NOTE: for assignment map
[PXProjection(typeof(Select2<Standalone.CROpportunity,
InnerJoin<Standalone.CROpportunityRevision,
On<Standalone.CROpportunityRevision.opportunityID, Equal<Standalone.CROpportunity.opportunityID>,
And<Standalone.CROpportunityRevision.revisionID, Equal<Standalone.CROpportunity.defRevisionID>>>>>), Persistent = true)]
public partial class CROpportunity : IBqlTable, IAssign, IPXSelectable
{
...
}
Because of that change, it's now required to declare 2 extension classes, one for Standalone.CROpportunity (normal DAC) and the CROpportunity (PXProjection).
On the PXProjection DAC Extension, please remind to add BqlField to the correspondent field on the Standalone DAC, Ex.: BqlField = typeof(CROpportunityStandaloneExt.usrTest)
public class CROpportunityExt : PXCacheExtension<PX.Objects.CR.CROpportunity>
{
#region UsrTest
[PXDBDecimal(BqlField = typeof(CROpportunityStandaloneExt.usrTest))]
[PXUIField(DisplayName="Test Field")]
public virtual Decimal? UsrTest { get; set; }
public abstract class usrTest : IBqlField { }
#endregion
}
Please find more information on this article below:
Custom field on CROpportunity doesn't display saved value since upgrading from 6.10 or 2017R2 to 2018R1
change made in customization tool

DryIOC Container Contents

StructureMap has a super-useful debug method on the Container class called WhatDoIHave()
It shows every type in the container along with its lifecycle, guid and a bunch of other info. It's useful for debugging.
There's some info here:
http://jeremydmiller.com/2014/02/18/structuremap-3-is-gonna-tell-you-whats-wrong-and-where-it-hurts/
Does DryIOC have an equivalent debug feature?
(I'm the creator of DryIoc).
You can use container.GetServiceRegistrations() to get registration infos as #fyodor-soikin suggested.
But at the latest version (2.0.0-rc3build339) I have added VerifyResolutions method that may help you to diagnose potential resolution problems, including missing registrations as well. Here the wiki explaining it.
Example from the wiki:
// Given following SUT
public class RequiredDependency {}
public class MyService { public MyService(RequiredDependency d) {} }
// Let's assume we forgot to register RequiredDependency
var container = new Container();
container.Register<MyService>();
// Find what's missing
var results = container.VerifyResolutions();
Assert.AreEqual(1, results.Length);
Verify result is array of ServiceRegistrationInfo and ContainerException KeyValuePairs. In this example the registration info will be:
MyNamespace.MyService registered as factory {ID=14, ImplType=MyNamespace.MyService}
And the exception will be:
DryIoc.ContainerException: Unable to resolve MyNamespace.RequiredDependency as parameter "d"
in MyNamespace.MyService.
Where no service registrations found
and number of Rules.FallbackContainers: 0
and number of Rules.UnknownServiceResolvers: 0
Update:
The functionality is available in latest stable DryIoc 2.0.0.

Sitecore dynamic data source locations

I have some components in my Sitecore install that can be added to one of any multiple placeholders on a page. The data source location of the renderings of these components can change based on what placeholder they are added to the site. I started creating a processor like
<getRenderingDatasource>
<processor patch:after="*[#type='custom']" type="custom" />
</getRenderingDatasource>
The class is like
public class GetDynamicDataSourceLocations : GetDatasourceLocation
{
public void Process(GetRenderingDatasourceArgs args)
{
...
}
}
I can't get the placeholder that I'm trying to attach the rendering to. Is there any way I can get the placeholder or atleast the parent where the component is being added?
Thanks
It's a very good idea you have here, but the GetRenderingDatasourceArgs can't provide you with the data you need if you're configuring the allowed datasource locations on the placeholder.
I've searched through querystring & form variables and context items as well, but there is no reference to the placeholder available in the getRenderingDatasource pipeline.
I did come up with something that could be the solution, although it's a bit hacky.
Create a processor for the getPlaceholderRenderings. The GetPlaceholderRenderingsArgs will provide you with a placeholder key.
Store the key in a session variable (I don't know another way of transferring data between pipelines at this point)
Retrieve the key from the session in your getRenderingDatasource processor.
This is the code I used to test it:
// Add to the getRenderingDatasource pipeline.
public class GetPlaceholderKey
{
public void Process(GetPlaceholderRenderingsArgs args)
{
System.Web.HttpContext.Current.Session["Placeholder"] = args.PlaceholderKey;
}
}
// Add to the getRenderingDatasource pipeline.
public class GetAllowedDatasources
{
public void Process(GetRenderingDatasourceArgs args)
{
Debug.WriteLine(System.Web.HttpContext.Current.Session["Placeholder"]);
}
}
This works when you add a rendering to a placeholder, but I have not tested other scenarios.
I can imagine it would not work when you set the datasource of a rendering that is already placed in the placeholder.

Sitecore Glass Mapper always null

I am using Sitecore Glass Mapper for a new project I'm setting up.
We are using Sitecore 7.2, latest version of Team Development for Sitecore (TDS) code generation and the latest version of glass.
The code I am trying to execute:
var b = new SitecoreContext();
var c = b.GetCurrentItem<T01_Homepage>();
b is not null. c is null.
var d = b.GetItem<T01_Homepage>("path")
d is null.
I added my assembly in GlassMapperScCustom:
public static IConfigurationLoader[] GlassLoaders(){
var attributes = new AttributeConfigurationLoader(new[] { "Company.Framework.Websites.Corporate", "Company.Framework.Core", "Company.Framework.Common" });
return new IConfigurationLoader[] { attributes };
}
When I look into b.GlassContext.TypeConfigurations all my models are there.
I figured it could be a language issue because the site is in dutch and maybe the wrong language would be resolved incorrectly. This was also not the case.
I disabled WebActivator and added the GlassMapperSc.Start() in my Global.asax Application_Start method.
We are also using Autofac as DI framework. But without it, it still isn't working as you can see above. Also when I create my own custom models without TDS code generation the result of GetCurrentItem<T> is null.
Does anyone have an idea how I can fix this?
Did you check your Sites.config and the default language for this website? There could be a difference between the language which is defined in your Sitecore languages folder and your configuration.
I had a similar problem with one of my projects where I changed the Sitecore.Context.Language to "nl" instead of "nl-NL". The glass mapper will return null, but Sitecore.Context.Database.GetItem will return an object in this case.
Most of the times it is a language issue. The mapper returns a null object when you do not have versions in the current or given language.
What can be confusing is that Sitecore.Context.Database.GetItem returns an object, even if it does not have a version in the current language. Be sure to check that item.Versions has any.
Some things you may try (this didn't fit in the comments field)
1) Confirm that the related fields in the Sitecore Item object contain values (so Sitecore.Context.Item for your "c" var and Sitecore.Context.Database.GetItem("path") for your "d" var)
2) Try to encapsulate the GetItem/GetCurrentItem call in a VersionCountDisabler, like this:
T01_Homepage model = null;
using (new VersionCountDisabler())
{
var context = new SitecoreContext();
model = context.GetItem<T01_Homepage>("path");
}
// Do you have data in model now?
3) Try to encapsulate the same call with a SecurityDisabler. Just to confirm it's not a security issue.
4) If you still don't know what it is, please update your question with some (simplified) code for your model.