diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index d44b132832..5d86e4cc2c 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -93,11 +93,6 @@ namespace Umbraco.Core.Models } } - public void SetLazyParentId(Lazy id) - { - _parentId = id; - } - /// /// Gets or sets the name of the current entity /// @@ -309,6 +304,27 @@ namespace Umbraco.Core.Models get { return PropertyGroups.SelectMany(x => x.PropertyTypes); } } + /// + /// Removes a PropertyType from the current ContentType + /// + /// Alias of the to remove + public void RemovePropertyType(string propertyTypeAlias) + { + foreach (var propertyGroup in PropertyGroups) + { + propertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias); + } + } + + /// + /// Sets the ParentId from the lazy integer id + /// + /// Id of the Parent + public void SetLazyParentId(Lazy id) + { + _parentId = id; + } + //TODO Implement moving PropertyType between groups. /*public bool MovePropertyTypeToGroup(string propertyTypeAlias, string groupName) {}*/ diff --git a/src/Umbraco.Core/Models/IContentTypeBase.cs b/src/Umbraco.Core/Models/IContentTypeBase.cs index db1a86f4e9..2b19dd216c 100644 --- a/src/Umbraco.Core/Models/IContentTypeBase.cs +++ b/src/Umbraco.Core/Models/IContentTypeBase.cs @@ -63,6 +63,16 @@ namespace Umbraco.Core.Models /// IEnumerable PropertyTypes { get; } + /// + /// Removes a PropertyType from the current ContentType + /// + /// Alias of the to remove + void RemovePropertyType(string propertyTypeAlias); + + /// + /// Sets the ParentId from the lazy integer id + /// + /// Id of the Parent void SetLazyParentId(Lazy id); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/PropertyTypeCollection.cs b/src/Umbraco.Core/Models/PropertyTypeCollection.cs index bba80a5ee0..27e3926f09 100644 --- a/src/Umbraco.Core/Models/PropertyTypeCollection.cs +++ b/src/Umbraco.Core/Models/PropertyTypeCollection.cs @@ -97,6 +97,14 @@ namespace Umbraco.Core.Models return this.Any(x => x.Alias == propertyAlias); } + public void RemoveItem(string propertyTypeAlias) + { + var key = IndexOfKey(propertyTypeAlias); + //Only removes an item if the key was found + if(key != -1) + RemoveItem(key); + } + public int IndexOfKey(string key) { for (var i = 0; i < this.Count; i++) diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs index 789646df2d..2dd018ac55 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs @@ -56,7 +56,19 @@ namespace Umbraco.Core.Persistence.Factories if (property.DataTypeDatabaseType == DataTypeDatabaseType.Integer && property.Value != null && string.IsNullOrWhiteSpace(property.Value.ToString()) == false) { - dto.Integer = int.Parse(property.Value.ToString()); + if (property.Value is bool) + { + int val = Convert.ToInt32(property.Value); + dto.Integer = val; + } + else + { + int val; + if (int.TryParse(property.Value.ToString(), out val)) + { + dto.Integer = val; + } + } } else if (property.DataTypeDatabaseType == DataTypeDatabaseType.Date && property.Value != null && string.IsNullOrWhiteSpace(property.Value.ToString()) == false) { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 2c06cb849f..e7f6bed492 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -8,14 +8,15 @@ using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using ClientDependency.Core; +using Umbraco.Core; +using Umbraco.Core.Models; +using umbraco.cms.businesslogic.web; using umbraco.cms.helpers; -using umbraco.cms.presentation.Trees; using umbraco.controls.GenericProperties; using umbraco.IO; using umbraco.presentation; -using umbraco.cms.businesslogic; using umbraco.BasePages; -using Tuple = System.Tuple; +using ContentType = umbraco.cms.businesslogic.ContentType; namespace umbraco.controls { @@ -60,7 +61,19 @@ namespace umbraco.controls base.OnInit(e); int docTypeId = getDocTypeId(); - cType = new cms.businesslogic.ContentType(docTypeId); + //Fairly hacky code to load the ContentType as the real type instead of its base type, so it can be properly saved. + if (Request.Path.ToLowerInvariant().Contains("editnodetypenew.aspx")) + { + cType = new cms.businesslogic.web.DocumentType(docTypeId); + } + else if (Request.Path.ToLowerInvariant().Contains("editmediatype.aspx")) + { + cType = new cms.businesslogic.media.MediaType(docTypeId); + } + else + { + cType = new cms.businesslogic.ContentType(docTypeId); + } setupInfoPane(); if (!HideStructure) @@ -127,6 +140,15 @@ namespace umbraco.controls SaveAllowedChildTypes(); + if (cType.ContentTypeItem is IContentType) + { + ((DocumentType)cType).Save(); + } + else if (cType.ContentTypeItem is IMediaType) + { + ((umbraco.cms.businesslogic.media.MediaType)cType).Save(); + } + // reload content type (due to caching) cType = new ContentType(cType.Id); @@ -319,8 +341,8 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } private void bindDataGenericProperties(bool Refresh) { - cms.businesslogic.ContentType.TabI[] tabs = cType.getVirtualTabs; - cms.businesslogic.datatype.DataTypeDefinition[] dtds = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); + var tabs = cType.getVirtualTabs.DistinctBy(x => x.ContentType).ToArray(); + var dtds = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); PropertyTypes.Controls.Clear(); @@ -517,8 +539,14 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); protected void gpw_Delete(object sender, System.EventArgs e) { - GenericProperties.GenericPropertyWrapper gpw = (GenericProperties.GenericPropertyWrapper)sender; + var gpw = (GenericProperties.GenericPropertyWrapper)sender; + var alias = gpw.PropertyType.Alias; + gpw.GenricPropertyControl.PropertyType.delete(); + //We have to ensure that the property type is removed from the underlying IContentType object + cType.ContentTypeItem.RemovePropertyType(alias); + cType.Save(); + cType = ContentType.GetContentType(cType.Id); this.bindDataGenericProperties(true); } @@ -765,14 +793,15 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); dt.Columns.Add("name"); dt.Columns.Add("id"); dt.Columns.Add("order"); - foreach (cms.businesslogic.ContentType.TabI tb in cType.getVirtualTabs.ToList()) + + foreach (var grp in cType.PropertyTypeGroups) { - if (tb.ContentType == cType.Id) + if (grp.ContentTypeId == cType.Id) { DataRow dr = dt.NewRow(); - dr["name"] = tb.GetRawCaption(); - dr["id"] = tb.Id; - dr["order"] = tb.SortOrder; + dr["name"] = grp.Name; + dr["id"] = grp.Id; + dr["order"] = grp.SortOrder; dt.Rows.Add(dr); } } diff --git a/src/umbraco.businesslogic/Application.cs b/src/umbraco.businesslogic/Application.cs index e776569fc6..9b1a6b5bab 100644 --- a/src/umbraco.businesslogic/Application.cs +++ b/src/umbraco.businesslogic/Application.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Web; using System.Xml.Linq; +using Umbraco.Core; using umbraco.DataLayer; using umbraco.IO; using System.Runtime.CompilerServices; @@ -79,8 +80,19 @@ namespace umbraco.BusinessLogic { try { - var databaseSettings = ConfigurationManager.ConnectionStrings[Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName]; - _sqlHelper = DataLayerHelper.CreateSqlHelper(databaseSettings.ConnectionString); + const string umbracoDsn = Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName; + + var connectionString = string.Empty; + + var databaseSettings = ConfigurationManager.ConnectionStrings[umbracoDsn]; + if(databaseSettings != null) + connectionString = databaseSettings.ConnectionString; + + // During upgrades we might still have the old appSettings connectionstring, and not the new one, so get that one instead + if (string.IsNullOrWhiteSpace(connectionString) && ConfigurationManager.AppSettings.ContainsKey(umbracoDsn)) + connectionString = ConfigurationManager.AppSettings[umbracoDsn]; + + _sqlHelper = DataLayerHelper.CreateSqlHelper(connectionString); } catch { } } diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 3db18b7762..529fefb11a 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -75,7 +75,7 @@ namespace umbraco.cms.businesslogic internal ContentType(IContentTypeComposition contentType) : base(contentType) { - _contentType = contentType; + ContentTypeItem = contentType; } #endregion @@ -279,7 +279,7 @@ namespace umbraco.cms.businesslogic private static readonly object propertyTypesCacheSyncLock = new object(); - private IContentTypeComposition _contentType; + protected internal IContentTypeComposition ContentTypeItem; #endregion @@ -304,7 +304,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery("update cmsContentType set alias = @alias where nodeId = @id", SqlHelper.CreateParameter("@alias", _alias), @@ -312,7 +312,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.Alias = _alias; + ContentTypeItem.Alias = _alias; } // Remove from cache @@ -333,13 +333,13 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery("update cmsContentType set icon='" + value + "' where nodeid = " + Id); } else { - _contentType.Icon = _iconurl; + ContentTypeItem.Icon = _iconurl; } // Remove from cache @@ -360,7 +360,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "update cmsContentType set isContainer = @isContainer where nodeId = @id", @@ -369,7 +369,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.IsContainer = _isContainerContentType; + ContentTypeItem.IsContainer = _isContainerContentType; } } } @@ -386,7 +386,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "update cmsContentType set allowAtRoot = @allowAtRoot where nodeId = @id", @@ -395,7 +395,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.AllowedAsRoot = _allowAtRoot; + ContentTypeItem.AllowedAsRoot = _allowAtRoot; } } } @@ -437,7 +437,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "update cmsContentType set description = @description where nodeId = @id", @@ -446,7 +446,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.Description = _description; + ContentTypeItem.Description = _description; } FlushFromCache(Id); @@ -466,7 +466,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "update cmsContentType set thumbnail = @thumbnail where nodeId = @id", @@ -475,7 +475,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.Thumbnail = _thumbnail; + ContentTypeItem.Thumbnail = _thumbnail; } FlushFromCache(Id); @@ -514,9 +514,9 @@ namespace umbraco.cms.businesslogic { base.Text = value; - if (_contentType != null) + if (ContentTypeItem != null) { - _contentType.Name = value; + ContentTypeItem.Name = value; } // Remove from cache @@ -543,7 +543,11 @@ namespace umbraco.cms.businesslogic TimeSpan.FromMinutes(15), delegate { - List result = new List(); + //MCH NOTE: For the timing being I have changed this to a dictionary to ensure that property types + //aren't added multiple times through the MasterContentType structure, because each level loads + //its own + inherited property types, which is wrong. Once we are able to fully switch to the new api + //this should no longer be a problem as the composition always contains a correct list of property types. + var result = new Dictionary(); using (IRecordsReader dr = SqlHelper.ExecuteReader( "select id from cmsPropertyType where contentTypeId = @ctId order by sortOrder", @@ -554,7 +558,7 @@ namespace umbraco.cms.businesslogic int id = dr.GetInt("id"); PropertyType pt = PropertyType.GetPropertyType(id); if (pt != null) - result.Add(pt); + result.Add(pt.Id, pt); } } @@ -563,14 +567,15 @@ namespace umbraco.cms.businesslogic { foreach (var mct in MasterContentTypes) { - List pts = ContentType.GetContentType(mct).PropertyTypes; + var pts = ContentType.GetContentType(mct).PropertyTypes; foreach (PropertyType pt in pts) { - result.Add(pt); + if(result.ContainsKey(pt.Id) == false) + result.Add(pt.Id, pt); } } } - return result; + return result.Select(x => x.Value).ToList(); }); } } @@ -582,7 +587,7 @@ namespace umbraco.cms.businesslogic if (m_masterContentTypes == null) { m_masterContentTypes = new List(); - if (_contentType == null) + if (ContentTypeItem == null) { //TODO Make this recursive, so it looks up Masters of the Master ContentType using ( @@ -599,7 +604,7 @@ namespace umbraco.cms.businesslogic } else { - m_masterContentTypes = _contentType.CompositionIds().ToList(); + m_masterContentTypes = ContentTypeItem.CompositionIds().ToList(); } } @@ -783,7 +788,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "delete from cmsContentTypeAllowedContentType where id=" + Id); @@ -805,7 +810,7 @@ namespace umbraco.cms.businesslogic sort++; } - _contentType.AllowedContentTypes = list; + ContentTypeItem.AllowedContentTypes = list; } } } @@ -912,6 +917,12 @@ namespace umbraco.cms.businesslogic public void removePropertyTypeFromTab(PropertyType pt) { pt.TabId = 0; //this will set to null in the database. + + if (ContentTypeItem != null) + { + ContentTypeItem.RemovePropertyType(pt.Alias); + } + // Remove from cache FlushFromCache(Id); } @@ -1051,8 +1062,8 @@ namespace umbraco.cms.businesslogic _thumbnail = contentType.Thumbnail; _description = contentType.Description; - if (_contentType == null) - _contentType = contentType; + if (ContentTypeItem == null) + ContentTypeItem = contentType; } protected void PopulateContentTypeNodeFromReader(IRecordsReader dr) diff --git a/src/umbraco.cms/businesslogic/media/Media.cs b/src/umbraco.cms/businesslogic/media/Media.cs index 4695fab3cc..9328bbf4fb 100644 --- a/src/umbraco.cms/businesslogic/media/Media.cs +++ b/src/umbraco.cms/businesslogic/media/Media.cs @@ -296,6 +296,9 @@ namespace umbraco.cms.businesslogic.media foreach (var property in GenericProperties) { + if (property.Value == null) + continue; + MediaItem.SetValue(property.PropertyType.Alias, property.Value); } diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 31c730dd45..b4840249ef 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -934,6 +934,9 @@ namespace umbraco.cms.businesslogic.web foreach (var property in GenericProperties) { + if (property.Value == null) + continue; + Content.SetValue(property.PropertyType.Alias, property.Value); } @@ -962,6 +965,9 @@ namespace umbraco.cms.businesslogic.web foreach (var property in GenericProperties) { + if(property.Value == null) + continue; + Content.SetValue(property.PropertyType.Alias, property.Value); }