Basic page

"uweb/page.php"

Uray Web Library (UWeb)

Uray M. János © 2018-2024

The main feature of UWeb is to generate HTML pages. This file contains the main classes and functions for this.

The most important class is basic_page, which is the base class of any user-defined page that is to be generated by UWeb.

abstract class basic_page;

To extend this class, the subclasses must define its abstract method content() to generate the content of the page inside the <body> element, and they should also override some other methods to define various attributes of the page (e.g. title(), css()).

But these classes can do more than just defining a static webpage: they can also use AJAX to dynamically update themselves. This is very convenient in UWeb: the same page class that defines content() to generate the webpage can also define methods that process AJAX queries and make modifications on the page, without writing any JavaScript. For more details, see AJAX.

To actually generate the page, call generate() (for static pages) or execute() (for dynamic pages with AJAX).

The generated page requires UWeb's basic CSS stylesheet to be available, otherwise it will not look correctly. See css() below and Generating CSS for more information.

Here is a simple example PHP file that generates a page:

<?php
require_once "uweb/page.php";
class example_page extends basic_page {
   function title () { return "Example page"; }
   function css () { return "uweb.css"; }
   function content () {
      echo "<p> All human beings are born free. </p>\n";
   }
}
generate(new example_page);

Contents

Contents

1. Page attributes

1.1. Text properties

1.1.1. content()

1.1.2. title()

1.1.3. full_title()

1.1.4. make_title()

1.1.5. description()

1.1.6. keywords()

1.1.7. author()

1.1.8. lng_obj()

1.2. Other page attributes

1.2.1. js()

1.2.2. css()

1.2.3. inline_css()

1.2.4. favicon()

1.2.5. base_dir()

1.2.6. canonical()

1.2.7. allow_robots()

1.2.8. bottom_space()

2. Components

2.1. Get page components

2.1.1. get_component()

2.1.2. comp_menu(), comp_footer()

2.2. Component base class

2.2.1. Properties

2.2.2. __construct()

2.2.3. get_code()

2.2.4. get_component()

2.2.5. independent()

2.3. basic_menu, basic_footer

2.3.1. content()

2.3.2. begin()

2.3.3. end()

2.3.4. item()

2.3.5. item_begin(), item_end()

2.3.6. has_query()

2.3.7. default_footer

3. Error handling

3.1. Error-related page methods

3.1.1. fatal_error()

3.1.2. comp_error()

3.1.3. create_error_message()

3.2. error_message

3.2.1. message()

3.2.2. message_text()

3.2.3. popup_class()

3.2.4. popup_button()

4. Global functions

4.1. generate()

4.2. execute()

4.3. redirect()

4.4. permanent_redirect()

1. Page attributes

This section describes all methods of basic_page that influence the generated page, most importantly content().

To actually generate the page, use generate() (or execute() if AJAX is involved).

1.1. Text properties

1.1.1. content()
abstract function basic_page::content ();

Generate the HTML content of the page inside the <body> element. This is the most important method of basic_page, and it must be defined by all subclasses.

1.1.2. title()
function basic_page::title ();

Return the title of the page.

This is used in two places: in the title bar (HTML <title>, see full_title()), and inside the generated title box (make_title()). Both cases can be overridden on their own (probably using title()).

The default version of the method returns $lng::title, where $lng = $this->lng_obj().

1.1.3. full_title()
function basic_page::full_title ();

Return the title of the page in the title bar, i.e. in the HTML <title> element.

The default version simply returns title(), but it can be overridden, usually to include the name of the site, e.g. "{$this->title()} &ndash; Some Website".

1.1.4. make_title()
function basic_page::make_title ();

Generate the HTML content of the title box, which is a framed box at the top of the page, and which contains the title (see e.g. the top of this documentation page). This comes at the beginning of <body>, even before content().

The default version simply prints title() inside a <p class='title'>.

The following CSS paragraph classes are defined in the default UWeb stylesheet for use in the title box: title, title large, title small, subtitle, subtitle small and author (the latter requires $has_author if the website generates its own CSS).

1.1.5. description()
function basic_page::description ();

Return a short description about the page, which goes into the <meta name='description'> element in the header (which is usually displayed by search engines in search results).

Default value: $lng::description if it exists, otherwise null

1.1.6. keywords()
function basic_page::keywords ();

Return a comma-separated list of keywords about the page, which goes into the <meta name='keywords'> element in the header (which may be used by search engines).

Default value: $lng::keywords if it exists, otherwise null

1.1.7. author()
function basic_page::author ();

Return the name of the author of the page, which goes into the <meta name='author'> element in the header.

Default value: $lng::author if it exists, otherwise null

1.1.8. lng_obj()
function basic_page::lng_obj ();

