Add a Header

If you visit the page now you will see a very basic non-themed form without any of the necessary navigational structure. Note that this happens because the form processing page, in this case view.php, is being accessed directly via the URL and not by being included in another page. This means that the necessary infrastructure must be added directly to the script. Add this by using the print_header function, but a few pieces of data are needed to build appropriate navigation. Make the following adjustments to view.php:

Don't forget to include definitions for the new strings that you are creating, into block_simplehtml.php

Form State Control

Now to add some basic form state control: The first step is to setup the appropriate actions based on the form state, accounting for three scenarios:

user has cancelled

form submitted and passes validation protocol. Process form data accordingly.

form either doesn't pass validation protocol or it is being displayed for the first time

To implement these three scenarios adjust the code a bit. The existing form display and header code will be used as the first time display code, and an if statement added after instantiating the simplehtml_form object will handle the logic behind the application flow:

if($simplehtml->is_cancelled()){// Cancelled forms redirect to the course main page.$courseurl=new moodle_url('/course/view.php',array('id'=>$id));
redirect($courseurl);}elseif($simplehtml->get_data()){// We need to add code to appropriately act on and store the submitted data// but for now we will just redirect back to the course main page.$courseurl=new moodle_url('/course/view.php',array('id'=>$courseid));
redirect($courseurl);}else{// form didn't validate or this is the first display$site= get_site();echo$OUTPUT->header();$simplehtml->display();echo$OUTPUT->footer();}

Notice that the existing header and form display code have been moved into the third branch of the conditional. Also, there isn't any code to handle form processing. That code will be added shortly.

Final Steps

Reviewing the progress so far:

simplehtml_form.php is created which defines the class used later to display our form.

view.php is created which:

loads base moodle API and any necessary third party modules or non-base API files.

loads the necessary course object and globals.

performs necessary access control.

loads our form and branches execution appropriately based on our form state.

So the form class is defined and the form is displayed in a separate file. Adding elements to the form and finishing the processing of our form will wrap it up!

Add Form Elements

Currently there are no form elements which can submit data. Editing the form class definition in simplehtml_form.php will change that by adding a wide set of form elements to the form for demonstrative purposes only. This will give an example of how to add and process various form elements.

To add the link title text field and the displaytext HTML area to the form, paste the following text in the function definition of the simplehtml_form.php file:

For full details on addElement() review the moodle documentation on addElement. Also review addRule() in moodle's documentation and the PEAR web site. PEAR is an included form processing library that moodle uses for form processing.

Now add additional form elements to simplehtml_form.php:

File Upload

This field allows the user to choose a file in the course file directory. Notice that the name of the element in the form is the same name as the field in the database. This will make it easy to insert and update the database records later.

Now include the above file in any files that need to use the function, for now this is just simplehtml_form.php. Add the following after require_once("$CFG->libdir/formslib.php"); in simplehtml_form.php

require_once($CFG->dirroot.'/blocks/simplehtml/lib.php');

You now need to add some pictures to the pix directory. In this example I have three gif images each a different colour, but you could use any image (small is better). Create a directory called pix in your simplehtml block directory. Now add the radio select to the form definition (simplethml_form.php)

Note that there is an attributes variable added to the text field to limit its size and length.

Date Time Selector

The setAdvanced() function adds advanced options to a form. To use this function pass in the name of the form element, group of elements, or header. The "Advanced Options" button appears in the upper right corner of the fieldset. In this example, there is a single element, but later you'll see an element within a header. Learn more about setAdvanced. The"Show/Hide Advanced" button won't be displayed until adding action buttons to the form during the next step of this tutorial.

The above code adds a form header and sets it to hide the date/time selector within the optional (advanced) form controls.

Add State Variables and Finalize the Form

Adding Form Buttons

Most moodle forms have a basic set of buttons. "Submit" and "Cancel" are added by calling the moodleform member function add_action_buttons(). Add the following at the end of simplehtml_form.php

$this->add_action_buttons();

Notice when calling add_action_buttons(), $this is used rather than $mform because add_action_buttons() is defined in the base class moodleform and would be outside scope for $mform.

Add State Variables

Sometimes forms need to keep track of additional data that is not intended to be visible to users. These fields should be placed in hidden elements. For this form blockid and the courseid are needed. Before the call to add_action_buttons() add:

Process Form Data

After creating the form, appropriate code must be added to process the submitted form data. Accomplish this by adding code to view.php. Typically when processing form data it is helpful to remove some of the final processing steps so that your script essentially terminates execution and does not redirect you to the course page or wherever makes sense. This is tremendously helpful while debugging. The processing code will be added to this block of code in view.php :

}elseif($fromform=$simplehtml->get_data()){// We need to add code to appropriately act on and store the submitted data// but for now we will just redirect back to the course main page.$courseurl=new moodle_url('/course/view.php',array('id'=>$courseid));
redirect($courseurl);

Notice that the else if statement has been modified to create the variable $fromform.

For now comment out the redirect and add the following above it.

print_object($fromform);

print_object() is a useful moodle function which prints out data from mixed data types showing the keys and data for arrays and objects. Now visit the "Add Page" link for the block and submit some form data. You should see something similar to:

The values in brackets are the keys and the portion after => is the data for that particular key. Since the form submission is verified as working as expected, save the submitted form data. The most direct way to save is with a call to insert_record(). This function takes the name of the table, 'block_simplehtml' in our case, and the object to be inserted. The object must have keys that map one-to-one with table column names. Choosing form element names that map directly to the database columns saves a bit of code. Save the submitted form data with the following code pasted above the commented out redirect:

// We need to add code to appropriately act on and store the submitted dataif(!$DB->insert_record('block_simplehtml',$fromform)){
print_error('inserterror','block_simplehtml');}

