Je dois construire une sorte de CMS personnalisé pour un de nos clients. Voici quelques-unes des exigences fonctionnelles :
- Doit être capable de gérer la liste des Pages dans le site
- Chaque Page peut contenir un certain nombre de Groupes de colonnes
- A Groupe de colonnes n'est rien d'autre qu'une liste de Colonnes dans un certain ColumnGroupLayout . Par exemple : "une colonne occupant toute la largeur de la page", "deux colonnes occupant chacune la moitié de la largeur", ...
- Chaque Colonne peut contenir un nombre Blocs de contenu
- Exemples d'une Bloc de contenu sont : Bloc de texte , NewsBlock , PictureBlock , ...
- Blocs de contenu peuvent faire l'objet d'un certain tri au sein d'une Colonne
- A Bloc de contenu peut être mis dans différents Colonnes afin que le contenu puisse être réutilisé sans avoir à être dupliqué.
Ma première ébauche rapide de ce à quoi cela pourrait ressembler en code C# (nous utilisons ASP.NET 4.0 pour développer le CMS) se trouve au bas de ma question.
L'une des exigences techniques est qu'il doit être aussi facile que possible d'ajouter de nouveaux types de ContentBlocks au CMS. Je voudrais donc modéliser tout ce qui est aussi flexible que possible. Malheureusement, je suis déjà coincé en essayant de comprendre à quoi devrait ressembler la base de données.
L'un des problèmes que je rencontre est lié au tri de différents types de blocs de contenu dans une colonne. Je pense que chaque type de ContentBlock (comme TextBlock, NewsBlock, PictureBlock, ...) devrait avoir sa propre table dans la base de données car chacun a ses propres champs différents. Un bloc de texte pourrait n'avoir qu'un champ appelé Texte alors qu'un bloc de nouvelles pourrait avoir des champs pour le Texte, le Résumé, la Date de publication, ...
Étant donné qu'une colonne peut avoir des blocs de contenu situés dans différentes tables, je suppose que je vais devoir créer une association many-to-many pour chaque type de bloc de contenu. Par exemple : ColumnTextBlocks, ColumnNewsBlocks et ColumnPictureBlocks.
Le problème que je rencontre avec cette configuration est le tri des différents ContentBlocks dans une colonne. Cela pourrait être quelque chose comme ceci :
- Bloc de texte
- NewsBlock
- Bloc de texte
- Bloc de texte
- PictureBlock
Où dois-je stocker le numéro de tri ? Si je les stocke dans les tables d'association, je devrai mettre à jour un grand nombre de tables lorsque je modifierai l'ordre de tri des blocs de contenu d'une colonne. Est-ce une bonne approche du problème ?
En gros, ma question est la suivante : quelle est la meilleure façon de modéliser ceci en gardant à l'esprit qu'il doit être facile d'ajouter de nouveaux types de ContentBlocks ?
Ma prochaine question est la suivante : quel ORM peut gérer ce type de modélisation ? Pour être honnête, nous sommes des vierges ORM au travail. J'ai lu un peu sur Linq-to-SQL et NHibernate, mais nous n'avons aucune expérience avec eux. En raison de l'IList dans la classe Column (voir le code ci-dessous), je pense que nous pouvons exclure Linq-to-SQL, n'est-ce pas ? NHibernate peut-il gérer le mappage des données de plusieurs tables différentes vers une IList ?
N'oubliez pas non plus qu'il ne s'agit que d'une toute petite partie du domaine. Les autres parties sont Utilisateurs appartenant à un certain Groupe d'utilisateurs ayant certains Permissions sur Pages , Groupes de colonnes , Colonnes y Blocs de contenu .
Le code (juste un premier jet rapide) :
public class Page
{
public int PageID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Keywords { get; set; }
public IList<ColumnGroup> ColumnGroups { get; set; }
}
public class ColumnGroup
{
public enum ColumnGroupLayout { OneColumn, HalfHalf, NarrowWide, WideNarrow }
public int ColumnGroupID { get; set; }
public ColumnGroupLayout Layout { get; set; }
public IList<Column> Columns { get; set; }
}
public class Column
{
public int ColumnID { get; set; }
public IList<IContentBlock> ContentBlocks { get; set; }
}
public interface IContentBlock
{
string GetSummary();
}
public class TextBlock : IContentBlock
{
public string GetSummary()
{
return "I am a piece of text.";
}
}
public class NewsBlock : IContentBlock
{
public string GetSummary()
{
return "I am a news item.";
}
}