/// <summary>
        /// Gets a list of ISecured and IEntity entities (all models) that have not yet been registered and adds them
        /// as an <see cref="Rock.Model.EntityType"/>.
        /// </summary>
        /// <param name="physWebAppPath">A <see cref="System.String"/> that represents the physical path of the web application</param>
        public static void RegisterEntityTypes(string physWebAppPath)
        {
            var entityTypes = new Dictionary <string, EntityType>();

            foreach (var type in Rock.Reflection.FindTypes(typeof(Rock.Data.IEntity)))
            {
                var entityType = new EntityType();
                entityType.Name         = type.Key;
                entityType.FriendlyName = type.Value.Name.SplitCase();
                entityType.AssemblyName = type.Value.AssemblyQualifiedName;
                entityType.IsEntity     = !type.Value.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute), false).Any();
                entityType.IsSecured    = false;
                entityTypes.Add(type.Key.ToLower(), entityType);
            }

            foreach (var type in Rock.Reflection.FindTypes(typeof(Rock.Security.ISecured)))
            {
                string key = type.Key.ToLower();

                if (entityTypes.ContainsKey(key))
                {
                    entityTypes[key].IsSecured = true;
                }
                else
                {
                    var entityType = new EntityType();
                    entityType.Name         = type.Key;
                    entityType.FriendlyName = type.Value.Name.SplitCase();
                    entityType.AssemblyName = type.Value.AssemblyQualifiedName;
                    entityType.IsEntity     = false;
                    entityType.IsSecured    = true;
                    entityTypes.Add(key, entityType);
                }
            }

            using (var rockContext = new RockContext())
            {
                var entityTypeService = new EntityTypeService(rockContext);

                // Find any existing EntityTypes marked as an entity or secured that are no longer an entity or secured
                foreach (var oldEntityType in entityTypeService.Queryable()
                         .Where(e => e.IsEntity || e.IsSecured)
                         .ToList())
                {
                    if (!entityTypes.Keys.Contains(oldEntityType.Name.ToLower()))
                    {
                        oldEntityType.IsSecured    = false;
                        oldEntityType.IsEntity     = false;
                        oldEntityType.AssemblyName = null;
                    }
                }

                // Update any existing entities
                foreach (var existingEntityType in entityTypeService.Queryable()
                         .Where(e => entityTypes.Keys.Contains(e.Name))
                         .ToList())
                {
                    var key = existingEntityType.Name.ToLower();

                    var entityType = entityTypes[key];

                    if (existingEntityType.Name != entityType.Name ||
                        existingEntityType.IsEntity != entityType.IsEntity ||
                        existingEntityType.IsSecured != entityType.IsSecured ||
                        existingEntityType.FriendlyName != (existingEntityType.FriendlyName ?? entityType.FriendlyName) ||
                        existingEntityType.AssemblyName != entityType.AssemblyName)
                    {
                        existingEntityType.Name         = entityType.Name;
                        existingEntityType.IsEntity     = entityType.IsEntity;
                        existingEntityType.IsSecured    = entityType.IsSecured;
                        existingEntityType.FriendlyName = existingEntityType.FriendlyName ?? entityType.FriendlyName;
                        existingEntityType.AssemblyName = entityType.AssemblyName;
                    }

                    entityTypes.Remove(key);
                }

                // Add the newly discovered entities
                foreach (var entityTypeInfo in entityTypes)
                {
                    // Don't add the EntityType entity as it will probably have been automatically
                    // added by the audit on a previous save in this method.
                    if (entityTypeInfo.Value.Name != "Rock.Model.EntityType")
                    {
                        entityTypeService.Add(entityTypeInfo.Value);
                    }
                }

                rockContext.SaveChanges();

                // make sure the EntityTypeCache is synced up with any changes that were made
                foreach (var entityTypeModel in entityTypeService.Queryable())
                {
                    EntityTypeCache.Get(entityTypeModel);
                }
            }
        }