This code checks to see if we are updating or inserting into the database. We have not created the database yet, so this code won't work. Continue on to the next section and create the database before testing this code.

Creating a Database

We will be using the XMLDB Editor to design and create the database table that will hold the data from the form that we have just created. We have eight pieces of information to store from the simplehtml form.
First create a folder named db under you main block directory. Next login to Moodle and navigate to the XMLDB editor, located in the 'Site administration->Development->XMLDB editor'. The XMLDB editor is a graphical interface to help generate the xml files that Moodle uses to create and maintain database tables. When you get to the XMLDB editor you will see all the blocks, modules and other areas that have db directories. Those that show a link already have tables defined that can be loaded and modified. Find the blocks/simplehtml/db and click on Create.

The db directory has an install.xml file with some basic information about your block and one table called simplehtml. In Moodle you will now see the block/simplehtml/db highlighted in green and the Load and Delete commands will be linked. Click on Load. Now you will see the Edit and Unload text linked. Click on Edit.

The simplehtml table must be modified to include the information entered from the form: click on the Edit link next to the simplehtml table to display the definition that is created by default for the table. Id field will be there and a primary key that links to the id field. Rename the table to block_simplehtml (if necessary). Alter the comments for this table here as well. Any changes to the comments field requires a click on the Change button for the changes to be recorded.

Now add the following fields:

blockid

pagetitle

displaytext

format

filename

picture

description

displaypicture

displaydate

blockid

The blockid is a foreign key that references the block table. This will be used to join our data rows to the block table. The block table houses generic block information for installed block instances. To add the blockid field:

Click the "New Field" link

Change the Name to blockid

Enter a Comment about the field

Set the Type to int

Enter a Length of 10

Set Not Null to not null

Set Sequence to No

Enter 0 for the Default

Click the Change button.

pagetitle

The pagetitle is simply text that will be used for links to this simplehtml page. Using default Moodle Themes, Moodle blocks cannot handle more than 25 characters without wrapping. To add the pagetitle field:

Click the "New Field" link

Change the Name to pagetitle

Enter a Comment about the field

Set the Type to char

Enter a Length of 25

Set Not Null to not null

Click the Change button.

display text

The displaytext field will be displayed as text on the simplehtml page, potentially as HTML. To add the dispaytext field:

