249 lines
7.8 KiB
C#
249 lines
7.8 KiB
C#
using System.Collections;
|
|
using System.Reflection;
|
|
using Pf2e.Common;
|
|
using Pf2e.Database.Model;
|
|
using Pf2e.Database.Model.Base;
|
|
using Pf2e.Database.Model.Common.I18n;
|
|
using Pf2e.Database.Model.Enum;
|
|
|
|
namespace Pf2e.Web.Helpers;
|
|
|
|
/// <summary>
|
|
/// Сериализатор сущности для отображения на веб-странице.
|
|
/// </summary>
|
|
public class EntitySerializer
|
|
{
|
|
/// <summary>
|
|
/// Результат сериализации сущности.
|
|
/// </summary>
|
|
public class SerializationResult
|
|
{
|
|
public List<FieldGroup> Groups { get; set; } = [];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Группа полей.
|
|
/// </summary>
|
|
public class FieldGroup
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public List<FieldInfo> Fields { get; set; } = [];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Информация о поле.
|
|
/// </summary>
|
|
public class FieldInfo
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public string Type { get; set; } = string.Empty;
|
|
public object? Value { get; set; }
|
|
public string DisplayValue { get; set; } = string.Empty;
|
|
public bool IsImplemented { get; set; } = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Сериализовать FullEntity.
|
|
/// </summary>
|
|
public SerializationResult Serialize(FullEntity fullEntity)
|
|
{
|
|
SerializationResult result = new();
|
|
|
|
// Группа для основных полей Entity
|
|
FieldGroup entityGroup = new() { Name = "Основные поля" };
|
|
AddFieldsToGroup(entityGroup, fullEntity.Entity);
|
|
result.Groups.Add(entityGroup);
|
|
|
|
// Группа для полей IEntity (SubEntity)
|
|
if (fullEntity.SubEntity != null)
|
|
{
|
|
FieldGroup subEntityGroup = new()
|
|
{
|
|
Name = "Поля " + fullEntity.SubEntity.GetType().Name,
|
|
};
|
|
AddFieldsToGroup(subEntityGroup, fullEntity.SubEntity);
|
|
result.Groups.Add(subEntityGroup);
|
|
}
|
|
|
|
// Группа для ссылок
|
|
FieldGroup referencesGroup = new() { Name = "Ссылки" };
|
|
AddReferencesToGroup(referencesGroup, fullEntity);
|
|
result.Groups.Add(referencesGroup);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Добавить поля объекта в группу.
|
|
/// </summary>
|
|
private void AddFieldsToGroup(FieldGroup group, object obj)
|
|
{
|
|
Type type = obj.GetType();
|
|
PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
|
|
foreach (PropertyInfo property in properties)
|
|
{
|
|
// Пропускаем навигационные свойства Entity
|
|
if (property.Name == "Entity")
|
|
continue;
|
|
|
|
FieldInfo fieldInfo = new()
|
|
{
|
|
Name = property.Name,
|
|
Type = GetTypeDisplayName(property.PropertyType),
|
|
Value = property.GetValue(obj),
|
|
};
|
|
|
|
// Обработка значения для отображения
|
|
var (displayValue, isImplemented) = FormatValue(fieldInfo.Value);
|
|
fieldInfo.DisplayValue = displayValue;
|
|
fieldInfo.IsImplemented = isImplemented;
|
|
|
|
group.Fields.Add(fieldInfo);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Добавить ссылки в группу.
|
|
/// </summary>
|
|
private void AddReferencesToGroup(FieldGroup group, FullEntity fullEntity)
|
|
{
|
|
// Добавляем информацию о связанных сущностях
|
|
Entity entity = fullEntity.Entity;
|
|
|
|
// Traits
|
|
if (entity.Traits?.Any() == true)
|
|
{
|
|
var (displayValue, isImplemented) = FormatValue(entity.Traits);
|
|
group.Fields.Add(
|
|
new FieldInfo
|
|
{
|
|
Name = "Traits",
|
|
Type = "ICollection<Trait>",
|
|
Value = entity.Traits,
|
|
DisplayValue = displayValue,
|
|
IsImplemented = isImplemented,
|
|
}
|
|
);
|
|
}
|
|
|
|
// Keywords
|
|
if (entity.Keywords?.Any() == true)
|
|
{
|
|
var (displayValue, isImplemented) = FormatValue(entity.Keywords);
|
|
group.Fields.Add(
|
|
new FieldInfo
|
|
{
|
|
Name = "Keywords",
|
|
Type = "ICollection<Keyword>",
|
|
Value = entity.Keywords,
|
|
DisplayValue = displayValue,
|
|
IsImplemented = isImplemented,
|
|
}
|
|
);
|
|
}
|
|
|
|
// Sources
|
|
if (entity.Sources?.Any() == true)
|
|
{
|
|
var (displayValue, isImplemented) = FormatValue(entity.Sources);
|
|
group.Fields.Add(
|
|
new FieldInfo
|
|
{
|
|
Name = "Sources",
|
|
Type = "ICollection<EntitySource>",
|
|
Value = entity.Sources,
|
|
DisplayValue = displayValue,
|
|
IsImplemented = isImplemented,
|
|
}
|
|
);
|
|
}
|
|
|
|
// Externals
|
|
if (entity.Externals?.Any() == true)
|
|
{
|
|
var (displayValue, isImplemented) = FormatValue(entity.Externals);
|
|
group.Fields.Add(
|
|
new()
|
|
{
|
|
Name = "Externals",
|
|
Type = "ICollection<EntityExternal>",
|
|
Value = entity.Externals,
|
|
DisplayValue = displayValue,
|
|
IsImplemented = isImplemented,
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Получить отображаемое имя типа.
|
|
/// </summary>
|
|
private string GetTypeDisplayName(Type type)
|
|
{
|
|
if (type.IsEnum)
|
|
return "enum";
|
|
|
|
return type.Name;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Форматировать значение для отображения.
|
|
/// </summary>
|
|
private (string displayValue, bool isImplemented) FormatValue(object? value)
|
|
{
|
|
if (value == null)
|
|
return ("null", true);
|
|
|
|
Type type = value.GetType();
|
|
|
|
// Обработка перечислений
|
|
if (type.IsEnum)
|
|
{
|
|
Enum enumValue = (Enum)value;
|
|
return ($"{enumValue} ({(int)(object)enumValue})", true);
|
|
}
|
|
|
|
// Обработка примитивных типов
|
|
if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal))
|
|
{
|
|
return (value.ToString() ?? "null", true);
|
|
}
|
|
|
|
// Обработка IEntity
|
|
if (typeof(IEntity).IsAssignableFrom(type))
|
|
{
|
|
var entity = (IEntity)value;
|
|
var entityType = entity.Entity.Type;
|
|
var typeName = PgNameHelper.GetPgName(entityType);
|
|
var slug = entity.Entity.Slug;
|
|
var name = entity.Entity.Name[LocaleType.English];
|
|
return ($"<a href=\"/{typeName}/{slug}\">{name}</a>", true);
|
|
}
|
|
|
|
// Обработка коллекций
|
|
if (typeof(IEnumerable).IsAssignableFrom(type) && type != typeof(string))
|
|
{
|
|
var collection = (IEnumerable)value;
|
|
var items = new List<string>();
|
|
bool allImplemented = true;
|
|
|
|
foreach (var item in collection)
|
|
{
|
|
var (itemDisplay, itemImplemented) = FormatValue(item);
|
|
items.Add(itemDisplay);
|
|
if (!itemImplemented)
|
|
allImplemented = false;
|
|
}
|
|
|
|
if (items.Count == 0)
|
|
return ("(empty)", true);
|
|
|
|
return (string.Join(", ", items), allImplemented);
|
|
}
|
|
|
|
// Для остальных сложных объектов
|
|
return ($"[{type.Name}] - НЕ РЕАЛИЗОВАНО", false);
|
|
}
|
|
}
|