silverstripe/silverstripe-framework — pull request #2206 by tractorcow (2013-07-09 23:02:35+00:00)
Title: API 3.2 Polymorphic has_one behaviour (don't merge)

This pull request introduces the ability to specify polymorphic `has_one` associations; That is, relationships that are not exclusive to a single foreign class. This function is supported by an additional (relation-name)Class column alongside the (relation-name)ID for such relationships.

Documentation has been updated to demonstrate how this could be used, although I haven't yet created an upgrade document (as my ORM pull request https://github.com/silverstripe/silverstripe-framework/pull/1360 actually creates the changelogs/3.2.0.md file). Should I make one for this PR too?

A polymorphic relationship is specified by using `DataObject` as the foreign class on the `$has_one`. There is no support for polymorphic `many_many`.

Implementation is provided by a new `PolymorphicHasManyList` class that extends `HasManyList`, and a `PolymorphicForeignKey` class which is actually a composite field. I have changed the behaviour of `FormScaffolder` to allow certain fields to 'opt out' of field scaffolding, as I don't feel there is currently an appropriate field that can be automatically scaffolded for polymorphic `has_one`. Please correct me if this is incorrect. :)

The main use case where this feature could be of benefit is when a generic feature (such as a banner image) could be used on 3-4 `SiteTree` subclasses across the site, but not on every one. Previously you would either have to add the relation to the `Page` class, duplicate or subclass the object for each `SiteTree` subclass, or force all of those classes to have a common parent class (whether or not that is appropriate).

There is slight a performance hit to such a relationship over a typical has_one, but if used effectively to replace areas where hacks or excessive coding would otherwise be necessary, it could have a net performance gain (especially where additional subclasses / page tables could be avoided). A specific warning on this topic has been added to the documentation.

As I was working through this project I resolved a series of additional issues which may or may not be necessary to merge into 3.1 as separate pull requests, although I'd probably err in favour of leaving them for 3.2.

- There were no docs on `belongs_to` in `topics/datamodel.md`, so I've created documentation
- There was a slight issue in `HasManyList` where items not belonging to the list could be 'removed'. The actual behaviour was to remove it from the list it actually belongs to instead. I've resolved this issue in both `HasManyList` and `PolymorphicHasManyList`, along with appropriate test cases for each.
- This pull request actually duplicates some changes from https://github.com/silverstripe/silverstripe-framework/pull/2202. I would like to get some feedback from you all on that pull request, and perhaps get that merged / closed before I finalise this pull request.
- There is a notable issue with this new feature is that it doesn't support objects changing class. If I turn a `HomePage` into `LandingPage`, any objects pointing to this via a polymorphic has_one will be orphaned. Can anyone give advice on whether or not this should be resolved somehow (and how), or otherwise assumed as an acceptable drawback when using polymorphic relations?

Lots of test cases have been included.