Click the "New Field" link

Change the Name to displaytext

Enter a Comment about the field

Set the Type to text

Set Not Null to not null

Click the Change button.

format

The format field will contain the integer value that represents the format the text was entered in. To add the format field:

Click the "New Field" link

Change the Name to format

Enter a Comment about the field

Set the Type to int

Enter a Length of 3

Set Not Null to not null

Set Sequence to No

Enter 0 for the Default

Click the Change button.

filename

The filename field stores the name of a file the instructor posts on the simplehtml page, which students can then download or view. To add the filename field:

Click the "New Field" link

Change the Name to filename

Enter a Comment about the field

Set the Type to char

Enter a Length of 255

Set Not Null to not null

Click the Change button.

picture

The URL for the user's chosen picture is in a predefined static variable that associates a number to a picture. This will allow the addition of more pictures later if necessary, or for changing the current pictures' URLs without updating the database. Because only the number is stored the database field should be created as an int rather than a char. To add the picture field:

Click the "New Field" link

Change the Name to picture

Enter a Comment about the field

Set the Type to int

Enter a Length of 2

Set Not Null to not null

Set Sequence to No

Enter 0 for the Default

Click the Change button.

description

Add the description field that will be displayed on the page. To add the description field:

Click the "New Field" link

Change the Name to description

Enter a Comment about the field

Set the Type to text

Set Not Null to not null

Click the Change button.

displaypicture

The displaypicture field will be the "yes" or "no" question on the form. This is best represented as an 'int'. To add the displaypicture field:

Click the "New Field" link

Change the Name to displaypicture

Enter a Comment about the field

Set the Type to int

Enter a Length of 1

Set Not Null to not null

Set Sequence to No

Enter 0 for the Default

Click the Change button.

displaydate

The final field to add to the table is the displaydate. It is a UNIX timestamp which is an integer value. To add the displaydate field:

Click the "New Field" link

Change the Name to displaydate

Enter a Comment about the field

Set the Type to int

Enter a Length of 10

Set Not Null to not null

Set Sequence to No

Enter 0 for the Default

Click the Change button.

Now that the fields have been added to the table the install.xml needs to be saved. Click the "Back" link and the "Back to Main". Once on the main page click the "Save" link to save the changes to the install.xml. Remember update code wasn't added to install the database table after the block has already been installed. When developing within a localized environment load the database by uninstalling the module and then reinstalling it. In normal circumstances where the block or module has been in production use you would need to do this with proper update code.
Now you should be able to test your code. You can view the data was stored in the proper table by viewing the table block_simplehtml via phpadmin.

Refining the User Interface

After successfully submitting data to the database via the form it is now time to begin displaying that data so that users can interact with the data and view what has been submitted. Both steps will be contained within simplehtml/block_simplehtml.php.

Add Links to Each Page of the Block

To retrieve the relevant rows we will call $DB->get_records(), which accepts two parameters::

The table name

An array with the name of the column or field to be queried and the value of the queried field we want to match.

Add the following code:

global$COURSE,$DB;//$COURSE should already be present...if(!empty($this->config->text)){$this->content->text=$this->config->text;}// This is the new code.if($simplehtmlpages=$DB->get_records('block_simplehtml',array('blockid'=>$this->instance->id))){$this->content->text.= html_writer::start_tag('ul');foreach($simplehtmlpagesas$simplehtmlpage){$pageurl=new moodle_url('/blocks/simplehtml/view.php',array('blockid'=>$this->instance->id,'courseid'=>$COURSE->id,'id'=>$simplehtmlpage->id,'viewpage'=>'1'));$this->content->text.= html_writer::start_tag('li');$this->content->text.= html_writer::link($pageurl,$simplehtmlpage->pagetitle);$this->content->text.= html_writer::end_tag('li');}$this->content->text.= html_writer::end_tag('ul');}

It is important to remember that the property $this->content->text is ignored by list blocks. Therefore, for this example ensure that the block_simplehtml class extends block_base and not block_list.

Refactor Display Method

