using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
{
///
/// Represents the Localization Service, which is an easy access to operations involving and
///
public class LocalizationService : ScopeRepositoryService, ILocalizationService
{
public LocalizationService(IScopeUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory)
: base(provider, logger, eventMessagesFactory)
{ }
///
/// Adds or updates a translation for a dictionary item and language
///
///
///
///
///
///
/// This does not save the item, that needs to be done explicitly
///
public void AddOrUpdateDictionaryValue(IDictionaryItem item, ILanguage language, string value)
{
if (item == null) throw new ArgumentNullException(nameof(item));
if (language == null) throw new ArgumentNullException(nameof(language));
var existing = item.Translations.FirstOrDefault(x => x.Language.Id == language.Id);
if (existing != null)
{
existing.Value = value;
}
else
{
item.Translations = new List(item.Translations)
{
new DictionaryTranslation(language, value)
};
}
}
///
/// Creates and saves a new dictionary item and assigns a value to all languages if defaultValue is specified.
///
///
///
///
///
public IDictionaryItem CreateDictionaryItemWithIdentity(string key, Guid? parentId, string defaultValue = null)
{
using (var uow = UowProvider.CreateUnitOfWork())
{
var repository = uow.CreateRepository();
//validate the parent
if (parentId.HasValue && parentId.Value != Guid.Empty)
{
var parent = GetDictionaryItemById(parentId.Value);
if (parent == null)
throw new ArgumentException($"No parent dictionary item was found with id {parentId.Value}.");
}
var item = new DictionaryItem(parentId, key);
if (defaultValue.IsNullOrWhiteSpace() == false)
{
var langs = GetAllLanguages();
var translations = langs.Select(language => new DictionaryTranslation(language, defaultValue))
.Cast()
.ToList();
item.Translations = translations;
}
var saveEventArgs = new SaveEventArgs(item);
if (uow.Events.DispatchCancelable(SavingDictionaryItem, this, saveEventArgs))
{
uow.Complete();
return item;
}
repository.AddOrUpdate(item);
uow.Complete();
// ensure the lazy Language callback is assigned
EnsureDictionaryItemLanguageCallback(item);
saveEventArgs.CanCancel = false;
uow.Events.Dispatch(SavedDictionaryItem, this, saveEventArgs);
return item;
}
}
///
/// Gets a by its id
///
/// Id of the
///
public IDictionaryItem GetDictionaryItemById(int id)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
var item = repository.Get(id);
//ensure the lazy Language callback is assigned
EnsureDictionaryItemLanguageCallback(item);
return item;
}
}
///
/// Gets a by its id
///
/// Id of the
///
public IDictionaryItem GetDictionaryItemById(Guid id)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
var item = repository.Get(id);
//ensure the lazy Language callback is assigned
EnsureDictionaryItemLanguageCallback(item);
return item;
}
}
///
/// Gets a by its key
///
/// Key of the
///
public IDictionaryItem GetDictionaryItemByKey(string key)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
var item = repository.Get(key);
//ensure the lazy Language callback is assigned
EnsureDictionaryItemLanguageCallback(item);
return item;
}
}
///
/// Gets a list of children for a
///
/// Id of the parent
/// An enumerable list of objects
public IEnumerable GetDictionaryItemChildren(Guid parentId)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
var query = Query().Where(x => x.ParentId == parentId);
var items = repository.GetByQuery(query).ToArray();
//ensure the lazy Language callback is assigned
foreach (var item in items)
EnsureDictionaryItemLanguageCallback(item);
return items;
}
}
///
/// Gets a list of descendants for a
///
/// Id of the parent, null will return all dictionary items
/// An enumerable list of objects
public IEnumerable GetDictionaryItemDescendants(Guid? parentId)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
var items = repository.GetDictionaryItemDescendants(parentId).ToArray();
//ensure the lazy Language callback is assigned
foreach (var item in items)
EnsureDictionaryItemLanguageCallback(item);
return items;
}
}
///
/// Gets the root/top objects
///
/// An enumerable list of objects
public IEnumerable GetRootDictionaryItems()
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
var query = Query().Where(x => x.ParentId == null);
var items = repository.GetByQuery(query).ToArray();
//ensure the lazy Language callback is assigned
foreach (var item in items)
EnsureDictionaryItemLanguageCallback(item);
return items;
}
}
///
/// Checks if a with given key exists
///
/// Key of the
/// True if a exists, otherwise false
public bool DictionaryItemExists(string key)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
var item = repository.Get(key);
return item != null;
}
}
///
/// Saves a object
///
/// to save
/// Optional id of the user saving the dictionary item
public void Save(IDictionaryItem dictionaryItem, int userId = 0)
{
using (var uow = UowProvider.CreateUnitOfWork())
{
if (uow.Events.DispatchCancelable(SavingDictionaryItem, this, new SaveEventArgs(dictionaryItem)))
{
uow.Complete();
return;
}
var repository = uow.CreateRepository();
repository.AddOrUpdate(dictionaryItem);
// ensure the lazy Language callback is assigned
EnsureDictionaryItemLanguageCallback(dictionaryItem);
uow.Events.Dispatch(SavedDictionaryItem, this, new SaveEventArgs(dictionaryItem, false));
Audit(uow, AuditType.Save, "Save DictionaryItem performed by user", userId, dictionaryItem.Id);
uow.Complete();
}
}
///
/// Deletes a object and its related translations
/// as well as its children.
///
/// to delete
/// Optional id of the user deleting the dictionary item
public void Delete(IDictionaryItem dictionaryItem, int userId = 0)
{
using (var uow = UowProvider.CreateUnitOfWork())
{
var deleteEventArgs = new DeleteEventArgs(dictionaryItem);
if (uow.Events.DispatchCancelable(DeletingDictionaryItem, this, deleteEventArgs))
{
uow.Complete();
return;
}
var repository = uow.CreateRepository();
repository.Delete(dictionaryItem);
deleteEventArgs.CanCancel = false;
uow.Events.Dispatch(DeletedDictionaryItem, this, deleteEventArgs);
Audit(uow, AuditType.Delete, "Delete DictionaryItem performed by user", userId, dictionaryItem.Id);
uow.Complete();
}
}
///
/// Gets a by its id
///
/// Id of the
///
public ILanguage GetLanguageById(int id)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
return repository.Get(id);
}
}
///
/// Gets a by its culture code
///
/// Culture Name - also refered to as the Friendly name
///
public ILanguage GetLanguageByCultureCode(string cultureName)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
return repository.GetByCultureName(cultureName);
}
}
///
/// Gets a by its iso code
///
/// Iso Code of the language (ie. en-US)
///
public ILanguage GetLanguageByIsoCode(string isoCode)
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
return repository.GetByIsoCode(isoCode);
}
}
///
/// Gets all available languages
///
/// An enumerable list of objects
public IEnumerable GetAllLanguages()
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
return repository.GetAll();
}
}
///
/// Saves a object
///
/// to save
/// Optional id of the user saving the language
public void Save(ILanguage language, int userId = 0)
{
using (var uow = UowProvider.CreateUnitOfWork())
{
var saveEventArgs = new SaveEventArgs(language);
if (uow.Events.DispatchCancelable(SavingLanguage, this, saveEventArgs))
{
uow.Complete();
return;
}
var repository = uow.CreateRepository();
repository.AddOrUpdate(language);
saveEventArgs.CanCancel = false;
uow.Events.Dispatch(SavedLanguage, this, saveEventArgs);
Audit(uow, AuditType.Save, "Save Language performed by user", userId, language.Id);
uow.Complete();
}
}
///
/// Deletes a by removing it (but not its usages) from the db
///
/// to delete
/// Optional id of the user deleting the language
public void Delete(ILanguage language, int userId = 0)
{
using (var uow = UowProvider.CreateUnitOfWork())
{
var deleteEventArgs = new DeleteEventArgs(language);
if (uow.Events.DispatchCancelable(DeletingLanguage, this, deleteEventArgs))
{
uow.Complete();
return;
}
var repository = uow.CreateRepository();
//NOTE: There isn't any constraints in the db, so possible references aren't deleted
repository.Delete(language);
deleteEventArgs.CanCancel = false;
uow.Events.Dispatch(DeletedLanguage, this, deleteEventArgs);
Audit(uow, AuditType.Delete, "Delete Language performed by user", userId, language.Id);
uow.Complete();
}
}
private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId)
{
var repo = uow.CreateRepository();
repo.AddOrUpdate(new AuditItem(objectId, message, type, userId));
}
///
/// This is here to take care of a hack - the DictionaryTranslation model contains an ILanguage reference which we don't want but
/// we cannot remove it because it would be a large breaking change, so we need to make sure it's resolved lazily. This is because
/// if developers have a lot of dictionary items and translations, the caching and cloning size gets much much larger because of
/// the large object graphs. So now we don't cache or clone the attached ILanguage
///
private void EnsureDictionaryItemLanguageCallback(IDictionaryItem d)
{
var item = d as DictionaryItem;
if (item == null) return;
item.GetLanguage = GetLanguageById;
foreach (var trans in item.Translations.OfType())
trans.GetLanguage = GetLanguageById;
}
public Dictionary GetDictionaryItemKeyMap()
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repository = uow.CreateRepository();
return repository.GetDictionaryItemKeyMap();
}
}
#region Event Handlers
///
/// Occurs before Delete
///
public static event TypedEventHandler> DeletingLanguage;
///
/// Occurs after Delete
///
public static event TypedEventHandler> DeletedLanguage;
///
/// Occurs before Delete
///
public static event TypedEventHandler> DeletingDictionaryItem;
///
/// Occurs after Delete
///
public static event TypedEventHandler> DeletedDictionaryItem;
///
/// Occurs before Save
///
public static event TypedEventHandler> SavingDictionaryItem;
///
/// Occurs after Save
///
public static event TypedEventHandler> SavedDictionaryItem;
///
/// Occurs before Save
///
public static event TypedEventHandler> SavingLanguage;
///
/// Occurs after Save
///
public static event TypedEventHandler> SavedLanguage;
#endregion
}
}