Inspired by Jeff Eaton and Roy Scholten's session on install profiles from Drupalcon Prague, I recently set about building a potential Snowman install profile for a musician using Drupal 8.

During the process I came across a few bugs in core (patches filed of course) and then started working on the main missing piece of the puzzle - a default content solution - using the REST and Serialization API's already in core.

Background

The first step in the process was getting a reasonable functioning site going with Drupal 8. As per the Snowman manifest, I was only allowed to use Core, no contributed modules. Much to my suprise I was able to get the site nearly fully functional, using only core. After the building was done, I started creating example content and then began looking at the best way to export it. I looked at how we did that in Drupal 7 and found that generally we encoded the data into a 'serialized' format. Now luckily the next session in my Drupalcon Prague playlist was Rest and Serialization in Drupal 8 by Lin Clark and Klaus Purer.

During that session I gleaned that the Serializer module in core is used by Rest module to encode a portable version of an entity. Sounds exactly like what we need for a default content solution.

First attempt

I started by enabling the Rest and Serialization modules and fetching some of the content in hal+json format and then saved them to disk and started stepping through the POST logic in the Rest module. This was relatively easy to get going, the Rest module is well architected and; as with most things in Drupal 8; being built on the plugin API made it immediately familiar.

Confident that I was onto something workable, I started work on creating a YAML serializer, as I felt the hal+json was too hard to hand-edit.

Here again, the architecture of the serialization module meant it was easy to register new serializers, and I was able to quickly knock-up a hybrid hal+yaml solution. Then I had something going in a basic format and thought it was time to discuss my approach with Lin and Klausi.

Community Feedback

So initial feedback from Lin and Klausi was that we had already rejected a Yaml serializer for Drupal core on security reasons (see the issue) so I decided to abandon that idea. Additionally they expressed trepidation about a hybrid hal+yaml format, as hal+json was an accepted format whilst the hal+yaml mutant hybrid was entering the unknown. So I reverted back to the original solution, hal+json and continued refactoring.

Dependency resolution

The next big piece of the puzzle was dependency resolution. If I had a default node file and that referenced a taxonomy term that was also default content, but not yet created, then the term reference field on the node would be empty. Luckily core already ships with Sam Boyers' Gliph library for resolving dependencies. With some help from Sam I was able to adapt my read logic to include a sort process so that entities were created in depdency order.

Putting it all together

Take the current code for a test spin from my github repo, note that without this core patch you can't import taxonomy terms, but thats down to a bug in the Hal EntityNormalizer.

Any module that requires default content can put hal+json versions of the entities in individual files inside {modulename}/content/{entity_type} folders. The module will detect any json files in folders matching content entity types at the time of install (just like default config) and import that content. 

For example see default_content_test in the repo which has the following structure

  • modules/default_content_test/content
  • modules/default_content_test/content/node
  • modules/default_content_test/content/node/imported.json
  • modules/default_content_test/content/taxonomy_term
  • modules/default_content_test/content/taxonomy_term/tag.json

This results in one node being imported (as specified in imported.json) and one term (tag.json).

At the moment these files need to be hand-created or exported using the Rest, Hal and Serialization modules. Note that the default functionality of the Hal module is to make all links point to the origin site's FDQN whilst the default_content module expects these (at this stage) to be relative to http://drupal.org as there is no point in having default content that can only be re-imported on the originating site. So for example the 'type' link for a page node-type has href http://drupal.org/rest/type/node/page, whereas the default hal serialization would use http://your.site/rest/type/node/page.

Next Steps

So the question from here is - where should this live - this is one of the final pieces of the Snowman puzzle and there is demand for this in core see these issues, however this is clearly a new feature, but maybe the new release cycle proposal means this can be considered for a future minor release.

If it lives in contrib, well that gives us time to iterate on a UI for exporting, although I'd argue that would never belong in core. 

So what do you think? Should I formulate this as a patch and add it to one of the core issues around default content? Or should it live out a cycle in contrib-land?