Return the language object of this page. It should call the global lng_obj() function with the appropriate arguments.

This method makes it convenient to just write $lng = $this->lng_obj() in each method where it is needed, instead of calling the global lng_obj() with the appropriate arguments each time. This method is also used by several other methods like title(), description() etc.

If the returned object has a constant named lang whose value is the language code (e.g. "en"), then this language will be indicated on the generated page (e.g. <html lang='en'>).

Default value: an empty object.

This method must not return null.

1.2. Other page attributes

1.2.1. js()
function basic_page::js ();

Return the list of required JavaScript files (*.js) for this page. It can return an array of filenames, a single filename (string) or null for no JavaScript. The pathnames of the files are relative to the HTML file (or to base_dir() if given).

By default, no JavaScript file (an empty array) is returned. However, if the page is not static, and it uses any of the JavaScript functionalities of UWeb (JavaScript, AJAX), then UWeb's JavaScript code must be included in whatever form. See Generating JS for more information.

1.2.2. css()
function basic_page::css ();

Return the list of required CSS stylesheet files (*.css) for this page. It can return an array of filenames, a single filename (string) or null for no CSS. The pathnames of the files are relative to the HTML file (or to base_dir() if given).

By default, no CSS file (an empty array) is returned. However, this method (or inline_css()) must be overridden to include at least the core UWeb styles in whatever form, otherwise the layout of the page will break. See Generating CSS for more information.

1.2.3. inline_css()
function basic_page::inline_css ();

Same as css(), but these CSS files will be inserted into the HTML page as inline <style>s rather than merely linking them to the page.

It can be useful to make a single self-contained HTML page without any external files.

Unlike in css(), these pathnames are relative to the source PHP file, not to the generated HTML file.

1.2.4. favicon()
function basic_page::favicon ();

Return the filename of the shortcut icon (favicon) of the page, which is usually displayed in the tab bar by browsers.

Default value: null, i.e. no shortcut icon

1.2.5. base_dir()
function basic_page::base_dir ();

Return the base directory for all relative URLs on the page, i.e. HTML links (<a>), JavaScript files etc. This makes these URLs relative to this directory rather than to the HTML file. It is implemented by inserting a <base href='...'> element to the header of the page.

Default value: null, i.e. no base directory

1.2.6. canonical()
function basic_page::canonical ();

Return the URL of the canonical version of this page, which helps search engines choose between identical pages. This inserts a <link rel='canonical'> element in the header.

Default value: null, i.e. no canonical URL

1.2.7. allow_robots()
function basic_page::allow_robots ();

Return whether robots should index this page. If this is false, the appropriate <meta> elements are inserted into the header to ask search engines not to display this page in search results.

Default value: true

Note: despite its name, it does not actually prevent robots from indexing the page, it merely asks them not to do so.

1.2.8. bottom_space()
function basic_page::bottom_space ();

Return whether a screen-sized space should be placed at the bottom of the page. This allows the user to scroll the page arbitrarily.

See for example the bottom of this documentation. Clicking on the last section in the table of contents will scroll the title of that section to the top of the window. Without bottom_space(), that section would be restricted to the bottom of the window, and another section would be at the top, thus confusing the user about which section was selected.

Default value: false

Requirement: $has_bottom_space if the website generates its own CSS

2. Components

A component is a part of the page that is defined in a separate class. When the page is being generated using content(), it can create the necessary component objects and call their appropriate generator methods (e.g. content(), or any other name).

The main feature of components in UWeb is that they work well with AJAX queries: when an AJAX query originates from a part of the page that was generated by a component, UWeb invokes the appropriate method on that component object, not on the page object like normally. For more information, see Components in AJAX.

In UWeb, components must be subclasses of the base class component.

Each component has a name called code, which is a unique identifier of the component within the page (or within another component). The page object can give access to its components based on their code, see get_component(). Components can store their code in the HTML by the attribute data-component.

2.1. Get page components

2.1.1. get_component()
function basic_page::get_component ($code);

Return the page component with the given code, or null if the page has no such component. The returned object must be an instance of component.

The easiest way for a page to define some components with predefined static codes is not to override this method and put a switch ($code) into it, but to define methods with names "comp_{$code}" (e.g. comp_xyz()), one for each component, and return the appropriate components in them. The default implementation of get_component() simply redirects to the appropriate "comp_{$code}" method (with dashes in $code converted to underscores) if it exists. There are a few special components used by UWeb: comp_menu(), comp_footer() and comp_error().

In more complex situations, such as when the components have dynamic codes, or when some components are maintained by another object, get_component() needs to be overridden. To ensure that the static components like comp_menu() are still found, the base class version should be called like this:

function get_component ($code) {
   if ($comp = parent::get_component($code)) {
      return $comp;
   } else {
      // find component by $code
   }
}
function basic_page::comp_menu   ();
function basic_page::comp_footer ();

