public IEnumerable <IDataType> GetImageCropperDataTypes(bool bypassCache = false)
        {
            IEnumerable <IDataType> imageCropperDataTypes;

            if (bypassCache)
            {
                imageCropperDataTypes = dataTypeService.GetByEditorAlias("Umbraco.ImageCropper");
                cacheManager.UpdateCache(ImageCropperCacheKeys.ImageCropperDataTypes, imageCropperDataTypes);

                return(imageCropperDataTypes);
            }
            else
            {
                imageCropperDataTypes = cacheManager.GetFromCache <IEnumerable <IDataType> >(ImageCropperCacheKeys.ImageCropperDataTypes);

                if (imageCropperDataTypes == null)
                {
                    imageCropperDataTypes = dataTypeService.GetByEditorAlias("Umbraco.ImageCropper");
                    cacheManager.UpdateCache(ImageCropperCacheKeys.ImageCropperDataTypes, imageCropperDataTypes);
                }
                return(imageCropperDataTypes);
            }
        }
        private static void ContentService_Saved(IContentTypeService contentTypeService, SaveEventArgs <IContentType> e)
        {
            foreach (IContentType content in e.SavedEntities)
            {
                List <string> itemDoctypeCompositionAliases = new List <string>();

                IEnumerable <IDataType> bentoItemDataTypes = DataTypeService.GetByEditorAlias(BentoItemDataEditor.EditorAlias);
                itemDoctypeCompositionAliases.AddRange(bentoItemDataTypes
                                                       .Select(dataType => (BentoItemConfiguration)dataType.Configuration)
                                                       .Select(config => config.ItemDoctypeCompositionAlias));

                IEnumerable <IDataType> bentoStackDataTypes = DataTypeService.GetByEditorAlias(BentoStackDataEditor.EditorAlias);
                itemDoctypeCompositionAliases
                .AddRange(bentoStackDataTypes.Select(dataType => (BentoStackConfiguration)dataType.Configuration)
                          .Select(config => config.ItemDoctypeCompositionAlias));

                IEnumerable <string> compositionAliases = content.ContentTypeComposition.Select(x => x.Alias);

                IEnumerable <string> result = compositionAliases.Where(x => itemDoctypeCompositionAliases.Any(y => y == x));

                if (!result.Any())
                {
                    continue;
                }

                string websiteViewMessage    = string.Empty;
                string backofficeViewMessage = string.Empty;

                StringBuilder view = new StringBuilder();
                view.AppendLine("@inherits Umbraco.Web.Mvc.UmbracoViewPage<IPublishedElement>");

                string contentAlias = content.Alias.First().ToString().ToUpper() + content.Alias.Substring(1);

                if (!Directory.Exists(IOHelper.MapPath("~\\Views\\Partials\\Bento")))
                {
                    Directory.CreateDirectory(IOHelper.MapPath("~\\Views\\Partials\\Bento"));
                }

                if (!Directory.Exists(IOHelper.MapPath("~\\Views\\Partials\\Bento\\Layouts")))
                {
                    Directory.CreateDirectory(IOHelper.MapPath("~\\Views\\Partials\\Bento\\Layouts"));
                }


                if (!File.Exists(IOHelper.MapPath($"~\\Views\\Partials\\Bento\\{contentAlias}.cshtml")))
                {
                    StringBuilder websiteView = new StringBuilder();
                    websiteView.Append(view);
                    websiteView.AppendLine($"<p>View for Bento doctype '{content.Name}' (alias: {content.Alias})</p>");

                    File.WriteAllText(IOHelper.MapPath($"~\\Views\\Partials\\Bento\\{contentAlias}.cshtml"), websiteView.ToString());

                    websiteViewMessage = $"'~/Views/Bento/{contentAlias}.cshtml'";
                }

                if (!File.Exists(IOHelper.MapPath($"~\\Views\\Partials\\Bento\\{contentAlias}BackOffice.cshtml")))
                {
                    StringBuilder backOfficeView = new StringBuilder();
                    backOfficeView.Append(view);
                    backOfficeView.AppendLine("<div class=\"card hero\">");
                    backOfficeView.AppendLine("\t<div class=\"card-content\">");
                    backOfficeView.AppendLine(
                        $"\t\t<div class=\"title\">Backoffice Bento view for '{content.Name}' (alias: {content.Alias})</div>");
                    backOfficeView.AppendLine(
                        $"\t\t<div class=\"sub-title\">To edit, please open the file at: ~/Views/Partials/Bento/{contentAlias}BackOffice.cshtml</div>");
                    backOfficeView.AppendLine("\t</div>");
                    backOfficeView.AppendLine("</div>");

                    File.WriteAllText(IOHelper.MapPath($"~\\Views\\Partials\\Bento\\{contentAlias}BackOffice.cshtml"),
                                      backOfficeView.ToString());

                    backofficeViewMessage = $"'~/Views/Partials/Bento/{contentAlias}BackOffice.cshtml'";
                }

                if (!string.IsNullOrWhiteSpace(websiteViewMessage) || !string.IsNullOrWhiteSpace(backofficeViewMessage))
                {
                    //todo: spent an hour trying to get this to work...
                    //from what i can gather online, this has never been implemented...
                    //bit of a shame as the user has no idea that the views have been created?!
                    e.Messages.Add(new EventMessage("Bento setup",
                                                    $"Bento view(s) created ({websiteViewMessage}{(string.IsNullOrWhiteSpace(backofficeViewMessage) ? string.Empty : " and ")}{backofficeViewMessage}).",
                                                    EventMessageType.Info));
                }
            }
        }
        public IPublishedElement ConvertValueToContent(string guid, string contentTypeAlias, IDictionary <string, object> propertyData)
        {
            var contentTypes = GetContentTypesByAlias(contentTypeAlias);
            var properties   = new List <IPublishedProperty>();

            foreach (var jProp in propertyData)
            {
                var propType = contentTypes.PublishedContentType.GetPropertyType(jProp.Key);

                if (propType == null)
                {
                    continue;
                }

                /* Because we never store the value in the database, we never run the property editors
                 * "ConvertEditorToDb" method however the property editors will expect their value to
                 * be in a "DB" state so to get round this, we run the "ConvertEditorToDb" here before
                 * we go on to convert the value for the view.
                 */
                var propEditor = _dataTypeService.GetByEditorAlias(propType.EditorAlias)?.FirstOrDefault();

                if (propEditor == null)
                {
                    continue;
                }

                var propValueEditor = propEditor.Editor.GetValueEditor();

                var propPreValues = GetPreValuesCollectionByDataTypeId(propType.DataType.Id);

                var contentPropData = new ContentPropertyData(jProp.Value, propPreValues);

                var newValue = propValueEditor.FromEditor(contentPropData, jProp.Value);

                /* Now that we have the DB stored value, we actually need to then convert it into its
                 * XML serialized state as expected by the published property by calling ConvertDbToString
                 */
                var propType2 = contentTypes.ContentType.CompositionPropertyTypes.First(x => x.PropertyEditorAlias.InvariantEquals(propType.DataType.EditorAlias));

                Property prop2 = null;
                try
                {
                    /* HACK: [LK:2016-04-01] When using the "Umbraco.Tags" property-editor, the converted DB value does
                     * not match the datatypes underlying db-column type. So it throws a "Type validation failed" exception.
                     * We feel that the Umbraco core isn't handling the Tags value correctly, as it should be the responsiblity
                     * of the "Umbraco.Tags" property-editor to handle the value conversion into the correct type.
                     * See: http://issues.umbraco.org/issue/U4-8279
                     */
                    prop2 = new Property(propType2);
                    prop2.SetValue(newValue);
                }
                catch (Exception ex)
                {
                    _logger.Error(typeof(EmbeddedContentService), ex, "[Bento] Error creating Property object.");
                }

                if (prop2 == null)
                {
                    continue;
                }

                var newValue2 = propValueEditor.ConvertDbToString(propType2, newValue, _dataTypeService);

                properties.Add(new DetachedPublishedProperty(propType, newValue2));
            }

            // Manually parse out the special properties
            propertyData.TryGetValue("name", out object nameObj);
            Guid.TryParse(guid, out Guid key);

            // Create the model based on our implementation of IPublishedElement
            IPublishedElement content = new DetachedPublishedElement(
                key,
                contentTypes.PublishedContentType,
                properties.ToArray());

            var publishedModelFactory = _publishedModelFactory;

            if (publishedModelFactory != null)
            {
                // Let the current model factory create a typed model to wrap our model
                content = publishedModelFactory.CreateModel(content);
            }

            return(content);
        }