7938 Posts in 1466 Topics by 943 members
|Go to End|
12 October 2011 at 3:40am Last edited: 12 October 2011 3:41am
At the moment we're developing a website which consists of pages which are to be entirely populated by "blocks" of content. The content author should be able to add as few as one block of content to a page, but also be allowed to add as many blocks of content as he wants to, in any order. All the blocks will be floated next to one another in the template and overflow to the next "line" when necessary (or when the content author decides a new line of blocks should start).
These blocks can be thought of as widgets. In fact, we've developed a similar website before using SilverStripe's Widget functionality to make the above description possible. However, we found that while Widget sounds like the most plausible approach, in practice it is lacking due to not being very organized (visually) and due to the fact that much hacking is needed to get certain FormField types to work in widgets.
Therefore, we are now trying a new approach with the current website, by developing the blocks of content as DataObjects and managing their order in a DataObjectManager. I've set up a "master" DataObject class which has a few DB fields which are shared among all the different content blocks (e.g. TextBlock, ImageBlock, VideoBlock, FormBlock, etc.) and a few other DataObject classes which have their own unique DB fields.
My question (finally ;-)) is whether or not there is any way to get a DataObjectManager to display all of the different classes representing blocks of content in a single DOM? When creating a DOM, one of the arguments is the source class and I've used the master class there. The $has_one and $has_many relationships between the classes are set up correctly. What I would like, is to be able to use the DOM's "Add" button to add any one of the block types (influencing the fields shown in the DOM popup) and also see the different block types listed in the same DOM instance.
13 October 2011 at 1:41am
An update: I've managed to get the DataObjectManager display the subclasses in it by using onAfterWrite() to retrieve the saved DataObject and implement newClassInstance() on it to duplicate it into the subclass table. Because of this, the ClassName field of the master class convienently is altered to contain the ClassName of the subclass it has been duplicated to.
The next step is saving the subclass data in its new record (in its own table), as upon creating an object of the master class, there was nowhere to put the data from the specific form fields during creation - but afterwards, there is. So I've saved the relevant form data into a Session variable (using onBeforeWrite()) and in onAfterWrite() I've added an update() to the subclass instance created with newClassInstance() to add the subclass data values to the DataObject. This does the job in terms of saving the DataObject to the database with a complete set of data, but there are still some problems at the moment.
1. Using the update() method in onAfterWrite() on the subclass instance causes SilverStripe to get stuck for a while and then display an error saying that memory has run out (this also happens if I try to set any random property of the subclass instance manually (e.g. $oSubInstance->RandomProperty = $randomVar); this occurs even though the records are successfully saved in the database.
2. Seeing as the master class' getCMSFields() function also retrieves the getCMSFields from the subclass which is being created at the time and adds them into the form, errors arise for form fields such as ImageUploadField. I think what's happening is the ImageUploadField tries to use URLs which point towards the master class' Form and seeing as the ImageUploadField isn't actually part of that Form, the actions aren't supported. Therefore, it's impossible to upload an image.
8 December 2011 at 2:48am
Hi, any chance on sharing your progress? I'm looking to do the exact same thing but not sure how to go about. I was thinking of using sub pages on the Site Tree to achieve the same functionality (these wouldn't appear in the menu but I would use the children control to get the sub content for each parent page and display accordingly).
14 December 2011 at 3:19am
Unfortunately, we abandoned this approach shortly after my last post in this thread, due to the problems I described in that post and seeing as no one else here seemed to have any ideas ;-) We ended up going with a single class which has an Enum database variable holding the names of all of the (previously available as) subclasses.
Following that, we limited the getCMSFields_forPopup() method to only allow setting of the generic properties when creating a new instance of the class. If the method is fired on an existing record, the Enum variable is checked and the designated FormFields are displayed for that CustomBlock type.
Hopefully this will give you some inspiration on how to deal with your problem?
14 January 2012 at 5:57pm
Here's my solution http://pitchandtone.co.nz/post/15812415474/inheritance-dataobjectmanager
14 January 2012 at 10:30pm
Your solution seems very promising, you should maybe make a module of it!
By the way, I’d like to congratulate you for your website, really nice posts there.
17 January 2012 at 2:05am
Thanks a lot for sharing your solution in this thread, it looks very promising I'll be sure to give it a shot next time we need this functionality in a project!
|Go to Top|