GithubHelp home page GithubHelp logo

contentful.codefirst's Introduction

contentful.codefirst

❗ Disclaimer

This project is not actively maintained or monitored. Feel free to fork and work on it in your account. If you want to maintain but also collaborate with fellow developers, feel free to reach out to Contentful's Developer Relations team to move the project into our community GitHub organisation contentful-userland.


Contentful is a content management platform for web applications, mobile apps and connected devices. It allows you to create, edit & manage content in the cloud and publish it anywhere via powerful API. Contentful offers tools for managing editorial teams and enabling cooperation between organizations.

This is a helper package that allows you to automatically create content types from your c# classes.

Setup

We recommend you use the NuGet package manager to add Contentful.codefirst to your .Net application using the following command in your NuGet package manager console.

Install-Package contentful.codefirst

Usage

The codefirst package can inspect your assemblies, load suitable models and create content types. To mark a class as a content type add a ContentType attribute to it.

[ContentType]
public class BlogPost {
  public string Title { get; set; }
  public string Body { get; set; }
  public DateTime Published { get; set; }
  public string Author { get; set; }
}

This marks the BlogPost class as a content type and it can be automatically loaded by the ContentTypeBuilder.

var configuration = new ContentfulCodeFirstConfiguration 
{
  ApiKey = "<management_api_key>",
  SpaceId = "<space_id>"
};

var createdContentTypes = ContentTypeBuilder.CreateContentTypesFromAssembly("AssemblyName", configuration);

Imagining that the BlogPost class would be part of the AssemblyName assembly this would create a content type in Contentful by the name BlogPost with 4 fields.

contenttype

As you can see the name and id of the content type has defaulted to the name of class. You can control this by specifying a number of properties on the ContentType attribute.

[ContentType(Name = "A blogpost", Id = "blogPost", DisplayField = "Title", Description = "A simple blog post content type")]
public class BlogPost {
  ...omitted for brevity.
}

Here we specify that the content type created from the BlogPost class should have the name "A blogpost" and the id "blogPost" as opposed to the default "BlogPost" for both values. We also specify which field should be the displayfield for the content type and give the content type a description. All of this meta data will be passed along to the created content type.

In a similar manner you can control the fields created from the properties of a class.

[ContentType(Name = "A blogpost", Id = "blogPost", DisplayField = "title", Description = "A simple blog post content type")]
public class BlogPost {

  [ContentField(Id = "title", Name = "The title!", Type = SystemFieldTypes.Symbol, Disabled = false, Omitted = false, Localized = true,  Required = true)]
  public string Title { get; set; }
  ...omitted for brevity.
}

We have now set the Id of the Title property to "title" and changed its name to "The title!". We've also specified a type for the field. This corresponds to the available field types in Contentful. We're using the helper class SystemFieldTypes from the Contentful.Net SDK to select a suitable field type. We also specify that the field should not be disabled for editing or omitted from the API response. False are the default values for all properties which means they could be excluded if not set to true. We also set Localized and Required to true to make sure the title of our blogpost can be localized and is a mandatory field when creating entries.

By default all public properties of a class is turned into fields of your content type. If you wish to ignore a certain field decorate it with a IgnoreContentField attribute.

[ContentType]
public class BlogPost {
  ...omitted for brevity.
  [IgnoreContentField]
  public string InternalId { get; set;}
}

The InternalId property will now be ignored when creating fields for the content type.

Validations

To add validations to fields you add a ValidationAttribute to the property.

[ContentType(Name = "A blogpost", Id = "blogPost", DisplayField = "title", Description = "A simple blog post content type")]
public class BlogPost {

  [ContentField(Id = "title", Name = "The title!", Type = SystemFieldTypes.Symbol, Disabled = false, Omitted = false, Localized = true,  Required = true)]
  [Unique]
  public string Title { get; set; }
  ...omitted for brevity.
}

This example adds a unique validation to the title field.

All possible validations in Contentful are supported with the following attributes.

  • Size — to control the maximum and minimum size of a field.
  • Range — to control that the value of a field is within a specific range.
  • LinkContentType — to control that links to other entries are of a certain content type.
  • InValues — to control that a fields value is in a given set of values.
  • MimeType — to control that an asset field file is of a certain mime type group.
  • Regex — to control that the value of a field adheres to the specified regular expression.
  • Unique — to verify that the value of a field is unique amongst the entries.

Links and collections

If you do not specify the Type for a field Contentful.CodeFirst will use the best suited type for your property. A string will be Text an int will be Integer and an arbitrary object will be Object. If the property is of type ICollection the type in Contentful will be Array.

When modeling a link to another entry you must specify the type yourself.

[ContentType]
public class BlogPost {
  ...omitted for brevity.
  [ContentField(Type = SystemFieldTypes.Link, LinkType = "Entry")]
  public Author Author { get; set; }
}

This changes our Author property from a string to an Author and with a ContentField attribute we specify that this is a Link field to another entry. If we wanted to control what types of entries can be added to the field we'd add a LinkContentType attribute.

