C5 versioning: Knowing if a block instance update should create a new version
Permalink 3 users found helpful
Howdy,
I have a custom block that has a one-to-many relationship in its db.xml file, and I'm having trouble with its versioning. Skipping going into heavy details, my block lists events (e.g. maybe one being a meeting and another an upcoming birthday). In its add.php and edit.php windows a user is capable of clicking a button that appends a fresh single event for them to fill out (they are able to keep appending more events as necessary, hence it being an event list).
In my controller save() method, I know when I'm coming from add.php or edit.php, and can save my data appropriately. When coming from an update (edit.php) my code checks each event for whether it has been either 1) newly added 2) just updated 3) left unchanged or 4) has been requested for removal. Each event is treated appropriately based on that check, with specific SQL carrying that out.
I should note here that I have one db table that C5 updates/handles being:
(yes... I ran into the single field mySQL error/C5 bug... *tear* thank you dummy_field, thank you)
And another table that has a foreign key relationship to the above one and that I do the handling of (hence the 1-4 options for what to do with each event when coming from edit.php).
The versioning issue I'm having comes when a user publishes a page with my block on it, then goes back into edit mode, making changes to the block, and then clicking save. In this scenario C5 has just created a new row with a new bID value in the table it deals with (this makes sense, that's its versioning at work) but I haven't found out yet how it knows it's supposed to create that new version. See, I need in on that info so I too, dear C5, can create new versions of my events with that new bID in the table I handle.
Is it that, perhaps, C5 never does an update on a block's rows but always re-creates them? I thought about taking such an approach, but in my thinking that opens up the potential for heavy data loss (which is why I update rather than remove a row and freshly create it).
Hopefully what I've said is clear, if not just let me know. Any clarifications or knowledge on how C5 deals with block versioning would be shaweet. So my question clearly stated (with nought but a tad bit of pre-filler *cough*) is how do I tell, from within my controller's save() method, that a user has just updated an instance of my block that should be saved as a new version within the database.
Cheers!
-Landson
P.S.
I am aware that you can turn off versioning for a block, but this is not what I need to do.
I have a custom block that has a one-to-many relationship in its db.xml file, and I'm having trouble with its versioning. Skipping going into heavy details, my block lists events (e.g. maybe one being a meeting and another an upcoming birthday). In its add.php and edit.php windows a user is capable of clicking a button that appends a fresh single event for them to fill out (they are able to keep appending more events as necessary, hence it being an event list).
In my controller save() method, I know when I'm coming from add.php or edit.php, and can save my data appropriately. When coming from an update (edit.php) my code checks each event for whether it has been either 1) newly added 2) just updated 3) left unchanged or 4) has been requested for removal. Each event is treated appropriately based on that check, with specific SQL carrying that out.
I should note here that I have one db table that C5 updates/handles being:
<field name="bID" type="I"> <key></key> <unsigned></unsigned> </field> <field name="dummy_field" type="I4"></field>
(yes... I ran into the single field mySQL error/C5 bug... *tear* thank you dummy_field, thank you)
And another table that has a foreign key relationship to the above one and that I do the handling of (hence the 1-4 options for what to do with each event when coming from edit.php).
The versioning issue I'm having comes when a user publishes a page with my block on it, then goes back into edit mode, making changes to the block, and then clicking save. In this scenario C5 has just created a new row with a new bID value in the table it deals with (this makes sense, that's its versioning at work) but I haven't found out yet how it knows it's supposed to create that new version. See, I need in on that info so I too, dear C5, can create new versions of my events with that new bID in the table I handle.
Is it that, perhaps, C5 never does an update on a block's rows but always re-creates them? I thought about taking such an approach, but in my thinking that opens up the potential for heavy data loss (which is why I update rather than remove a row and freshly create it).
Hopefully what I've said is clear, if not just let me know. Any clarifications or knowledge on how C5 deals with block versioning would be shaweet. So my question clearly stated (with nought but a tad bit of pre-filler *cough*) is how do I tell, from within my controller's save() method, that a user has just updated an instance of my block that should be saved as a new version within the database.
Cheers!
-Landson
P.S.
I am aware that you can turn off versioning for a block, but this is not what I need to do.
Thanks for the reply mkly, it is useful knowing what you posted! I'm not overly pleased with C5 not helping a bro out with this matter (I suggest a method "prestoVersioningWorks()" in a future release), but I'm still determined to find a way to accomplish what I've been working on via the manner of which I've been trying to do so.
I seem to recall I dealt with similar issues with an add-on I built 12 months back. It has foreign key relationship with a second table. Don't know if I dealt with it properly - but versioning was definitely an issue that caused a few bugs for me.
I don't recall what I did, but happy to send it you if you think it might help.
I don't recall what I did, but happy to send it you if you think it might help.
I have now solved my block's versioning issues, but thanks a ton for offering your block in my aid! That gesture is much appreciated!
Glad you resolved it. Your solution didn't ring any bells at all with me, but it was a while back. Looks very sensible though. Thanks for posting that back here.
I have finally resolved my block's versioning issues. The key in doing so was implementing my own version of the duplicate() method within my controller. What tipped me off to this method was this posthttp://www.concrete5.org/community/forums/customizing_c5/block-desi... .
Some useful files to inspect/try to understand are:
1) concrete/libraries/block_controller.php
2) concrete/libraries/block_view.php {NOTE: the class BlockRecord resides within this file}
3) concrete/libraries/3rdparty/adodb/adodb-active-record.inc.php
4) concrete/models/block.php
5) concrete/models/collection.php
Within the duplicate() method of your controller, $this->bID refers to the bID value of the block instance you just edited. It is the "old" version's value. If you want the new version's bID value you can get it by doing:
$this->bID in the save() method will be the new version's bID value, not the old one.
Worth noting is that when a new version of a block instance is created, the duplicate() method is called before the save() method gets called. What I found was that once my save() method was working, to implement versioning I only needed to make slight tweaks to it with the bulk of my efforts being on coding the duplicate() method.
Keep in mind that the duplicate() method only has to deal with just that, duplication. It doesn't need to handle how your POST data gets saved, it "simply" needs to duplicate (within the database) the instance of your block that has just been edited. The save() method is then called, and you can deal with updating/removing/adding to the new version's fields and table(s) there.
I'm hoping I've been clear enough, and am correct, in all that I've stated. My only saving grace is that it's almost 5am and I'm on 2 energy drinks/need to sleep.
Hope this versioning info helps someone out,
-Landson
Some useful files to inspect/try to understand are:
1) concrete/libraries/block_controller.php
2) concrete/libraries/block_view.php {NOTE: the class BlockRecord resides within this file}
3) concrete/libraries/3rdparty/adodb/adodb-active-record.inc.php
4) concrete/models/block.php
5) concrete/models/collection.php
Within the duplicate() method of your controller, $this->bID refers to the bID value of the block instance you just edited. It is the "old" version's value. If you want the new version's bID value you can get it by doing:
public function duplicate( $newBID ) { $newRecord = parent::duplicate( $newBID ); $newRecord->bID; // This is the new version's bID value }
$this->bID in the save() method will be the new version's bID value, not the old one.
Worth noting is that when a new version of a block instance is created, the duplicate() method is called before the save() method gets called. What I found was that once my save() method was working, to implement versioning I only needed to make slight tweaks to it with the bulk of my efforts being on coding the duplicate() method.
Keep in mind that the duplicate() method only has to deal with just that, duplication. It doesn't need to handle how your POST data gets saved, it "simply" needs to duplicate (within the database) the instance of your block that has just been edited. The save() method is then called, and you can deal with updating/removing/adding to the new version's fields and table(s) there.
I'm hoping I've been clear enough, and am correct, in all that I've stated. My only saving grace is that it's almost 5am and I'm on 2 energy drinks/need to sleep.
Hope this versioning info helps someone out,
-Landson
That was helpful! C5 should give you an award! I hope this gets added in the future documentations cause most of the solutions I've found are from people in the forums. Anyway, thanks for this!
Another way to go at it would be to make the Events Container a page type and then make an Event page type and make those events children of that particular Events Container. Basically creating an ancestral type has many relationship.
Trying to do it in a block is fairly complex at this point and you end up trying to hide from concrete5 versioning in my experience.
Someday I'm going to create a new more data based object off of the Collection object so we can stop using the Page object for everything, but that's currently how most people do it.
You can then you a block as a page list block essential grabbing particular pages.