Swiftpack.co - Package - contentful/contentful-persistence.swift

contentful-persistence.swift

Version Carthage compatible License Platform Build Status Coverage Status

An integration to simplify persisting data from Contentful to a local CoreData database; built on top of the official Contentful Swift SDK. This library specifically uses the /sync endpoint of the Content Delivery API to synchronize all content in a Contentful space to device.

What is Contentful?

Contentful provides a content infrastructure for digital teams to power content in websites, apps, and devices. Unlike a CMS, Contentful was built to integrate with the modern software stack. It offers a central hub for structured content, powerful management and delivery APIs, and a customizable web app that enable developers and content creators to ship digital products faster.

Getting started

Prerequisite

Before getting started, it is highly recommended that you familiarize yourself with Apple's CoreData framework as many issues encountered during development may be CoreData specific. Read the CoreData Programming Guide and check out other (non-Contentful) examples.

Usage

The SynchronizationManager manages the state of your CoreData database and keeps it in sync with the data from your Contentful Space:

// Tell the library which of your `NSManagedObject` subclasses that conform to `EntryPersistable` should be used when mapping API resonses to CoreData entities.
let entryTypes = [Author.self, Category.self, Post.self]

// Initialize the data store and it's schema.
let store = CoreDataStore(context: self.managedObjectContext)
let persistenceModel = PersistenceModel(spaceType: SyncInfo.self, assetType: Asset.self, entryTypes: entryTypes)

// Initialize the Contentful.Client with a persistenceIntegration which will receive messages about changes when calling `sync methods`
self.client = Client(spaceId: "<YOUR_SPACE_ID>", accessToken: "<YOUR_ACCESS_TOKEN>")

// Create the manager.
self.syncManager = SynchronizationManager(client: self.client,
                                          localizationScheme: LocalizationScheme.all, // Save data for all locales your space supports.
                                          persistenceStore: self.store, 
                                          persistenceModel: persistenceModel)

// Sync with the API. 
self.syncManager.sync { _ in
  do {
    // Fetch all `Posts` from CoreData
    let post: Post? = try self.store.fetchAll(type: Post.self, predicate: NSPredicate(value: true))
  } catch {
    // Handle error thrown by CoreData fetches.
  }
}

Define your CoreData model

To make your model classes work with contentful-persistence.swift you will need to either conform to AssetPersistable for Contentful Assets, or EntryPersistable for Contentful entry types.

Then you will need to make the corresponding model in your projects xcdatamodel file. Both EntryPersistable and AssetPersistable types must have a non-optional id property as well as optional localeCode, createdAt, and updatedAt properties.

NOTE: Optionality on CoreData entities is a bit different than Swift optionality. Optionality on CoreData entities means that the property may be absent when a save-to-database operation is performed. To configure a property's optionality, open the "Data Model Inspector" in Xcode's "Utilities" right sidebar and toggle the "Optional" checkbox:

The mapping of Contentful fields to your data model entities will be derived automatically, but you can also customize it, by implementing the static func mapping() -> [FieldName: String]? on your class.

Below is an example of a model class.

import Foundation
import CoreData
import ContentfulPersistence
import Contentful

// The following @objc attribute is only necessary if your xcdatamodel Default configuration doesn't have your module
// name prepended to the Swift class. To enable removing the @objc attribute, change the Class for your entity to `ModuleName.Post`
@objc(Post) 
class Post: NSManagedObject, EntryPersistable {
      
    // The identifier of the corresponding Content Type in Contentful.
    static let contentTypeId = "post"

    // Properties of the `sys` object of Contentful resources.
    @NSManaged var id: String
    @NSManaged var localeCode: String?
    @NSManaged var createdAt: Date? 
    @NSManaged var updatedAt: Date?

    // Custom fields on the content type.
    @NSManaged var body: String?
    @NSManaged var comments: NSNumber?
    // NOTE: Unlike date fields in sys properties, this library can't store `Date` for custom fields.
    // Use `String` and map to date after fetching from CoreData
    @NSManaged var customDateField: String? 
    @NSManaged var date: Date?
    @NSManaged var slug: String?
    @NSManaged var tags: Data?
    @NSManaged var title: String?
    @NSManaged var authors: NSOrderedSet?
    @NSManaged var category: NSOrderedSet?
    @NSManaged var theFeaturedImage: Asset?