Return the menu or the footer component, respectively, of the page if it has one. It should be an instance of a subclass of basic_menu or basic_footer, respectively. For more information, see the description of these classes.

Default value: null

2.2. Component base class

abstract class component;

This is the base class of all page components.

2.2.1. Properties

The base class component has two protected properties (accessible by subclasses):

$this->page: the page object (basic_page) that this component is a part of.

$this->code: the code of the component.

2.2.2. __construct()
function component::__construct ($page, $code);

This is the constructor of the base class component, and of any subclass that does not define its own constructor.

$page: the page object that this component is a part of.

$code: the code of the component.

2.2.3. get_code()
function component::get_code ();

Return the code of the component.

2.2.4. get_component()
function component::get_component ($code);

Return a subcomponent by code. This method works in the same way as basic_page::get_component(), but inside this component.

2.2.5. independent()
function component::independent ();

Return whether this component is independent from the page, i.e. its AJAX queries are still valid in case of a page error.

Examples of independent components are basic_menu and basic_footer. For example, if the menu has a login functionality implemented by AJAX, then it should work regardless of whether the current page has an error or not. But any component that is semantically part of the failed page (i.e. dependent components) should not allow AJAX queries.

Default value: false

abstract class basic_menucomponent

abstract class basic_footercomponent

These classes provide bases for menu and footer components of a page.

The menu is a list of links (or other elements) at the top of the page in the title box, after the title generated by make_title(). It is supposed to be a way to navigate across the different pages of the website.

The footer is a list of links (or other elements) at the very bottom of the page. It has a similar function than the menu, but it is supposed to be less significant (and it uses smaller font size by default).

If the page defines a menu or a footer, it should extend basic_menu or basic_footer respectively, and return an instance of that subclass in comp_menu()/comp_footer() of the page.

Here is an example of defining a menu:

class example_page extends basic_page {
   // ... other stuff ...
   function comp_menu () { return new example_menu($this, "menu"); }
}
class example_menu extends basic_menu {
   function content () {
      echo "<hr/>";
      $this->begin();
      $this->item("First page", "first.html");
      $this->item("Second page", "second.html");
      $this->item("Just a text");
      $this->end();
   }
}

Using basic_menu and basic_footer requires $has_menu and $has_footer, respectively, when generating the CSS.

abstract function basic_menu/footer::content ();

Generate the content of the menu or footer. It must be overridden by the subclass, using the helper methods defined below.

protected function basic_menu/footer::begin ($attrs = []);

Print the HTML opening tag of the whole menu/footer.

$attrs: optional attributes of the element (see: attrs()).

protected function basic_menu/footer::end ();

Print the HTML closing tag of the whole menu/footer.

protected function basic_menu/footer::item ($content,     $attrs = []);
protected function basic_menu/footer::item ($text, $href, $attrs = []);

Print a menu/footer item.

For the first version, $content is the HTML content of the item.

The second version makes the item a link with the given parameters, as in alink().

$attrs: optional additional arguments of the menu/footer item (first version) or the link (second version) (see: attrs()).

protected function basic_menu/footer::item_begin ($attrs = []);
protected function basic_menu/footer::item_end   ();

Print the HTML opening and closing tag, respectively, of a menu/footer item.

These two methods can be used together as an alternative to item() if the content of the item is more complicated and requires multiple statements to generate.

$attrs: optional attributes of the element (see: attrs()).

function basic_menu/footer::has_query ();

Return whether the menu/footer may have its own AJAX queries. If not, UWeb can optimize away some attributes of the menu/footer element.

Default value: false

class default_footerbasic_footercomponent

This is a predefined footer class for convenience. It prints a single item containing the name of the author, a copyright symbol and a date. More precisely, it prints "{$page->author()} &copy; {$page->date()}", where $page is the page object.

$page->date(): return the date to be printed in the footer (e.g. "2020" or "2010-2020"). If it is incomplete, i.e. it ends with a dash (e.g. "2010-"), then it is extended with the current year (see finish_year_range()). This method is not defined by basic_page, so it must be defined by the page class if it uses default_footer.

3. Error handling

Sometimes the webpage cannot be generated normally for some reason, e.g. when the user enters an invalid value in the URL query string (e.g. webpage.php?param=invalid), when only authenticated users can access the page, or when some resource (e.g. database) is temporarily unavailable.

In these cases, UWeb makes it easy to handle the errors without having to check them every time, i.e. when generating the page and in every AJAX query. The errors are reported using PHP exception classes, whose base class is basic_error. Usually, the constructor of the page class looks like this:

function __construct () {
   try {
      // initialization, which may throw exceptions
   } catch (basic_error $error) {
      $this->fatal_error($error);
   }
}