To avoid any code duplication and make it easy to reuse this functionality create a function in lib.php to handle the page display. A preloaded simplehtml page is passed in as a single parameter, and an optional parameter will control whether the data is returned or directly printed out. Most Moodle functions that print information can be passed a true value as the last parameter. This is the function's return value, which tells the function to return the HTML and not print or echo it to the user. For development, set the return value to false so that the data is printed out.

function block_simplehtml_print_page($simplehtml,$return=false){}

Now consider what the function needs to do in order to display all of the necessary information from our page.

Page Title

Print this out as a centered header for the HTML PAGE

Display Text

Print this out in whatever format the user specified, centered in a box on the page

Filename

Display a link to the file in the course file directory so the user has the option to download it. This will be centered in the same box as the display text.

Display Picture

Display the picture with the description on the right of the picture in a box if the user has chosen for the picture to display

Display date

Display the date under the page title in a smaller font

Add Page Title

To display the page title use the $OUTPUT class. Add the following to block_simplehtml_print_page() in lib.php

After we have displayed the title, let's add a box to put around the rest of the elements that we will display.

$display.=$OUTPUT->box_start();

This is the opening tag for the box, we will have to enter similar code later, to encapsulate the elements.

Display the Date

The requirements for date display call for displaying the date in a smaller font under the page title. Moodle has a userdate() function that has several advantages over PHP's date() function. It displays the date in the user's preferred format and adjusts the date for any timezone difference.

Notice that since the user had an option of choosing a date or not that you must check to ensure that it was set before trying to output it. Take a look at the displayed page: click on one of your page links from the block. There's no output. Add some additional code that handles the value of $return. Add the following at the end of the function definition:

if($return){return$display;}else{echo$display;}

As mentioned earlier, the requirements for the date field were to be centered under the page title and smaller. This can be controlled with a stylesheet.

First, put a div tag around the date, and give it a class to target with CSS later. Change the date output lines:

Choosing the second option, adding a styles.css file, allows more flexibility and avoids needing to create multiple entries if the site is using more than one theme. Create styles.css and add this CSS:

Try the simpleHTML block out and view the different pages that you have created.

Add editing capability

At the moment we have no way to edit the pages that we have created. Our block really does need a way to edit the existing data. The edit feature will use an image to link to the view.php instead of text. This image will only appear when the instructor turns editing on.

Moodle stores pictures and icons in the pix directory under the base moodle directory. You can also use pictures that are custom to a theme. These are stored within the theme's pix directory. For this example, use the icons in the pix directory for moodle. The image should be encapsulated in an HTML link to simplehtml.php. The url should pass the block instance id, block id, and course id to simplehtml.php.

Notice that there's a link to the same file view.php that handled the page adding. Make a few adjustments to view.php so that pages can also be updated.

First, modify the form to have a new hidden field called id to store the id of the record in the database to know which page to update. Add the following to simplehtml_form.php :

$mform->addElement('hidden','id','0');

Second, we alter the way the submit is handled in view.php

...$toform['blockid']=$blockid;$toform['courseid']=$courseid;$toform['id']=$id;...// We need to add code to appropriately act on and store the submitted dataif($fromform->id!=0){if(!$DB->update_record('block_simplehtml',$fromform)){
print_error('updateerror','block_simplehtml');}}else{if(!$DB->insert_record('block_simplehtml',$fromform)){
print_error('inserterror','block_simplehtml');}}...// form didn't validate or this is the first display$site= get_site();echo$OUTPUT->header();if($id){$simplehtmlpage=$DB->get_record('block_simplehtml',array('id'=>$id));if($viewpage){
block_simplehtml_print_page($simplehtmlpage);}else{$simplehtml->set_data($simplehtmlpage);$simplehtml->display();}}else{$simplehtml->display();}...

Page Deletion

After being able to add a page and edit a page, what else would someone need to do with our html pages? Delete! Deleting is a simple operation; requiring a few simple steps::

Add a link to a new delete.php file

Create the delete.php file

Print a verification form to the screen in case the user made a mistake

