Advanced Block Development: Part Four
Andrew starts by discussing some details about cache lifetime and then segues into...
Blocks and Databases
You can find the db.xml that Andrew is running through in concrete/blocks/survey/db.xml. If you look in the survey block's db.xml, you can see how most blocks are structured.
The file has a basic definition of a block, which should be familiar if you've built a block before:
<table name="btSurvey"> <field name="bID" type="I"> <key ></key> <unsigned ></unsigned> </field> <field name="question" type="C" size="255"> <default value=""></default> </field> <field name="requiresRegistration" type="I"> <default value="0"></default> </field> </table>
Since this is a more complicated block, it also includes some tables to store the auxilary data, like the
btSurveyOptions table, which has its own primary key, but also the bID of the original block it is stored on in order to establish a relation of the two tables.
<table name="btSurveyOptions"> <field name="optionID" type="I"> <key></key> <unsigned></unsigned> <autoincrement></autoincrement> </field> <field name="bID" type="I" ></field> <field name="optionName" type="C" size="255" ></field> <field name="displayOrder" type="I"> <default value="0"></default> </field> </table>
If you check out the block's controller, you can see how the database queries are built. Concrete5 uses the ADODB database library, but it does not have a full ORM / CRUD system.So you will need to write database queries in order to retrieve or update data.
Here is a link to the ADODB manual. Here is a simple select statement from
hasVoted in the survey block's controller:
$db = Loader::db(); $v = array($u->getUserID(), $this->bID, $this->cID); $q = "select count(resultID) as total from btSurveyResults where uID = ? and bID = ? AND cID = ?"; $result = $db->getOne($q,$v);
It uses the loader to get a connection to the database, sets an array of data from the object, assigns a query to a string, then gets the first result from the database that matches that query. In this case the database should only have one result for this query. The main thing to notice here is the order of the items in the array, and then the order of the
column = ? pairs in the query string. ADODB will use the query string, then apply the values in the array to the question marks, so be sure that your array is in the right order on more elaborate queries or you will have data problems.
Typically you want to use the ADODB library's
Get... functions for
SELECT stuff and
Blocks and Actions
As Andrew points out, the main difference between block actions and page actions is the way the function is named in the controller. So for instance posting to
$this->action('action') would call
function action_action() in a block controller and not
function action() as it would in a page controller.
Delete and Duplicate
A block will clean its own table up, but for the same reasons relational data doesn't get created automagically, you need to write some queries. So for example, if the survey block only had
btSurvey to look after, it would clean itself up. But since it has supporting data, this needs to be cleaned up first. You can check out
delete in the survey block controller. In general, you delete any rows from your supporting data "where bID = the bID of this block", then run
parent::delete() to get rid of the row from your block's table.
The same thing goes for duplicate, except your queries will be more elaborate. Like Andrew says: don't forget this, or copied blocks and pages featuring this block will be a mess.
Andrew mentions that you can set
$btIncludeAll = true and the block will not version. This basically defeats one of the key features of concrete5, but it might have its place.
Blocks Outside of View Context
It is possible to use
Loader::block('block_handle') to load the controller for a block, which doesn't actually load a block, but it does make the class of your block available. This is particularly useful if your block controller has some static methods and you can then do things like
Andrew wraps up by reviewing some concepts from basic block development and looks up this example about using ajax. He also mentions the "Mobile Theme Switcher" add-on. This is part of the core as of 5.6.
Hopefully this has provided you with some insight on how to create more interesting, interactive blocks within concrete5.