If the initialization throws an exception, this code tells UWeb that the page is not completely valid, and it should generate an error page instead of the actual content, based on the exception.

3.1. Error-related page methods

3.1.1. fatal_error()
final function basic_page::fatal_error ($error);

Make the page fail by a fatal error.

$error: the exception object that caused the error. It must be an instance of basic_error.

This method causes the page to be in an invalid state, which means that its content() will not be generated by generate(), or in case of an AJAX query, it will not be executed. Instead, an error message will be displayed based on $error. To customize this error message, see create_error_message(). Note that although content() is not called when generating the page, all other methods described in Page attributes above (e.g. title(), make_title() etc.) still can be.

fatal_error() is usually called in the constructor of the page, see Error handling ahove.

It this function is called multiple times, the last one overrides the previous errors.

3.1.2. comp_error()
final function basic_page::comp_error ();

Return the error message component of the page if it has failed (by fatal_error()), otherwise null.

It basically calls create_error_message() with the $error parameter of fatal_error().

3.1.3. create_error_message()
protected function basic_page::create_error_message ($error);

Return the appropriate error message component for this exception.

$error: the parameter passed to fatal_error(), an instance of basic_error.

By default, a new error_message object is returned. This behaviour can be overriden in two ways. Of course, this method itself can be overridden, but an easier way is to define custom error message classes for certain exceptions. This method finds them by the name erm_ + the exception class name (e.g. erm_some_error if $error is a some_error), but also for its parent class name etc., up to basic_error (so an erm_basic_error would override error_message globally). These erm_* classes should be the subclasses of error_message. If they are defined in a separate file, then create_error_message() can be overridden just to include this file and then call the base version.

3.2. error_message

class error_messagecomponent

This class defines how page errors are displayed by default. This is also the base class for custom error messages. See create_error_message() for how to replace the default error_message.

An error message object $error (i.e. an instance of error_message or its subclass) can be displayed in two forms. The first one happens when generating the page, in which case $error->content() generates the error message in place of the usual page content (basic_page::content()). The second form happens when processing an AJAX query, where $error->q_error() is called instead of executing the actual query. This method prints the error message in a popup box.

A subclass of error_message could override these two methods (content() and q_error()) to customize the error message, but it is easier to override message() and/or message_text() instead, which are used by the default implementation of both above methods.

Using the default content() requires $has_error if the website generates its own CSS.

This class has the following protected property:

$this->error: the exception class that triggered the error, the argument of basic_page::fatal_error(). It is an instance of basic_error.

3.2.1. message()
function error_message::message ($full);

Generate the error message content in HTML.

The subclass of error_message can override this to customize the format and the content of the error message.

$full: if true, this was called when generating the page, otherwise it was called when processing an AJAX query. In the former case, the message is printed as the page content, and in the latter case, it is displayed in a popup box. The overridden implementation can use $full to distinguish between the two cases, and probably to produce a more verbose error message in the first (true) case.

The default implementation simply generates an HTML paragraph with message_text() as the content.

3.2.2. message_text()
protected function error_message::message_text ();

Return the error message text.

This is used by the default implementation of message(), and it can also be used by overridden implementations of that method, which makes it easy to separately customize the format and the content of the various error messages.

The default implementation simply returns $this->error->getMessage(), i.e. the error message of the exception class (getMessage() is a method of the built-in PHP base class Exception).

3.2.3. popup_class()
protected function error_message::popup_class ();

Return the CSS class of the popup box when the error message is displayed in an AJAX query.

Default value: "small"

3.2.4. popup_button()
protected function error_message::popup_button ();

Return the HTML code for the buttons in the popup box when the error message is displayed in an AJAX query.

Default value: popup_ok()

4. Global functions

4.1. generate()
function generate ($page);

Generate the full HTML code of the page to the standard output (with echo).

$page: instance of basic_page.

This function is supposed to be used for static pages, i.e. without any AJAX queries. Otherwise execute() should be used.

For a simple example of generate(), see the top of this documentation.

4.2. execute()
function execute ($page);

Execute the page. This can mean either of the following two cases: by default, it generates the full HTML code of the page (with generate()), but when the PHP file is invoked by an AJAX query, then the appropriate query method (q_*()) is called on the appropriate object.

$page: instance of basic_page.

4.3. redirect()
function redirect ($target);

Redirect the browser to another page.

$target: URL of the new page (absolute or relative).

This function terminates the PHP script and never returns.

Note: the point of this function is that it works both when the page is first loaded and in an AJAX-query.

4.4. permanent_redirect()
function permanent_redirect ($target);

This is the same as redirect(), but it tells the browser to redirect permanently, which can be used e.g. when a page has been moved to another URL. (Technically it returns the HTTP status code 301 instead of 302).