├── Dependencies ├── NuGet.exe └── Libraries │ ├── WebTestRunner │ ├── nunit.core.dll │ ├── nunit.util.dll │ ├── nunit.framework.dll │ ├── nunit.core.interfaces.dll │ ├── NUnitContrib.Web.TestRunner.dll │ ├── NUnitContrib.Web.TestRunner.pdb │ └── README.txt │ └── README.txt ├── Source ├── Synthesis │ ├── InstanceType.cs │ ├── FieldTypes │ │ ├── Interfaces │ │ │ ├── IBooleanField.cs │ │ │ ├── ITristateField.cs │ │ │ ├── IIntegerField.cs │ │ │ ├── INumericField.cs │ │ │ ├── IValuedFieldType.cs │ │ │ ├── IDateTimeField.cs │ │ │ ├── IFieldRenderableValuedFieldType.cs │ │ │ ├── IFieldRenderableFieldType.cs │ │ │ ├── IDictionaryField.cs │ │ │ ├── IRichTextField.cs │ │ │ ├── IFieldType.cs │ │ │ ├── IPathItemReferenceField.cs │ │ │ ├── IImageField.cs │ │ │ ├── IContentHubImageField.cs │ │ │ ├── ITextField.cs │ │ │ ├── IItemReferenceField.cs │ │ │ ├── IItemReferenceListField.cs │ │ │ ├── IFileField.cs │ │ │ └── IHyperlinkField.cs │ │ ├── IFieldMappingProvider.cs │ │ ├── XmlFieldType.cs │ │ ├── FieldMapping.cs │ │ ├── LazyField.cs │ │ ├── BooleanField.cs │ │ ├── RichTextField.cs │ │ ├── TristateField.cs │ │ ├── Adapters │ │ │ ├── IEditingAdapter.cs │ │ │ ├── IAxesAdapter.cs │ │ │ ├── EditingAdapter.cs │ │ │ └── DatabaseAdapter.cs │ │ ├── PathItemReferenceField.cs │ │ ├── NumericField.cs │ │ ├── IntegerField.cs │ │ ├── TextField.cs │ │ ├── ItemReferenceField.cs │ │ ├── DateTimeField.cs │ │ ├── ImageField.cs │ │ └── DictionaryField.cs │ ├── Generation │ │ ├── IMetadataGenerator.cs │ │ ├── ITemplateCodeGenerator.cs │ │ ├── IGeneratorParametersProvider.cs │ │ ├── Model │ │ │ ├── FieldPropertyInfo.cs │ │ │ └── TypeNovelizer.cs │ │ ├── GeneratorParameterException.cs │ │ └── NamingUtility.cs │ ├── Initializers │ │ ├── IInitializerProvider.cs │ │ ├── ITemplateInitializer.cs │ │ └── StandardTemplateInitializer.cs │ ├── Configuration │ │ ├── Registration │ │ │ ├── ISynthesisConfigurationRegistration.cs │ │ │ ├── DefaultConfigurationRegistration.cs │ │ │ ├── ProxyGeneratorParametersProvider.cs │ │ │ └── SynthesisConfigurationRegistration.cs │ │ ├── ITypeListProvider.cs │ │ ├── ConfigurationUtility.cs │ │ ├── IProviderConfiguration.cs │ │ └── ProviderResolver.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ContentSearch │ │ ├── IFieldNameTranslatorFactory.cs │ │ ├── IQueryableResolver.cs │ │ ├── DocumentMappingResult.cs │ │ ├── ContentSearchUtilities.cs │ │ ├── IndexFieldNameMapper.cs │ │ ├── Lucene │ │ │ └── ResolveLuceneQueryable.cs │ │ ├── SynthesisFieldNameTranslator.cs │ │ └── ComputedFields │ │ │ └── InheritedTemplates.cs │ ├── Templates │ │ ├── ITemplateSignatureProvider.cs │ │ ├── ITemplateFieldInfo.cs │ │ ├── ITemplateInfo.cs │ │ ├── ITemplateInputProvider.cs │ │ ├── Database │ │ │ └── ItemTemplateFieldInfo.cs │ │ └── Sha1TemplateSignatureProvider.cs │ ├── Pipelines │ │ ├── SynthesisSearchContextArgs.cs │ │ └── Initialize │ │ │ └── CheckModelSynchronization.cs │ ├── Utility │ │ ├── WildcardUtility.cs │ │ ├── DebugUtility.cs │ │ ├── SingleFieldEditor.cs │ │ └── ObjectActivator.cs │ ├── Synchronization │ │ ├── SyncSource.cs │ │ ├── ModelTemplateReference.cs │ │ ├── TemplateComparisonResultCollection.cs │ │ └── RepresentsSitecoreTemplateAttribute.cs │ ├── FieldDictionary.cs │ ├── MissingTemplateFieldException.cs │ ├── Standard Config Files │ │ ├── Synthesis.ContentHub.config.disabled │ │ ├── Synthesis.ControlPanel.config │ │ ├── Synthesis.ControlPanel.IdentityServer.config.disabled │ │ ├── Synthesis.Startup.config │ │ └── Synthesis.AutoRegenerate.config │ ├── SynthesisEditContext.cs │ ├── FieldExtensions.cs │ ├── Synthesis.nuspec │ ├── Synthesis.csproj │ └── EventHandlers │ │ └── AutomaticModelRebuilder.cs ├── Synthesis.Solr │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Standard Config Files │ │ └── Synthesis.Solr.Config │ ├── Synthesis.Solr.nuspec │ ├── Synthesis.Solr.csproj │ └── ContentSearch │ │ ├── ResolveSolrQueryable.cs │ │ └── SynthesisSolrFieldNameTranslatorFactory.cs ├── Synthesis.Tests │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Synthesis.Tests.v3.ncrunchproject │ ├── Fixtures │ │ ├── ContentSearch │ │ │ ├── InitializerForcer.cs │ │ │ ├── Data │ │ │ │ └── ISearchTemplateItem.cs │ │ │ ├── ContentSearchTestFixture.cs │ │ │ └── ContentSearchQueryExtensionTests.cs │ │ ├── TemplateSignatureProviderTests.cs │ │ └── ItemExtensionsTests.cs │ ├── _HOW TO TEST.txt │ ├── Utility │ │ ├── TestingContants.cs │ │ ├── TemplateFieldTypes.cs │ │ └── TestItemContext.cs │ ├── TestFields.cs │ ├── IFakeTemplateItem.cs │ ├── FieldTypes │ │ ├── IntegerFieldTests.cs │ │ ├── NumericFieldTests.cs │ │ ├── ItemReferenceFieldTests.cs │ │ ├── TextFieldTests.cs │ │ ├── FileFieldTests.cs │ │ └── ContentHubImageFieldTests.cs │ ├── Synthesis.TestRunnerConfig.config │ ├── ConfigureServices.cs │ └── Synthesis.Tests.csproj ├── Synthesis.Mvc │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── UI │ │ ├── IContextSite.cs │ │ ├── IContextIndex.cs │ │ ├── IContextDatabase.cs │ │ ├── IContextItem.cs │ │ ├── README.txt │ │ ├── IRenderingContext.cs │ │ └── SitecoreRenderingContext.cs │ ├── Utility │ │ ├── SiteHelper.cs │ │ ├── DisplayModeSwitcher.cs │ │ └── RenderingDiagnosticsDisabler.cs │ ├── RenderingErrorModel.cs │ ├── TagRenderingContext.cs │ ├── Synthesis.Mvc.nuspec │ ├── ViewModelTypeResolver.cs │ ├── Synthesis.Mvc.csproj │ ├── RenderingDisplayPathResolver.cs │ ├── Extensions │ │ ├── FileFields.cs │ │ ├── DateFields.cs │ │ ├── TextFields.cs │ │ ├── HyperlinkFields.cs │ │ └── NumberFields.cs │ ├── Helpers │ │ ├── TextHelper.cs │ │ ├── DateHelper.cs │ │ └── FileHelper.cs │ ├── Pipelines │ │ └── GetModel │ │ │ └── GetFromSynthesis.cs │ └── Standard Config Files │ │ └── Synthesis.Mvc.config ├── Synthesis.Testing │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── TestFieldType.cs │ ├── Attributes │ │ └── AutoNSubstituteAttribute.cs │ ├── TestBooleanField.cs │ ├── TestRichTextField.cs │ ├── TestTristateField.cs │ ├── Synthesis.Testing.nuspec │ ├── Synthesis.Testing.csproj │ ├── TestNumericField.cs │ ├── TestDateTimeField.cs │ ├── TestIntegerField.cs │ ├── TestTextField.cs │ ├── TestImageField.cs │ ├── TestDictionaryField.cs │ ├── TestFileField.cs │ ├── TestItemReferenceField.cs │ └── TestContentHubImageField.cs ├── Synthesis.Solr.Tests │ ├── Synthesis.Solr.Tests.v3.ncrunchproject │ ├── App_Config │ │ └── Include │ │ │ ├── Synthesis.Solr.Config │ │ │ └── Sitecore.ContentSearch.Solr.Index.Master.config │ ├── ContentSearch │ │ └── SynthesisSolrFieldNameTranslatorTests.cs │ └── Synthesis.Solr.Tests.csproj ├── SharedAssemblyInfo.cs └── App.config ├── Build ├── PackageNuGet.cmd ├── Push NuGet.ps1 ├── Synthesis.Solr.nuget │ └── Synthesis.Solr.nuspec ├── Synthesis.Mvc.nuget │ └── Synthesis.Mvc.nuspec ├── Synthesis.nuget │ └── readme.txt └── PackageNuGet.ps1 ├── Documentation └── Visual Studio Templates │ ├── Synthesis.Blade │ └── Synthesis Presenter.zip │ └── README.txt ├── Synthesis.v3.ncrunchsolution ├── .github └── ISSUE_TEMPLATE.md ├── GitVersion.yml ├── Packages └── repositories.config ├── NuGet.config ├── .gitignore └── license.txt /Dependencies/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blipson89/Synthesis/HEAD/Dependencies/NuGet.exe -------------------------------------------------------------------------------- /Source/Synthesis/InstanceType.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis 2 | { 3 | public enum InstanceType 4 | { 5 | Search, Database 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Build/PackageNuGet.cmd: -------------------------------------------------------------------------------- 1 | @ECHO off 2 | 3 | SET scriptRoot=%~dp0 4 | 5 | powershell.exe -ExecutionPolicy Unrestricted -NoExit .\PackageNuGet.ps1 %scriptRoot% -------------------------------------------------------------------------------- /Dependencies/Libraries/WebTestRunner/nunit.core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blipson89/Synthesis/HEAD/Dependencies/Libraries/WebTestRunner/nunit.core.dll -------------------------------------------------------------------------------- /Dependencies/Libraries/WebTestRunner/nunit.util.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blipson89/Synthesis/HEAD/Dependencies/Libraries/WebTestRunner/nunit.util.dll -------------------------------------------------------------------------------- /Dependencies/Libraries/WebTestRunner/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blipson89/Synthesis/HEAD/Dependencies/Libraries/WebTestRunner/nunit.framework.dll -------------------------------------------------------------------------------- /Dependencies/Libraries/WebTestRunner/nunit.core.interfaces.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blipson89/Synthesis/HEAD/Dependencies/Libraries/WebTestRunner/nunit.core.interfaces.dll -------------------------------------------------------------------------------- /Source/Synthesis.Solr/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("Synthesis.Solr")] 4 | [assembly: AssemblyDescription("Synthesis Solr Support")] -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("Synthesis.Tests")] 4 | [assembly: AssemblyDescription("Synthesis unit tests")] -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IBooleanField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface IBooleanField : IValuedFieldType 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Dependencies/Libraries/README.txt: -------------------------------------------------------------------------------- 1 | To build this from source, place the Sitecore assemblies you want to build from in a Sitecore folder under here 2 | 3 | e.g. /Dependencies/Libraries/Sitecore -------------------------------------------------------------------------------- /Dependencies/Libraries/WebTestRunner/NUnitContrib.Web.TestRunner.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blipson89/Synthesis/HEAD/Dependencies/Libraries/WebTestRunner/NUnitContrib.Web.TestRunner.dll -------------------------------------------------------------------------------- /Dependencies/Libraries/WebTestRunner/NUnitContrib.Web.TestRunner.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blipson89/Synthesis/HEAD/Dependencies/Libraries/WebTestRunner/NUnitContrib.Web.TestRunner.pdb -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/ITristateField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface ITristateField : IValuedFieldType 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("Synthesis.Mvc")] 4 | [assembly: AssemblyDescription("Sitecore object mapping framework")] -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IIntegerField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface IIntegerField : IFieldRenderableValuedFieldType 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("Synthesis.Testing")] 4 | [assembly: AssemblyDescription("Synthesis unit testing helper library")] -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/INumericField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface INumericField : IFieldRenderableValuedFieldType 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Documentation/Visual Studio Templates/Synthesis.Blade/Synthesis Presenter.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blipson89/Synthesis/HEAD/Documentation/Visual Studio Templates/Synthesis.Blade/Synthesis Presenter.zip -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/UI/IContextSite.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Sites; 2 | 3 | namespace Synthesis.Mvc.UI 4 | { 5 | public interface IContextSite 6 | { 7 | SiteContext ContextSite { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IValuedFieldType.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface IValuedFieldType : IFieldType 4 | { 5 | TValue Value { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Synthesis.Tests.v3.ncrunchproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | True 4 | 5 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IDateTimeField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Synthesis.FieldTypes.Interfaces 4 | { 5 | public interface IDateTimeField : IFieldRenderableValuedFieldType 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Synthesis.v3.ncrunchsolution: -------------------------------------------------------------------------------- 1 | 2 | 3 | True 4 | True 5 | 6 | -------------------------------------------------------------------------------- /Source/Synthesis/Generation/IMetadataGenerator.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.Generation.Model; 2 | 3 | namespace Synthesis.Generation 4 | { 5 | public interface IMetadataGenerator 6 | { 7 | TemplateGenerationMetadata GenerateMetadata(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Source/Synthesis/Initializers/IInitializerProvider.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data; 2 | 3 | namespace Synthesis.Initializers 4 | { 5 | public interface IInitializerProvider 6 | { 7 | ITemplateInitializer GetInitializer(ID templateId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Source/Synthesis/Configuration/Registration/ISynthesisConfigurationRegistration.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.Configuration.Registration 2 | { 3 | public interface ISynthesisConfigurationRegistration 4 | { 5 | IProviderConfiguration GetConfiguration(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Source/Synthesis/Configuration/ITypeListProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Synthesis.Configuration 5 | { 6 | public interface ITypeListProvider 7 | { 8 | IEnumerable CreateTypeList(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/IFieldMappingProvider.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.Templates; 2 | 3 | namespace Synthesis.FieldTypes 4 | { 5 | public interface IFieldMappingProvider 6 | { 7 | FieldMapping GetFieldType(ITemplateFieldInfo templateField); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Source/Synthesis/Generation/ITemplateCodeGenerator.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.Generation.Model; 2 | 3 | namespace Synthesis.Generation 4 | { 5 | public interface ITemplateCodeGenerator 6 | { 7 | void Generate(TemplateGenerationMetadata metadata); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IFieldRenderableValuedFieldType.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface IFieldRenderableValuedFieldType : IFieldType, IFieldRenderableFieldType 4 | { 5 | TValue Value { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Source/Synthesis.Solr.Tests/Synthesis.Solr.Tests.v3.ncrunchproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | True 5 | 6 | -------------------------------------------------------------------------------- /Source/Synthesis/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | [assembly: AssemblyTitle("Synthesis")] 5 | [assembly: AssemblyDescription("Sitecore object mapping framework")] 6 | [assembly: InternalsVisibleTo("Synthesis.Tests")] -------------------------------------------------------------------------------- /Build/Push NuGet.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true)] [string] $version, 3 | [Parameter(Mandatory=$true)] [string] $apiKey 4 | ) 5 | gci "versions\$version\*.nupkg" -exclude *.symbols.nupkg | % { dotnet nuget push $_.FullName --api-key $apiKey -s https://api.nuget.org/v3/index.json } -------------------------------------------------------------------------------- /Source/Synthesis/ContentSearch/IFieldNameTranslatorFactory.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.ContentSearch; 2 | 3 | namespace Synthesis.ContentSearch 4 | { 5 | public interface IFieldNameTranslatorFactory 6 | { 7 | AbstractFieldNameTranslator GetFieldNameTranslator(ISearchIndex index); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Dependencies/Libraries/WebTestRunner/README.txt: -------------------------------------------------------------------------------- 1 | This is a precompiled copy of Jorge Lusar's sctestrunner @ 080d740fea3e3ebd5e806a543a034cf9e15b1956 2 | 3 | The projects were modified to compile against .NET 4.5 for Sitecore 7. 4 | 5 | https://github.com/jorgelusar/sctestrunner 6 | 7 | This is MIT-licensed per the repo. -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/UI/IContextIndex.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.ContentSearch; 2 | 3 | namespace Synthesis.Mvc.UI 4 | { 5 | public interface IContextIndex 6 | { 7 | /// 8 | /// Gets the Sitecore index for the context item 9 | /// 10 | ISearchIndex ContextIndex { get; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Do you want to request a *feature* or report a *bug*?** 2 | 3 | **What is the current behavior?** 4 | 5 | **If the current behavior is a bug, please provide the steps to reproduce.** 6 | 7 | **What is the expected behavior?** 8 | 9 | **Please mention your Sitecore version and Synthesis version.** -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestFieldType.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.Testing 5 | { 6 | public abstract class TestFieldType : IFieldType 7 | { 8 | public abstract bool HasValue { get; } 9 | 10 | public ID Id 11 | { 12 | get { return ID.Null; } 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Source/Synthesis/Templates/ITemplateSignatureProvider.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.Templates 2 | { 3 | /// 4 | /// Provides a unique signature for a template used for comparing versions 5 | /// 6 | public interface ITemplateSignatureProvider 7 | { 8 | string GenerateTemplateSignature(ITemplateInfo templateItem); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Source/Synthesis/ContentSearch/IQueryableResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Synthesis.Pipelines; 3 | 4 | namespace Synthesis.ContentSearch 5 | { 6 | public interface IQueryableResolver 7 | { 8 | IQueryable GetSynthesisQueryable(SynthesisSearchContextArgs args) 9 | where TResult : IStandardTemplateItem; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Source/Synthesis/Templates/ITemplateFieldInfo.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data; 2 | 3 | namespace Synthesis.Templates 4 | { 5 | public interface ITemplateFieldInfo 6 | { 7 | string Name { get; } 8 | string DisplayName { get; } 9 | string FullPath { get; } 10 | ID Id { get; } 11 | string HelpText { get; } 12 | string Type { get; } 13 | ITemplateInfo Template { get; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | mode: ContinuousDeployment 2 | assembly-file-versioning-scheme: MajorMinorPatchTag 3 | increment: none 4 | legacy-semver-padding: 0 5 | build-metadata-padding: 0 6 | commits-since-version-source-padding: 0 7 | branches: 8 | master: 9 | regex: ^main$ 10 | increment: patch 11 | feature: 12 | increment: minor 13 | ignore: 14 | sha: [] 15 | merge-message-formats: {} 16 | -------------------------------------------------------------------------------- /Source/Synthesis/Generation/IGeneratorParametersProvider.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Synthesis.Generation 3 | { 4 | /// 5 | /// Provides a default set of parameters to feed to the generator. Used to allow configuration files, etc. 6 | /// 7 | public interface IGeneratorParametersProvider 8 | { 9 | GeneratorParameters CreateParameters(string configurationName); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Source/Synthesis/Pipelines/SynthesisSearchContextArgs.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.ContentSearch; 2 | using Sitecore.ContentSearch.Linq.Common; 3 | using Sitecore.Pipelines; 4 | 5 | namespace Synthesis.Pipelines 6 | { 7 | public class SynthesisSearchContextArgs : PipelineArgs 8 | { 9 | public IExecutionContext[] ExecutionContext { get; set; } 10 | public IProviderSearchContext SearchContext { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Source/SharedAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System; 4 | 5 | [assembly: AssemblyCompany("Synthesis")] 6 | [assembly: AssemblyProduct("Synthesis")] 7 | [assembly: ComVisible(false)] 8 | [assembly: AssemblyVersion("9.1.2.1")] 9 | [assembly: AssemblyFileVersion("9.1.2.1")] 10 | [assembly: AssemblyInformationalVersion("9.1.2.1")] 11 | [assembly: CLSCompliant(false)] -------------------------------------------------------------------------------- /Source/Synthesis/ContentSearch/DocumentMappingResult.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.ContentSearch 2 | { 3 | public class DocumentMappingResult 4 | { 5 | public DocumentMappingResult(TItem result, bool success) 6 | { 7 | Document = result; 8 | MappedSuccessfully = success; 9 | } 10 | 11 | public TItem Document { get; private set; } 12 | public bool MappedSuccessfully { get; private set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Packages/repositories.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/UI/IContextDatabase.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Adapters; 2 | 3 | namespace Synthesis.Mvc.UI 4 | { 5 | public interface IContextDatabase 6 | { 7 | /// 8 | /// Gets the current context database. 9 | /// If the content database is set (e.g. when shell is the context site) returns that instead of the context database. 10 | /// 11 | IDatabaseAdapter ContextDatabase { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/Attributes/AutoNSubstituteAttribute.cs: -------------------------------------------------------------------------------- 1 | using AutoFixture; 2 | using AutoFixture.AutoNSubstitute; 3 | using AutoFixture.Xunit2; 4 | 5 | namespace Synthesis.Testing.Attributes 6 | { 7 | public class AutoNSubstituteAttribute : AutoDataAttribute 8 | { 9 | public AutoNSubstituteAttribute() : base(() => new Fixture().Customize(new AutoNSubstituteCustomization())) 10 | { 11 | 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Documentation/Visual Studio Templates/README.txt: -------------------------------------------------------------------------------- 1 | These templates make it easy to create views, presenters, and models for Synthesis.Blade 2 | 3 | To use them just place them in your Visual Studio user templates folder, e.g. 4 | 5 | C:\Users\yourname\Documents\Visual Studio 2010\Templates\ItemTemplates\Blade 6 | 7 | Then in VS go to add an item and you'll see a new Blade category in the add items window. 8 | 9 | This template may be combined with the regular Blade templates in the same folder. -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Utility/SiteHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sitecore; 3 | 4 | namespace Synthesis.Mvc.Utility 5 | { 6 | class SiteHelper 7 | { 8 | private static readonly HashSet InvalidSites = new HashSet { "shell", "core", "login", "admin", "service", "modules_shell", "scheduler", "publisher", "system" }; 9 | public static bool IsValidSite() 10 | { 11 | return !InvalidSites.Contains(Context.Site.Name); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IFieldRenderableFieldType.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Synthesis.FieldTypes.Interfaces 3 | { 4 | /// 5 | /// Base interface for field types that are capable of being rendered using a FieldRenderer 6 | /// 7 | public interface IFieldRenderableFieldType 8 | { 9 | /// 10 | /// Renders the field using a Sitecore FieldRenderer and returns the result 11 | /// 12 | string RenderedValue { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IDictionaryField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface IDictionaryField : IFieldType 4 | { 5 | /// 6 | /// Gets the set of IDs that make up the relationships 7 | /// 8 | string this[string key] { get; set; } 9 | 10 | int Count { get; } 11 | 12 | void Add(string key, string value); 13 | bool Remove(string key); 14 | void Clear(); 15 | bool ContainsKey(string key); 16 | } 17 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IRichTextField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface IRichTextField : ITextField 4 | { 5 | /// 6 | /// Gets the raw value of the field with dynamic links expanded into friendly URLs. Unlike RenderedValue this does not support Page Editor, but neither does it require loading a search-based instance's underlying item like RenderedValue. 7 | /// 8 | string ExpandedLinksValue { get; } 9 | } 10 | } -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestBooleanField.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Interfaces; 2 | 3 | namespace Synthesis.Testing 4 | { 5 | /// 6 | /// Encapsulates a boolean (checkbox) field from Sitecore 7 | /// 8 | public class TestBooleanField : TestFieldType, IBooleanField 9 | { 10 | public TestBooleanField(bool value) 11 | { 12 | Value = value; 13 | } 14 | 15 | public bool Value { get; set; } 16 | 17 | public override bool HasValue 18 | { 19 | get { return true; } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Source/Synthesis/Utility/WildcardUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace Synthesis.Utility 4 | { 5 | public static class WildcardUtility 6 | { 7 | /// 8 | /// Checks if a string matches a wildcard argument (using regex) 9 | /// 10 | public static bool IsWildcardMatch(string input, string wildcards) 11 | { 12 | return Regex.IsMatch(input, "^" + Regex.Escape(wildcards).Replace("\\*", ".*").Replace("\\?", ".") + "$", RegexOptions.IgnoreCase); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/Synthesis/Generation/Model/FieldPropertyInfo.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes; 2 | using Synthesis.Templates; 3 | 4 | namespace Synthesis.Generation.Model 5 | { 6 | public class FieldPropertyInfo 7 | { 8 | public FieldPropertyInfo(ITemplateFieldInfo field) 9 | { 10 | Field = field; 11 | } 12 | 13 | public ITemplateFieldInfo Field { get; } 14 | 15 | public FieldMapping FieldType { get; set; } 16 | public string SearchFieldName { get; set; } 17 | public string FieldPropertyName { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Fixtures/ContentSearch/InitializerForcer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Synthesis.ContentSearch; 3 | using Synthesis.Initializers; 4 | 5 | namespace Synthesis.Tests.Fixtures.ContentSearch 6 | { 7 | internal class InitializerForcer : IDisposable 8 | { 9 | public InitializerForcer(ITemplateInitializer initializer) 10 | { 11 | SynthesisDocumentTypeMapper.OverrideInitializer(initializer); 12 | } 13 | 14 | public void Dispose() 15 | { 16 | SynthesisDocumentTypeMapper.RemoveOverrideInitializer(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Source/Synthesis/ContentSearch/ContentSearchUtilities.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Sitecore.Data; 3 | 4 | namespace Synthesis.ContentSearch 5 | { 6 | internal static class ContentSearchUtilities 7 | { 8 | internal static ID[] ParseIndexIdList(string indexValue) 9 | { 10 | return indexValue.Split('|') 11 | .Select(x => 12 | { 13 | ShortID id; 14 | if (!ShortID.TryParse(x, out id)) return null; 15 | return id.ToID(); 16 | }) 17 | .Where(x => x != (ID)null) 18 | .ToArray(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Source/Synthesis/Synchronization/SyncSource.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.Synchronization 2 | { 3 | /// 4 | /// Indicates where a sync-checked item exists 5 | /// 6 | public enum SyncSource 7 | { 8 | /// 9 | /// The template exists only in Sitecore 10 | /// 11 | Sitecore, 12 | /// 13 | /// The template exists only in the Model 14 | /// 15 | Model, 16 | /// 17 | /// The template exists in both places. Does NOT imply that it is necessarily synchronized. 18 | /// 19 | Both 20 | } 21 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IFieldType.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data; 2 | 3 | namespace Synthesis.FieldTypes.Interfaces 4 | { 5 | public interface IFieldType 6 | { 7 | /// 8 | /// Checks if this field has a value. Note that this is always true for a boolean field. 9 | /// 10 | bool HasValue { get; } 11 | 12 | /// 13 | /// The ID of the field instance in Sitecore, used to locate fields for Validators and other internal processes. 14 | /// Loads the inner field if this is a search-backed instance. 15 | /// 16 | ID Id { get; } 17 | } 18 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IPathItemReferenceField.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data.Fields; 2 | 3 | namespace Synthesis.FieldTypes.Interfaces 4 | { 5 | public interface IPathItemReferenceField : IFieldType 6 | { 7 | /// 8 | /// Gets the item path that the relationship refers to 9 | /// 10 | string TargetPath { get; set; } 11 | 12 | /// 13 | /// Gets the entity that the relationship is to. Returns null if the entity doesn't exist. 14 | /// 15 | IStandardTemplateItem Target { get; } 16 | 17 | ReferenceField ToReferenceField(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IImageField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface IImageField : IFileField, IFieldRenderableFieldType 4 | { 5 | /// 6 | /// Gets the width of the image, if one was entered 7 | /// 8 | int? Width { get; set; } 9 | 10 | /// 11 | /// Gets the height of the image, if one was entered 12 | /// 13 | int? Height { get; set; } 14 | 15 | /// 16 | /// Gets the alt text of the image, if any was entered 17 | /// 18 | string AlternateText { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/XmlFieldType.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data.Fields; 2 | 3 | namespace Synthesis.FieldTypes 4 | { 5 | public abstract class XmlFieldType : FieldType 6 | { 7 | protected XmlFieldType(LazyField innerField, string searchValue) : base(innerField, searchValue) 8 | { 9 | } 10 | 11 | /// 12 | /// Gets the value of the attribute named 13 | /// 14 | /// 15 | /// 16 | protected string GetAttribute(string attribute) => ((XmlField) InnerField).GetAttribute(attribute); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldDictionary.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes; 2 | 3 | namespace Synthesis 4 | { 5 | /// 6 | /// Provides indexed access to Synthesis item fields by name 7 | /// 8 | public class FieldDictionary 9 | { 10 | private readonly IStandardTemplateItem _item; 11 | 12 | internal FieldDictionary(IStandardTemplateItem item) 13 | { 14 | _item = item; 15 | } 16 | 17 | public FieldType this[string fieldName] 18 | { 19 | get 20 | { 21 | var field = _item.InnerItem.Fields[fieldName]; 22 | 23 | return field?.AsStronglyTyped(); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/UI/IContextItem.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.Mvc.UI 2 | { 3 | public interface IContextItem 4 | { 5 | /// 6 | /// Gets the Sitecore context item (e.g. the current page) as a specified template 7 | /// 8 | /// The context item, or null if the context item is not set or is not the expected template. 9 | TItem GetContextItem() 10 | where TItem : class, IStandardTemplateItem; 11 | 12 | /// 13 | /// Gets the Sitecore context item (e.g. the current page) 14 | /// 15 | IStandardTemplateItem ContextItem { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Source/Synthesis/Initializers/ITemplateInitializer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sitecore.Data; 3 | using Sitecore.Data.Items; 4 | 5 | namespace Synthesis.Initializers 6 | { 7 | /// 8 | /// Represents the contract for a template initializer (a proxy class that allows fast, reflection-less creation of model objects) 9 | /// 10 | public interface ITemplateInitializer 11 | { 12 | IStandardTemplateItem CreateInstance(Item innerItem); 13 | IStandardTemplateItem CreateInstanceFromSearch(IDictionary searchFields); 14 | ID InitializesTemplateId { get; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Utility/DisplayModeSwitcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore.Sites; 3 | 4 | namespace Synthesis.Mvc.Utility 5 | { 6 | public class DisplayModeSwitcher : IDisposable 7 | { 8 | private readonly DisplayMode _originalMode; 9 | 10 | public DisplayModeSwitcher(DisplayMode newDisplayMode) 11 | { 12 | _originalMode = Sitecore.Context.Site.DisplayMode; 13 | Sitecore.Context.Site.SetDisplayMode(newDisplayMode, DisplayModeDuration.Temporary); 14 | } 15 | 16 | public void Dispose() 17 | { 18 | Sitecore.Context.Site.SetDisplayMode(_originalMode, DisplayModeDuration.Temporary); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Source/Synthesis/Generation/GeneratorParameterException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Synthesis.Generation 4 | { 5 | [Serializable] 6 | public class GeneratorParameterException : Exception 7 | { 8 | public GeneratorParameterException() { } 9 | public GeneratorParameterException(string message) : base(message) { } 10 | public GeneratorParameterException(string message, Exception inner) : base(message, inner) { } 11 | protected GeneratorParameterException( 12 | System.Runtime.Serialization.SerializationInfo info, 13 | System.Runtime.Serialization.StreamingContext context) 14 | : base(info, context) { } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Source/Synthesis/Configuration/Registration/DefaultConfigurationRegistration.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.Configuration.Registration 2 | { 3 | /// 4 | /// Registers the default configuration. 5 | /// To register this, enable registering configurations for the Synthesis assembly (which Synthesis does by default) 6 | /// using the initialize pipeline and SynthesisConfigRegistrar processor. 7 | /// 8 | public class DefaultConfigurationRegistration : ISynthesisConfigurationRegistration 9 | { 10 | public IProviderConfiguration GetConfiguration() 11 | { 12 | return new ConfigurationProviderConfiguration(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/Synthesis/Initializers/StandardTemplateInitializer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sitecore.Data; 3 | using Sitecore.Data.Items; 4 | 5 | namespace Synthesis.Initializers 6 | { 7 | public class StandardTemplateInitializer : ITemplateInitializer 8 | { 9 | public IStandardTemplateItem CreateInstance(Item innerItem) 10 | { 11 | return new StandardTemplateItem(innerItem); 12 | } 13 | 14 | public IStandardTemplateItem CreateInstanceFromSearch(IDictionary searchFields) 15 | { 16 | return new StandardTemplateItem(searchFields); 17 | } 18 | 19 | public ID InitializesTemplateId => ID.Null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/RenderingErrorModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Synthesis.Mvc 4 | { 5 | public class RenderingErrorModel 6 | { 7 | public string ViewName { get; set; } 8 | public string DataSource { get; set; } 9 | public Type ModelType { get; set; } 10 | public object Model { get; set; } 11 | public Exception Exception { get; set; } 12 | 13 | public RenderingErrorModel(string viewName, string dataSource, Type modelType, object model, Exception exception) 14 | { 15 | ViewName = viewName; 16 | DataSource = dataSource; 17 | ModelType = modelType; 18 | Model = model; 19 | Exception = exception; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Utility/RenderingDiagnosticsDisabler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Synthesis.Mvc.Pipelines.GetRenderer; 3 | 4 | namespace Synthesis.Mvc.Utility 5 | { 6 | public class RenderingDiagnosticsDisabler : IDisposable 7 | { 8 | private readonly bool _originalValue; 9 | public RenderingDiagnosticsDisabler() 10 | { 11 | _originalValue = RenderingDiagnosticsInjector.DiagnosticsEnabledForThisRequest; 12 | RenderingDiagnosticsInjector.DiagnosticsEnabledForThisRequest = false; 13 | } 14 | 15 | public void Dispose() 16 | { 17 | RenderingDiagnosticsInjector.DiagnosticsEnabledForThisRequest = _originalValue; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/_HOW TO TEST.txt: -------------------------------------------------------------------------------- 1 | To run these tests you must be in a web context, with Sitecore present. 2 | 3 | Setup instructions: 4 | 1. Add a reference to this project in your Sitecore site 5 | 2. Add references to all of the assemblies in Dependencies/Libraries/WebTestRunner to your Sitecore site 6 | 3. Add the Synthesis.TestRunnerConfig.config to your App_Config\Include folder 7 | 4. Hit /synthesistests on your Sitecore site 8 | 9 | The web test runner is Jorge Lusar's work: https://github.com/jorgelusar/sctestrunner 10 | You can change the test running URL in the config file. 11 | 12 | Any NUnit web test runner will also work, if you have one you prefer. -------------------------------------------------------------------------------- /Source/Synthesis/Utility/DebugUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Configuration; 3 | 4 | namespace Synthesis.Utility 5 | { 6 | /// 7 | /// Caches the result of checking if dynamic debug is enabled, which seems to not cache its result in the BCL. 8 | /// 9 | public static class DebugUtility 10 | { 11 | public static bool IsDynamicDebugEnabled => DebugEnabled.Value; 12 | 13 | private static readonly Lazy DebugEnabled = new Lazy(() => 14 | { 15 | var config = WebConfigurationManager.GetSection("system.web/compilation") as CompilationSection; 16 | 17 | return config?.Debug ?? false; 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Fixtures/TemplateSignatureProviderTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace Synthesis.Tests.Fixtures 5 | { 6 | [Trait("Category", "Template Synchronization Tests")] 7 | public class TemplateSignatureProviderTests : IDisposable 8 | { 9 | [Fact(Skip = "Not Implemented")] 10 | public void TemplateSignatureProvider_SignatureIsValidOnTestTemplate() 11 | { 12 | 13 | } 14 | 15 | [Fact(Skip = "Not Implemented")] 16 | public void TemplateSignatureProvider_SignatureIsValidOnEmptyTemplate() 17 | { 18 | 19 | } 20 | 21 | public void Dispose() 22 | { 23 | 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IContentHubImageField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface IContentHubImageField : IImageField 4 | { 5 | /// 6 | /// Gets the StyleLabs Content ID 7 | /// 8 | string ContentId { get; } 9 | 10 | /// 11 | /// Gets the Thumbnail Src 12 | /// 13 | string ThumbnailSrc { get; } 14 | 15 | /// 16 | /// Gets the StyleLabs Content Type 17 | /// 18 | string ContentType { get; } 19 | 20 | /// 21 | /// Returns if the image is from Content Hub 22 | /// 23 | bool IsContentHub { get; } 24 | } 25 | } -------------------------------------------------------------------------------- /Source/Synthesis/MissingTemplateFieldException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Synthesis 5 | { 6 | [Serializable] 7 | public class MissingTemplateFieldException : Exception 8 | { 9 | public MissingTemplateFieldException() 10 | { 11 | } 12 | 13 | public MissingTemplateFieldException(string message) : base(message) 14 | { 15 | } 16 | 17 | public MissingTemplateFieldException(string message, Exception inner) : base(message, inner) 18 | { 19 | } 20 | 21 | protected MissingTemplateFieldException( 22 | SerializationInfo info, 23 | StreamingContext context) : base(info, context) 24 | { 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Fixtures/ContentSearch/Data/ISearchTemplateItem.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.ContentSearch; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.Tests.Fixtures.ContentSearch.Data 5 | { 6 | internal interface ISearchTemplateItem : IStandardTemplateItem 7 | { 8 | [IndexField("__bucketable")] 9 | IBooleanField BooleanField { get; } 10 | [IndexField("_templatesimplemented")] 11 | IItemReferenceListField MultilistField { get; } 12 | [IndexField("__smallupdateddate")] 13 | IDateTimeField Timestamp { get; } 14 | [IndexField("_template")] 15 | IItemReferenceField Lookup { get; } 16 | [IndexField("_templatename")] 17 | ITextField Text { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ######## GENERAL IGNORES ####### 2 | 3 | # ignore logs, OS cache files 4 | *.log 5 | .DS_Store* 6 | ehthumbs.db 7 | Icon? 8 | Thumbs.db 9 | 10 | ######## GENERAL .NET IGNORES ######## 11 | 12 | .vs/ 13 | 14 | # Ignore binaries in the source 15 | Source/*/bin 16 | Source/*/obj 17 | 18 | # Ignore user-scoped solution and project settings 19 | *.user 20 | *.suo 21 | 22 | # Ignore generated Version.cs files 23 | Source/*/Properties/Version.cs 24 | 25 | # NuGet output 26 | Build/*.nupkg 27 | Build/Versions 28 | Build/tools 29 | 30 | # NuGet packages 31 | Packages/* 32 | !Packages/repositories.config 33 | 34 | # Any Sitecore assemblies copied local 35 | Dependencies/Libraries/Sitecore/* 36 | _NCrunch* 37 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Utility/TestingContants.cs: -------------------------------------------------------------------------------- 1 | using Sitecore; 2 | using Sitecore.Configuration; 3 | using Sitecore.Data; 4 | using Sitecore.Data.Items; 5 | 6 | namespace Synthesis.Tests.Utility 7 | { 8 | public static class TestingContants 9 | { 10 | const string TEMPLATE_PARENT_PATH = "/sitecore/Templates"; 11 | public const string TEMPLATE_FOLDER = "SynTemp"; 12 | 13 | public static string TestTemplatePath => TEMPLATE_PARENT_PATH + "/" + TEMPLATE_FOLDER; 14 | public static Item TestTemplateFolder => Factory.GetDatabase("master").GetItem(TestTemplatePath); 15 | public static ID TestTemplateFolderId = new ID("F24A9D1F-EEA9-4816-92DA-489EA06D1074"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Source/Synthesis/ContentSearch/IndexFieldNameMapper.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.Templates; 2 | 3 | namespace Synthesis.ContentSearch 4 | { 5 | /// 6 | /// Maps a template field name to a search index field name 7 | /// Not using FieldNameTranslator because that tries to get too fancy for Solr, 8 | /// mapping e.g. [IndexField("foo_t")] when [IndexField("foo")] would do. 9 | /// 10 | public class IndexFieldNameMapper 11 | { 12 | public virtual string MapToSearchField(ITemplateFieldInfo field) 13 | { 14 | // this seems to work just fine across Solr and Lucene 15 | // using something else? Patch in a different one. 16 | return field.Name.Replace(" ", "_").ToLowerInvariant(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/ITextField.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Interfaces 2 | { 3 | public interface ITextField : IFieldRenderableFieldType, IFieldType 4 | { 5 | /// 6 | /// Gets the raw value of the field. If the value is null an empty string will be returned. 7 | /// For rich text fields, this will not expand dynamic links in the content - use ExpandedLinksValue for that 8 | /// Setting this value will cause the underlying item to be loaded for search-based instances. 9 | /// 10 | string RawValue { get; set; } 11 | 12 | /// 13 | /// Checks if the field has a null, empty, or whitespace-only value 14 | /// 15 | bool HasTextValue { get; } 16 | } 17 | } -------------------------------------------------------------------------------- /Source/Synthesis.Tests/TestFields.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Synthesis.Tests 3 | { 4 | internal static class TestFields 5 | { 6 | internal const string BOOLEAN = "Yes Or No"; 7 | internal const string DATETIME = "Timestamp"; 8 | internal const string FILE = "File"; 9 | internal const string HYPERLINK = "Link"; 10 | internal const string IMAGE = "Terrible Picture"; 11 | internal const string CONTENT_HUB_IMAGE = "Content Hub Image"; 12 | internal const string INTEGER = "Days Till Christmas"; 13 | internal const string MULTIPLE_RELATION = "Related Folders"; 14 | internal const string NUMERIC = "Account Balance"; 15 | internal const string SINGLE_RELATION = "Related Folder"; 16 | internal const string TEXT = "Title"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Source/Synthesis/Configuration/ConfigurationUtility.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Synthesis.Configuration 3 | { 4 | internal static class ConfigurationUtility 5 | { 6 | /// 7 | /// Applies the available formats for a Synthesis configuration path (i.e. root-relative, absolute) to a given path 8 | /// 9 | public static string ResolveConfigurationPath(string configPath) 10 | { 11 | if (configPath.StartsWith("~")) 12 | { 13 | return System.Web.Hosting.HostingEnvironment.MapPath("~/") + configPath.Substring(1); 14 | // +1 to Stack Overflow: 15 | // http://stackoverflow.com/questions/4742257/how-to-use-server-mappath-when-httpcontext-current-is-nothing 16 | } 17 | 18 | return configPath; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/IFakeTemplateItem.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Interfaces; 2 | 3 | namespace Synthesis.Tests 4 | { 5 | //[RepresentsSitecoreTemplate("{76036F5E-ABCE-46D1-AF0A-4143F9B557AA}", "DN8cOiiO0ckeD/NPjd9Q8nJuPSk=")] 6 | internal interface IFakeTemplateItem 7 | { 8 | IBooleanField YesOrNo { get; } 9 | IDateTimeField Timestamp { get; } 10 | IFileField File { get; } 11 | IHyperlinkField Link { get; } 12 | IImageField TerriblePicture { get; } 13 | IContentHubImageField ContentHubPicture { get; } 14 | IIntegerField DaysTillChristmas { get; } 15 | IItemReferenceListField RelatedFolders { get; } 16 | INumericField AccountBalance { get; } 17 | IItemReferenceField RelatedFolder { get; } 18 | ITextField Title { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Utility/TemplateFieldTypes.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Synthesis.Tests.Utility 3 | { 4 | public static class TemplateFieldTypes 5 | { 6 | 7 | public const string CHECKBOX_FIELD = "Checkbox"; 8 | public const string DATETIME_FIELD = "Datetime"; 9 | public const string FILE_FIELD = "File"; 10 | public const string IMAGE_FIELD = "Image"; 11 | public const string CONTENT_HUB_IMAGE_FIELD = "Image"; 12 | public const string INTEGER_FIELD = "Integer"; 13 | public const string NUMBER_FIELD = "Number"; 14 | public const string TEXT_FIELD = "Single-Line Text"; 15 | public const string TREELIST_FIELD = "Treelist"; 16 | public const string GENERAL_LINK_FIELD = "General Link"; 17 | public const string DROPLINK_FIELD = "Droplink"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestRichTextField.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Interfaces; 2 | 3 | namespace Synthesis.Testing 4 | { 5 | /// 6 | /// Represents a field whose contents are HTML written by a rich text editor that may contain dynamic links 7 | /// 8 | public class TestRichTextField : TestTextField, IRichTextField 9 | { 10 | public TestRichTextField(string value) : base(value) 11 | { 12 | } 13 | 14 | /// 15 | /// Gets the raw value of the field with dynamic links expanded into friendly URLs. Unlike RenderedValue this does not support Page Editor, but neither does it require loading a search-based instance's underlying item like RenderedValue. 16 | /// 17 | public virtual string ExpandedLinksValue => RawValue; 18 | } 19 | } -------------------------------------------------------------------------------- /Source/Synthesis/ContentSearch/Lucene/ResolveLuceneQueryable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Synthesis.Pipelines; 4 | 5 | namespace Synthesis.ContentSearch.Lucene 6 | { 7 | [Obsolete("Lucene is no longer supported. All references will be removed in a later version.")] 8 | public class ResolveLuceneQueryable : IQueryableResolver 9 | { 10 | [Obsolete("Lucene is no longer supported. All references will be removed in a later version.")] 11 | public IQueryable GetSynthesisQueryable(SynthesisSearchContextArgs args) where TResult : IStandardTemplateItem 12 | { 13 | throw new NotSupportedException("Lucene is no longer supported with Synthesis. To continue to use Content Search, please install Synthesis.Solr"); 14 | } 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IItemReferenceField.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Sitecore.Data; 3 | using Sitecore.Data.Fields; 4 | 5 | namespace Synthesis.FieldTypes.Interfaces 6 | { 7 | public interface IItemReferenceField : IFieldType 8 | { 9 | /// 10 | /// Gets the item ID that the relationship refers to 11 | /// 12 | [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ID", Justification = "Coherent with Sitecore convention")] 13 | ID TargetId { get; set; } 14 | 15 | /// 16 | /// Gets the entity that the relationship is to. Returns null if the entity doesn't exist. 17 | /// 18 | IStandardTemplateItem Target { get; } 19 | 20 | ReferenceField ToReferenceField(); 21 | } 22 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/FieldMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Synthesis.FieldTypes 4 | { 5 | /// 6 | /// Represents a type mapping for a Sitecore field type to a Synthesis generated field 7 | /// 8 | public class FieldMapping 9 | { 10 | public FieldMapping(Type publicFieldType, Type internalFieldType) 11 | { 12 | PublicFieldType = publicFieldType; 13 | InternalFieldType = internalFieldType; 14 | } 15 | 16 | /// 17 | /// The internal type of the field property (e.g. 'BooleanField') 18 | /// 19 | public Type InternalFieldType { get; private set; } 20 | 21 | /// 22 | /// The external type of the field property (e.g. IBooleanField) 23 | /// 24 | public Type PublicFieldType { get; private set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestTristateField.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Interfaces; 2 | 3 | namespace Synthesis.Testing 4 | { 5 | /// 6 | /// Encapsulates a tri-state (Yes/No/Default) field from Sitecore 7 | /// 8 | public class TestTristateField : TestFieldType, ITristateField 9 | { 10 | public TestTristateField(bool? value) 11 | { 12 | Value = value; 13 | } 14 | 15 | /// 16 | /// Gets the value of the field. If called when HasValue is false, returns false. 17 | /// 18 | public bool? Value { get; set; } 19 | 20 | /// 21 | /// Checks if this field has a value. Note that this is always true for a tristate field because no value is still a valid value ("default"). 22 | /// 23 | public override bool HasValue => true; 24 | } 25 | } -------------------------------------------------------------------------------- /Source/Synthesis/Standard Config Files/Synthesis.ContentHub.config.disabled: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/Synthesis.Testing.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Synthesis.Testing 5 | $version$ 6 | Ben Lipson,Kam Figy 7 | Connective DX 8 | http://opensource.org/licenses/MIT 9 | https://github.com/blipson89/Synthesis 10 | false 11 | 12 | Utilities to assist in unit testing with Synthesis 13 | 14 | Copyright 2017 Ben Lipson/Connective DX 15 | sitecore 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Source/Synthesis/Templates/ITemplateInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | using Sitecore.Data; 4 | 5 | namespace Synthesis.Templates 6 | { 7 | public interface ITemplateInfo 8 | { 9 | ID TemplateId { get; } 10 | string Name { get; } 11 | IList Fields { get; } 12 | string HelpText { get; } 13 | string FullPath { get; } 14 | IList OwnFields { get; } 15 | 16 | /// 17 | /// Gets immediate ancestor base templates 18 | /// 19 | ReadOnlyCollection BaseTemplates { get; } 20 | 21 | /// 22 | /// Gets all base templates (including base templates of base templates back up to the standard template) 23 | /// 24 | ReadOnlyCollection AllNonstandardBaseTemplates { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /Source/Synthesis/Templates/ITemplateInputProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sitecore.Data; 3 | 4 | namespace Synthesis.Templates 5 | { 6 | /// 7 | /// Provides the list of templates that should have strongly typed items generated from them 8 | /// 9 | public interface ITemplateInputProvider 10 | { 11 | /// 12 | /// Gets all templates that should be used 13 | /// 14 | /// 15 | IEnumerable CreateTemplateList(); 16 | 17 | /// 18 | /// Checks if a template field should be included 19 | /// 20 | bool IsFieldIncluded(ID fieldId); 21 | 22 | /// 23 | /// Forces the provider to invalidate any internal caches and retrieve the latest data from Sitecore 24 | /// 25 | void Refresh(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IItemReferenceListField.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | using Sitecore.Data; 4 | using Sitecore.Data.Fields; 5 | using Sitecore.Data.Items; 6 | 7 | namespace Synthesis.FieldTypes.Interfaces 8 | { 9 | public interface IItemReferenceListField : ICollection, IFieldType 10 | { 11 | /// 12 | /// Gets the set of IDs that make up the relationships 13 | /// 14 | ReadOnlyCollection TargetIds { get; } 15 | 16 | /// 17 | /// Gets the items that make up the relationships 18 | /// 19 | ReadOnlyCollection TargetItems { get; } 20 | 21 | void Add(Item item); 22 | void Add(IStandardTemplateItem item); 23 | bool Remove(Item item); 24 | bool Remove(IStandardTemplateItem item); 25 | MultilistField ToMultilistField(); 26 | } 27 | } -------------------------------------------------------------------------------- /Source/Synthesis/Synchronization/ModelTemplateReference.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace Synthesis.Synchronization 5 | { 6 | /// 7 | /// A reference to a model template type and its synchronization attribute 8 | /// 9 | public class ModelTemplateReference 10 | { 11 | public ModelTemplateReference(Type type) 12 | { 13 | InterfaceType = type; 14 | Metadata = InterfaceType.GetCustomAttributes(typeof(RepresentsSitecoreTemplateAttribute), false).FirstOrDefault() as RepresentsSitecoreTemplateAttribute; 15 | } 16 | 17 | public ModelTemplateReference(Type type, RepresentsSitecoreTemplateAttribute attribute) 18 | { 19 | InterfaceType = type; 20 | Metadata = attribute; 21 | } 22 | 23 | public Type InterfaceType { get; private set; } 24 | public RepresentsSitecoreTemplateAttribute Metadata { get; private set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IFileField.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data; 2 | using Sitecore.Data.Items; 3 | using Sitecore.Resources.Media; 4 | 5 | namespace Synthesis.FieldTypes.Interfaces 6 | { 7 | public interface IFileField : IFieldType 8 | { 9 | /// 10 | /// Gets the URL to the media item. If HasValue is false returns an empty string. 11 | /// 12 | string Url { get; } 13 | 14 | /// 15 | /// Gets the ID of the media item the mediafield references 16 | /// 17 | ID MediaItemId { get; set; } 18 | 19 | /// 20 | /// The MediaItem that is the target of the file field 21 | /// 22 | MediaItem MediaItem { get; } 23 | 24 | /// 25 | /// Gets a stream of the binary data in the file field. Make sure to dispose of the object when done! 26 | /// 27 | MediaStream MediaStream { get; } 28 | } 29 | } -------------------------------------------------------------------------------- /Source/Synthesis/Synchronization/TemplateComparisonResultCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | using System.Linq; 4 | 5 | namespace Synthesis.Synchronization 6 | { 7 | /// 8 | /// A collection of synchronization results 9 | /// 10 | public class TemplateComparisonResultCollection : ReadOnlyCollection 11 | { 12 | private bool? _syncResult; 13 | 14 | public TemplateComparisonResultCollection(IList results) : base(results) 15 | { 16 | 17 | } 18 | 19 | /// 20 | /// Checks if all synchronization results in the collection are synchronized 21 | /// 22 | public bool AreTemplatesSynchronized 23 | { 24 | get 25 | { 26 | if (_syncResult == null) 27 | _syncResult = this.All(x => x.IsSynchronized); 28 | 29 | return _syncResult.Value; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/Synthesis/SynthesisEditContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore.Data.Items; 3 | 4 | namespace Synthesis 5 | { 6 | #pragma warning disable 0618 // disable the warning about InnerItem here - it's cool 7 | 8 | /// 9 | /// Provides a means to put an item in editing mode. 10 | /// 11 | /// 12 | /// The item is enters editing mode when this object is created and leaves editing 13 | /// mode when the object is disposed. 14 | /// This provides an easy to use mechanism for editing items. 15 | /// 16 | [Obsolete("You should not use an edit context because if an exception is thrown partial updates may be written to the item anyway. Use Editing.BeginEdit()...Editing.EndEdit() instead.")] 17 | public class SynthesisEditContext : EditContext 18 | { 19 | public SynthesisEditContext(IStandardTemplateItem item) : base(item.InnerItem) 20 | { 21 | 22 | } 23 | } 24 | 25 | #pragma warning restore 0618 26 | } 27 | -------------------------------------------------------------------------------- /Source/Synthesis.Solr/Standard Config Files/Synthesis.Solr.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/TagRenderingContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | using Sitecore.Diagnostics; 4 | using Sitecore.Mvc; 5 | using Synthesis.FieldTypes; 6 | 7 | namespace Synthesis.Mvc 8 | { 9 | public class TagRenderingContext : IDisposable 10 | { 11 | private readonly HtmlHelper _helper; 12 | 13 | public TagRenderingContext(HtmlHelper helper, FieldType field, object parameters) 14 | { 15 | Assert.ArgumentNotNull(helper, nameof(helper)); 16 | Assert.ArgumentNotNull(field, nameof(field)); 17 | Assert.ArgumentNotNull(parameters, nameof(parameters)); 18 | 19 | _helper = helper; 20 | 21 | var fieldValue = helper.Sitecore().BeginField(field.InnerField.ID.ToString(), field.InnerField.Item, parameters); 22 | 23 | helper.ViewContext.Writer.Write(fieldValue.ToHtmlString()); 24 | } 25 | 26 | public void Dispose() 27 | { 28 | _helper.ViewContext.Writer.Write(_helper.Sitecore().EndField()); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/Synthesis.Solr.Tests/App_Config/Include/Synthesis.Solr.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Source/Synthesis.Solr/Synthesis.Solr.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Synthesis.Solr.Core 5 | $version$ 6 | Ben Lipson,Kam Figy,Jeff Darchuk 7 | Synthesis Team 8 | http://opensource.org/licenses/MIT 9 | https://github.com/blipson89/Synthesis 10 | http://www.benlipson.net/wp-content/uploads/2018/12/synthesis-logo.png 11 | false 12 | 13 | Adds Solr support to Synthesis. This package contains the core library for class libraries. Use Synthesis.Solr to include configuration. 14 | 15 | Copyright 2021 Ben Lipson/Synthesis Team 16 | sitecore,synthesis,solr 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/LazyField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore.Data.Fields; 3 | 4 | namespace Synthesis.FieldTypes 5 | { 6 | public class LazyField 7 | { 8 | private readonly string _fieldName; 9 | private readonly string _templateName; 10 | private readonly Lazy _innerLazyField; 11 | 12 | public LazyField(Func valueFactory, string templateName, string fieldName) 13 | { 14 | _innerLazyField = new Lazy(valueFactory); 15 | _templateName = templateName; 16 | _fieldName = fieldName; 17 | } 18 | 19 | public bool IsLoaded => _innerLazyField.IsValueCreated; 20 | 21 | public Field Value 22 | { 23 | get 24 | { 25 | var value = _innerLazyField.Value; 26 | if (value == null) throw new MissingTemplateFieldException($"The field {_fieldName} on template {_templateName} was not found. It may be unpublished, missing, or you may need to regenerate your Synthesis model."); 27 | 28 | return value; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/Synthesis.Testing.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net471 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | Properties\SharedAssemblyInfo.cs 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Synthesis.Mvc.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Synthesis.Mvc.Core 5 | $version$ 6 | Ben Lipson,Kam Figy 7 | Synthesis Team 8 | http://opensource.org/licenses/MIT 9 | https://github.com/blipson89/Synthesis 10 | http://www.benlipson.net/wp-content/uploads/2018/12/synthesis-logo.png 11 | false 12 | 13 | Automatic injection of Synthesis models for Sitecore MVC view renderings. This package contains the core library for class libraries. Use Synthesis.Mvc to include configuration. 14 | 15 | NOTE: Synthesis 9.1.0 and above requires Sitecore 9.1.0 or higher 16 | 17 | Copyright 2021 Ben Lipson/Synthesis Team 18 | sitecore 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/FieldTypes/IntegerFieldTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Synthesis.Tests.Utility; 3 | using Xunit; 4 | 5 | namespace Synthesis.Tests.FieldTypes 6 | { 7 | [Trait("Category", "FieldType Tests")] 8 | public class IntegerFieldTests : IDisposable 9 | { 10 | public IntegerFieldTests() 11 | { 12 | new FieldTestTemplateCreator().CreateSampleTemplate(); 13 | } 14 | 15 | public void Dispose() 16 | { 17 | new FieldTestTemplateCreator().DeleteSampleTemplate(); 18 | } 19 | 20 | [Fact(Skip = "TODO")] 21 | public void IntegerField_GetValue_ReturnsValue() 22 | { 23 | 24 | } 25 | 26 | [Fact(Skip = "TODO")] 27 | public void IntegerField_GetValue_ReturnsDefaultIntWhenBlank() 28 | { 29 | 30 | } 31 | 32 | [Fact(Skip = "TODO")] 33 | public void IntegerField_SetValue_SavesValue() 34 | { 35 | 36 | } 37 | 38 | [Fact(Skip = "TODO")] 39 | public void IntegerField_HasValue_WhenTrue() 40 | { 41 | 42 | } 43 | 44 | [Fact(Skip = "TODO")] 45 | public void IntegerField_HasValue_WhenFalse() 46 | { 47 | 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/FieldTypes/NumericFieldTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Synthesis.Tests.Utility; 3 | using Xunit; 4 | 5 | namespace Synthesis.Tests.FieldTypes 6 | { 7 | [Trait("Category", "FieldType Tests")] 8 | public class NumericFieldTests : IDisposable 9 | { 10 | public NumericFieldTests() 11 | { 12 | new FieldTestTemplateCreator().CreateSampleTemplate(); 13 | } 14 | 15 | public void Dispose() 16 | { 17 | new FieldTestTemplateCreator().DeleteSampleTemplate(); 18 | } 19 | 20 | [Fact(Skip = "TODO")] 21 | public void NumericField_GetValue_ReturnsValue() 22 | { 23 | 24 | } 25 | 26 | [Fact(Skip = "TODO")] 27 | public void NumericField_GetValue_ReturnsDefaultDecimalWhenBlank() 28 | { 29 | 30 | } 31 | 32 | [Fact(Skip = "TODO")] 33 | public void NumericField_SetValue_SavesValue() 34 | { 35 | 36 | } 37 | 38 | [Fact(Skip = "TODO")] 39 | public void NumericField_HasValue_WhenTrue() 40 | { 41 | 42 | } 43 | 44 | [Fact(Skip = "TODO")] 45 | public void NumericField_HasValue_WhenFalse() 46 | { 47 | 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/BooleanField.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data.Fields; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.FieldTypes 5 | { 6 | /// 7 | /// Encapsulates a boolean (checkbox) field from Sitecore 8 | /// 9 | public class BooleanField : FieldType, IBooleanField 10 | { 11 | public BooleanField(LazyField field, string indexValue) : base(field, indexValue) { } 12 | 13 | /// 14 | /// Gets the value of the field. If called when HasValue is false, returns false. 15 | /// 16 | public virtual bool Value 17 | { 18 | get { return ((CheckboxField)InnerField).Checked; } 19 | set 20 | { 21 | SetFieldValue(delegate { 22 | ((CheckboxField)InnerField).Checked = value; 23 | }); 24 | } 25 | } 26 | 27 | /// 28 | /// Checks if this field has a value. Note that this is always true for a boolean field. 29 | /// 30 | public override bool HasValue => true; 31 | 32 | public override string ToString() 33 | { 34 | return Value.ToString(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | THE MIT LICENSE 2 | 3 | Copyright (c) 2013 ISITE Design/Kam Figy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Source/Synthesis/Configuration/IProviderConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.ContentSearch.Linq.Common; 2 | using Synthesis.ContentSearch; 3 | using Synthesis.Templates; 4 | using Synthesis.Generation; 5 | using Synthesis.FieldTypes; 6 | using Synthesis.Generation.Model; 7 | using Synthesis.Initializers; 8 | using Synthesis.Synchronization; 9 | 10 | namespace Synthesis.Configuration 11 | { 12 | public interface IProviderConfiguration 13 | { 14 | string Name { get; } 15 | IFieldMappingProvider FieldMappingProvider { get; } 16 | IGeneratorParametersProvider GeneratorParametersProvider { get; } 17 | ITemplateInputProvider TemplateInputProvider { get; } 18 | ITemplateSignatureProvider TemplateSignatureProvider { get; } 19 | ITypeListProvider TypeListProvider { get; } 20 | IInitializerProvider InitializerProvider { get; } 21 | IndexFieldNameMapper IndexFieldNameMapper { get; } 22 | IMetadataGenerator CreateMetadataGenerator(GeneratorParameters parameters); 23 | ITemplateCodeGenerator CreateCodeGenerator(); 24 | SynchronizationEngine CreateSyncEngine(TemplateGenerationMetadata metadata); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/RichTextField.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Interfaces; 2 | using Synthesis.Utility; 3 | 4 | namespace Synthesis.FieldTypes 5 | { 6 | /// 7 | /// Represents a field whose contents are HTML written by a rich text editor that may contain dynamic links 8 | /// 9 | public class RichTextField : TextField, IRichTextField 10 | { 11 | public RichTextField(LazyField field, string indexValue) : base(field, indexValue) { } 12 | 13 | /// 14 | /// Gets the raw value of the field with dynamic links expanded into friendly URLs. Unlike RenderedValue this does not support Page Editor, but neither does it require loading a search-based instance's underlying item like RenderedValue. 15 | /// 16 | public virtual string ExpandedLinksValue => FieldUtility.ExpandDynamicLinks(RawValue); 17 | 18 | /// 19 | /// Converts the field into it's string representation. Returns the same value as the ExpandedLinksValue property. 20 | /// 21 | public override string ToString() 22 | { 23 | return ExpandedLinksValue; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Synthesis.TestRunnerConfig.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Source/Synthesis/Templates/Database/ItemTemplateFieldInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Sitecore.Data; 3 | using Sitecore.Data.Items; 4 | using Sitecore.Diagnostics; 5 | 6 | namespace Synthesis.Templates.Database 7 | { 8 | [DebuggerDisplay("{Name}")] 9 | public class ItemTemplateFieldInfo : ITemplateFieldInfo 10 | { 11 | private readonly TemplateFieldItem _field; 12 | 13 | public ItemTemplateFieldInfo(TemplateFieldItem field) 14 | { 15 | Assert.ArgumentNotNull(field, "field"); 16 | 17 | _field = field; 18 | } 19 | 20 | public ItemTemplateFieldInfo(TemplateFieldItem field, ITemplateInfo template) : this(field) 21 | { 22 | Assert.ArgumentNotNull(template, "template"); 23 | 24 | Template = template; 25 | } 26 | 27 | public string Name => _field.Name; 28 | 29 | public string DisplayName => _field.DisplayName; 30 | 31 | public string FullPath => _field.InnerItem.Paths.FullPath; 32 | 33 | public ID Id => _field.ID; 34 | 35 | public string HelpText => _field.Description; 36 | 37 | public string Type => _field.Type; 38 | 39 | public ITemplateInfo Template { get; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/Synthesis/Utility/SingleFieldEditor.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data.Items; 2 | 3 | namespace Synthesis.Utility 4 | { 5 | /// 6 | /// When used with a using clause, transparently enables item editing for a single field edit transaction if edit mode is not already enabled 7 | /// 8 | internal class SingleFieldEditor 9 | { 10 | private bool _initiatedEdit; 11 | private readonly Item _item; 12 | 13 | public SingleFieldEditor(Item item) 14 | { 15 | _item = item; 16 | EnsureEditMode(); 17 | } 18 | 19 | /// 20 | /// Ends edit mode if we initiated it, otherwise leaves it alone 21 | /// 22 | public void EnsureEndEditIfStarted() 23 | { 24 | if (_initiatedEdit && _item.Editing.IsEditing) 25 | _item.Editing.EndEdit(); 26 | } 27 | 28 | /// 29 | /// Ensures that the item is in edit mode. Does not handle any security changes. 30 | /// 31 | private void EnsureEditMode() 32 | { 33 | if (!_item.Editing.IsEditing) 34 | { 35 | _item.Editing.BeginEdit(); 36 | _initiatedEdit = true; 37 | } 38 | else _initiatedEdit = false; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/Synthesis/Standard Config Files/Synthesis.ControlPanel.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | /synthesis.aspx 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Source/Synthesis/Configuration/Registration/ProxyGeneratorParametersProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Synthesis.Generation; 3 | 4 | namespace Synthesis.Configuration.Registration 5 | { 6 | /// 7 | /// Wraps an inner generator parameters provider and allows mutating its resultant parameters 8 | /// 9 | public class ProxyGeneratorParametersProvider : IGeneratorParametersProvider 10 | { 11 | private readonly IGeneratorParametersProvider _innerProvider; 12 | private readonly Action _permutationAction; 13 | 14 | public ProxyGeneratorParametersProvider(IGeneratorParametersProvider innerProvider, Action permutationAction) 15 | { 16 | _innerProvider = innerProvider; 17 | _permutationAction = permutationAction; 18 | } 19 | 20 | 21 | public GeneratorParameters CreateParameters(string configurationName) 22 | { 23 | // we call base here so the parameters begin as a copy of what's in global config (e.g. base classes, etc) 24 | var parameters = _innerProvider.CreateParameters(configurationName); 25 | 26 | _permutationAction(parameters); 27 | 28 | return parameters; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/Synthesis/Standard Config Files/Synthesis.ControlPanel.IdentityServer.config.disabled: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | /synthesis.aspx 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestNumericField.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.Testing 5 | { 6 | public class TestNumericField : TestFieldType, INumericField 7 | { 8 | private decimal? _value; 9 | 10 | public TestNumericField(decimal? value) 11 | { 12 | _value = value; 13 | } 14 | 15 | /// 16 | /// Gets the value of the field. If the field does not have a value or the value isn't parseable, returns default(int). 17 | /// 18 | public virtual decimal Value 19 | { 20 | get { return _value ?? default(int); } 21 | set { _value = value; } 22 | } 23 | 24 | /// 25 | /// Renders the field using a Sitecore FieldRenderer and returns the result 26 | /// 27 | public virtual string RenderedValue => Value.ToString(CultureInfo.InvariantCulture); 28 | 29 | /// 30 | /// Checks if the field has a valid integer value 31 | /// 32 | /// Note that Value will always return a valid int (0) even if HasValue is false. So check this first :) 33 | public override bool HasValue => _value.HasValue; 34 | } 35 | } -------------------------------------------------------------------------------- /Source/Synthesis.Solr.Tests/ContentSearch/SynthesisSolrFieldNameTranslatorTests.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using FluentAssertions; 3 | using Sitecore.ContentSearch; 4 | using Sitecore.FakeDb; 5 | using Synthesis.FieldTypes.Interfaces; 6 | using Synthesis.Solr.ContentSearch; 7 | using Synthesis.Testing.Attributes; 8 | using Xunit; 9 | 10 | namespace Synthesis.Solr.Tests.ContentSearch 11 | { 12 | public class SynthesisSolrFieldNameTranslatorTests 13 | { 14 | [Theory, AutoNSubstitute] 15 | public void GetIndexFieldNameMemberInfo_IfMemberIsSynthesisFieldType_ReturnName(SynthesisSolrFieldNameTranslator sut) 16 | { 17 | using (new Db("master")) 18 | { 19 | PropertyInfo propertyInfo = typeof(MockItem).GetProperty(nameof(MockItem.TextField)); 20 | string name = sut.GetIndexFieldName(propertyInfo); 21 | name.Should().BeEquivalentTo(propertyInfo.GetCustomAttribute().IndexFieldName); 22 | } 23 | } 24 | } 25 | public class MockItem 26 | { 27 | [IndexField("textfield_t")] 28 | public ITextField TextField { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestDateTimeField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Sitecore.Data.Fields; 4 | using Synthesis.FieldTypes.Interfaces; 5 | 6 | namespace Synthesis.Testing 7 | { 8 | public class TestDateTimeField : TestFieldType, IDateTimeField 9 | { 10 | public TestDateTimeField(DateTime dateTime) 11 | { 12 | Value = dateTime; 13 | } 14 | 15 | /// 16 | /// Gets the value of the field. If no value exists, returns DateTime.MinValue 17 | /// 18 | public DateTime Value { get; set; } 19 | 20 | /// 21 | /// Checks if the field has a value. For a DateTime, this checks if it equals default(DateTime). 22 | /// 23 | public override bool HasValue 24 | { 25 | get { return Value != DateTime.MinValue; } 26 | } 27 | 28 | /// 29 | /// Renders the field using a Sitecore FieldRenderer and returns the result 30 | /// 31 | public virtual string RenderedValue 32 | { 33 | get { return Value.ToString(CultureInfo.InvariantCulture); } 34 | } 35 | 36 | public DateField ToDateField() 37 | { 38 | throw new NotImplementedException("Test date fields cannot return Sitecore item objects"); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestIntegerField.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.Testing 5 | { 6 | public class TestIntegerField : TestFieldType, IIntegerField 7 | { 8 | private int? _value; 9 | 10 | public TestIntegerField(int? value) 11 | { 12 | _value = value; 13 | } 14 | 15 | /// 16 | /// Gets the value of the field. If the field does not have a value or the value isn't parseable, returns default(int). 17 | /// 18 | public virtual int Value 19 | { 20 | get { return _value ?? default(int); } 21 | set { _value = value; } 22 | } 23 | 24 | /// 25 | /// Renders the field using a Sitecore FieldRenderer and returns the result 26 | /// 27 | public virtual string RenderedValue 28 | { 29 | get { return Value.ToString(CultureInfo.InvariantCulture); } 30 | } 31 | 32 | /// 33 | /// Checks if the field has a valid integer value 34 | /// 35 | /// Note that Value will always return a valid int (0) even if HasValue is false. So check this first :) 36 | public override bool HasValue 37 | { 38 | get { return _value.HasValue; } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Interfaces/IHyperlinkField.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data.Fields; 2 | 3 | namespace Synthesis.FieldTypes.Interfaces 4 | { 5 | public interface IHyperlinkField : IFieldType, IFieldRenderableFieldType 6 | { 7 | /// 8 | /// The CSS class of the link, if one was entered 9 | /// 10 | string CssClass { get; set; } 11 | 12 | /// 13 | /// Gets the link URL. Handles internal links, external, media, etc types. 14 | /// 15 | string Href { get; set; } 16 | 17 | /// 18 | /// The target attribute of the link, if one was entered. Note that "_blank" is interpreted as rel="external" by default for XHTML compatibility. 19 | /// 20 | string Target { get; set; } 21 | 22 | /// 23 | /// The text of the link, if one was entered. 24 | /// 25 | string Text { get; set; } 26 | 27 | /// 28 | /// The title attribute of the link, if one was entered 29 | /// 30 | string Title { get; set; } 31 | 32 | /// 33 | /// Gets the target Sitecore item of this link (if the link is internal) 34 | /// 35 | IStandardTemplateItem TargetItem { get; } 36 | 37 | LinkField ToLinkField(); 38 | } 39 | } -------------------------------------------------------------------------------- /Source/Synthesis/Standard Config Files/Synthesis.Startup.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 25 | Log 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Fixtures/ContentSearch/ContentSearchTestFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using AutoFixture; 3 | using AutoFixture.AutoNSubstitute; 4 | using NSubstitute; 5 | using Sitecore.ContentSearch; 6 | using Sitecore.ContentSearch.Maintenance; 7 | using Sitecore.ContentSearch.Security; 8 | using Sitecore.ContentSearch.SolrProvider; 9 | using Sitecore.FakeDb; 10 | 11 | namespace Synthesis.Tests.Fixtures.ContentSearch 12 | { 13 | public class ContentSearchTestFixture : IDisposable 14 | { 15 | private Db database; 16 | private ConfigureServices _services; 17 | public ContentSearchTestFixture() 18 | { 19 | _services = new ConfigureServices(); 20 | database = new Db("master"); 21 | ContentSearchManager.SearchConfiguration.Indexes.Clear(); 22 | ContentSearchManager.SearchConfiguration.Indexes.Add("sitecore_master_index", Substitute.For()); 23 | } 24 | 25 | public void Dispose() 26 | { 27 | _services.Dispose(); 28 | database.Dispose(); 29 | } 30 | protected IProviderSearchContext CreateTestSearchContext() 31 | { 32 | return ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext(SearchSecurityOptions.DisableSecurityCheck); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/FieldTypes/ItemReferenceFieldTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Synthesis.Tests.FieldTypes 4 | { 5 | [Trait("Category", "FieldType Tests")] 6 | public class ItemReferenceFieldTests 7 | { 8 | [Fact(Skip = "TODO")] 9 | public void ItemReferenceField_GetTargetID_ReturnsValue() 10 | { 11 | 12 | } 13 | 14 | [Fact(Skip = "TODO")] 15 | public void ItemReferenceField_GetTargetID_HandlesMalformedFieldValues() 16 | { 17 | 18 | } 19 | 20 | [Fact(Skip = "TODO")] 21 | public void ItemReferenceField_GetTargetID_ReturnsNullWhenBlank() 22 | { 23 | 24 | } 25 | 26 | [Fact(Skip = "TODO")] 27 | public void ItemReferenceField_GetTargetItem_ReturnsValue() 28 | { 29 | 30 | } 31 | 32 | [Fact(Skip = "TODO")] 33 | public void ItemReferenceField_GetTargetItem_ReturnsNullWhenInvalidID() 34 | { 35 | 36 | } 37 | 38 | [Fact(Skip = "TODO")] 39 | public void ItemReferenceField_GetTargetItem_ReturnsNullWhenBlank() 40 | { 41 | 42 | } 43 | 44 | [Fact(Skip = "TODO")] 45 | public void ItemReferenceField_HasValue_WhenTrue() 46 | { 47 | } 48 | 49 | [Fact(Skip = "TODO")] 50 | public void ItemReferenceField_HasValue_WhenFalse() 51 | { 52 | 53 | } 54 | 55 | [Fact(Skip = "TODO")] 56 | public void ItemReferenceField_CanImplicitCastToReferenceField() 57 | { 58 | 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/TristateField.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data.Fields; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.FieldTypes 5 | { 6 | /// 7 | /// Encapsulates a tri-state (Yes/No/Default) field from Sitecore 8 | /// 9 | public class TristateField : FieldType, ITristateField 10 | { 11 | public TristateField(LazyField field, string indexValue) : base(field, indexValue) { } 12 | 13 | /// 14 | /// Gets the value of the field. If called when HasValue is false, returns false. 15 | /// 16 | public virtual bool? Value 17 | { 18 | get 19 | { 20 | if (InnerField.Value == "1") return true; 21 | if (InnerField.Value == "0") return false; 22 | 23 | return null; 24 | } 25 | set 26 | { 27 | SetFieldValue(delegate 28 | { 29 | if (value == null) 30 | InnerField.Value = string.Empty; 31 | else 32 | ((CheckboxField)InnerField).Checked = value.Value; 33 | }); 34 | } 35 | } 36 | 37 | /// 38 | /// Checks if this field has a value. Note that this is always true for a tristate field because no value is still a valid value ("default"). 39 | /// 40 | public override bool HasValue => true; 41 | 42 | public override string ToString() 43 | { 44 | return Value.ToString(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/Synthesis.Solr/Synthesis.Solr.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net471 4 | false 5 | 6 | 7 | bin\Debug\ 8 | TRACE;DEBUG;CODE_ANALYSIS 9 | full 10 | true 11 | 12 | 13 | pdbonly 14 | true 15 | bin\Release\ 16 | 17 | 18 | 19 | 20 | Properties\SharedAssemblyInfo.cs 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestTextField.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Interfaces; 2 | 3 | namespace Synthesis.Testing 4 | { 5 | public class TestTextField : TestFieldType, ITextField 6 | { 7 | public TestTextField(string value) 8 | { 9 | RawValue = value; 10 | } 11 | 12 | /// 13 | /// Gets the raw value of the field. If the value is null an empty string will be returned. 14 | /// For rich text fields, this will not expand dynamic links in the content - use ExpandedLinksValue for that 15 | /// Setting this value will cause the underlying item to be loaded for search-based instances. 16 | /// 17 | public string RawValue { get; set; } 18 | 19 | /// 20 | /// Renders the field using a Sitecore FieldRenderer and returns the result 21 | /// Getting this value will cause the underlying item to be loaded for search-based instances. 22 | /// 23 | public virtual string RenderedValue => RawValue; 24 | 25 | /// 26 | /// Checks if the field has a null or empty value 27 | /// 28 | public override bool HasValue => !string.IsNullOrEmpty(RawValue); 29 | 30 | /// 31 | /// Checks if the field has a null, empty, or whitespace-only value 32 | /// 33 | public virtual bool HasTextValue => !string.IsNullOrWhiteSpace(RawValue); 34 | } 35 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Adapters/IEditingAdapter.cs: -------------------------------------------------------------------------------- 1 | namespace Synthesis.FieldTypes.Adapters 2 | { 3 | public interface IEditingAdapter 4 | { 5 | /// 6 | /// Gets a value that indicates if the item is being edited. 7 | /// 8 | /// 9 | /// 10 | /// 11 | /// true if this instance is editing; otherwise, false. 12 | /// 13 | /// 14 | bool IsEditing { get; } 15 | 16 | /// 17 | /// Marks the beginning of an editing operation. 18 | /// 19 | /// 20 | void BeginEdit(); 21 | 22 | /// 23 | /// Cancels the edit. 24 | /// 25 | /// 26 | void CancelEdit(); 27 | 28 | /// 29 | /// Ends an edit operation. 30 | /// 31 | /// 32 | /// 33 | /// 34 | /// The edit. 35 | /// 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// Editing an item without calling BeginEdit throws an exception. 41 | /// 42 | /// 43 | /// 44 | /// It is usually easier and more readable to using the EditContext class instead 45 | /// of a BeginEdit and EndEdit pair. 46 | /// 47 | /// 48 | /// 49 | bool EndEdit(); 50 | 51 | /// 52 | /// Rejects the changes. 53 | /// 54 | /// 55 | void RejectChanges(); 56 | } 57 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore.Data.Fields; 3 | using Sitecore.Diagnostics; 4 | using Synthesis.Configuration; 5 | using Synthesis.Templates.Database; 6 | using FieldType = Synthesis.FieldTypes.FieldType; 7 | 8 | namespace Synthesis 9 | { 10 | public static class FieldExtensions 11 | { 12 | /// 13 | /// Converts a Sitecore Field into a specific Synthesis field equivalent 14 | /// 15 | public static TField As(this Field field) 16 | where TField : FieldType 17 | { 18 | return AsStronglyTyped(field) as TField; 19 | } 20 | 21 | /// 22 | /// Converts a Sitecore Field into a Synthesis field equivalent 23 | /// 24 | public static FieldType AsStronglyTyped(this Field field) 25 | { 26 | if (field == null) return null; 27 | 28 | var templateField = field.Item.Template.GetField(field.ID); 29 | var configuration = ProviderResolver.FindConfigurationWithTemplate(field.Item.TemplateID); 30 | 31 | Assert.IsNotNull(configuration, "The template field was not part of any Synthesis template."); 32 | 33 | var mapping = configuration.FieldMappingProvider.GetFieldType(new ItemTemplateFieldInfo(templateField)); 34 | 35 | var lazy = new Lazy(() => field); 36 | 37 | return Activator.CreateInstance(mapping.InternalFieldType, lazy, null) as FieldType; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/ViewModelTypeResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Compilation; 3 | using Sitecore.Diagnostics; 4 | 5 | namespace Synthesis.Mvc 6 | { 7 | /// 8 | /// Credit where due: this is based on Fortis' model resolver: 9 | /// https://github.com/Fortis-Collection/fortis/blob/master/Fortis.Mvc/Pipelines/GetModel/GetFromView.cs 10 | /// 11 | public class ViewModelTypeResolver 12 | { 13 | public virtual Type GetViewModelType(string viewPath) 14 | { 15 | if (string.IsNullOrWhiteSpace(viewPath)) return typeof(object); 16 | 17 | // Retrieve the compiled view 18 | try 19 | { 20 | var compiledViewType = BuildManager.GetCompiledType(viewPath); 21 | var baseType = compiledViewType.BaseType; 22 | 23 | // Check to see if the view has been found and that it is a generic type 24 | if (baseType == null || !baseType.IsGenericType) return typeof (object); 25 | 26 | return baseType.GetGenericArguments()[0]; 27 | } 28 | catch (ArgumentException aex) 29 | { 30 | // this can occur if an invalid path (e.g. a relative path) is passed in; we ignore the error for now and let it pass 31 | // down to the MVC machinery to show a regular error message later 32 | Log.Error("Synthesis could not resolve the model type for view rendering " + viewPath, aex, this); 33 | return typeof (object); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestImageField.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Interfaces; 2 | 3 | namespace Synthesis.Testing 4 | { 5 | public class TestImageField : TestFileField, IImageField 6 | { 7 | public TestImageField(string url, int? width = null, int? height = null, string alternateText = null) 8 | : base(url) 9 | { 10 | Width = width; 11 | Height = height; 12 | AlternateText = alternateText; 13 | } 14 | 15 | /// 16 | /// Gets the width of the image, if one was entered 17 | /// 18 | public int? Width { get; set; } 19 | 20 | /// 21 | /// Gets the height of the image, if one was entered 22 | /// 23 | public int? Height { get; set; } 24 | 25 | /// 26 | /// Gets the alt text of the image, if any was entered 27 | /// 28 | public string AlternateText { get; set; } 29 | 30 | /// 31 | /// Renders the field using a Sitecore FieldRenderer and returns the result 32 | /// 33 | public string RenderedValue 34 | { 35 | get 36 | { 37 | string tag = $"\"{AlternateText"; 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Source/Synthesis.Tests/FieldTypes/TextFieldTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Synthesis.Tests.Utility; 3 | using Xunit; 4 | 5 | namespace Synthesis.Tests.FieldTypes 6 | { 7 | [Trait("Category", "FieldType Tests")] 8 | public class TextFieldTests : IDisposable 9 | { 10 | public TextFieldTests() 11 | { 12 | new FieldTestTemplateCreator().CreateSampleTemplate(); 13 | } 14 | 15 | public void Dispose() 16 | { 17 | new FieldTestTemplateCreator().DeleteSampleTemplate(); 18 | } 19 | 20 | [Fact(Skip = "TODO")] 21 | public void TextField_GetRawValue_ReturnsValue() 22 | { 23 | 24 | } 25 | 26 | [Fact(Skip = "TODO")] 27 | public void TextField_SetRawValue_SavesValue() 28 | { 29 | 30 | } 31 | 32 | [Fact(Skip = "TODO")] 33 | public void TextField_HasValue_WhenTrue() 34 | { 35 | 36 | } 37 | 38 | [Fact(Skip = "TODO")] 39 | public void TextField_HasValue_WhenEmptyValue() 40 | { 41 | 42 | } 43 | 44 | [Fact(Skip = "TODO")] 45 | public void TextField_HasValue_WhenWhitespaceValue() 46 | { 47 | 48 | } 49 | 50 | [Fact(Skip = "TODO")] 51 | public void TextField_HasTextValue_WhenTrue() 52 | { 53 | 54 | } 55 | 56 | [Fact(Skip = "TODO")] 57 | public void TextField_HasTextValue_WhenEmptyValue() 58 | { 59 | 60 | } 61 | 62 | [Fact(Skip = "TODO")] 63 | public void TextField_HasTextValue_WhenWhitespaceValue() 64 | { 65 | 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Source/Synthesis/Synthesis.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Synthesis.Core 5 | $version$ 6 | Ben Lipson,Kam Figy 7 | Synthesis Team 8 | http://opensource.org/licenses/MIT 9 | https://github.com/blipson89/Synthesis 10 | http://www.benlipson.net/wp-content/uploads/2018/12/synthesis-logo.png 11 | false 12 | 13 | Synthesis is a universal object mapper with LINQ support for Sitecore 8.1 and up. Use the same strongly typed objects to run queries against search indexes or the database, or transparently convert from indexed to database when necessary. Supports fully polymorphic Sitecore template inheritance via a generated interface hierarchy. 14 | 15 | NOTE: Synthesis 9.1.0 and above requires Sitecore 9.1.0 or higher 16 | 17 | Copyright 2021 Ben Lipson/Synthesis Team 18 | sitecore 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/PathItemReferenceField.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data.Fields; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.FieldTypes 5 | { 6 | public class PathItemReferenceField : FieldType, IPathItemReferenceField 7 | { 8 | public PathItemReferenceField(LazyField field, string indexValue) : base(field, indexValue) { } 9 | 10 | /// 11 | /// Gets the item ID that the relationship refers to 12 | /// 13 | public virtual string TargetPath 14 | { 15 | get 16 | { 17 | if (!IsFieldLoaded && InnerSearchValue != null) 18 | { 19 | return InnerSearchValue; 20 | } 21 | 22 | return ((ReferenceField)InnerField).Path; 23 | } 24 | set { SetFieldValue(value); } 25 | } 26 | 27 | /// 28 | /// Gets the entity that the relationship is to. Returns null if the entity doesn't exist. 29 | /// 30 | public virtual IStandardTemplateItem Target 31 | { 32 | get 33 | { 34 | if (HasValue) 35 | return InnerItem.Database.GetItem(TargetPath).AsStronglyTyped(); 36 | 37 | return null; 38 | } 39 | } 40 | 41 | /// 42 | /// Checks if the relationship has a value. Does not check if the ID refers to a valid entity. 43 | /// 44 | public override bool HasValue => !string.IsNullOrWhiteSpace(TargetPath); 45 | 46 | public ReferenceField ToReferenceField() 47 | { 48 | return InnerField; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/Synthesis/Standard Config Files/Synthesis.AutoRegenerate.config: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Source/Synthesis/Generation/NamingUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace Synthesis.Generation 5 | { 6 | internal static class NamingExtensions 7 | { 8 | /// 9 | /// Converts a string into a valid .NET identifier 10 | /// 11 | public static string AsIdentifier(this string identifier) 12 | { 13 | // allow for fields that start with a number 14 | if (char.IsDigit(identifier[0])) 15 | identifier = "_" + identifier; 16 | 17 | return Regex.Replace(identifier, "[^a-zA-Z0-9_\\.]+", string.Empty); 18 | } 19 | 20 | /// 21 | /// Converts a string into a valid .NET identifer that is unique across a collection of existing values 22 | /// 23 | public static string AsNovelIdentifier(this string identifier, ICollection existingValues) 24 | { 25 | return AsNovel(AsIdentifier(identifier), existingValues); 26 | } 27 | 28 | /// 29 | /// Novelizes a string, given a list of existing values, by appending a number to it until it becomes unique 30 | /// 31 | /// The novel name 32 | public static string AsNovel(this string identifier, ICollection existingValues) 33 | { 34 | string fixedId = identifier; 35 | int index = 1; 36 | 37 | while (existingValues.Contains(fixedId)) 38 | { 39 | fixedId = identifier + index; 40 | index++; 41 | } 42 | 43 | return fixedId; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/UI/README.txt: -------------------------------------------------------------------------------- 1 | These classes are designed to be wired to an IoC container of your choice to enable pretty sweet constructor injection into controller renderings. 2 | 3 | The general idea is that you wire IRenderingContext up to SitecoreRenderingContext (and if you wish, IContextDatabase, et al as well to SitecoreRenderingContext). 4 | 5 | You may do the wiring as a singleton as SitecoreRenderingContext has no internal state. 6 | 7 | Then you can simply constructor inject your rendering context, e.g. 8 | 9 | public class Foo : Controller 10 | { 11 | private readonly IRenderingContext _renderingContext; 12 | 13 | public Foo(IRenderingContext renderingContext) 14 | { 15 | Assert.ArgumentNotNull(renderingContext, nameof(renderingContext)); 16 | 17 | _renderingContext = renderingContext; 18 | } 19 | 20 | public ActionResult DoFoo() 21 | { 22 | var model = _renderingContext.GetRenderingDatasource(); 23 | 24 | // TODO: check for null here, which occurs if the datasource is the wrong type or not set (return a different view or Content(string.Empty)) 25 | 26 | return View(model); 27 | } 28 | } 29 | 30 | This buys you stupidly easy unit tests on your controller renderings (without FakeDb!) because now you can speak entirely in Synthesis interfaces which you can fake in your favorite idiom. 31 | 32 | I like NSubstitute, myself. 33 | 34 | See this blog post for additional ideas: http://www.martywoods.nl/unit-testing-sitecore-mvc-its-easy-when-using-synthesis/ -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestDictionaryField.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Specialized; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.Testing 5 | { 6 | /// 7 | /// Represents a field that is a logical dictionary (i.e. a Key Value List) 8 | /// 9 | public class TestDictionaryField : TestFieldType, IDictionaryField 10 | { 11 | private NameValueCollection _values; 12 | 13 | public TestDictionaryField(NameValueCollection values) 14 | { 15 | _values = values ?? new NameValueCollection(); 16 | } 17 | 18 | /// 19 | /// Gets the set of IDs that make up the relationships 20 | /// 21 | public string this[string key] 22 | { 23 | get { return _values[key]; } 24 | set { _values[key] = value; } 25 | } 26 | 27 | /// 28 | /// Checks if the field has at least one key 29 | /// 30 | public override bool HasValue => _values.Count > 0; 31 | 32 | public void Add(string key, string value) 33 | { 34 | _values.Add(key, value); 35 | } 36 | 37 | public bool Remove(string key) 38 | { 39 | if (!ContainsKey(key)) return false; 40 | 41 | _values.Remove(key); 42 | 43 | return true; 44 | } 45 | 46 | public void Clear() 47 | { 48 | _values = new NameValueCollection(); 49 | } 50 | 51 | public bool ContainsKey(string key) 52 | { 53 | return _values[key] != null; 54 | } 55 | 56 | public int Count 57 | { 58 | get { return _values.Count; } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Source/Synthesis/Synthesis.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net471 4 | false 5 | 6 | 7 | bin\Debug\ 8 | TRACE;DEBUG;CODE_ANALYSIS 9 | full 10 | true 11 | 12 | 13 | pdbonly 14 | true 15 | bin\Release\ 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Properties\SharedAssemblyInfo.cs 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/NumericField.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using Sitecore.Web.UI.WebControls; 3 | using Synthesis.FieldTypes.Interfaces; 4 | 5 | namespace Synthesis.FieldTypes 6 | { 7 | public class NumericField : FieldType, INumericField 8 | { 9 | public NumericField(LazyField field, string indexValue) : base(field, indexValue) { } 10 | 11 | /// 12 | /// Gets the value of the field. If the field does not have a value, default(decimal) is returned instead. 13 | /// 14 | public virtual decimal Value 15 | { 16 | get 17 | { 18 | decimal value; 19 | if (decimal.TryParse(InnerField.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out value)) return value; 20 | 21 | return default(decimal); 22 | } 23 | set { SetFieldValue(value.ToString(CultureInfo.InvariantCulture)); } 24 | } 25 | 26 | /// 27 | /// Renders the field using a Sitecore FieldRenderer and returns the result 28 | /// 29 | public virtual string RenderedValue => FieldRenderer.Render(InnerItem, InnerField.ID.ToString()); 30 | 31 | /// 32 | /// Checks if the field has a value 33 | /// 34 | public override bool HasValue 35 | { 36 | get 37 | { 38 | if (InnerField == null) return false; 39 | 40 | decimal value; 41 | return decimal.TryParse(InnerField.Value, out value); 42 | } 43 | } 44 | 45 | public override string ToString() 46 | { 47 | return Value.ToString(CultureInfo.InvariantCulture); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/ConfigureServices.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Sitecore.DependencyInjection; 8 | using Synthesis.ContentSearch; 9 | using Synthesis.Solr.ContentSearch; 10 | 11 | namespace Synthesis.Tests 12 | { 13 | public class ConfigureServices : IDisposable 14 | { 15 | private readonly IServiceScope _scope; 16 | private readonly IServiceProvider _defaultProvider; 17 | public ConfigureServices() 18 | { 19 | IServiceCollection serviceCollection = new ServiceCollection(); 20 | new DefaultSitecoreServicesConfigurator().Configure(serviceCollection); 21 | Configure(serviceCollection); 22 | 23 | _scope = serviceCollection.BuildServiceProvider().CreateScope(); 24 | _defaultProvider = ServiceLocator.ServiceProvider; 25 | ServiceLocator.SetServiceProvider(_scope.ServiceProvider); 26 | } 27 | public void Configure(IServiceCollection serviceCollection) 28 | { 29 | serviceCollection.AddTransient(); 30 | serviceCollection.AddTransient(); 31 | } 32 | 33 | public void Dispose() 34 | { 35 | ServiceLocator.SetServiceProvider(_defaultProvider); 36 | _scope.Dispose(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Adapters/IAxesAdapter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics.CodeAnalysis; 3 | using Sitecore.Data; 4 | 5 | namespace Synthesis.FieldTypes.Adapters 6 | { 7 | public interface IAxesAdapter 8 | { 9 | IStandardTemplateItem Parent { get; } 10 | IStandardTemplateItem[] GetAncestors(); 11 | IStandardTemplateItem GetChild(ID childId); 12 | IStandardTemplateItem GetChild(string itemName); 13 | IStandardTemplateItem GetDescendant(string name); 14 | 15 | [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Following Sitecore Axes naming")] 16 | IEnumerable GetDescendants(); 17 | 18 | IStandardTemplateItem GetItem(string path); 19 | 20 | [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Following Sitecore Axes naming")] 21 | IStandardTemplateItem GetNextSibling(); 22 | 23 | [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Following Sitecore Axes naming")] 24 | IStandardTemplateItem GetPreviousSibling(); 25 | 26 | bool IsAncestorOf(IStandardTemplateItem item); 27 | bool IsDescendantOf(IStandardTemplateItem item); 28 | IEnumerable SelectItems(string query); 29 | IStandardTemplateItem SelectSingleItem(string query); 30 | 31 | [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Following Sitecore Axes naming")] 32 | IEnumerable GetChildren(); 33 | } 34 | } -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestFileField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore.Data; 3 | using Sitecore.Data.Items; 4 | using Sitecore.Resources.Media; 5 | using Synthesis.FieldTypes.Interfaces; 6 | 7 | namespace Synthesis.Testing 8 | { 9 | public class TestFileField : TestFieldType, IFileField 10 | { 11 | public TestFileField(string url) 12 | { 13 | Url = url; 14 | MediaItemId = ID.Null; 15 | } 16 | 17 | /// 18 | /// Gets the URL to the media item. If HasValue is false returns an empty string. 19 | /// 20 | public string Url { get; private set; } 21 | 22 | /// 23 | /// Gets the ID of the media item the mediafield references 24 | /// 25 | public ID MediaItemId { get; set; } 26 | 27 | /// 28 | /// The MediaItem that is the target of the file field 29 | /// 30 | public MediaItem MediaItem 31 | { 32 | get { throw new NotImplementedException("Test field types cannot access Sitecore classes."); } 33 | } 34 | 35 | /// 36 | /// Gets a stream of the binary data in the file field. Make sure to dispose of the object when done! 37 | /// 38 | public MediaStream MediaStream 39 | { 40 | get { throw new NotImplementedException("Test field types cannot access Sitecore classes."); } 41 | } 42 | 43 | /// 44 | /// Checks if the media field has a reference value. Does not validate that the referenced ID actually exists. 45 | /// 46 | public override bool HasValue 47 | { 48 | get { return string.IsNullOrEmpty(Url); } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestItemReferenceField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using Sitecore.Data; 4 | using Sitecore.Data.Fields; 5 | using Synthesis.FieldTypes.Interfaces; 6 | 7 | namespace Synthesis.Testing 8 | { 9 | /// 10 | /// Represents a singular item reference field type (e.g. lookup, droplink, droptree, etc) that stores its value as an ID 11 | /// 12 | public class TestItemReferenceField : TestFieldType, IItemReferenceField 13 | { 14 | public TestItemReferenceField(ID reference = null, IStandardTemplateItem target = null) 15 | { 16 | TargetId = reference; 17 | Target = target; 18 | } 19 | 20 | /// 21 | /// Gets the item ID that the relationship refers to 22 | /// 23 | [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ID", Justification = "Coherent with Sitecore convention")] 24 | public ID TargetId { get; set; } 25 | 26 | /// 27 | /// Gets the entity that the relationship is to. Returns null if the entity doesn't exist. 28 | /// 29 | public IStandardTemplateItem Target { get; } 30 | 31 | /// 32 | /// Checks if the relationship has a value. Does not check if the ID refers to a valid entity. 33 | /// 34 | public override bool HasValue => TargetId != (ID) null && !TargetId.IsNull && !TargetId.IsGlobalNullId; 35 | 36 | public ReferenceField ToReferenceField() 37 | { 38 | throw new NotImplementedException("Test date fields cannot return Sitecore item objects"); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Build/Synthesis.Solr.nuget/Synthesis.Solr.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Synthesis.Solr 5 | $version$ 6 | Ben Lipson,Kam Figy,Jeff Darchuk 7 | Synthesis Team 8 | http://opensource.org/licenses/MIT 9 | https://github.com/blipson89/Synthesis 10 | http://www.benlipson.net/wp-content/uploads/2018/12/synthesis-logo.png 11 | false 12 | 13 | Adds Solr support to Synthesis. This package contains the core library and configuration and is appropriate for the web project. 14 | 15 | NOTE: Synthesis 9.1.0 and above requires Sitecore 9.1.0 or higher 16 | 17 | Copyright 2021 Ben Lipson/Synthesis Team 18 | sitecore,synthesis,solr 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/IntegerField.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using Sitecore.Web.UI.WebControls; 3 | using Synthesis.FieldTypes.Interfaces; 4 | 5 | namespace Synthesis.FieldTypes 6 | { 7 | public class IntegerField : FieldType, IIntegerField 8 | { 9 | public IntegerField(LazyField field, string indexValue) : base(field, indexValue) { } 10 | 11 | /// 12 | /// Gets the value of the field. If the field does not have a value or the value isn't parseable, returns default(int). 13 | /// 14 | public virtual int Value 15 | { 16 | get 17 | { 18 | int value; 19 | if (int.TryParse(InnerField.Value, out value)) return value; 20 | 21 | return default(int); 22 | } 23 | set { SetFieldValue(value.ToString(CultureInfo.InvariantCulture)); } 24 | } 25 | 26 | /// 27 | /// Renders the field using a Sitecore FieldRenderer and returns the result 28 | /// 29 | public virtual string RenderedValue => FieldRenderer.Render(InnerItem, InnerField.ID.ToString()); 30 | 31 | /// 32 | /// Checks if the field has a valid integer value 33 | /// 34 | /// Note that Value will always return a valid int (0) even if HasValue is false. So check this first :) 35 | public override bool HasValue 36 | { 37 | get 38 | { 39 | if (InnerField == null) return false; 40 | 41 | int value; 42 | return int.TryParse(InnerField.Value, out value); 43 | } 44 | } 45 | 46 | public override string ToString() 47 | { 48 | return Value.ToString(CultureInfo.InvariantCulture); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Build/Synthesis.Mvc.nuget/Synthesis.Mvc.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Synthesis.Mvc 5 | $version$ 6 | Ben Lipson,Kam Figy 7 | Synthesis Team 8 | http://opensource.org/licenses/MIT 9 | https://github.com/blipson89/Synthesis 10 | http://www.benlipson.net/wp-content/uploads/2018/12/synthesis-logo.png 11 | false 12 | 13 | Automatic injection of Synthesis models for Sitecore MVC view renderings. This package contains the core library and configuration and is appropriate for the web project. 14 | 15 | NOTE: Synthesis 9.1.0 and above requires Sitecore 9.1.0 or higher 16 | 17 | Copyright 2021 Ben Lipson/Synthesis Team 18 | sitecore 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Synthesis.Mvc.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net471 4 | false 5 | 6 | 7 | bin\Debug\ 8 | TRACE;DEBUG;CODE_ANALYSIS 9 | full 10 | true 11 | 12 | 13 | pdbonly 14 | true 15 | bin\Release\ 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Properties\SharedAssemblyInfo.cs 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Source/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/RenderingDisplayPathResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore.Diagnostics; 3 | using Sitecore.Mvc.Presentation; 4 | using Synthesis.Mvc.Pipelines.GetRenderer; 5 | 6 | namespace Synthesis.Mvc 7 | { 8 | public class RenderingDisplayPathResolver 9 | { 10 | /// 11 | /// Gets the rendering path for the rendering 12 | /// 13 | /// 14 | /// 15 | /// 16 | public virtual string ResolveRenderingPath(Rendering rendering) 17 | { 18 | var renderer = rendering.Renderer; 19 | 20 | if (renderer == null) 21 | { 22 | Log.Warn($"[{nameof(ResolveRenderingPath)}] No renderer was passed to ResolveRenderingPath", this); 23 | } 24 | 25 | if (renderer is RenderingDiagnosticsInjector.DiagnosticsRenderer diags) renderer = diags.InnerRenderer; 26 | 27 | switch (renderer) 28 | { 29 | 30 | case ViewRenderer view: 31 | return view.ViewPath; 32 | case ControllerRenderer controller: 33 | return controller.ControllerName + "::" + controller.ActionName; 34 | case MethodRenderer method: 35 | return method.TypeName + "." + method.MethodName + "()"; 36 | } 37 | 38 | if (renderer != null) 39 | { 40 | Log.Warn($"[{nameof(ResolveRenderingPath)}] Unhandled renderer passed to {nameof(ResolveRenderingPath)}: {renderer.GetType().FullName}", this); 41 | } 42 | 43 | if (rendering.Item == null) 44 | { 45 | Log.Error($"[{nameof(ResolveRenderingPath)}] Rendering item is null", this); 46 | return string.Empty; 47 | } 48 | 49 | return rendering.Item.Paths.FullPath; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Extensions/FileFields.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Text; 3 | using System.Web; 4 | using System.Web.Mvc; 5 | using Synthesis.FieldTypes.Interfaces; 6 | 7 | namespace Synthesis.Mvc.Extensions 8 | { 9 | /// 10 | /// Extensions to enable simple rendering of Synthesis field types in Sitecore MVC 11 | /// These are the preferred method of emitting Synthesis models to the markup as they handle 12 | /// things like HTML encoding and field renderer parameters for you. 13 | /// 14 | /// They are very simple to use: 15 | /// 16 | /// @mySynthesisObject.Field.Render() 17 | /// 18 | public static class FileHelper 19 | { 20 | public static IHtmlString Render(this IFileField field, string linkText = null, string cssClass = null) 21 | { 22 | return Render(field, linkText, new { @class = cssClass }); 23 | } 24 | 25 | public static IHtmlString Render(this IFileField field, string linkText, object attributes) 26 | { 27 | if (field.HasValue) 28 | { 29 | var sb = new StringBuilder(); 30 | sb.Append(" x.CanRead)) 35 | { 36 | var value = attribute.GetValue(attributes, null); 37 | 38 | if (value == null) continue; 39 | 40 | sb.AppendFormat(" {0}=\"{1}\"", attribute.Name.Replace('_', '-'), HttpUtility.HtmlEncode(value)); 41 | } 42 | 43 | sb.Append(">"); 44 | sb.Append(linkText ?? field.Url); 45 | sb.Append(""); 46 | 47 | return new MvcHtmlString(sb.ToString()); 48 | } 49 | 50 | return new MvcHtmlString(string.Empty); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Extensions/DateFields.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using System.Web.Mvc; 4 | using Sitecore.Web.UI.WebControls; 5 | using Synthesis.FieldTypes.Interfaces; 6 | 7 | namespace Synthesis.Mvc.Extensions 8 | { 9 | /// 10 | /// Extensions to enable simple rendering of Synthesis field types in Sitecore MVC 11 | /// These are the preferred method of emitting Synthesis models to the markup as they handle 12 | /// things like HTML encoding and field renderer parameters for you. 13 | /// 14 | /// They are very simple to use: 15 | /// 16 | /// @mySynthesisObject.Field.Render() 17 | /// 18 | public static class DateFields 19 | { 20 | public static IHtmlString Render(this IDateTimeField field) 21 | { 22 | return Render(field, "g", true); 23 | } 24 | 25 | public static IHtmlString Render(this IDateTimeField field, bool editable) 26 | { 27 | return Render(field, "g", editable); 28 | } 29 | 30 | public static IHtmlString Render(this IDateTimeField field, string format) 31 | { 32 | return Render(field, format, true); 33 | } 34 | 35 | public static IHtmlString Render(this IDateTimeField field, string format, bool editable) 36 | { 37 | return Render(field, x => 38 | { 39 | x.Format = format; 40 | x.DisableWebEditing = !editable; 41 | }); 42 | } 43 | 44 | public static IHtmlString Render(IDateTimeField field, Action parameters) 45 | { 46 | if (field.HasValue || Sitecore.Context.PageMode.IsExperienceEditor) 47 | { 48 | var date = new Date(); 49 | date.AttachToDateTimeField(field); 50 | parameters(date); 51 | 52 | return new MvcHtmlString(date.RenderAsText()); 53 | } 54 | 55 | return new MvcHtmlString(string.Empty); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Source/Synthesis/ContentSearch/SynthesisFieldNameTranslator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Sitecore.ContentSearch; 6 | 7 | namespace Synthesis.ContentSearch 8 | { 9 | /// 10 | /// This translates field names into the index the same way Synthesis generates them for objects. 11 | /// 12 | public class SynthesisFieldNameTranslator : AbstractFieldNameTranslator 13 | { 14 | private readonly AbstractFieldNameTranslator _innerTranslator; 15 | 16 | public SynthesisFieldNameTranslator(AbstractFieldNameTranslator innerTranslator) 17 | { 18 | _innerTranslator = innerTranslator; 19 | } 20 | 21 | public override string GetIndexFieldName(MemberInfo member) 22 | { 23 | return _innerTranslator.GetIndexFieldName(member); 24 | } 25 | 26 | public override string GetIndexFieldName(string fieldName, Type returnType) 27 | { 28 | return _innerTranslator.GetIndexFieldName(PreProcessSynthesisFieldName(fieldName), returnType); 29 | } 30 | 31 | public override string GetIndexFieldName(string fieldName) 32 | { 33 | return _innerTranslator.GetIndexFieldName(PreProcessSynthesisFieldName(fieldName)); 34 | } 35 | 36 | public override Dictionary> MapFieldsToType(IEnumerable fieldNames, Type type, MappingTargetType target) 37 | { 38 | return _innerTranslator.MapFieldsToType(fieldNames, type, target); 39 | } 40 | 41 | public override IEnumerable GetTypeFieldNames(string fieldName) 42 | { 43 | return _innerTranslator.GetTypeFieldNames(fieldName); 44 | } 45 | 46 | protected virtual string PreProcessSynthesisFieldName(string fieldName) 47 | { 48 | return fieldName.Split('.').First(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Build/Synthesis.nuget/readme.txt: -------------------------------------------------------------------------------- 1 | SYNTHESIS README 2 | 3 | Thanks for installing Synthesis! Here are some tips to get you started: 4 | 5 | First, you should set up your base configuration. 6 | Make a copy of App_Config\Include\Synthesis.LocalConfig.config.example, and rename it to .config. 7 | Tweak your namespaces and output locations to your liking within your patch file. 8 | 9 | Next, you'll want to run a build so the Synthesis assemblies are in your /bin folder and don't cause an error. 10 | 11 | To generate your model, go to /synthesis.aspx on your project in a web browser. 12 | Should this URL not work, you may need to change the activationUrl at the bottom of the config file to not include the aspx and try /synthesis 13 | If you do not see an option to regenerate your model, make sure you have in your web.config as regeneration is disabled in release mode. 14 | 15 | Finally, in Visual Studio set the project to Show All Files and include your generated code file for compilation. 16 | This file will be located at the ModelOutputPath in your config patch you created. 17 | 18 | NOTE: your project including the model classes must reference Sitecore.Kernel and Sitecore.ContentSearch.Linq for the model to compile. 19 | 20 | Using modular architecture (e.g. Habitat) and need a model per module? See the example in the GitHub [README.md](https://github.com/blipson89/Synthesis) for directions to create a configuration registration. 21 | 22 | Want deeper documentation? The Synthesis Wiki on GitHub has you covered: https://github.com/blipson89/Synthesis/wiki 23 | 24 | Have questions? Tweet @bllipson or find me on Sitecore Community Slack. 25 | 26 | Found a bug? Send me a pull request on GitHub if you're feeling awesome: https://github.com/blipson89/Synthesis 27 | (or an issue if you're feeling lazy) -------------------------------------------------------------------------------- /Source/Synthesis.Solr.Tests/App_Config/Include/Sitecore.ContentSearch.Solr.Index.Master.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | $(id) 9 | sitecore_master_index 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | master 18 | /sitecore 19 | 20 | 21 | false 22 | false 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Source/Synthesis/Synchronization/RepresentsSitecoreTemplateAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore.StringExtensions; 3 | 4 | namespace Synthesis.Synchronization 5 | { 6 | /// 7 | /// Tags an interface as representing a Sitecore template of a particular version. Used for synchronization checks. 8 | /// 9 | [AttributeUsage(AttributeTargets.Interface)] 10 | public sealed class RepresentsSitecoreTemplateAttribute : Attribute 11 | { 12 | [Obsolete("This is only here to help upgraders not break the build")] 13 | public RepresentsSitecoreTemplateAttribute(string templateId, string versionSignature) : this(templateId, versionSignature, null) 14 | { 15 | } 16 | 17 | /// 18 | /// Constructor 19 | /// 20 | /// Sitecore Template ID represented 21 | /// Signature of the template version this represents (generated by a TemplateSignatureProvider) 22 | /// Name of the Synthesis configuration the template belongs to 23 | public RepresentsSitecoreTemplateAttribute(string templateId, string versionSignature, string configurationName) 24 | { 25 | TemplateId = templateId; 26 | VersionSignature = versionSignature; 27 | ConfigurationName = configurationName.IsNullOrEmpty() ? "Default Configuration" : configurationName; 28 | } 29 | 30 | /// 31 | /// Sitecore Template ID represented 32 | /// 33 | public string TemplateId { get; private set; } 34 | 35 | /// 36 | /// Signature of the template version this represents (generated by a TemplateSignatureProvider) 37 | /// 38 | public string VersionSignature { get; private set; } 39 | 40 | public string ConfigurationName { get; private set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Utility/TestItemContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore.Configuration; 3 | using Sitecore.Data; 4 | using Sitecore.Data.Fields; 5 | using Sitecore.Data.Items; 6 | using Sitecore.SecurityModel; 7 | 8 | namespace Synthesis.Tests.Utility 9 | { 10 | internal class TestItemContext : IDisposable 11 | { 12 | const string ROOT_PATH = "/sitecore/content"; 13 | 14 | internal TestItemContext() 15 | { 16 | var testName = "test-" + ID.NewID.ToShortID(); 17 | var database = Sitecore.Context.Database; 18 | 19 | using (new SecurityDisabler()) 20 | { 21 | var parent = database.GetItem(ROOT_PATH); 22 | TestItem = parent.Add(testName, new TemplateID(FieldTestTemplateCreator.CurrentTestTemplateID)); 23 | Xunit.Assert.NotNull(TestItem); 24 | } 25 | } 26 | 27 | internal TestItemContext(TemplateID templateId) 28 | { 29 | var testName = "test-" + ID.NewID.ToShortID(); 30 | var database = Factory.GetDatabase("master"); 31 | 32 | using (new SecurityDisabler()) 33 | { 34 | var parent = database.GetItem(ROOT_PATH); 35 | TestItem = parent.Add(testName, templateId); 36 | } 37 | } 38 | 39 | internal Item TestItem { get; private set; } 40 | 41 | internal void SetField(string fieldName, string fieldValue) 42 | { 43 | using (new SecurityDisabler()) 44 | {using (new EditContext(TestItem)) 45 | 46 | { 47 | TestItem[fieldName] = fieldValue; 48 | } 49 | } 50 | } 51 | 52 | internal Field this[string fieldname] => TestItem.Fields[fieldname]; 53 | 54 | public void Dispose() 55 | { 56 | if (TestItem == null) return; 57 | 58 | using (new SecurityDisabler()) 59 | { 60 | TestItem.Delete(); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Adapters/EditingAdapter.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Data.Items; 2 | 3 | namespace Synthesis.FieldTypes.Adapters 4 | { 5 | public class EditingAdapter : IEditingAdapter 6 | { 7 | private readonly ItemEditing _itemEditing; 8 | 9 | public EditingAdapter(ItemEditing itemEditing) 10 | { 11 | _itemEditing = itemEditing; 12 | } 13 | 14 | /// 15 | /// Gets a value that indicates if the item is being edited. 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// true if this instance is editing; otherwise, false. 21 | /// 22 | /// 23 | public bool IsEditing => _itemEditing.IsEditing; 24 | 25 | /// 26 | /// Marks the beginning of an editing operation. 27 | /// 28 | /// 29 | public void BeginEdit() 30 | { 31 | _itemEditing.BeginEdit(); 32 | } 33 | 34 | /// 35 | /// Cancels the edit. 36 | /// 37 | /// 38 | public void CancelEdit() 39 | { 40 | _itemEditing.CancelEdit(); 41 | } 42 | 43 | /// 44 | /// Ends an edit operation. 45 | /// 46 | /// 47 | /// 48 | /// 49 | /// The edit. 50 | /// 51 | /// 52 | /// 53 | /// 54 | /// 55 | /// Editing an item without calling BeginEdit throws an exception. 56 | /// 57 | /// 58 | /// 59 | /// It is usually easier and more readable to using the EditContext class instead 60 | /// of a BeginEdit and EndEdit pair. 61 | /// 62 | /// 63 | /// 64 | public bool EndEdit() 65 | { 66 | return _itemEditing.EndEdit(); 67 | } 68 | 69 | /// 70 | /// Rejects the changes. 71 | /// 72 | /// 73 | public void RejectChanges() 74 | { 75 | _itemEditing.RejectChanges(); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/TextField.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Web.UI.WebControls; 2 | using Synthesis.FieldTypes.Interfaces; 3 | 4 | namespace Synthesis.FieldTypes 5 | { 6 | public class TextField : FieldType, ITextField 7 | { 8 | public TextField(LazyField field, string indexValue) : base(field, indexValue) { } 9 | 10 | /// 11 | /// Gets the raw value of the field. If the value is null an empty string will be returned. 12 | /// For rich text fields, this will not expand dynamic links in the content - use ExpandedLinksValue for that 13 | /// Setting this value will cause the underlying item to be loaded for search-based instances. 14 | /// 15 | public virtual string RawValue 16 | { 17 | get 18 | { 19 | if(!IsFieldLoaded && InnerSearchValue != null) return InnerSearchValue; 20 | return InnerField?.Value; 21 | } 22 | set { SetFieldValue(value); } 23 | } 24 | 25 | /// 26 | /// Renders the field using a Sitecore FieldRenderer and returns the result 27 | /// Getting this value will cause the underlying item to be loaded for search-based instances. 28 | /// 29 | public virtual string RenderedValue => FieldRenderer.Render(InnerItem, InnerField.ID.ToString()); 30 | 31 | /// 32 | /// Checks if the field has a null or empty value 33 | /// 34 | public override bool HasValue => !string.IsNullOrEmpty(RawValue); 35 | 36 | /// 37 | /// Checks if the field has a null, empty, or whitespace-only value 38 | /// 39 | public virtual bool HasTextValue => !string.IsNullOrWhiteSpace(RawValue); 40 | 41 | /// 42 | /// Converts the field into it's string representation. Returns the same value as the RawValue property. 43 | /// 44 | public override string ToString() 45 | { 46 | return RawValue; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/FieldTypes/FileFieldTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Synthesis.Tests.Utility; 3 | using Xunit; 4 | 5 | namespace Synthesis.Tests.FieldTypes 6 | { 7 | [Trait("Category", "FieldType Tests")] 8 | public class FileFieldTests : IDisposable 9 | { 10 | public FileFieldTests() 11 | { 12 | new FieldTestTemplateCreator().CreateSampleTemplate(); 13 | } 14 | 15 | public void Dispose() 16 | { 17 | new FieldTestTemplateCreator().DeleteSampleTemplate(); 18 | } 19 | 20 | [Fact(Skip = "TODO")] 21 | public void FileField_GetUrl_IsResultValid() 22 | { 23 | 24 | } 25 | 26 | [Fact(Skip = "TODO")] 27 | public void FileField_GetUrl_ReturnsEmptyStringWhenNoFile() 28 | { 29 | 30 | } 31 | 32 | [Fact(Skip = "TODO")] 33 | public void FileField_GetMediaItemID_ValidMediaItem() 34 | { 35 | 36 | } 37 | 38 | [Fact(Skip = "TODO")] 39 | public void FileField_GetMediaItemID_InvalidMediaItem() 40 | { 41 | 42 | } 43 | 44 | [Fact(Skip = "TODO")] 45 | public void FileField_SetMediaItemID_SavesValue() 46 | { 47 | 48 | } 49 | 50 | [Fact(Skip = "TODO")] 51 | public void FileField_HasValue_WhenTrue() 52 | { 53 | 54 | } 55 | 56 | [Fact(Skip = "TODO")] 57 | public void FileField_HasValue_WhenFalse() 58 | { 59 | 60 | } 61 | 62 | [Fact(Skip = "TODO")] 63 | public void FileField_AttachLink_SetsInvisibleWhenNoValue() 64 | { 65 | 66 | } 67 | 68 | [Fact(Skip = "TODO")] 69 | public void FileField_AttachLink_SetsCorrectUrl() 70 | { 71 | 72 | } 73 | 74 | [Fact(Skip = "TODO")] 75 | public void FileField_RenderLink_RendersNothingWhenNoValue() 76 | { 77 | 78 | } 79 | 80 | [Fact(Skip = "TODO")] 81 | public void FileField_RenderLink_RendersCorrectLink() 82 | { 83 | 84 | } 85 | 86 | [Fact(Skip = "TODO")] 87 | public void FileField_CanImplicitCastToSitecoreFileField() 88 | { 89 | 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Helpers/TextHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using System.Web.Mvc; 4 | using Synthesis.FieldTypes; 5 | using Synthesis.FieldTypes.Interfaces; 6 | 7 | namespace Synthesis.Mvc.Helpers 8 | { 9 | /// 10 | /// HTML helpers to enable simple rendering of Synthesis field types in Sitecore MVC 11 | /// These are the preferred method of emitting Synthesis models to the markup as they handle 12 | /// things like HTML encoding and field renderer parameters for you. 13 | /// 14 | /// They all work similar to the form helpers in that they're lambdas on the model: 15 | /// 16 | /// @Html.TextFor(x=>x.MyTextField) 17 | /// 18 | /// You can also use them on non-model Synthesis objects if needed: 19 | /// 20 | /// @Html.ImageFor(x=>someObject.ImageField, "image-class") 21 | /// 22 | public static class TextHelper 23 | { 24 | [Obsolete("Use the Synthesis.Mvc.Extensions ITextField.Render() extension methods instead for improved readability.")] 25 | public static IHtmlString TextFor(this HtmlHelper helper, Func selector) 26 | { 27 | return TextFor(helper, selector, true); 28 | } 29 | 30 | [Obsolete("Use the Synthesis.Mvc.Extensions ITextField.Render() extension methods instead for improved readability.")] 31 | public static IHtmlString TextFor(this HtmlHelper helper, Func selector, bool editable) 32 | { 33 | var field = selector(helper.ViewData.Model); 34 | 35 | if (field.HasTextValue || Sitecore.Context.PageMode.IsExperienceEditor) 36 | { 37 | if (editable) 38 | return new MvcHtmlString(field.RenderedValue); 39 | 40 | var richText = field as RichTextField; 41 | 42 | if (richText != null) return new MvcHtmlString(richText.ExpandedLinksValue); 43 | 44 | return new MvcHtmlString(field.RawValue); 45 | } 46 | 47 | return new MvcHtmlString(string.Empty); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Source/Synthesis/EventHandlers/AutomaticModelRebuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Sitecore; 4 | using Sitecore.Data.Items; 5 | using Sitecore.Diagnostics; 6 | using Sitecore.Events; 7 | using Synthesis.Utility; 8 | 9 | namespace Synthesis.EventHandlers 10 | { 11 | public class AutomaticModelRebuilder 12 | { 13 | protected static readonly Timer RegenerateTimer = new Timer(Regenerate); 14 | const int RegenerateDelayMs = 500; 15 | 16 | public void OnItemSavedMovedRenamedOrDeleted(object sender, EventArgs e) 17 | { 18 | var item = Event.ExtractParameter(e, 0); 19 | 20 | Process(item); 21 | } 22 | 23 | public virtual void Process(Item item) 24 | { 25 | // disable if compilation debug=true is in web.config (e.g. deployed off dev box) 26 | if (!DebugUtility.IsDynamicDebugEnabled) return; 27 | 28 | if (item == null) return; 29 | 30 | // not a template change, ignore 31 | if (item.TemplateID != TemplateIDs.Template && item.TemplateID != TemplateIDs.TemplateField) return; 32 | 33 | // not in master db, ignore 34 | if (!item.Database.Name.Equals("master")) return; 35 | 36 | // signal regeneration to start in the delay time 37 | // if additional events trigger this (like say saving 20 template fields) 38 | // they will push the timer further out and it will fire [delay] after the last event has completed. 39 | RegenerateTimer.Change(RegenerateDelayMs, Timeout.Infinite); 40 | } 41 | 42 | private static void Regenerate(object obj) 43 | { 44 | Log.Info("[AutomaticModelRebuilder] Regenerating Synthesis models due to change in template items.", typeof(AutomaticModelRebuilder)); 45 | try 46 | { 47 | SynthesisHelper.RegenerateAll(); 48 | } 49 | catch (Exception ex) 50 | { 51 | Log.Error("[AutomaticModelRebuilder] An error occurred rebuilding the model.", ex, typeof(AutomaticModelRebuilder)); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Extensions/TextFields.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using Sitecore.Sites; 3 | using Synthesis.FieldTypes; 4 | using Synthesis.FieldTypes.Interfaces; 5 | using Synthesis.Mvc.Utility; 6 | 7 | namespace Synthesis.Mvc.Extensions 8 | { 9 | /// 10 | /// Extensions to enable simple rendering of Synthesis field types in Sitecore MVC 11 | /// These are the preferred method of emitting Synthesis models to the markup as they handle 12 | /// things like HTML encoding and field renderer parameters for you. 13 | /// 14 | /// They are very simple to use: 15 | /// 16 | /// @mySynthesisObject.Field.Render() 17 | /// 18 | public static class TextFields 19 | { 20 | public static IHtmlString Render(this ITextField field) 21 | { 22 | return Render(field, true); 23 | } 24 | 25 | public static IHtmlString Render(this ITextField field, bool editable, params object[] formatParameters) 26 | { 27 | var isEditing = Sitecore.Context.PageMode.IsExperienceEditor; 28 | 29 | if (field.HasTextValue || isEditing) 30 | { 31 | if (editable) 32 | { 33 | string result = field.RenderedValue; 34 | 35 | if (!isEditing) 36 | { 37 | result = Format(field.RenderedValue, formatParameters); 38 | } 39 | 40 | return new HtmlString(result); 41 | } 42 | 43 | var richText = field as RichTextField; 44 | 45 | if (richText != null) return new HtmlString(Format(richText.ExpandedLinksValue, formatParameters)); 46 | 47 | using (new DisplayModeSwitcher(DisplayMode.Normal)) 48 | { 49 | return new HtmlString(Format(field.RenderedValue, formatParameters)); 50 | } 51 | } 52 | 53 | return new HtmlString(string.Empty); 54 | } 55 | 56 | private static string Format(string value, object[] parameters) 57 | { 58 | if (parameters == null || parameters.Length == 0) return value; 59 | 60 | return string.Format(value, parameters); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Extensions/HyperlinkFields.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using System.Web.Mvc; 4 | using Sitecore.Web.UI.WebControls; 5 | using Synthesis.FieldTypes; 6 | using Synthesis.FieldTypes.Interfaces; 7 | 8 | namespace Synthesis.Mvc.Extensions 9 | { 10 | /// 11 | /// Extensions to enable simple rendering of Synthesis field types in Sitecore MVC 12 | /// These are the preferred method of emitting Synthesis models to the markup as they handle 13 | /// things like HTML encoding and field renderer parameters for you. 14 | /// 15 | /// They are very simple to use: 16 | /// 17 | /// @mySynthesisObject.Field.Render() 18 | /// 19 | public static class HyperlinkFields 20 | { 21 | public static IHtmlString Render(this IHyperlinkField field, string linkText = null, string cssClass = null, bool editable = true) 22 | { 23 | return Render(field, x => 24 | { 25 | if (linkText != null) 26 | x.Text = linkText; 27 | 28 | if (cssClass != null) 29 | x.CssClass = cssClass; 30 | 31 | if(!editable) 32 | x.DisableWebEditing = true; 33 | }); 34 | } 35 | 36 | public static IHtmlString Render(this IHyperlinkField field, Action parameters) 37 | { 38 | if (field.HasValue || Sitecore.Context.PageMode.IsExperienceEditor) 39 | { 40 | var link = new Link(); 41 | link.AttachToLinkField(field); 42 | parameters(link); 43 | 44 | return new MvcHtmlString(link.RenderAsText()); 45 | } 46 | 47 | return new MvcHtmlString(string.Empty); 48 | } 49 | 50 | public static IDisposable RenderWithBody(this IHyperlinkField field, HtmlHelper helper, string cssClass = null) 51 | { 52 | object parameters = new { haschildren = true }; 53 | 54 | if (cssClass != null) 55 | { 56 | parameters = new { haschildren = true, @class = cssClass }; 57 | } 58 | 59 | return new TagRenderingContext(helper, (FieldType)field, parameters); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/FieldTypes/ContentHubImageFieldTests.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.Tests.Utility; 2 | using Xunit; 3 | 4 | namespace Synthesis.Tests.FieldTypes 5 | { 6 | [Trait("Category", "FieldType Tests")] 7 | public class ContentHubImageFieldTests 8 | { 9 | public ContentHubImageFieldTests() 10 | { 11 | new FieldTestTemplateCreator().CreateSampleTemplate(); 12 | } 13 | 14 | public void Disposable() 15 | { 16 | new FieldTestTemplateCreator().DeleteSampleTemplate(); 17 | } 18 | 19 | [Fact(Skip = "TODO")] 20 | public void ContentHubImageField_GetContentId_ReturnsCorrectValue() 21 | { 22 | 23 | } 24 | 25 | [Fact(Skip = "TODO")] 26 | public void ContentHubImageField_GetContentId_ReturnsEmptyStringWhenBlank() 27 | { 28 | 29 | } 30 | 31 | [Fact(Skip = "TODO")] 32 | public void ContentHubImageField_SetContentId_SavesValue() 33 | { 34 | 35 | } 36 | 37 | [Fact(Skip = "TODO")] 38 | public void ContentHubImageField_GetThumbnailSrc_ReturnsCorrectValue() 39 | { 40 | 41 | } 42 | 43 | [Fact(Skip = "TODO")] 44 | public void ContentHubImageField_GetThumbnailSrc_ReturnsEmptyStringWhenBlank() 45 | { 46 | 47 | } 48 | 49 | [Fact(Skip = "TODO")] 50 | public void ContentHubImageField_SetThumbnailSrc_SavesValue() 51 | { 52 | 53 | } 54 | 55 | [Fact(Skip = "TODO")] 56 | public void ContentHubImageField_GetContentType_ReturnsCorrectValue() 57 | { 58 | 59 | } 60 | 61 | [Fact(Skip = "TODO")] 62 | public void ContentHubImageField_GetContentType_ReturnsEmptyStringWhenBlank() 63 | { 64 | 65 | } 66 | 67 | [Fact(Skip = "TODO")] 68 | public void ContentHubImageField_SetContentType_SavesValue() 69 | { 70 | 71 | } 72 | 73 | [Fact(Skip = "TODO")] 74 | public void ContentHubImageField_CanImplicitCastToContentHubImageField() 75 | { 76 | 77 | } 78 | 79 | [Fact(Skip = "TODO")] 80 | public void ContentHubImageField_HasValue_WhenTrue() 81 | { 82 | 83 | } 84 | 85 | [Fact(Skip = "TODO")] 86 | public void ContentHubImageField_HasValue_WhenFalse() 87 | { 88 | 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/UI/IRenderingContext.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.Mvc.Presentation; 2 | 3 | namespace Synthesis.Mvc.UI 4 | { 5 | public interface IRenderingContext : IContextItem, IContextSite, IContextDatabase, IContextIndex 6 | { 7 | /// 8 | /// Gets the current rendering's datasource as an expected type 9 | /// 10 | /// The datasource, if it is set and of the correct template. Or null if not set or the wrong template. Returns the context item if the datasource is not set. 11 | TItem GetRenderingDatasource() 12 | where TItem : class, IStandardTemplateItem; 13 | 14 | /// 15 | /// Gets the current rendering's datasource 16 | /// Returns the context item if the datasource is not set. 17 | /// 18 | IStandardTemplateItem RenderingDatasource { get; } 19 | 20 | /// 21 | /// Gets the current rendering's parameters. 22 | /// Returns empty parameters if no rendering is in context. 23 | /// 24 | RenderingParameters Parameters { get; } 25 | 26 | /// 27 | /// Is Experience Editor enabled (exclusive of IsPreview, IsNormal) 28 | /// 29 | bool IsEditing { get; } 30 | 31 | /// 32 | /// Is Preview enabled (exclusive of IsEditing, IsNormal) 33 | /// 34 | bool IsPreview { get; } 35 | 36 | /// 37 | /// Is Normal page rendering enabled (exclusive of IsEditing, IsPreview). NOTE: Debugging or Experience Explorer may be active when IsNormal=true. 38 | /// 39 | bool IsNormal { get; } 40 | 41 | /// 42 | /// Is the Experience Explorer active? 43 | /// 44 | bool IsExperienceExplorer { get; } 45 | 46 | /// 47 | /// Is the Sitecore Debugger active? 48 | /// 49 | bool IsDebugging { get; } 50 | 51 | /// 52 | /// Is the page rendering completely normal? In other words, both Normal page mode and NOT debugging and NOT experience explorer - what an end user would see. 53 | /// 54 | bool IsCompletelyNormal { get; } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Source/Synthesis/Templates/Sha1TemplateSignatureProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Security.Cryptography; 5 | using System.Text; 6 | 7 | namespace Synthesis.Templates 8 | { 9 | /// 10 | /// Provides a signature of a template based on the SHA-1 hash of its path, ID and field names, IDs, and types 11 | /// This should be a unique signature for all modifications that would affect the standard domain model generation 12 | /// 13 | [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sha", Justification="It's a hash algorithm name")] 14 | public class Sha1TemplateSignatureProvider : ITemplateSignatureProvider 15 | { 16 | public virtual string GenerateTemplateSignature(ITemplateInfo templateItem) 17 | { 18 | string signatureText = GenerateTextSignature(templateItem); 19 | return HashTextSignature(signatureText); 20 | } 21 | 22 | protected virtual string GenerateTextSignature(ITemplateInfo templateItem) 23 | { 24 | List keyElements = new List(); 25 | 26 | keyElements.Add(templateItem.FullPath); // full path will cover us for namespace changes 27 | keyElements.Add(templateItem.TemplateId.ToString()); // ID is used for creating new items and syncing 28 | 29 | foreach (var field in templateItem.OwnFields) 30 | { 31 | keyElements.Add(field.Name); // name determines property names 32 | keyElements.Add(field.Id.ToString()); // ID determines internal property lookups for speed 33 | keyElements.Add(field.Type); // type determines property Type 34 | } 35 | 36 | keyElements.Sort(); // sorting these gives us a standard order, so that merely reordering fields doesn't potentially invalidate the signature 37 | 38 | return string.Join("|", keyElements.ToArray()); 39 | } 40 | 41 | protected virtual string HashTextSignature(string rawSignature) 42 | { 43 | byte[] hash = new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(rawSignature)); 44 | 45 | return Convert.ToBase64String(hash); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Source/Synthesis/Utility/ObjectActivator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using System.Reflection; 4 | 5 | namespace Synthesis.Utility 6 | { 7 | public delegate T ObjectActivator(params object[] args); 8 | /// 9 | /// Dynamic Activator using compiled lambda expressions. Performs better than Activator.CreateInstance 10 | /// 11 | /// 12 | /// Credit: Roger Johansson (https://rogerjohansson.blog/2008/02/28/linq-expressions-creating-objects) 13 | /// 14 | /// 15 | public static class ObjectActivator 16 | { 17 | public static ObjectActivator GetActivator(ConstructorInfo ctor) 18 | { 19 | var paramsInfo = ctor.GetParameters(); 20 | 21 | //create a single param of type object[] 22 | ParameterExpression param = Expression.Parameter(typeof(object[]), "args"); 23 | 24 | var argsExp = new Expression[paramsInfo.Length]; 25 | 26 | //pick each arg from the params array 27 | //and create a typed expression of them 28 | for (var i = 0; i < paramsInfo.Length; i++) 29 | { 30 | Expression index = Expression.Constant(i); 31 | Type paramType = paramsInfo[i].ParameterType; 32 | Expression paramAccessorExp = Expression.ArrayIndex(param, index); 33 | Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType); 34 | argsExp[i] = paramCastExp; 35 | } 36 | 37 | //make a NewExpression that calls the 38 | //ctor with the args we just created 39 | NewExpression newExp = Expression.New(ctor, argsExp); 40 | 41 | //create a lambda with the New 42 | //Expression as body and our param object[] as arg 43 | LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp, param); 44 | 45 | //compile it 46 | var compiled = (ObjectActivator)lambda.Compile(); 47 | return compiled; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Synthesis.Solr/ContentSearch/ResolveSolrQueryable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Sitecore.ContentSearch; 5 | using Sitecore.ContentSearch.Linq.Common; 6 | using Sitecore.ContentSearch.SolrProvider; 7 | using Sitecore.Diagnostics; 8 | using Synthesis.ContentSearch; 9 | using Synthesis.Pipelines; 10 | 11 | namespace Synthesis.Solr.ContentSearch 12 | { 13 | public class ResolveSolrQueryable : IQueryableResolver 14 | { 15 | private readonly IFieldNameTranslatorFactory _fieldNameTranslator; 16 | 17 | public ResolveSolrQueryable(IFieldNameTranslatorFactory fieldNameTranslator) 18 | { 19 | _fieldNameTranslator = fieldNameTranslator; 20 | } 21 | public IQueryable GetSynthesisQueryable(SynthesisSearchContextArgs args) where TResult : IStandardTemplateItem 22 | { 23 | Assert.IsNotNull(args, "Args must not be null"); 24 | if (!(args.SearchContext is SolrSearchContext solrContext)) 25 | throw new NotImplementedException("A Solr index is not being used, if you're using Azure make sure that you're not overridding the synthesisSearchContext pipeline with the Solr processor"); 26 | 27 | var overrideMapper = new SynthesisSolrDocumentTypeMapper(); 28 | overrideMapper.Initialize(args.SearchContext.Index); 29 | var mapperExecutionContext = new OverrideExecutionContext>>(overrideMapper); 30 | var executionContexts = new List(); 31 | if (args.ExecutionContext != null) executionContexts.AddRange(args.ExecutionContext); 32 | executionContexts.Add(mapperExecutionContext); 33 | return GetSolrQueryable(solrContext, executionContexts.ToArray()); 34 | } 35 | private IQueryable GetSolrQueryable(SolrSearchContext context, IExecutionContext[] executionContext) 36 | where TResult : IStandardTemplateItem 37 | { 38 | context.Index.FieldNameTranslator = _fieldNameTranslator.GetFieldNameTranslator(context.Index); 39 | return context.GetQueryable(executionContext); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/ItemReferenceField.cs: -------------------------------------------------------------------------------- 1 | using Sitecore.ContentSearch.Converters; 2 | using Sitecore.Data; 3 | using Sitecore.Data.Fields; 4 | using System.Diagnostics.CodeAnalysis; 5 | using Synthesis.FieldTypes.Interfaces; 6 | 7 | namespace Synthesis.FieldTypes 8 | { 9 | /// 10 | /// Represents a singular item reference field type (e.g. lookup, droplink, droptree, etc) that stores its value as an ID 11 | /// 12 | public class ItemReferenceField : FieldType, IItemReferenceField 13 | { 14 | public ItemReferenceField(LazyField field, string indexValue) : base(field, indexValue) { } 15 | 16 | /// 17 | /// Gets the item ID that the relationship refers to 18 | /// 19 | [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ID", Justification = "Coherent with Sitecore convention")] 20 | public virtual ID TargetId 21 | { 22 | get 23 | { 24 | if (!IsFieldLoaded && InnerSearchValue != null) 25 | { 26 | var converter = new IndexFieldIDValueConverter(); 27 | // ReSharper disable once PossibleNullReferenceException 28 | return (ID)converter.ConvertFrom(InnerSearchValue); 29 | } 30 | 31 | return ((ReferenceField)InnerField).TargetID; 32 | } 33 | set { SetFieldValue(value.ToString()); } 34 | } 35 | 36 | /// 37 | /// Gets the entity that the relationship is to. Returns null if the entity doesn't exist. 38 | /// 39 | public virtual IStandardTemplateItem Target 40 | { 41 | get 42 | { 43 | if (HasValue) 44 | return InnerItem.Database.GetItem(TargetId).AsStronglyTyped(); 45 | 46 | return null; 47 | } 48 | } 49 | 50 | /// 51 | /// Checks if the relationship has a value. Does not check if the ID refers to a valid entity. 52 | /// 53 | public override bool HasValue 54 | { 55 | get 56 | { 57 | if (InnerField == null) return false; 58 | return TargetId != (ID)null && !TargetId.IsNull && !TargetId.IsGlobalNullId; 59 | } 60 | } 61 | 62 | public ReferenceField ToReferenceField() 63 | { 64 | return InnerField; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Fixtures/ItemExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | namespace Synthesis.Tests.Fixtures 3 | { 4 | [Trait("Category", "Object Conversion Tests")] 5 | public class ItemExtensionsTests 6 | { 7 | [Fact(Skip = "TODO")] 8 | public void ItemExtensions_AsT_ConvertsValidItem() 9 | { 10 | 11 | } 12 | 13 | [Fact(Skip = "TODO")] 14 | public void ItemExtensions_AsT_ReturnsNullIfInvalidCast() 15 | { 16 | 17 | } 18 | 19 | [Fact(Skip = "TODO")] 20 | public void ItemExtensions_AsStronglyTyped_ConvertsValidItem() 21 | { 22 | 23 | } 24 | 25 | [Fact(Skip = "TODO")] 26 | public void ItemExtensions_AsStronglyTyped_ReturnsNullConvertingInvalidItem() 27 | { 28 | 29 | } 30 | 31 | [Fact(Skip = "TODO")] 32 | public void ItemExtensions_AsStronglyTyped_ReturnsNullConvertingNullItem() 33 | { 34 | 35 | } 36 | 37 | [Fact(Skip = "TODO")] 38 | public void ItemExtensions_AsCollectionOfT_ReturnsEnumerableOfValidItems() 39 | { 40 | 41 | } 42 | 43 | [Fact(Skip = "TODO")] 44 | public void ItemExtensions_AsCollectionOfT_ReturnsEnumerableOfSomeValidItems() 45 | { 46 | 47 | } 48 | 49 | [Fact(Skip = "TODO")] 50 | public void ItemExtensions_AsCollectionOfT_ReturnsEmptyEnumerableWithNoValidItems() 51 | { 52 | 53 | } 54 | 55 | [Fact(Skip = "TODO")] 56 | public void ItemExtensions_AsCollectionOfT_ReturnsEmptyEnumerableWithNoItems() 57 | { 58 | 59 | } 60 | 61 | [Fact(Skip = "TODO")] 62 | public void ItemExtensions_AsStronglyTypedCollection_ReturnsEnumerableOfValidItems() 63 | { 64 | 65 | } 66 | 67 | [Fact(Skip = "TODO")] 68 | public void ItemExtensions_AsStronglyTypedCollection_ReturnsEnumerableOfSomeValidItems() 69 | { 70 | 71 | } 72 | 73 | [Fact(Skip = "TODO")] 74 | public void ItemExtensions_AsStronglyTypedCollection_ReturnsEmptyEnumerableWithNoValidItems() 75 | { 76 | 77 | } 78 | 79 | [Fact(Skip = "TODO")] 80 | public void ItemExtensions_AsStronglyTypedCollection_ReturnsEmptyEnumerableWithNoItems() 81 | { 82 | 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/DateTimeField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Sitecore; 4 | using Sitecore.ContentSearch.Converters; 5 | using Sitecore.Data.Fields; 6 | using Sitecore.Web.UI.WebControls; 7 | using Synthesis.FieldTypes.Interfaces; 8 | 9 | namespace Synthesis.FieldTypes 10 | { 11 | public class DateTimeField : FieldType, IDateTimeField 12 | { 13 | public DateTimeField(LazyField field, string indexValue) : base(field, indexValue) { } 14 | 15 | /// 16 | /// Gets the value of the field. If no value exists, returns DateTime.MinValue 17 | /// 18 | public virtual DateTime Value 19 | { 20 | get 21 | { 22 | if (!IsFieldLoaded && InnerSearchValue != null) 23 | { 24 | DateTime ret; 25 | if (DateTime.TryParse(InnerSearchValue, out ret)) 26 | return ret; 27 | if (DateTime.TryParseExact(InnerSearchValue, "yyyyMMdd'T'HHmm'Z'", CultureInfo.CurrentCulture, 28 | DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out ret)) 29 | return ret; 30 | var converter = new IndexFieldDateTimeValueConverter(); 31 | //// ReSharper disable once PossibleNullReferenceException 32 | return (DateTime)converter.ConvertFrom(InnerSearchValue); 33 | } 34 | 35 | return ((DateField)InnerField).DateTime; 36 | } 37 | set { SetFieldValue(DateUtil.ToIsoDate(value)); } 38 | } 39 | 40 | /// 41 | /// Checks if the field has a value. For a DateTime, this checks if it equals default(DateTime). 42 | /// 43 | public override bool HasValue 44 | { 45 | get 46 | { 47 | if (InnerField == null) return false; 48 | 49 | return Value != DateTime.MinValue; 50 | } 51 | } 52 | 53 | /// 54 | /// Renders the field using a Sitecore FieldRenderer and returns the result 55 | /// 56 | public virtual string RenderedValue => FieldRenderer.Render(InnerItem, InnerField.ID.ToString()); 57 | 58 | public override string ToString() 59 | { 60 | return Value.ToString(CultureInfo.InvariantCulture); 61 | } 62 | 63 | public DateField ToDateField() 64 | { 65 | return InnerField; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Helpers/DateHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using System.Web.Mvc; 4 | using Sitecore.Web.UI.WebControls; 5 | using Synthesis.FieldTypes.Interfaces; 6 | 7 | namespace Synthesis.Mvc.Helpers 8 | { 9 | /// 10 | /// HTML helpers to enable simple rendering of Synthesis field types in Sitecore MVC 11 | /// These are the preferred method of emitting Synthesis models to the markup as they handle 12 | /// things like HTML encoding and field renderer parameters for you. 13 | /// 14 | /// They all work similar to the form helpers in that they're lambdas on the model: 15 | /// 16 | /// @Html.TextFor(x=>x.MyTextField) 17 | /// 18 | /// You can also use them on non-model Synthesis objects if needed: 19 | /// 20 | /// @Html.ImageFor(x=>someObject.ImageField, "image-class") 21 | /// 22 | public static class DateHelper 23 | { 24 | [Obsolete("Use the Synthesis.Mvc.Extensions IDateTimeField.Render() extension methods instead for improved readability.")] 25 | public static IHtmlString DateTimeFor(this HtmlHelper helper, Func selector) 26 | { 27 | return DateTimeFor(helper, selector, "g"); 28 | } 29 | 30 | [Obsolete("Use the Synthesis.Mvc.Extensions IDateTimeField.Render() extension methods instead for improved readability.")] 31 | public static IHtmlString DateTimeFor(this HtmlHelper helper, Func selector, string format) 32 | { 33 | return DateTimeFor(helper, selector, x => { x.Format = format; }); 34 | } 35 | 36 | [Obsolete("Use the Synthesis.Mvc.Extensions IDateTimeField.Render() extension methods instead for improved readability.")] 37 | public static IHtmlString DateTimeFor(this HtmlHelper helper, Func selector, Action parameters) 38 | { 39 | var field = selector(helper.ViewData.Model); 40 | 41 | if (field.HasValue || Sitecore.Context.PageMode.IsExperienceEditor) 42 | { 43 | var date = new Date(); 44 | date.AttachToDateTimeField(field); 45 | parameters(date); 46 | 47 | return new MvcHtmlString(date.RenderAsText()); 48 | } 49 | 50 | return new MvcHtmlString(string.Empty); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/UI/SitecoreRenderingContext.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using Sitecore.ContentSearch; 3 | using Sitecore.ExperienceExplorer.Core.State; 4 | using Sitecore.Mvc.Presentation; 5 | using Sitecore.Sites; 6 | using Synthesis.FieldTypes.Adapters; 7 | 8 | namespace Synthesis.Mvc.UI 9 | { 10 | public class SitecoreRenderingContext : IRenderingContext 11 | { 12 | public TItem GetRenderingDatasource() where TItem : class, IStandardTemplateItem 13 | { 14 | return RenderingContext.CurrentOrNull?.Rendering?.Item.As(); 15 | } 16 | 17 | public IStandardTemplateItem RenderingDatasource => GetRenderingDatasource(); 18 | 19 | public TItem GetContextItem() where TItem : class, IStandardTemplateItem 20 | { 21 | return Sitecore.Context.Item.As(); 22 | } 23 | 24 | public IStandardTemplateItem ContextItem => GetContextItem(); 25 | 26 | public bool IsEditing => Sitecore.Context.Site.DisplayMode == DisplayMode.Edit; 27 | public bool IsPreview => Sitecore.Context.Site.DisplayMode == DisplayMode.Preview; 28 | public bool IsNormal => Sitecore.Context.Site.DisplayMode == DisplayMode.Normal; 29 | public bool IsExperienceExplorer => DependencyResolver.Current.GetService()?.IsExplorerMode() ?? false; 30 | public bool IsDebugging => Sitecore.Context.PageMode.IsDebugging || Sitecore.Context.Diagnostics.Profiling || Sitecore.Context.Diagnostics.Tracing; 31 | public bool IsCompletelyNormal => IsNormal && !IsExperienceExplorer && !IsDebugging; 32 | 33 | public SiteContext ContextSite => Sitecore.Context.Site; 34 | 35 | public IDatabaseAdapter ContextDatabase => new DatabaseAdapter(Sitecore.Context.ContentDatabase ?? Sitecore.Context.Database); 36 | 37 | public RenderingParameters Parameters => RenderingContext.CurrentOrNull?.Rendering?.Parameters ?? new RenderingParameters(string.Empty); 38 | 39 | public ISearchIndex ContextIndex 40 | { 41 | get 42 | { 43 | var contextItem = ContextItem?.InnerItem; 44 | 45 | if (contextItem == null) return null; 46 | 47 | return ContentSearchManager.GetIndex(new SitecoreIndexableItem(contextItem)); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/Synthesis/ContentSearch/ComputedFields/InheritedTemplates.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sitecore; 3 | using Sitecore.ContentSearch; 4 | using Sitecore.ContentSearch.ComputedFields; 5 | using Sitecore.ContentSearch.Utilities; 6 | using Sitecore.Data.Items; 7 | using Sitecore.Diagnostics; 8 | 9 | namespace Synthesis.ContentSearch.ComputedFields 10 | { 11 | /// 12 | /// A computed field that correctly recurses all templates, unlike the default. 13 | /// 14 | /// Code is courtesy of http://mikael.com/2013/05/sitecore-7-query-items-that-inherits-a-template/ 15 | /// 16 | /// Note that the default Sitecore.ContentSearch.ComputedFields.AllTemplates field does NOT do the same thing 17 | /// as this implementation. That one will get all _immediate_ base templates, whereas this one is 18 | /// recursive and gets ALL base templates, even of grandparent and above templates. 19 | /// 20 | public class InheritedTemplates : IComputedIndexField 21 | { 22 | public string FieldName { get; set; } 23 | 24 | public string ReturnType { get; set; } 25 | 26 | public object ComputeFieldValue(IIndexable indexable) 27 | { 28 | Assert.ArgumentNotNull(indexable, "indexable"); 29 | return GetAllTemplates(indexable as SitecoreIndexableItem); 30 | } 31 | 32 | private static List GetAllTemplates(Item item) 33 | { 34 | // SitecoreIndexableItem is not of type Sitecore.Data.Items.Item 35 | if (item == null) 36 | { 37 | return new List(); 38 | } 39 | 40 | Assert.IsNotNull(item.Template, "Item template not found."); 41 | var list = new List { IdHelper.NormalizeGuid(item.TemplateID) }; 42 | RecurseTemplates(list, item.Template); 43 | return list; 44 | } 45 | 46 | private static void RecurseTemplates(ICollection list, TemplateItem template) 47 | { 48 | foreach (var baseTemplateItem in template.BaseTemplates) 49 | { 50 | list.Add(IdHelper.NormalizeGuid(baseTemplateItem.ID)); 51 | if (baseTemplateItem.ID != TemplateIDs.StandardTemplate) 52 | { 53 | RecurseTemplates(list, baseTemplateItem); 54 | } 55 | 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/Synthesis.Testing/TestContentHubImageField.cs: -------------------------------------------------------------------------------- 1 | using Synthesis.FieldTypes.Interfaces; 2 | 3 | namespace Synthesis.Testing 4 | { 5 | public class TestContentHubImageField : TestImageField, IContentHubImageField 6 | { 7 | public TestContentHubImageField(string url, string contentId = null, string thumbnailSrc = null, string contentType = null, bool isContentHub = true, 8 | int? width = null, int? height = null, string alternateText = null) 9 | : base(url, width, height, alternateText) 10 | { 11 | ContentId = contentId; 12 | ThumbnailSrc = thumbnailSrc; 13 | ContentType = contentType; 14 | IsContentHub = isContentHub; 15 | } 16 | 17 | /// 18 | /// Gets the content ID of the image 19 | /// 20 | public string ContentId { get; set; } 21 | 22 | /// 23 | /// Gets the thumbnail src of the image 24 | /// 25 | public string ThumbnailSrc { get; set; } 26 | 27 | /// 28 | /// Gets the content type of the image 29 | /// 30 | public string ContentType { get; set; } 31 | 32 | /// 33 | /// Determine if image is from Content Hub or Media Library 34 | /// 35 | public bool IsContentHub { get; set; } 36 | 37 | /// 38 | /// Renders the field using a Sitecore FieldRenderer and returns the result 39 | /// 40 | public new string RenderedValue 41 | { 42 | get 43 | { 44 | if (IsContentHub) 45 | { 46 | string tag = $"\"{AlternateText"; 49 | 50 | return tag; 51 | } 52 | else 53 | { 54 | string tag = $"\"{AlternateText"; 62 | } 63 | 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Synthesis.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net471 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | App.config 13 | Always 14 | 15 | 16 | license.xml 17 | Always 18 | 19 | 20 | 21 | 22 | Properties\SharedAssemblyInfo.cs 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/ImageField.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using Sitecore.Web.UI.WebControls; 3 | using Synthesis.FieldTypes.Interfaces; 4 | 5 | namespace Synthesis.FieldTypes 6 | { 7 | public class ImageField : FileField, IImageField 8 | { 9 | private int? _width, _height; 10 | 11 | public ImageField(LazyField field, string indexValue) : base(field, indexValue) { } 12 | 13 | /// 14 | /// Gets the width of the image, if one was entered 15 | /// 16 | public virtual int? Width 17 | { 18 | get 19 | { 20 | if (_width != null) return _width; 21 | 22 | int width; 23 | if (int.TryParse(((Sitecore.Data.Fields.ImageField)InnerField).Width, out width)) return width; 24 | 25 | return null; 26 | } 27 | set 28 | { 29 | SetFieldValue(delegate 30 | { 31 | ((Sitecore.Data.Fields.ImageField)InnerField).Width = value?.ToString(CultureInfo.InvariantCulture) ?? string.Empty; 32 | _width = null; 33 | }); 34 | } 35 | } 36 | 37 | /// 38 | /// Gets the height of the image, if one was entered 39 | /// 40 | public virtual int? Height 41 | { 42 | get 43 | { 44 | if (_height != null) return _height; 45 | 46 | int height; 47 | if (int.TryParse(((Sitecore.Data.Fields.ImageField)InnerField).Height, out height)) return height; 48 | 49 | return null; 50 | } 51 | set 52 | { 53 | SetFieldValue(delegate 54 | { 55 | ((Sitecore.Data.Fields.ImageField)InnerField).Height = value?.ToString(CultureInfo.InvariantCulture) ?? string.Empty; 56 | _height = null; 57 | }); 58 | } 59 | } 60 | 61 | /// 62 | /// Gets the alt text of the image, if any was entered 63 | /// 64 | public virtual string AlternateText 65 | { 66 | get { return ((Sitecore.Data.Fields.ImageField)InnerField).Alt; } 67 | set 68 | { 69 | SetFieldValue(delegate 70 | { 71 | ((Sitecore.Data.Fields.ImageField)InnerField).Alt = value; 72 | }); 73 | } 74 | } 75 | 76 | /// 77 | /// Renders the field using a Sitecore FieldRenderer and returns the result 78 | /// 79 | public virtual string RenderedValue => FieldRenderer.Render(InnerItem, InnerField.ID.ToString()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Pipelines/GetModel/GetFromSynthesis.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using Sitecore.Diagnostics; 3 | using Sitecore.Mvc.Pipelines.Response.GetModel; 4 | using Sitecore.Mvc.Presentation; 5 | using Synthesis.Mvc.Pipelines.GetRenderer; 6 | using Synthesis.Mvc.Utility; 7 | 8 | namespace Synthesis.Mvc.Pipelines.GetModel 9 | { 10 | 11 | public class GetFromSynthesis : GetModelProcessor 12 | { 13 | private readonly ViewModelTypeResolver _typeResolver; 14 | 15 | public GetFromSynthesis() : this(new ViewModelTypeResolver()) 16 | { 17 | 18 | } 19 | 20 | public GetFromSynthesis(ViewModelTypeResolver typeResolver) 21 | { 22 | Assert.ArgumentNotNull(typeResolver, "typeResolver"); 23 | 24 | _typeResolver = typeResolver; 25 | } 26 | 27 | protected static ConcurrentDictionary SynthesisRenderingCache = new ConcurrentDictionary(); 28 | 29 | protected virtual object GetFromViewPath(Rendering rendering, GetModelArgs args) 30 | { 31 | var viewPath = rendering.ToString().Replace("View: ", string.Empty); 32 | 33 | if(!SiteHelper.IsValidSite()) return null; 34 | 35 | var useSynthesisModelType = SynthesisRenderingCache.GetOrAdd(rendering.ToString(), key => 36 | { 37 | var renderer = rendering.Renderer; 38 | 39 | var diagnosticRenderer = renderer as RenderingDiagnosticsInjector.DiagnosticsRenderer; 40 | if (diagnosticRenderer != null) renderer = diagnosticRenderer.InnerRenderer; 41 | 42 | var viewRenderer = renderer as ViewRenderer; 43 | if (viewRenderer != null) viewPath = viewRenderer.ViewPath; 44 | 45 | var modelType = _typeResolver.GetViewModelType(viewPath); 46 | 47 | // Check to see if no model has been set 48 | if (modelType == typeof(object)) return false; 49 | 50 | // Check that the model is a Synthesis type (if not, we ignore it) 51 | if (!typeof(IStandardTemplateItem).IsAssignableFrom(modelType)) return false; 52 | 53 | return true; 54 | }); 55 | 56 | return useSynthesisModelType ? rendering.Item.AsStronglyTyped() : null; 57 | } 58 | 59 | public override void Process(GetModelArgs args) 60 | { 61 | if (args.Result == null) 62 | { 63 | args.Result = GetFromViewPath(args.Rendering, args); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Build/PackageNuGet.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [string]$scriptRoot, 3 | [string]$Mode = "Release" 4 | ) 5 | 6 | $ErrorActionPreference = "Stop" 7 | function Resolve-MsBuild { 8 | $msb2019 = Resolve-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\*\MSBuild\*\bin\msbuild.exe" -ErrorAction SilentlyContinue 9 | if($msb2019) { 10 | return $msb2019 11 | } 12 | throw "Unable to find MS Build 2019" 13 | } 14 | 15 | $msBuild = Resolve-MsBuild 16 | if ($msBuild -is [array]) { 17 | $msBuild = $msBuild[1] 18 | } 19 | 20 | $nuGet = "$scriptRoot..\Dependencies\NuGet.exe" 21 | $solution = "$scriptRoot\..\Synthesis.sln" 22 | Push-Location (Resolve-Path -Path "$scriptRoot\..") 23 | $gitversion = ConvertFrom-Json ([string](dotnet-gitversion /updateassemblyinfo "Source/SharedAssemblyInfo.cs")) 24 | Pop-Location 25 | 26 | & $nuGet restore $solution 27 | & $msBuild $solution /p:Configuration=$Mode /t:Rebuild /m 28 | 29 | $targetAssemblyVersion = $gitversion.NuGetVersion 30 | 31 | & $nuGet pack "$scriptRoot\Synthesis.nuget\Synthesis.nuspec" -version $targetAssemblyVersion -OutputDirectory "$scriptRoot\Versions\$targetAssemblyVersion" 32 | 33 | & $nuGet pack "$scriptRoot\..\Source\Synthesis\Synthesis.csproj" -version $targetAssemblyVersion -Symbols -Prop Configuration=$Mode -OutputDirectory "$scriptRoot\Versions\$targetAssemblyVersion" 34 | 35 | & $nuGet pack "$scriptRoot\..\Source\Synthesis.Testing\Synthesis.Testing.csproj" -version $targetAssemblyVersion -Symbols -Prop Configuration=$Mode -OutputDirectory "$scriptRoot\Versions\$targetAssemblyVersion" 36 | 37 | & $nuGet pack "$scriptRoot\Synthesis.Mvc.nuget\Synthesis.Mvc.nuspec" -version $targetAssemblyVersion -OutputDirectory "$scriptRoot\Versions\$targetAssemblyVersion" 38 | 39 | & $nuGet pack "$scriptRoot\..\Source\Synthesis.Mvc\Synthesis.Mvc.csproj" -version $targetAssemblyVersion -Symbols -Prop Configuration=$Mode -OutputDirectory "$scriptRoot\Versions\$targetAssemblyVersion" 40 | 41 | & $nuGet pack "$scriptRoot\Synthesis.Solr.nuget\Synthesis.Solr.nuspec" -version $targetAssemblyVersion -OutputDirectory "$scriptRoot\Versions\$targetAssemblyVersion" 42 | 43 | & $nuGet pack "$scriptRoot\..\Source\Synthesis.Solr\Synthesis.Solr.csproj" -version $targetAssemblyVersion -Symbols -Prop Configuration=$Mode -OutputDirectory "$scriptRoot\Versions\$targetAssemblyVersion" -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Extensions/NumberFields.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | using Synthesis.FieldTypes.Interfaces; 4 | 5 | namespace Synthesis.Mvc.Extensions 6 | { 7 | /// 8 | /// Extensions to enable simple rendering of Synthesis field types in Sitecore MVC 9 | /// These are the preferred method of emitting Synthesis models to the markup as they handle 10 | /// things like HTML encoding and field renderer parameters for you. 11 | /// 12 | /// They are very simple to use: 13 | /// 14 | /// @mySynthesisObject.Field.Render() 15 | /// 16 | public static class NumberFields 17 | { 18 | public static IHtmlString Render(this IIntegerField field) 19 | { 20 | return Render(field, "g"); 21 | } 22 | 23 | public static IHtmlString Render(this IIntegerField field, bool editable) 24 | { 25 | return Render(field, "g", editable); 26 | } 27 | public static IHtmlString Render(this IIntegerField field, string format) 28 | { 29 | return Render(field, format, true); 30 | } 31 | 32 | public static IHtmlString Render(this IIntegerField field, string format, bool editable) 33 | { 34 | if (Sitecore.Context.PageMode.IsExperienceEditor && editable) 35 | { 36 | return new HtmlString(field.RenderedValue); 37 | } 38 | 39 | if (field.HasValue) 40 | { 41 | return new HtmlString(field.Value.ToString(format)); 42 | } 43 | 44 | return new MvcHtmlString(string.Empty); 45 | } 46 | 47 | public static IHtmlString Render(this INumericField field) 48 | { 49 | return Render(field, "g"); 50 | } 51 | 52 | public static IHtmlString Render(this INumericField field, bool editable) 53 | { 54 | return Render(field, "g", editable); 55 | } 56 | 57 | public static IHtmlString Render(this INumericField field, string format) 58 | { 59 | return Render(field, format, true); 60 | } 61 | 62 | public static IHtmlString Render(this INumericField field, string format, bool editable) 63 | { 64 | if (Sitecore.Context.PageMode.IsExperienceEditor && editable) 65 | { 66 | return new HtmlString(field.RenderedValue); 67 | } 68 | 69 | if (field.HasValue) 70 | { 71 | return new HtmlString(field.Value.ToString(format)); 72 | } 73 | 74 | return new MvcHtmlString(string.Empty); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Source/Synthesis/Pipelines/Initialize/CheckModelSynchronization.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sitecore; 3 | using Sitecore.Diagnostics; 4 | using Sitecore.Pipelines; 5 | using Sitecore.StringExtensions; 6 | 7 | namespace Synthesis.Pipelines.Initialize 8 | { 9 | public class CheckModelSynchronization 10 | { 11 | public string StartupCheckMode { get; set; } 12 | 13 | public void Process(PipelineArgs args) 14 | { 15 | // this will happen if the http handler is registered too early in the handlers list (before the sitecore handlers run) 16 | if (Globals.LinkDatabase == null) throw new InvalidOperationException("Link database was null. Most likely Sitecore has not yet been initialized for this request yet; you may need to change the HTTP module order so Synthesis initializes after Sitecore."); 17 | 18 | switch (StartupCheckMode) 19 | { 20 | case "Off": return; 21 | case "Log": 22 | DoLogSync(); 23 | return; 24 | 25 | case "Regenerate": 26 | DoRegenerateSync(); 27 | 28 | return; 29 | 30 | default: 31 | Log.Warn("Invalid setting \"" + StartupCheckMode + "\" for StartupCheckMode. Assuming you mean Off and skipping synchronization.", this); 32 | return; 33 | } 34 | } 35 | 36 | private void DoLogSync() 37 | { 38 | var syncStatus = SynthesisHelper.CheckSyncAll(); 39 | 40 | foreach (var configuration in syncStatus) 41 | { 42 | var syncResult = configuration.Value; 43 | 44 | if (syncResult.AreTemplatesSynchronized) return; 45 | 46 | foreach (var template in syncResult) 47 | { 48 | if (!template.IsSynchronized) 49 | Log.Warn("Synthesis template desynchronization ({0}): {1}".FormatWith(configuration.Key.Name, template), this); 50 | } 51 | } 52 | } 53 | 54 | private void DoRegenerateSync() 55 | { 56 | var syncStatus = SynthesisHelper.CheckSyncAllAndRegenerate(); 57 | 58 | foreach (var configuration in syncStatus) 59 | { 60 | var syncResult = configuration.Value; 61 | 62 | if (syncResult.AreTemplatesSynchronized) return; 63 | 64 | foreach (var template in syncResult) 65 | { 66 | if (!template.IsSynchronized) 67 | Log.Warn("Synthesis template desynchronization ({0}): {1}".FormatWith(configuration.Key.Name, template), this); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Source/Synthesis/Configuration/ProviderResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Sitecore.Data; 4 | using Synthesis.Initializers; 5 | 6 | namespace Synthesis.Configuration 7 | { 8 | public sealed class ProviderResolver 9 | { 10 | private static volatile List _configurations = new List(); 11 | 12 | /// 13 | /// Registers a new dependency configuration with the provider resolver. 14 | /// 15 | public static void RegisterConfiguration(IProviderConfiguration configuration) 16 | { 17 | _configurations.Add(configuration); 18 | } 19 | 20 | /// 21 | /// Gets a specific provider configuration by name 22 | /// 23 | public static IProviderConfiguration GetConfiguration(string name) 24 | { 25 | return _configurations.FirstOrDefault(x => x.Name == name); 26 | } 27 | 28 | /// 29 | /// Gets all currently registered provider configurations 30 | /// 31 | public static IReadOnlyCollection GetConfigurations() 32 | { 33 | return _configurations.AsReadOnly(); 34 | } 35 | 36 | /// 37 | /// Finds an initializer class for a template ID in any configuration 38 | /// Note that the first configuration that has a matching template ID is returned 39 | /// (so if two configurations include the same template, you may have unexpected results) 40 | /// 41 | public static ITemplateInitializer FindGlobalInitializer(ID templateId) 42 | { 43 | foreach (var configuration in _configurations) 44 | { 45 | var initializer = configuration.InitializerProvider.GetInitializer(templateId); 46 | 47 | if(initializer != null) return initializer; 48 | } 49 | 50 | return new StandardTemplateInitializer(); 51 | } 52 | 53 | /// 54 | /// Finds the configuration that contains a given template ID. Returns null if none do. 55 | /// 56 | public static IProviderConfiguration FindConfigurationWithTemplate(ID templateId) 57 | { 58 | foreach (var configuration in _configurations) 59 | { 60 | var initializer = configuration.InitializerProvider.GetInitializer(templateId); 61 | 62 | if (initializer != null) return configuration; 63 | } 64 | 65 | return null; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Helpers/FileHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using Synthesis.FieldTypes.Interfaces; 7 | 8 | namespace Synthesis.Mvc.Helpers 9 | { 10 | /// 11 | /// HTML helpers to enable simple rendering of Synthesis field types in Sitecore MVC 12 | /// These are the preferred method of emitting Synthesis models to the markup as they handle 13 | /// things like HTML encoding and field renderer parameters for you. 14 | /// 15 | /// They all work similar to the form helpers in that they're lambdas on the model: 16 | /// 17 | /// @Html.TextFor(x=>x.MyTextField) 18 | /// 19 | /// You can also use them on non-model Synthesis objects if needed: 20 | /// 21 | /// @Html.ImageFor(x=>someObject.ImageField, "image-class") 22 | /// 23 | public static class FileHelper 24 | { 25 | [Obsolete("Use the Synthesis.Mvc.Extensions IFileField.Render() extension methods instead for improved readability.")] 26 | public static IHtmlString FileLinkFor(this HtmlHelper helper, Func selector, string linkText = null, string cssClass = null) 27 | { 28 | return FileLinkFor(helper, selector, linkText, new { @class = cssClass }); 29 | } 30 | 31 | [Obsolete("Use the Synthesis.Mvc.Extensions IFieldField.Render() extension methods instead for improved readability.")] 32 | public static IHtmlString FileLinkFor(this HtmlHelper helper, Func selector, string linkText, object attributes) 33 | { 34 | var field = selector(helper.ViewData.Model); 35 | 36 | if (field.HasValue) 37 | { 38 | var sb = new StringBuilder(); 39 | sb.Append(" x.CanRead)) 44 | { 45 | var value = attribute.GetValue(attributes, null); 46 | 47 | if (value == null) continue; 48 | 49 | sb.AppendFormat(" {0}=\"{1}\"", attribute.Name.Replace('_', '-'), HttpUtility.HtmlEncode(value)); 50 | } 51 | 52 | sb.Append(">"); 53 | sb.Append(linkText ?? field.Url); 54 | sb.Append(""); 55 | 56 | return new MvcHtmlString(sb.ToString()); 57 | } 58 | 59 | return new MvcHtmlString(string.Empty); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/DictionaryField.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Specialized; 3 | using System.Web; 4 | using System; 5 | using Synthesis.FieldTypes.Interfaces; 6 | 7 | namespace Synthesis.FieldTypes 8 | { 9 | /// 10 | /// Represents a field that is a logical dictionary (i.e. a Key Value List) 11 | /// 12 | public class DictionaryField : FieldType, IDictionaryField 13 | { 14 | NameValueCollection _values; 15 | 16 | public DictionaryField(LazyField field, string indexValue) : base(field, indexValue) { } 17 | 18 | /// 19 | /// Gets the set of IDs that make up the relationships 20 | /// 21 | public virtual string this[string key] 22 | { 23 | get { return Values[key]; } 24 | set { Values[key] = value; } 25 | } 26 | 27 | /// 28 | /// Gets the keys and values in the field 29 | /// 30 | public virtual NameValueCollection Values 31 | { 32 | get 33 | { 34 | if (_values == null) 35 | { 36 | _values = HttpUtility.ParseQueryString(InnerField.Value); 37 | } 38 | 39 | return _values; 40 | } 41 | } 42 | 43 | /// 44 | /// Checks if the field has at least one key 45 | /// 46 | public override bool HasValue 47 | { 48 | get 49 | { 50 | if (InnerField == null) return false; 51 | return Values.Count > 0; 52 | } 53 | } 54 | 55 | public void Add(string key, string value) 56 | { 57 | Values.Add(key, value); 58 | 59 | SetFieldValue(ValueToQueryString()); 60 | } 61 | 62 | public bool Remove(string key) 63 | { 64 | if (!ContainsKey(key)) return false; 65 | 66 | Values.Remove(key); 67 | SetFieldValue(ValueToQueryString()); 68 | 69 | return true; 70 | } 71 | 72 | public void Clear() 73 | { 74 | SetFieldValue(string.Empty); 75 | _values = null; 76 | } 77 | 78 | public bool ContainsKey(string key) 79 | { 80 | return Values[key] != null; 81 | } 82 | 83 | public int Count => Values.Count; 84 | 85 | private string ValueToQueryString() 86 | { 87 | var items = new List(); 88 | 89 | foreach (string name in Values) 90 | items.Add(string.Concat(Uri.EscapeDataString(name), "=", Uri.EscapeDataString(Values[name]))); 91 | 92 | return string.Join("&", items); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Source/Synthesis/Generation/Model/TypeNovelizer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Synthesis.Generation.Model 4 | { 5 | /// 6 | /// Collects and maintains data about a set of templates undergoing generation. Handles naming, uniqueness, and other state. 7 | /// 8 | public class TypeNovelizer 9 | { 10 | private readonly bool _useRelativeNamespaces; 11 | private readonly string _namespaceRoot; 12 | private readonly HashSet _existingFullNames = new HashSet(); 13 | 14 | public TypeNovelizer(bool useRelativeNamespaces, string namespaceRoot) 15 | { 16 | _useRelativeNamespaces = useRelativeNamespaces; 17 | _namespaceRoot = namespaceRoot; 18 | } 19 | 20 | /// 21 | /// Calculates a namespace and type name for a template that is unique among all templates in the collection 22 | /// 23 | public string GetNovelFullTypeName(string templateName, string fullPath) 24 | { 25 | string name; 26 | 27 | if (_useRelativeNamespaces) 28 | { 29 | name = fullPath.Replace(_namespaceRoot, string.Empty).Trim('/').Replace('/', '.'); 30 | 31 | var nameParts = name.Split('/'); 32 | 33 | for (int cnt = 0; cnt < nameParts.Length; cnt++) 34 | { 35 | string namePart = nameParts[cnt]; 36 | int v; 37 | if (int.TryParse(namePart.Substring(0, 1), out v)) 38 | { 39 | namePart = "_" + namePart; 40 | } 41 | 42 | nameParts[cnt] = namePart; 43 | } 44 | 45 | name = string.Join(".", nameParts); 46 | 47 | if (name.Contains(".")) 48 | { 49 | // we need to make sure the namespace and full type name are both unique 50 | // i.e. you could have (and this happens with the standard templates) a template called 51 | // foo.bar and another called foo.bar.baz - and the foo.bar namespace for foo.bar.baz wouldn't work because a type existed called foo.bar already 52 | 53 | string typeName = name.Substring(name.LastIndexOf('.') + 1); 54 | string namespaceName = name.Substring(0, name.LastIndexOf('.')).AsNovelIdentifier(_existingFullNames); 55 | 56 | name = string.Concat(namespaceName, ".", typeName).AsNovelIdentifier(_existingFullNames); 57 | } 58 | } 59 | else name = templateName.AsNovelIdentifier(_existingFullNames); 60 | 61 | _existingFullNames.Add(name); 62 | 63 | return name; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Source/Synthesis/FieldTypes/Adapters/DatabaseAdapter.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Sitecore.Collections; 3 | using Sitecore.Data; 4 | using Sitecore.Globalization; 5 | using Version = Sitecore.Data.Version; 6 | 7 | namespace Synthesis.FieldTypes.Adapters 8 | { 9 | public class DatabaseAdapter : IDatabaseAdapter 10 | { 11 | private readonly Database _database; 12 | 13 | public DatabaseAdapter(Database database) 14 | { 15 | _database = database; 16 | } 17 | 18 | public string Name => _database.Name; 19 | 20 | public Database InnerDatabase => _database; 21 | 22 | public IStandardTemplateItem GetItem(ID itemId) 23 | { 24 | return _database.GetItem(itemId).AsStronglyTyped(); 25 | } 26 | 27 | public IStandardTemplateItem GetItem(ID itemId, Language language) 28 | { 29 | return _database.GetItem(itemId, language).AsStronglyTyped(); 30 | } 31 | 32 | public IStandardTemplateItem GetItem(ID itemId, Language language, Version version) 33 | { 34 | return _database.GetItem(itemId, language, version).AsStronglyTyped(); 35 | } 36 | 37 | public IStandardTemplateItem GetItem(string path) 38 | { 39 | return _database.GetItem(path).AsStronglyTyped(); 40 | } 41 | 42 | public IStandardTemplateItem GetItem(string path, Language language) 43 | { 44 | return _database.GetItem(path, language).AsStronglyTyped(); 45 | } 46 | 47 | public IStandardTemplateItem GetItem(string path, Language language, Version version) 48 | { 49 | return _database.GetItem(path, language, version).AsStronglyTyped(); 50 | } 51 | 52 | public IStandardTemplateItem GetItem(DataUri uri) 53 | { 54 | return _database.GetItem(uri).AsStronglyTyped(); 55 | } 56 | 57 | public LanguageCollection GetLanguages() 58 | { 59 | return _database.GetLanguages(); 60 | } 61 | 62 | public IStandardTemplateItem GetRootItem() 63 | { 64 | return _database.GetRootItem().AsStronglyTyped(); 65 | } 66 | 67 | public IStandardTemplateItem GetRootItem(Language language) 68 | { 69 | return _database.GetRootItem(language).AsStronglyTyped(); 70 | } 71 | 72 | public IStandardTemplateItem[] SelectItems(string query) 73 | { 74 | return _database.SelectItems(query).AsStronglyTypedCollection().ToArray(); 75 | } 76 | 77 | public IStandardTemplateItem SelectSingleItem(string query) 78 | { 79 | return _database.SelectSingleItem(query).AsStronglyTyped(); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Source/Synthesis.Tests/Fixtures/ContentSearch/ContentSearchQueryExtensionTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using FluentAssertions; 4 | using Sitecore; 5 | using Xunit; 6 | 7 | namespace Synthesis.Tests.Fixtures.ContentSearch 8 | { 9 | /* 10 | * ASSUMPTIONS OF THESE TESTS: 11 | * Standard sitecore_master_index configured 12 | * All items in master are allowed to be indexed 13 | * The _system_ templates are relatively unmodified (used as query playground) 14 | */ 15 | [Trait("Category", "FieldType Tests")] 16 | public class ContentSearchQueryExtensionTests : ContentSearchTestFixture 17 | { 18 | [Fact(Skip = "Need to determine how to properly mock ContentSearch")] 19 | public void ContentSearch_FindsSublayoutsOrWorkflowStates_WhenContainsOrIsUsed() 20 | { 21 | using (var context = CreateTestSearchContext()) 22 | { 23 | var query = context.GetSynthesisQueryable() 24 | .ContainsOr(x => x.TemplateIds, new[] { TemplateIDs.Sublayout, TemplateIDs.WorkflowState }) 25 | .ToArray(); 26 | 27 | Assert.True(query.All(x => x.TemplateIds.Contains(TemplateIDs.Sublayout) || x.TemplateIds.Contains(TemplateIDs.WorkflowState)), "ContainsOr results contained unexpected template IDs"); 28 | Assert.True(query.Any(x => x.TemplateId == TemplateIDs.Sublayout), "ContainsOr result contained no sublayout items"); 29 | Assert.True(query.Any(x => x.TemplateId == TemplateIDs.WorkflowState), "ContainsOr result contained no workflow state items"); 30 | } 31 | } 32 | 33 | 34 | [Fact(Skip = "Need to determine how to properly mock ContentSearch")] 35 | public void ContentSearch_FindsSecurityFolderOrRenderingOptions_WhenContainsOrIsUsed() 36 | { 37 | using (var context = CreateTestSearchContext()) 38 | { 39 | var listOfNames = new List {"Security folder", "Rendering Options"}; 40 | var query = context.GetSynthesisQueryable() 41 | .ContainsOr(x => x.Name, listOfNames) 42 | .ToArray(); 43 | 44 | query.Length.Should().BeGreaterOrEqualTo(2);//, "ContainsOr (string) results contained too few results"); 45 | Assert.True(query.Any(x => x.Name == listOfNames[0]), "ContainsOr result contained no security folder item"); 46 | Assert.True(query.Any(x => x.Name == listOfNames[1]), "ContainsOr result contained no rendering options item"); 47 | } 48 | } 49 | 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Source/Synthesis.Mvc/Standard Config Files/Synthesis.Mvc.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 30 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Source/Synthesis.Solr/ContentSearch/SynthesisSolrFieldNameTranslatorFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Sitecore.ContentSearch; 3 | using Sitecore.ContentSearch.Abstractions; 4 | using Sitecore.ContentSearch.SolrProvider; 5 | using Sitecore.ContentSearch.SolrProvider.FieldNames; 6 | using Sitecore.ContentSearch.SolrProvider.FieldNames.Normalization; 7 | using Sitecore.ContentSearch.SolrProvider.FieldNames.TypeResolving; 8 | using Sitecore.Diagnostics; 9 | using Synthesis.ContentSearch; 10 | using Synthesis.Utility; 11 | 12 | namespace Synthesis.Solr.ContentSearch 13 | { 14 | public class SynthesisSolrFieldNameTranslatorFactory : IFieldNameTranslatorFactory 15 | { 16 | public AbstractFieldNameTranslator GetFieldNameTranslator(ISearchIndex index) 17 | { 18 | SolrFieldMap fieldMap = index.Configuration.FieldMap as SolrFieldMap; 19 | SolrIndexSchema schema = index.Schema as SolrIndexSchema; 20 | ISettings instance = index.Locator.GetInstance(); 21 | SolrIndexConfiguration configuration = index.Configuration as SolrIndexConfiguration; 22 | Assert.IsNotNull(fieldMap, "FieldMap is null."); 23 | Assert.IsNotNull(schema, "SolrSchema is null."); 24 | Assert.IsNotNull(instance, "Settings is null."); 25 | Assert.IsNotNull(configuration, "This constructor requires SolrIndexConfiguration."); 26 | TemplateFieldTypeResolverFactory typeResolverFactory = configuration.TemplateFieldTypeResolverFactory; 27 | Assert.IsNotNull(typeResolverFactory, "normalizerFactory is null."); 28 | TemplateFieldTypeResolver fieldTypeResolver = typeResolverFactory.Create(); 29 | Assert.IsNotNull(fieldTypeResolver, "FieldTypeResolver is null."); 30 | SolrFieldConfigurationResolver configurationResolver = new SolrFieldConfigurationResolver(fieldMap, schema, fieldTypeResolver); 31 | var ctor = typeof(SolrFieldNameTranslator).Assembly 32 | .GetType("Sitecore.ContentSearch.SolrProvider.FieldNames.CultureContextGuard") 33 | .GetConstructors().First(); 34 | 35 | 36 | ICultureContextGuard cultureContextGuard = ObjectActivator.GetActivator(ctor).Invoke(); 37 | return new SynthesisSolrFieldNameTranslator(fieldMap, schema, instance, configurationResolver, new ExtensionStripHelper(fieldMap, schema), typeResolverFactory, cultureContextGuard); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Source/Synthesis/Configuration/Registration/SynthesisConfigurationRegistration.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Synthesis.Generation; 3 | using Synthesis.Templates; 4 | 5 | namespace Synthesis.Configuration.Registration 6 | { 7 | public abstract class SynthesisConfigurationRegistration : ConfigurationProviderConfiguration, ISynthesisConfigurationRegistration 8 | { 9 | protected abstract string ConfigurationName { get; } 10 | 11 | protected abstract IEnumerable IncludedTemplates { get; } 12 | 13 | protected abstract string NamespaceTemplatePathRoot { get; } 14 | 15 | protected abstract string ModelOutputFilePath { get; } 16 | 17 | protected abstract string RootGeneratedNamespace { get; } 18 | 19 | protected virtual IEnumerable ExcludedTemplates 20 | { 21 | get { yield break; } 22 | } 23 | 24 | protected virtual IEnumerable ExcludedFields 25 | { 26 | get { yield return "__*"; } 27 | } 28 | 29 | protected virtual void ConfigureGeneratorParameters(GeneratorParameters parameters) 30 | { 31 | parameters.InterfaceNamespace = RootGeneratedNamespace; 32 | parameters.InterfaceOutputPath = ModelOutputFilePath; 33 | parameters.ItemNamespace = RootGeneratedNamespace + ".Concrete"; 34 | parameters.ItemOutputPath = ModelOutputFilePath; 35 | parameters.TemplatePathRoot = NamespaceTemplatePathRoot; 36 | } 37 | 38 | public virtual IProviderConfiguration GetConfiguration() 39 | { 40 | Name = ConfigurationName; 41 | 42 | return this; 43 | } 44 | 45 | protected override IGeneratorParametersProvider LoadGeneratorParametersProviderFromConfig() 46 | { 47 | // take default config's parameters and tweak them for our config 48 | return new ProxyGeneratorParametersProvider(base.LoadGeneratorParametersProviderFromConfig(), ConfigureGeneratorParameters); 49 | } 50 | 51 | protected override ITemplateInputProvider LoadTemplateInputProviderFromConfig() 52 | { 53 | var templates = new ConfigurationTemplateInputProvider(); 54 | 55 | foreach (var path in IncludedTemplates) 56 | { 57 | templates.AddTemplatePath(path); 58 | } 59 | 60 | foreach (var path in ExcludedTemplates) 61 | { 62 | templates.AddTemplateExclusion(path); 63 | } 64 | 65 | foreach (var field in ExcludedFields) 66 | { 67 | templates.AddFieldExclusion(field); 68 | } 69 | 70 | return templates; 71 | } 72 | 73 | public override string Name 74 | { 75 | get { return ConfigurationName; } 76 | set { base.Name = value; } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Source/Synthesis.Solr.Tests/Synthesis.Solr.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net471 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | App.config 14 | Always 15 | 16 | 17 | license.xml 18 | Always 19 | 20 | 21 | 22 | 23 | Properties\SharedAssemblyInfo.cs 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | --------------------------------------------------------------------------------