[ContentType]
public class BlogPost {
  ...omitted for brevity.
  [ContentField(Type = SystemFieldTypes.Link, LinkType = "Entry")]
  [LinkContentType("author")]
  public Author Author { get; set; }
}

Collection of entries or assets works the same way, but you have to specify the type of items in the collection instead of for the field.

[ContentType]
public class BlogPost {
  ...omitted for brevity.
  [ContentField(ItemsType = SystemFieldTypes.Link, ItemsLinkType = "Entry")]
  [LinkContentType("author")]
  public List<Author> Author { get; set; }
}

Note how the Type property of the ContentField attribute can be omitted as the type Array is inferred from the List type.

Appearance of fields

If you wish to control how a field appears in the Contentful web app you can use the FieldAppearance attribute.

[ContentType]
public class BlogPost {
  ...omitted for brevity.
  [FieldAppearance(extensionId: SystemWidgetIds.SingleLine, helpText: "The title of the blog post")]
  public string Title { get; set; }
}

There are specialized appearance attributes for boolean, ratings and datepicker fields respectively.

[ContentType]
public class BlogPost {
  ...omitted for brevity.
  [BooleanAppearance(trueLabel: "Yes", falseLabel: "No", helpText: "Is this blog post published or not?")]
  public bool Published { get; set; }
}
[ContentType]
public class Movie {
  [RatingAppearance(7, "This film gets 5 out of 7 stars!")]
  public int Rating { get; set; }
}
[ContentType]
public class Movie {
  [DatePickerAppearance(dateFormat: EditorInterfaceDateFormat.timeZ, clockFormat: "am", helpText: "The release date.")]
  public DateTime ReleaseDate { get; set; }
}

You can easily create your own appearances by creating an attribute that inherits from FieldAppearanceAttribute.

contentful.codefirst's People

Contributors

khaledgarbaya avatar roblinde avatar stefanjudis avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

Forkers

thomhoward

contentful.codefirst's Issues

Array field's item type should be "Link" or "Symbol"

Currently, Contentful only supports arrays of entries, assets, or short strings. When it's a list of entries or assets the item type is "Link."

From the Contentful web app:

{
      "name": "Test List References of Type",
      "id": "testListReferencesOfType",
      "type": "Array",
      "items": {
        "type": "Link",
        "linkType": "Entry",
        "validations": [
          {
            "linkContentType": [
              "toDo"
            ]
          }
        ]
      },
      "validations": []
    }

Refactor FieldTypeConverter to be inheritable

This would open up the developer to be able to inherit and use IOC and dependency injection if they want their own FieldTypeConverter.

As an example to create a FieldTypeConverter that handles enums:

if (type.IsEnum)
{
        return SystemFieldTypes.Symbol;
}

and they can create custom logic to automatically add an InValues validator.

This is a use case I had when developing my own content type builder against the SDK.

Make all validators return a validator as a property

I really like what @mercedesb did for the FileSizeValidatorAttribute. It has a property that returns a validator.

To me this makes a lot of sense as the only reason for the attributes existence is to be able to create a validator from it. It feels natural that this logic should be in that class and not in the ContentTypeBuilder.

We should refactor all validatorattributes to adhere to this pattern.

Add fluent builder

See discussion in #12

It would be nice to have the option to have some sort of fluent builder API if you don't want to clutter your classes with attributes.

Defining Editor Interface Code first

Being able to change the widget to use for the field would be nice to do code first as well.

Thinking through ideas, I'm not sure if it makes sense to add the widget Id and help text to the current content type attribute or make it it's own attribute.

I'm leaning towards the latter since it's separate from the actual field definition and the editor interface requires separate CMA calls, but it would require iterating through the type's properties again which feels inefficient.

Array items type automatically converted

It would be nice for the types in the array to be automatically converted (if attribute prop not explicitly set) like the other types are converted.

One gotcha that I've noticed while working is that Contentful only allows lists of type Symbol and Link so this makes handling this one tricky. I've started a solution for it but it doesn't feel quite right.

Support for Rich Text field type

Is it currently possible to support Rich Text fields? I'm running into problems updating a model that has this type of field and I use the following syntax:

 [ContentField(Id = "topic", Name = "Topic", Disabled = false, Required = false, Localized = false, Omitted = false, Type = SystemFieldTypes.Text)]
 public Document Topic { get; set; }

It gives me this exception:

Unhandled Exception: Contentful.Core.Errors.ContentfulException: Previously published fields are invalid

Would be good to only add validations to fields where they are allowed

Could add a property to ContentfulValidationAttribute for string[] ValidFieldTypes. Then during InitializeContentTypes we wouldn't add invalid validators to fields of the wrong type. I have a commit in my fork for this if it seems like a good idea.

I think it would prevent errors and doesn't rely on the developer to know what attributes can be added to what types.

Need to allow null in validation attributes (size, file size, image size)

I committed a file size validation attribute that handles null. Returning a validator from the attribute may not be the way we want to do it, but we need a way to return the nullable int without making it an attribute property.

The current SizeAttribute implementation will cause a Contentful error when it runs if the developer only wants a min size and null for max. The max will be sent to Contentful as 0 and we'll get an error that max cannot be smaller than min.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.