    // Define the mapping from the fields on your Contentful.Entry to your model class. 
    // In the below example, only the `title`, `date` and `author` fields and `featuredImage` link will be populated.
    static func fieldMapping() -> [FieldName: String] {
        return [
            "title": "title",
            "featuredImage": "theFeaturedImage",
            "author": "authors"
            "date": "date"
        ]    
    }
}

HINT: For array-based field types (like Short text, list), use the type Binary Data in the data model, and the type Data? (e.g. var tags: Data?) in the Swift code. To access the actual array contents, unpack the Data field with NSKeyedUnarchiver, e.g.:

extension Post {

    var theTags: [String]? {
        guard let tagsData = self.tags else { return nil }
        return NSKeyedUnarchiver.unarchiveObject(with: tagsData) as? [String]
    }
}

Installation

CocoaPods installation

CocoaPods is the dependency manager for Objective-C and Swift, which automates and simplifies the process of using 3rd-party libraries like the ContentfulPersistence in your projects.

platform :ios, '9.3'
use_frameworks!

target :MyApp do
  pod 'ContentfulPersistenceSwift', '~> 0.13.0'
end

Carthage installation

You can also use Carthage for integration by adding the following to your Cartfile:

github "contentful/contentful.swift" ~> 0.13.0

Documentation

For further information, check out the Developer Documentation or browse the API documentation. The latter can also be loaded into Xcode as a Docset.

Contributing and development

To get started contributing, clone the project, cd into the root directory and run the following: make setup_env.

make setup_env
carthage bootstrap --platform all

This command will install all the development dependencies necessary to build the project, and execute the tests. To run the tests from the command line, execute make test. Tests should also all run directly from the Xcode app.

License

Copyright (c) 2018 Contentful GmbH. See LICENSE for further details.

Github

link
Stars: 14

Dependencies

Used By

Total: 0

Releases

0.15.3 - 2020-09-01 09:38:53

  • Updated contentful.swift dependency to 5.2.0.
  • Fixed updating relationships between entry and its parent when that entry has been unpublished and published between synchronization calls.

NB: Resyncing data is necessary to make the relationship cache work for all models. The sync token should be removed and content should be synced again to let the RelationshipCache cache all the relationships.

0.15.2 - 2020-06-17 08:37:05

  • Update Contentful.swift version

- 2020-01-08 11:04:48

0.14.0 - 2019-11-26 14:26:52

0.13.0 - 2018-11-22 17:18:44

Changed

  • BREAKING: contentful.swift has removed its own dependency on Interestellar and therefore the package is no longer a required import. The Contentful SDK now has its own Result type. If you were relying on fetch methods that returned an Observable, you will need to update your code to simply switch on the result.
  • BREAKING: Another side-effect of the updated dependency on contentful.swift is that the localeCode property on your NSManagedObject subclasses must now be marked as optional. Don't forget to check the "Optional" box in the assistant Xcode editor for your @NSManaged variable in the CoreData model editor.
  • The project is now updated to Swift 4.2.

0.12.1 - 2018-07-30 10:57:18

Fixed

0.12.0 - 2018-07-02 14:09:34

Changed

  • If there are ever any (currently) unresolvable relationships returned on a page, they will now be cached to disk so that if the user quits the app, the relationship will still be resolved when the target resources are returned in subsequent sync operations. Thanks to @marcin-bo for submitting the fix in #60

0.11.0 - 2018-04-24 14:39:17

Changed

  • BREAKING: If you were using the methods to seed a CoreData database on first launch, you will need to re-run the command from contentful-utilities.swift to generate the bundle files. This change coencides with the fact that environments are now locale specific.
  • BREAKING: Upgrades project to Xcode 9.3 and Swift 4.1

0.10.0 - 2018-04-06 13:23:47

Added

  • BREAKING: Ability to store all asset metadata in AssetPersistable has been added. Conforming to the new protocol contstraints is a breaking change and you should make sure to resync all data to ensure this metedata is stored properly.
  • You can now use the fetchData(for:with:) method from contentful.swift on AssetPersistable instances

