Developing Using the Framework

Adding a new page

The Framework is entirely driven from the database so you have to add new pages using the Admin > Pages menu item as this will create the necessary database entries. You will normally chose either a Template or a Object page — all the other options are for redirecting to other URLS, either internally or externally. If the page is essentially static, that is it has no sub-pages or does no form handling, then you should chose Template, otherwise chose Object.

If your system has appropriate access permissions then adding a page, let's say called example, will create a file called twigs/content/example.twig. If you have chosen an Object type, then it will also create class/pages/example.php. If these files do not appear then you should create them yourself based on the structure contained in the files sample.txt that are in the class/pages/ and twigs/content/ directories. Remember to rename the class from Sample to whatever your page name is, and to fill in the various comment fields with relevant information.

It's important you do not alter any of the files in class/framework, twigs/framework or any of the framework model files in class/model as this could interfere with updates and new features that get released. The framework provides hooks for extending its functionality : the files in class/support and class/modelextend give you ways of adding new methods to existing framework objects.

Headers, footers etc.

The directory twigs/surround/ contains files that can contain page headers and footers that will appear by default on every page. These are distributed as empty so no footers or headers will appear. The file navbar.twig controls the content of the navigation bar that appears at the top of each page and this is where you should add new menu items. Be careful not to remove the Admin menu items!

Handling RESTful URLs

If you are using AJAX then you need to read the AJAX documentation to see how to integrate your code into the Framework AJAX backend. You will need to use some of the methods described below when implementing your code.

The Framework treats all incoming (non-AJAX) URLS the same way. It sees them as being constructed:

/action/rest…

Where “action” is the name used to identify the page handler to invoke and “rest...” represents the remaining parts of the URL (if any). You can find out the current action by calling $context->action() or by accessing the Twig variable action (see below), however you are only going to need to do this if you are handling several actions in a single handler class (the Framework UserLogin class is an exampe of doing this it handles /login, /logout etc.

To get the rest of the URL you use the method $context->rest() which does various clean ups and returns a 0 indexed array containing the values passed in the URL. If there are no other values then the first element of the array contains an empty string. N.B. This array does not contain the query string values! You access those using the form handling facilities for GETs.

If the incoming URL is

/example/val1/val2/val3

Then $context->action() returns the string "xample" and $context->rest() returns the array

["val1", "val2", "val3"]

When working with RESTful URLs, inside the handler for the action, you call $context->rest() and this gives you the parameters being passed into the action. If you have your URL structured correctly the value in $rest[0] will tell you to interpret any other values in the array. For example:

/book/26/delete

You will be inside the handler for the book action, and have retrieved the URL values using $context->rest(). The value in $rest[0] is an integer so that tells you that this is the ID of a Book bean, so you take the value and use $context->load(…) to retrieve it. The value in $rest[1] is delete so that tells you that the caller is asking to delete the bean. You need to do some error checking — is this a POST ($context->web()->isPost()), does the user have the right permissions to delete the bean, etc. — and then trash the bean. If the value in $rest[1] were edit then you would do whatever was needed to support editing the bean — where of course, a POST would indicate the end of an edit as it would have the values to be stored in it.

Predefined Twig Variables

The Framework automatically sets up up some Twig variables containing useful values:

  • assets — use when linking to css files etc. : <link rel="stylesheet" href="{{assets}}/css/extra.css>
  • base — use when building local URLS : {{base}}/operation
  • context — the context object. Gives access to basic information e.g {{context.hasadmin}}
  • action — the action that triggered the current page i.e. the first part of the URL : /about => about
  • siteinfo — an object with utility methods to retrieve site related things e.g. all the users on the site {{siteinfo.users}}
  • ajax — see below
  • usebootbox — see below

If you are using the pagination features provided by the framework then there will be two more variables:

  • page — contains the index of the current "page". Note the index starts at 1 for user convenience
  • pagesize — contains the maximum number of elements that can appear on the page

If you wish to use pagination in your site, look at how various admin parts of the framework use it. There are functions that support pulling from the database in pagesized chunks.

If your page uses AJAX then the relevant twig file should contain
{% set ajax = TRUE %}
before any extend or include commands. This ensures that a suitable version of jQuery is included when the page loads.

By default the JavaScript for using the BootBox messaging package is included on every page. If you do not need it then you can stop it being included by adding
{% set usebootbox = FALSE %}
before any extend or include commands.

File uploading/downloading

The Framework provides you with a complete set of operations for handling file uploads and downloads should you chose to adopt them. There are two settings in the installer that will affect how these work: one that allows uploads that have no access control and one that enforces access control. No access control uloads are stored in the directory public in the assets directory, and access controlled files are stored in the directory private which is in the root of the framework. Both these directories need to be read and write accessible to your web server - the installer will ensure this but if you add these features later you will need to set permissions correctly.

Uploads

When you are handling an upload, you need to use code similar to this:

$upl = \R::dispense('upload');
$upl->savefile($context, $fa, $acc, $user, $ix);

where

  • $context is the system context object
  • $fa is the file data retrieved from the input using either FAIterator or FormData
  • $acc is TRUE if the upload is not to be access controlled otherwise FALSE
  • $user is the user bean for the owner of the file
  • $ix is the index value if the upload is associated with an array (this is potentially only used if the addData facility is being used and you are wanting to access other form fields that are also arrays.

Downloads

The Framework provides code that works with the public/private structure for downloading files. Go to the Admin > Pages menu item and a add a page called private of type Object with classname \Framework\Pages\GetFile and mark it as active. Then in your twig you can make a link to {{base}}/private/file/{{upload.getID}} where upload is the Upload bean associated with the file you want to download.

When a file gets downloaded using \Framework\Page\GetFile, it will call the method downloaded that is defined in class/modelextend/upload.php. In this method you can implement whatever you want, e.g. download counting.

Replacing

There is a replace method for uploads defined in class/model/upload.php. This lets you replace the uploaded file with another file, without creating a new upload bean. updateData from class/modelextend/upload.php if there is anything special you need to do when an upload is replaced.

Deleting

There is a delete method for uploads defined in class/modelextend/upload.php. This handles removing the file and does anything else that you want to add to this function. It does NOT delete the database entry. This method is called automatically when you use \R::trash to delete the bean, you do not call it explicitly.

Debugging

There are lots of ways you can approach debugging your code when using the Framework. If you have a mailer set up on your machine then, if an error is detected, you will be emailed a message about error. However, it is not always possible or easy to set up a mailer on a laptop so the message should also appear on the screen. Note that for some reason on some Windows machines and some browsers the 500 HTTP status code is translated into a screen that implies that the site is not reachable. If you see this, then it is very likely that an error has arisen. You can test if this happens on your system by using the "Fail" or "Throw" items on the Developer dropdown that allow testing of the error handling system. These should show you a message and a stack trace, if not then you may have the mis-feature.

If you do get an Internal Error message on the screen or in mail and you need more information, you can re-run the page with the query string ?fwtrace=1 - this will generate an on-screen stack dump as well as the message. You can adjust the depth of the stack trace by also specifying fwdepth=n in the query string.

If you want to trace through your code, you can use the PHP echo command to send output, or the var_dump function to dump the contents of variables. There are also PHP debugger extensions such as XDebug that you can install on your system. The Framework provides you with a Debug class that generates output that is saved into a file in the debug directory in the top level of your site. It can also generate an X-Debug HTTP response header that is sometimes a useful way of seeing debugging information if you are using the network monitoring features in a browser.