As well as containing services and variables, the Pines object
($pines) also includes several useful
methods.
To run an action, use the action
method. Actions are run automatically when requested in the URL by
the client. The "option" request variable determines the component
to which the action belongs, and the "action" request variable
determines which action to run. The action is run by the system init
script i60action.php.
Sometimes, actions need to be run manually in code. For
example, the default action (default.php in a
component's action directory) can be used to
direct the user to a common action by calling
action.
When an action is run, action will
look in the component's actions directory for a
file with the same name as the desired action (with .php appended).
If the desired component is "system", Pines will instead look in the
system's actions directory. If no action was
specified, action will look for a
default.php file. If no component was
specified, action will use the default
component specified in Pines' configuration. Once the correct file
is found, action will run the file. The
$pines variable is already included when the file
is run, so there is no need to include it with the
global keyword.
![]() | Note |
|---|---|
|
Since actions are run inside a function, they are not in the global scope. This means actions don't have to clean up variables and need not worry about naming collisions, unlike init scripts, which will be discussed later. |
If no action file was found for the given arguments,
action will throw a new 404
HttpClientException. Otherwise, it
will return the value returned by the action file. If
i60action.php catches a
HttpClientException or a
HttpServerException when it runs the
requested action, it will attach a module with the system's "error"
view into the page's "content" position and send the corresponding
HTTP status code. This means your action can throw either of these
exceptions (HttpServerException for a
5XX error, and HttpClientException
for a 4XX error) and the HTTP status code will be sent to the
client, along with an explanation of the error (or an optional
message you provide).
Sessions in Pines are handled exclusively through the
session method. Using this method, you can
access an existing session for reading or writing, and close or
destroy it. Using this method to open a session for reading allows
asynchronous requests to Pines to respond quickly, without
blocking.
If you've never experienced blocking in PHP sessions, it occurs when a script has a session open for writing, and another script (or the same one in a different request) tries to open the same session. The second script will pause execution until the first script either closes the session or exits.
The session method takes one
argument, the access type requested. It can be one of the
following:
read
Open the session for reading only. This is the default.
write
Open the session for reading and writing.
close
Close a session that was opened for writing. The session remains open for reading.
destroy
Unset and destroy a session.
If you open a session for writing, you should always close it once you don't need write access anymore.
// Open the session for reading.
$pines->session('read');
// Also works.
$pines->session();
// Now the session variable is full of the session data.
echo $_SESSION['messages'];
// Open the session for writing.
$pines->session('write');
// Now use the session variable normally.
$_SESSION['messages'] = '';
foreach ($messages as $cur_message) {
if (empty($cur_message)) {
// If you exit out of the script, remember to close the session.
$pines->session('close');
pines_error('Broken message encountered.');
return;
}
$_SESSION['messages'] .= " $cur_message";
}
// Now that we're done, close the session.
$pines->session('close');
pines_notice('Messages saved.');
The Pines object includes redirect, a
method to redirect users to a different URL. Using this method
ensures that any messages and errors that are queued to be displayed
to the user will be displayed when the user reaches the destination
URL, assuming that URL is also handled by the same Pines
installation. The HTTP status code returned to the client can be
changed and defaults to 303 (See Other).
// Notices and errors will be saved.
pines_notice('You have been redirected here.');
$pines->redirect(pines_url('com_example', 'widgets/list'));
// Redirect to the homepage.
$pines->redirect(pines_url());
// Use a permanent redirection code.
$pines->redirect(pines_url('com_example', 'widgets/list'), 301);
There are several types of content that need to be formatted correctly before being output to the user. The Pines object provides functions to allow easy formatting of this data.
To format content, use
format_content. By itself,
format_content does nothing. Its purpose
is to provide a way for components to alter content before it is
shown to the client. By using this method to format your
component's content before outputting it, you allow other
components to use the hooking system to provide special
alterations to your content. This is meant to provide things like
string replacements, inline modules, HTML cleansers, etc. This
does not mean you should always run content through this method.
Certain types of content, such as page text, blog post text,
product descriptions, etc are appropriate for content formatting.
However, content such as user comments, forum posts, etc may allow
an unprivileged user to use dangerous services if run through the
formatter. A good idea may be to use a configuration option to
allow certain content to be altered by other components. Generally
only user provided content should ever be formatted. Content like
your component's forms should most likely never be
formatted.
As mentioned, components can hook this function to provide special alterations to content. See the Hook section in Core Services for information about hooks.
To format a date or time using a timestamp, use
format_date. The current user's timezone
is automatically loaded by the user manager and used for
calculations. You can also pass
format_date a timezone to use. When using
a custom format, any format recognized by the
format method of the
DateTime class can be used.
format_date supports several format
types.
Table 3.1. Date Format Types
| Type | Format Code | Description |
|---|---|---|
| full_sort | Y-m-d H:i T | Date and time, big endian and 24 hour format so it is sortable. |
| full_long | l, F j, Y g:i A T | Date and time, long format. |
| full_med | j M Y g:i A T | Date and time, medium format. |
| full_short | n/d/Y g:i A T | Date and time, short format. |
| date_sort | Y-m-d | Only the date, big endian so it is sortable. |
| date_long | l, F j, Y | Only the date, long format. |
| date_med | j M Y | Only the date, medium format. |
| date_short | n/d/Y | Only the date, short format. |
| time_sort | H:i T | Only the time, 24 hour format so it is sortable. |
| time_long | g:i:s A T | Only the time, long format. |
| time_med | g:i:s A | Only the time, medium format. |
| time_short | g:i A | Only the time, short format. |
| custom | (Contents of $format) | Use whatever is passed in
$format. |
To format a date or time range using two timestamps, use
format_date_range. Like
format_date, the current user's timezone
is used for calculations. One wouldn't think that a timezone would
be a concern when showing a range of time, but if your time range
displays hours and a Daylight Savings Time change occurs during it
in the selected timezone, you will have a different number of
hours than in a timezone without DST.
$format is built using macros, which
are substrings replaced by the corresponding number of units.
There are singular macros, such as #year#, which are used if the
number of that unit is 1. For example, if the range is 1 year and
both #year# and #years# are present, #year# will be used and
#years# will be ignored. This allows you to use a different
description for each one. You accomplish this by surrounding the
macro and its description in curly brackets. If the unit is 0,
everything in that curly bracket will be removed. This allows you
to place both #year# and #years# and always end up with the right
one.
Since the units in curly brackets that equal 0 are removed, you can include as many as you want and only the relevant ones will be used. If you choose not to include one, such as year, then the next available one will include the time that would have been placed in it. For example, if the time range is 2 years, but you only include months, then months will be set to 24.
After formatting, any leading and trailing whitespace is trimmed before the result is returned.
Table 3.2. Macros Available in Date Range Formats
| Macro | Corresponding Value |
|---|---|
#years# | The number of years. |
#year# | The number 1 if applicable. |
#months# | The number of months. |
#month# | The number 1 if applicable. |
#weeks# | The number of weeks. |
#week# | The number 1 if applicable. |
#days# | The number of days. |
#day# | The number 1 if applicable. |
#hours# | The number of hours. |
#hour# | The number 1 if applicable. |
#minutes# | The number of minutes. |
#minute# | The number 1 if applicable. |
#seconds# | The number of seconds. |
#second# | The number 1 if applicable. |
If $format is left null, it
defaults to the following: "{#years# years}{#year# year}
{#months# months}{#month# month} {#days# days}{#day# day} {#hours#
hours}{#hour# hour} {#minutes# minutes}{#minute# minute}
{#seconds# seconds}{#second# second}"
Here are some examples of formats and what would be returned given a time range of 2 years 5 months 1 day and 4 hours. (These values were calculated on Fri Oct 14 2011 in San Diego, which has DST. 2012 is a leap year.)
#years# years {#days# days}{#day#
day}
2 years 152
days
{#months# months}{#month# month} {#days#
days}{#day# day}
29 months 1
day
{#weeks# weeks}{#week# week} {#days# days}{#day#
day}
126 weeks 1
day
#days# days #hours# hours #minutes#
minutes
883 days 4 hours 0
minutes
{#minutes#min} {#seconds#sec}
1271760min
#seconds#
76305600
To format a fuzzy time string using a timestamp, use
format_fuzzy_time. This method does not
use timezones, so it may not give perfectly precise time strings.
Seeing as it is used for a time estimation, that shouldn't be a
problem.
There are three methods of checking whether an IP address is on a given network in the Pines object.
You can use check_ip_cidr to check
an IP address using the CIDR notation of a
network.
You can use check_ip_range to check
an IP address using an IP range.
You can use check_ip_subnet to
check an IP address using the subnet mask of a
network.