Changed

  • BREAKING: The library is now upgraded to Swift 4.1 and Xcode 9.3

FIXED

  • Assets that contained media files that were not images failed to deserialize the metadata about the file properly, see contentful.swift #182

0.9.1 - 2018-02-07 14:59:31

Fixed

  • Relationships were not resolving when seeding a database from bundled content if the source and destination resources were in different files. Fixed in #48

0.9.0 - 2018-01-09 17:43:26

Improved

  • Improved test coverage to capture edge cases for various models.

Added

  • Contentful.Location can now be stored as an 'Transformable' attribute on a CoreData entity in the Xcode data model editor and on your NSManagedObject subclasses.

0.8.0 - 2017-11-28 13:29:16

Changed

  • Travis now deploys the reference documentation from the gh-pages branch when a new tag is pushed.
  • Upgraded dependency on Contentful to 1.0.0-beta3 and updated development dependencies.

Fixed

  • Issue where seeding CoreData db from bundled JSON files only created entities for the spaces default locale in #39

0.7.0 — Swift 4 - 2017-10-06 08:25:09

Changed

  • BREAKING: Migrated to Swift 4; you must now use Xcode 9 in order to develop with the persistence library

6.6.2 - 2017-09-22 08:55:58

  • Bug that caused SynchronizationManager to fail seeding a CoreData database from bundled content because of lack of localization context.

0.6.1 - 2017-09-08 15:53:04

Fixed

  • Project configuration so that contentful-persistence.swift may be built from source without warnings. Implications:
  • Dependencies are still managed via Carthage but using the --use-submodules flag. Thus, dependencies are all tracked as submodules and the source (i.e. Carthage/Checkouts) is now tracked in git.
  • Now travis doesn't install carthage or use it at all to build the project and ContentfulPersistence.xcodeproj framework search paths are cleared.

Added

  • Methods on SynchronizationManager to seed a CoreData database from bundled content.

0.6.0 - 2017-07-31 13:53:11

Added

  • The ability to a LocalizationScheme on SynchronizationManager which determines for which locales data should be saved to your persistent store.

Changed

  • BREAKING: ContentPersistable is now called ContentSysPersistable
  • BREAKING: mapping() is now called fieldMapping() to clarify that only 'fields' from your Entries ContentModel must be mapped.
  • BREAKING: localeCode: String is now a necessary property for ContentSysPersistable model classes.

Fixed

  • Removed use of try! in the codebase Issue #25. Fix by @tapwork in #26

0.5.0 - 2017-07-18 14:24:14

Fixed

  • Bug where "clearing" a field in an Entry did not nullify the corresponding persisted property.
  • Bug where deleting a relationship in Contentful did not nullify the corresponding persisted relationship.
  • Crash caused by explicitly defining mapping for relationships.

Changed

  • BREAKING: Mapping must be explictly define for types conforming to EntryPersistable

0.4.0 - 2017-06-21 15:06:09

Changed

  • BREAKING: ContentfulSynchronizer is now called SynchronizationManager
  • BREAKING: Rather than initializing SynchronizationManager with a Contentful.Client instance, the - Contentful.Client is now initialized with a SynchronizationManager instance as the persistenceIntegration parameter in the Client initializer.
  • BREAKING: The manner in which content type identifiers map Contentful responses to NSManagedObject model classes is now changed: SynchronizationManager is initialized with a PersistenceModel which is constructed by passing in your NSManagedObject subclasses that conform to either SyncSpacePersistable AssetPersistable or EntryPersistable.

v0.3.0 - 2017-02-07 09:37:37

  • Swift 3 support
  • Cross-platform support for Carthage installations.

v0.2.3 - 2017-01-27 12:43:24

Updated release to be used with contenful.swift v0.2.3 fixing an issue where links were not resolved on subsequent sync operations, or multiple page sync operations.

contentful-persistence.swift 0.2.0 - 2016-05-18 12:48:13

Added

  • fetchRequest convenience method on CoreDataStore

Fixed

  • Use ContentfulSwift as module name for the Pod

contentful-persistence.swift 0.1.0 - 2016-04-19 12:52:56

Initial release.