Use delete_record() to delete a record from the simplehtml table given an id and a confirmation.

Add a link to delete a simpleHTML page

Begin by editing block_simplehtml.php and creating a link just after the edit link.

Create delete.php

Refresh the course page and you should now see a black X icon next to each page after the edit icon (when editing is turned on). The purpose of delete.php is to print out a notice to the user with a verification that the user wants to delete the simplehtml page. The notice will either return the user to the course if they say No, or delete the page and return the user to the course if they say Yes. Moodle has a predefined core function in weblib.php that will create the Yes-No form for you and send the user on to the correct locations based on the answer to the question. The function is called notice_yesno(). Before using this, setup the basic file structure for delete.php (it's similar to what has been used for most of the other files like view.php and simplehtml.php).

Notice that this is similar to what has been used so far, but there another optional parameter 'confirm' has been added.

This variable will be set when the user clicks the Yes or No button on the form. This means that a test needs to be added to test for the return value; if it is set then the database record containing the simple page id should be deleted. Add the following code after the all to the $PAGE->set_heading($heading); function:

In the if statement above, the two variables optionsno and optionsyes are set. These are used to pass variables from the form to get or post when the user selects "yes" or "no." They are passed to the $OUTPUT->confirm() function as the third and fourth parameters. If the user clicks "no" they are sent to the course page, which means the courseid needs to be added to the form. If the user clicks "yes" the database record containing the simplehtml page id is deleted and the user is forwarded to the course. The page id, courseid, confirm, and the session key need to be passed to the form. The session key is passed to prevent the possibility of a cross-site scripting attach or users submitting valid form data without using Moodle.

Final Clean up

The block is almost finished! The one thing that has not been done is the cleanup of all data associated with the block on deletion. This is accomplished by adding a function named instance_delete() to block_simplehtml.php. In this function call delete records uses the blockid to pass in the $this->instance->id variable. The function looks like this:

Now bump the version number up in blocks/simplehtml/version.php. Increment the last digit of $plugin->version.

Next go to the notifications link in the Site Administration block. This should update the simplehtml block. Verify that capabilities have been added by going to Users > Permissions > Define roles and selecting Manager. Search for simplehtml.

What does the simplehtml:viewpages mean? The presence of a string surrounded by double square brackets implies that there is a string referenced in code that has not been defined in an appropriate language file. Add the following to lang/en/block_simplehtml.php:

Add check to the block for the capability

With the two new capabilities created, it's time to use them and add a link to the form in the block. The link to the creation page is in the footer, so it's critical that the person viewing this link has the capability to manage a simplehtml page. Modify the get_content() function in blocks/simplehtml/block_simplehtml.php to check for the correct capabilities.To check for the capabilities, use the has_capability() function found in lib/access.php. Alter block_simplehtml.php to include checks for these capabilities.

$context= context_course::instance($COURSE->id);if(has_capability('block/simplehtml:managepages',$context)){$url=new moodle_url('/blocks/simplehtml/view.php',array('blockid'=>$this->instance->id,'courseid'=>$COURSE->id));$this->content->footer= html_writer::link($url, get_string('addpage','block_simplehtml'));}else{$this->content->footer='';}// Check to see if we are in editing mode and that we can manage pages.$canmanage= has_capability('block/simplehtml:managepages',$context)&&$PAGE->user_is_editing($this->instance->id);$canview= has_capability('block/simplehtml:viewpages',$context);...if($canview){$this->content->text.= html_writer::link($pageurl,$simplehtmlpage->pagetitle);}else{$this->content->text.= html_writer::tag('div',$simplehtmlpage->pagetitle);}

Refresh the Moodle course to which you have added the simplehtml block. As an administrator or teacher you should see the 'addpage' link; as a student you should not see the link. If you login as a guest you should also not that you can no longer view the pages.

Add Role to the simplehtml Form

Currently any logged-in user can use the simplehtml form. In development this is not as big of a concern, but before moving into production always ensure that users have access to only those portions of the application that they should. Add the following line in view.php after require_login($course);.