Italian (Italy)

VikRestaurants APIs

Vik Restaurants - Documentation

Version: 1.2.1

API Framework

The API Framework is a collection of tools useful to make a communication between VikRestaurants and all your external applications.

For example, through the API Framework, a CLIENT software, installed on your computer, can communicate with your server to retrieve all the reservations and orders stored in VikRestaurants.

The API Framework can be accessed from the Configuration of VikRestaurants, by visiting the Applications section.

Configuration

Enable APIs
Enable this setting if you want to connect external applications to your website. 
The connection is allowed only if the credentials of the client are valid.

If this option is disabled, any connection attempt will be denied.

Max Failure Attempts
Every time a client fails the login to your system, its failure attempts number is increased by one. When the number of attempts reaches this value, the calling IP Address will be automatically (and permanently) banned.

Register Logs
Choose the type of messages the system should log. It is possible to log only anything or to log only the errors. Otherwise it is possible to completely disable the logs.

Auto-Flush Logs
You can allow the system to remove the stored logs automatically after some time. The possible options are: Every DayEvery WeekEvery MonthNever.

Communication Usage

It is possible to start a communication with your server by reaching the following BASE URL:

.../index.php?option=com_vikrestaurants&task=apis

The ellipsis (...) are meaning the name of your website, such as:
http://yourdomain.com/index.php?option=com_vikrestaurants&task=apis

By reaching this BASE URL you will get the authorisation error below:

{
"errcode": 101,
"error": "Authentication Error! The username is empty or invalid."
}

In order to use the API Framework it is required the authentication of your credentials.
This means that you have to extend the BASE URL to send your username and your password.

.../index.php?option=com_vikrestaurants&task=apis&username=[YOUR_USERNAME]&password=[YOUR_PASSWORD]

The system also accepts login credentials sent by using the HTTP BASIC_AUTH header.

@see API Users to create some valid API credentials.

Once the BASE URL will contain a valid username and password, it will raise another type of error:

{
"errcode": 201,
"error": "File Not Found! The event requested does not exists."
}

The API Framework is built to execute certain pieces of code and it is mandatory to specify also the name of the EVENT (or PLUGIN) to run.
To complete the BASE URL we have to add an additional parameter called event.

.../index.php?option=com_vikrestaurants&task=apis&username=[YOUR_USERNAME]&password=[YOUR_PASSWORD]&event=[YOUR_EVENT_NAME]

To make sure your BASE URL is correct, you can try to use a pre-installed event called connection_ping.
Your URL should look like the one below:

.../index.php?option=com_vikrestaurants&task=apis&username=my_username&password=my_password&event=connection_ping

which should return the successful message below:

{
"status": 1
}
Event Arguments

Your events (or plugins) may work depending on different values, such as a certain table ID or for a certain date.

For this reason, it is possible to pass certain arguments within the BASE URL. The special &args[] field can be placed in the query string to send all the additional arguments needed for your plugin.

To pass, for example, the fields first name, last name and e-mail, we can use the following query string:

&args[first_name]=John&args[last_name]=Smith&args[email]=Questo indirizzo email è protetto dagli spambots. È necessario abilitare JavaScript per vederlo.

which must be concatenated to your BASE URL.

API Users

It is possible to see and manage the API Users by clicking the See Users List button from the Application configuration section.

This is a list of all the applications and their relative credentials that can communicate with your VikRestaurants.

Application Details

An API User can be configured with all the fields below.

  • Application Name - the name of the application. If not specified, the username will be used.
  • Username - the username of the application, used to authenticate the requests.
  • Password - the password of the application, used to authenticate the requests. Press the icon to show the password.
    Press the Generate Password button to insert a random and safe password.
  • Active - enable this option it the application can access to the API Framework.

Allowed IPs

It is possible to specify also one or more IP Addresses to restrict the origin from which the application can connect itself to your VikRestaurants.

Press the Add IP Address button to insert the 4 parts of your IP (min 0.0.0.0 and max 255.255.255.255).

By leaving the list of IPs empty, all the IP Addresses will be accepted.

Plugin Rules

You can also specify the plugins that the application can perform.

If you are not able to deny a certain plugin, it means that it is always enabled for all the active applications.
@see EventAPIs::alwaysAllowed() for a better explanation.

Credentials Requirements

The username and password credentials MUST follow the restrictions of the API Framework, otherwise they won't be considered as valid and the authentication will fail.

Username Requirements

  • It accepts only letters (uppercase and lowercase), digits, dots (.) and underscores (_). White spaces ARE NOT accepted.
  • The username length MUST be between 3 and 128 characters.

Password Requirements

  • It accepts only letters (uppercase and lowercase), digits, and all these !?@#$%{}[]()_-. symbols. White spaces ARE NOT accepted.
  • The password length MUST be between 8 and 128 characters.
  • The password MUST contain at least one letter.
  • The password MUST contain at least one number.
Logs

It is possible to see the stored Logs from the API Users page, by clicking the See Logs button.

The logs describe the result of the actions performed by your applications.
In case a log is referring to an authentication error, considering it is not possible to evaluate the application name, it will be used the IP Address of the caller instead.

It is possible to filter the logs by Application Name and/or by Content.

  • ID - the ID of the log. By deleting all the existing logs, the ID will be reset.
  • Created On - the creation date of the log. Hover the mouse above these values to see the detailed date.
  • Content - the description of the log.
  • Status - the status of the log: OK on success, ERROR on failure. Depending on your configuration, you may not be able to see successful logs.
  • Application Name - the name of the application authenticated, otherwise the caller IP Address.
Banned List

It is possible to see the Banned List from the API Users page, by clicking the See Banned List button.

Here you can find the list of the IP Addresses that ARE NOT allowed to use your API Framework.
It is not possible to add manually an IP Address in this blacklist, as the system evaluates automatically if an IP Address should be considered as malevolent.

An IP Address is banned depending on the value specified for the Max Failure Attempts setting. For example, if this parameter is set to 20, an IP Address is pushed in the blacklist if it gets 20 authentication failures in a row.

By removing an IP Address from the blacklist, it will be able to re-try the authentication to your API Framework.

From the dropdown located in this page, you can select the All Records option to see the list of the IP Addresses that have failed at least once the authentication. The records in this list are STILL able to try the authentication to your API Framework.

It is possible to filter the list by IP Address only.

  • ID - the ID of the banned user.
  • IP Address - the IP Address from which the user is attempting to authenticate itself.
  • Last Update - the last update of the record. Hover the mouse above these values to see the detailed date.
  • Failure Attempts - the current number of failures made in a row (failures / max_failures). When the failures count reaches the max_failures setting, the IP Address will be banned. When an IP Address authenticates itself successfully, the failures count will be reset (only if the failures count is still lower than the max_failure amount).
API Plugins

It is possible to see and test the API Plugins by clicking the See Installed Plugins button from the Application configuration section.

This is a list of all the plugins (or events) installed on your system than can be used for the communication between VikRestaurants and all your applications.

It is possible to filter the installed Plugins by name.

Structure & Path

The plugins are simple .PHP files that extend the methods of the EventAPIs class of the API Framework library.
All these files are placed in the directory below:

/wp-content/plugins/vikrestaurants/site/helpers/library/apislib/apis/plugins/

If you are planning to implement your own plugin, it is recommended to use the apposite hook to safely load your third-party applications. This will avoid losing your files after updating VikRestaurants to a newer version. Here's the hook link: https://vikwp.com/support/knowledge-base/vik-restaurants/hooks/api/init-framework.

Plugin Description

You can click the icon to see a full description of the installed plugins.
The description is generated starting from the string returned by the EventAPIs::getDescription() method.

Libraries

Take a look at all the classes and methods that can be used to create your own API Plugins.

Classes

Here is a list of all the classes that can be used in order to develop a custom plugin/event that all your external applications can run.

UserAPIs
abstract

This class is used from the API framework to wrap the details of the connecting users and to handle the authorizations of the events.

Considering this is an abstract class, you have to use a class that inherits it.
If you need to access it, you can use our LoginAPIs object.

@since 1.0

__construct

Class constructor.

@param string $username The username of the user for login.
@param string $password The password of the user for login.
@param string $ip The IP address from which the user is trying to login (default NULL).

/* fatal error : abstract class */
$user = new UserAPIs("test", "test_pwd", "127.0.0.1");
/* correct instantiation */
$user = new LoginAPIs("test", "test_pwd", "127.0.0.1");
getUsername

Get the username of the user.
The username is not empty only if it is verified from the constructor.

@return string The username of the user.

@see UserAPIs::getCredentials()   Get always the provided credentials, also in failure cases.

$username = $user->getUsername();
getPassword

Get the password of the user.
The password is not empty only if it is verified from the constructor.

@return string The password of the user.

@see UserAPIs::getCredentials()   Get always the provided credentials, also in failure cases.

$password = $user->getPassword();
getCredentials

Get the credentials of the user, also in failure cases.

@return object An object containing the credentials of the user.

$credentials = $user->getCredentials();
echo $credentials->username . ", " . $credentials->password;
assign

Set the ID of the user after a successful login.
By setting an ID through this method, the framework assumes that the user is currently connected.

@return UserAPIs This object to support chaining.

if ($id_user = doLogin()) { // this method does not exist
	$user->assign(id_user);
}
id

Get the ID of the user. Return NULL in case the user is not yet connected.

@return integer The ID of the user or NULL.

if ($user->id()) {
	/* user is logged */
}
isConnectable

Return true if the credentials provided match the structure requirements.
When true, it is possible to proceed with the login check, otherwise it means the username and/or password are not correctly filled in (for example they have not enough characters).

 @return boolean True if the username and password are not empty (accepted).

if ($user->isConnectable()) {
	/* user can login */
}
getSourceIp

Get the origin IP address from which the user is trying to connect.

@return string The IP address if provided, otherwise NULL.

$ip = $user->getSourceIp();
authorise

Check if the user is able to perform the event provided.

@param EventAPIs $event The event to authorise.

@return boolean True if the event can be performed, otherwise false.

@see EventAPIs

/* the event below exists, but it must be included first */
$event = new ConnectionPing('connection_ping');
if ($user->authorise($event)) {
/* the event can be performed */
}
ErrorAPIs

This class is a basic representation of an error that can be raised from the API Framework.

The errors are (and must be) raised in case something gone wrong. The external applications are able to see the raised errors.

@since 1.0

__construct

Class constructor.

@param integer $errcode The code identifier.
@param string $error The text description.

$err = new ErrorAPIs(404, "Not Found!");

echo $err->errcode . ", " . $err->error;
toJSON

Return this object encoded in JSON format.

@return string This object in JSON.

$json = $err->toJSON();
$obj = json_decode($json);
echo $obj->errcode . ", " . $obj->error;
raise

static

Raise the specified error and stop the flow if needed.

This method can be accessed only statically.

@param integer $errcode The code identifier.
@param string $error The text description.
@param boolean $exit True to stop the execution, otherwise false (default true).

/* the code below */
ErrorAPIs::raise(404, "Not Found!");
/* is equals to this one */
$err = ErrorAPIs::raise(404, "Not Found!", false);
echo $err->toJSON();
exit;
ResponseAPIs

This class is used to wrap the details of a valid response for the API Framework.

The responses are used to log something about the performed events, on success or failure. The logs are not accessible from external applications.

@since 1.0

__construct

Class constructor.

@param boolean $status True for success response, otherwise false (default false).
@param string $content The text description of the response (default empty string).

$response = new ResponseAPIs(false, "Response Error.");
/* or */
$response = new ResponseAPIs(true);
setStatus

Set the status of the response.

@param boolean $status True for success response, otherwise false.

@return ResponseAPIs This object to support chaining.

$response->setStatus(true);
isVerified

Return true if the status of the response is success, otherwise false.

@return boolean True on success, otherwise false.

if ($response->isVerified()) {
/* status is TRUE */
}
isError

Return true if the status of the response is failure, otherwise false.

@return boolean True on failure, otherwise false.

if ($response->isError()) {
/* status is FALSE */
}
setContent

Set the text description of the response.

@param string $content The content of the response.

@return ResponseAPIs This object to support chaining.

$response->setContent("content [1]");
appendContent

Append some text to the existing description of the response.

@param string $content The content of the response.

@return ResponseAPIs This object to support chaining.

$response->setContent("content [1]")
->appendContent(" - content [2]");

/* content [1] - content [2] */
prependContent

Prepend some text to the existing description of the response.

@param string $content The content of the response.

@return ResponseAPIs This object to support chaining.

$response->setContent("content [1]")
->appendContent(" - content [2]");
->prependContent("content [0] - ");

/* content[0] - content [1] - content [2] */
clearContent

Clear the text description of the response.

@return ResponseAPIs This object to support chaining.

$response->clearContent();
getContent

Get the text description of the response.

@return string The text description of the response.

$content = $response->getContent();
createdOn

Get the initial unix timestamp of the response.
The initial time is recorded during the creation (instantiation) of the response.

@return integer The initial timestamp in seconds.

$created_on = $response->createdOn();
echo date('Y-m-d H:i:d', $created_on);
getElapsedTime

Get the elapsed time (in seconds) between the current time and the initial time.

@return integer The elapsed time in seconds.

$elapsed = $response->getElapsedTime();
EventAPIs

This class is the representation of a callable event in the API Framework.
If you need to implement a new event (also called plugin) to perform a certain request, you have to create a new CLASS that inherits EventAPIs.

The classname of an event/plugin MUST follow the standard below:
e.g. Filename = plugin.php   Classname = Plugin
e.g. Filename = plugin_name.php   Classname = PluginName

@since 1.0
@abstract Extend this class in order to perform a specific action.

__construct

Class constructor.

@param string $name The name of the event.
@param mixed $options An optional configuration array/object.

/* the event below exists, but it must be included first */
$event = new ConnectionPing('connection_ping');
if ($event instanceof EventAPIs) {
/* ConnectionPing inherits EventAPIs class */
}
getName

Get the name of the event.

@return string The name of the event.

$name = $event->getName(); /* connection_ping */
getTitle

Get the title of the event.

@return string The title of the event.

$title = $event->getTitle(); /* Connection Ping */
getDescription

Get the description (in HTML) of the event.

@return string Returns an empty string. To display a description, override this method from the child class.

$desc = $event->getDescription();
alwaysAllowed

Returns true if the plugin is always authorised, otherwise false.
When this value is false, the system will need to authorise the plugin through the ACL of the user.

@return boolean Always false. To always allow this plugin, override this method from the child class.

$allowed = $event->alwaysAllowed();
run

Perform the specified action of the event.

@param array $args Some arguments to pass to the event.
@param ResponseAPIs &$response The response object for admin (passed by reference).

@return ErrorAPIs The error occurred, if any.

@uses EventAPIs::doAction()   Executes the code written in the child class.

@see ResponseAPIs
@see ErrorAPIs

$response = new ResponseAPIs(false);
/* the event below exists, but it must be included first */
$event = new ConnectionPing('connection_ping');

$err = $event->run(array(), $response);

if ($err && $err instanceof ErrorAPIs) {
echo $err->toJSON();
exit;
}
echo $response->getContent();
doAction

protected

The custom action that the event has to perform. This is an abstract method that should be defined from the child class.
This method should not contain any exit or die function, otherwise the event won't be stopped properly.

On success, all the information to return to the applications should be echoed instead.

In case of failure, you can return a new ErrorAPIs instance.

@param array $args Some arguments to pass to the event.
@param ResponseAPIs &$response The response object for admin (passed by reference).

@return ErrorAPIs The error occurred, if any.

@protected Use EventAPIs::run() instead.
@abstract Implement this method in a child class to perform all the actions you need.

@see ResponseAPIs
@see ErrorAPIs

class HeadsOrTails extends EventAPIs
{
	protected function doAction(array $args, ResponseAPIs &$response)
	{
		/* 0 for tails, 1 for heads */
		$coin = rand(0, 1);

		if (!$coin) {
			/* if tails, raise error */
			$response->setContent('It is Tails!'); // error for admin
			return new ErrorAPIs(501, 'Tails!'); // error for customer
		}

		/* otherwise, display message */
		$response->setStatus(1)
			->setContent('It is Heads!'); // success message for admin

		$obj = stdClass;
		$obj->message = 'Heads!'; // success message for customer

		echo json_encode($obj);
	}
}
APIs
abstract

The base API Framework of VikRestaurants.
This class is used to run all the installed events/plugins listed in a given directory.

The classname of the plugins must follow the standard below:
e.g. Filename = plugin.php   Classname = Plugin
e.g. Filename = plugin_name.php   Classname = PluginName

All the events are runnable only if the user is correctly authenticated.

Considering this is an abstract class, you have to use a class that inherits it.
If you need to access it, you can use our FrameworkAPIs object.

__construct

protected

Class constructor.

@param string $event_path The dir path containing all the plugins (default empty string).
If no event path is provided, it will be used the default one:
/wp-content/plugins/vikrestaurants/site/helpers/library/apislib/apis/plugins/

@protected Use APIs::getInstance() instead to create this class.

/* fatal error : protected method */
$api = new APIs();
/* fatal error : abstract class */
$api = APIs::getInstance();
/* correct instantiation */
$api = FrameworkAPIs::getInstance();
getInstance

static

Get the instance of the APIs object. Thanks to this method, it is possible to use a single and global instance of the APIs.

This method can be accessed only statically.

@param string $event_path The dir path containing all the plugins.

@return APIs The instance of the API framework.

$api = FrameworkAPIs::getInstance('/folder/plugins/');
$path = $api->getEventPath(); /* /folder/plugins/ */
$api = FrameworkAPIs::getInstance('/fake/folder/plugins/');
$path = $api->getEventPath(); /* /folder/plugins/ (it is still the same) */
isEnabled

Returns true if the APIs framework is enabled and accessible.

@return boolean True if enabled, otherwise false.

if ($api->isEnabled()) {
	/* $api object can be used */
}
isConnected

Returns true if the user is correctly logged.

@return boolean True if logged, otherwise false.

if ($api->isConnected()) {
	/* user is authenticated */
}
getUser

Returns the object of the logged user.

@return UserAPIs The object of the authenticated user, otherwise NULL.

@see UserAPIs

if ($user = $api->getUser()) {
	echo $user->getUsername() . ", " . $user->getPassword();
}
disconnect

Disconnect the authenticated user.

@return APIs This object to support chaining.

$api->disconnect();
getIncludePaths

Returns the list of folders from which the API will load the supported application plugins.

@return array A list of folders.

@since 1.1

$folders = $api->getIncludePaths();
setIncludePaths

Replaces the include path folders with the specified ones.

@param array A list of folders to set.

@return APIs This object to support chaining.

@since 1.1

$api->setIncludePaths([$folder]);
addIncludePath

Adds the specified folder within the list of include paths. The path will be added only if it doesn't exist yet.

@param string The folder to insert.

@return APIs This object to support chaining.

@since 1.1

$api->addIncludePath($folder);
addIncludePaths

Adds the specified folders within the list of include paths. Each path will be added only if it doesn't exist yet.

@param array The folders to insert.

@return APIs This object to support chaining.

@since 1.1

$api->addIncludePaths($folders);
getEventPath

Get the path of the folder containing the plugins.

@return string The plugins folder.

$path = $api->getEventPath();
/* default path is /wp-content/plugins/vikrestaurants/site/helpers/library/apislib/apis/plugins/ */
getPluginsList

Get the object of the given plugin name.
If not specified, it returns the object of all the installed plugins.

@param string $plg_name The name of the plugin to get (default "*" means all plugins).

@return array A list containing the plugins found.

/* get a specific plugin */
$arr = $api->getPluginsList('connection_ping');
if (count($arr)) {
	echo $arr[0]->getTitle(); /* Connection Ping */
}

/* get all the installed plugins */
$arr = $api->getPluginsList();
foreach ($arr as $plugin) {
	echo $plugin->getTitle() . "\n";
}
hasError

Returns true if an error has been raised.

@return boolean True in case of error, otherwise false.

if ($api->hasError()) {
/* an error has been thrown */
}
getError

Get the last error caught and clean it.

@return ErrorAPIs The error object if exists, otherwise NULL.

@see ErrorAPIs

if ($api->hasError()) {
$err = $api->getError(); /* returns an error */
$err = $api->getError(); /* returns NULL (error cleaned)*/
}
has

Check if the specified key is set in the configuration.

@param string $key The configuration key to check.

@return boolean True if exists, otherwise false.

if ($api->has('apimaxfail')) {
/* the setting exists */
}
get

Get the configuration value of the specified setting.

@param string $key The configuration key to check.
@param mixed $def The default value if not exists (default null).

@return mixed The configuration value if exists, otherwise the default specified value.

$max_fail = $api->get('apimaxfail', 0); /* this setting always exists */ 
var_dump($max_fail); /* an integer higher than 0 */

$something = $api->get('something', null); /* this setting does not exist by default */
var_dump($something); /* null */
set

Set the configuration value for the specified setting.

@param string $key The key of the configuration value to set.
@param mixed $val The configuration value to set.

@return APIs This object to support chaining.

$fake = $api->get('fake', null);
var_dump($fake); /* null */
$api->set('fake', 100); $fake = $api->get('fake', null); var_dump($fake); /* 100 */
connect

Connect the specified user to the APIs framework.

In case the login fails, here is evaluated a permanent BAN.
Otherwise the MANIFEST of the user is updated and the BAN is reset.

This method can raise the following internal errors:

  • 100 - Authentication Error (Generic)
  • 101 - The username is empty or invalid
  • 102 - The password is empty or invalid
  • 103 - The username and password do not match
  • 104 - The account is blocked
  • 105 - The source IP is not authorised

@param UserAPIs $user The object to represent the user login.

@return boolean True if the user is accepted, otherwise false.

@see UserAPIs

$input = JFactory::getApplication()->input;

$username = $input->getString('username');
$password = $input->getString('password');

$user = new LoginAPIs($username, $password);

if (!$api->connect($user)) {
	/* user is not authenticated */
	echo $api->getError()->toJSON();
	exit;
}
/* user is authenticated */
trigger

Trigger the specified event.
Accessible only in case the user is correctly connected.

This method can raise the following internal errors:

  • 100 - Authentication Error (Generic)
  • 201 - The event requested does not exists
  • 202 - The event requested is not valid
  • 203 - The event requested is not runnable
  • 204 - The event requested is not authorised
  • 500 - Internal error of the plugin executed (Generic)
  • xxx - A custom error raised from the plugin.

The response of the plugin is always echoed.

@param string $event The filename of the plugin to run.
@param array $args The arguments to pass within the plugin (default empty array).
@param boolean $register True to register the response, otherwise false to ignore it (default true).

@return boolean True if the plugin is executed without errors.

/* only if the user is connected */
$event_name = 'connection_ping';
$args = array(); if (!$api->trigger($event_name, $args)) { /* plugin error */ echo $api->getError()->toJSON(); exit; } /* successful response automatically echoed from the plugin */
dispatch

Dispatch the specified event to catch the response echoed from the plugin.
Accessible only in case the user is correctly connected.

This method can raise the following internal errors:

  • 100 - Authentication Error (Generic)
  • 201 - The event requested does not exists
  • 202 - The event requested is not valid
  • 203 - The event requested is not runnable
  • 204 - The event requested is not authorised
  • 500 - Internal error of the plugin executed (Generic)
  • xxx - A custom error raised from the plugin.

The response of the plugin is never echoed.
This method is useful to dispatch events during the execution of other plugins, in order to manipulate the response retrieved.

@param string $event The filename of the plugin to run.
@param array $args The arguments to pass within the plugin (default empty array).
@param boolean $register True to register the response, otherwise false to ignore it (default true).

@return string The response echoed from the plugin on success.

@throws Exception In case of failure, an exception is thrown.

/* only if the user is connected */
$event_name = 'connection_ping';
$args = array();

try { $json = $api->dispatch($event_name, $args);
} catch (Exception $e) {
/* plugin error */
ErrorAPIs::raise($e->getCode(), $e->getMessage()); /* echoes the error and exit */
} /* successful response retrieved from the plugin */ echo $json; exit;
Integration

Here are the steps to follow to understand how an API Plugin for VikRestaurants can be developed.

In this guide, we will build an API Plugin to retrieve the rooms and all the relative tables from your VikRestaurants.

Problem Description

For example, our CLIENT software needs to retrieve the rooms & tables from VikRestaurants in JSON format.

The JSON structure below seems to be appropriate for our case:

[
	{
		"id": 1,
		"name": "Room A",
		"published": 1,
		"description": "",
		"tables": [
			{
				"id": 1,
				"name": "Table A1",
				"min": 2,
				"max": 4,
				"published": 1
			},
			{
				"id": 2,
				"name": "Table A2",
				"min": 4,
				"max": 6,
				"published": 0
			}
		]
	},
	{
		"id": 2,
		"name": "Room B",
		"published": 1,
		"description": "",
		"tables": [
			{
				"id": 3,
				"name": "Table B1",
				"min": 4,
				"max": 8,
				"published": 1
			}
		]
	},
	{
		"id": 3,
		"name": "Room C",
		"published": 0,
		"description": "",
		"tables": []
	}
]

We also may consider to implement a parameter to ignore/accept the unpublished rooms and tables. 

Getting Started

Before to start coding the API Plugin it is required to enable the API Framework and create a new Application for the authentication.

Enable Framework

From the configuration of VikRestaurants in the back-end, under the Applications section, we have to make sure the APIs setting is enabled.

New Application

Once the framework is enabled, the See Users List button should become visible. Click this button to see the list of the users and press the NEW button to create an Application.

Feel free to configure your application as displayed in the image below (you can ignore all the other fields).

@see API Users for further details.

Test Authentication

It is possible to test the authentication of your app by using one of the pre-installed plugins. You can see the list of plugins by clicking the See Installed Plugins button from the Applications section of the configuration.

Find the Connection Ping plugin and press its icon to see the full description.

Insert your credentials in the username and password fields, click outside of the input to refresh the URL properly and finally click it.

 The system should open the clicked URL in a different tab of your browser. Make sure the response you get is equals to the one below.

{
	"status": 1
}
Plugin Skeleton

After a successful authentication, we can proceed with the creation of an empty API Plugin.

File Creation

Create a new file on your local computer and rename it as:

rooms_tables.php
Paste Base Code

Copy & paste the code below into the file created previously, or download it from HERE.

<?php

// No direct access to this file
defined('ABSPATH') or die('Restricted access');

class RoomsTables extends EventAPIs
{
	// parent override
	protected function doAction(array $args, ResponseAPIs &$response)
	{

	}

	// parent override
	public function alwaysAllowed()
	{
		return false;
	}

	// parent override
	public function getDescription()
	{
		return '';
	}
}

It is MANDATORY that the filename (rooms_tables.php) and the classname (RoomsTables) follow the standard described from the EventAPIs parent class.

FTP Upload

Access to your server via FTP (e.g. by using FileZilla) and upload the rooms_tables.php file onto the directory below:

/wp-content/plugins/vikrestaurants/site/helpers/library/apislib/apis/plugins/

IMPORTANT NOTE: it is recommended to use the apposite hook to safely load your third-party applications. This will avoid losing your files after updating VikRestaurants to a newer version. Here's the hook link: https://vikwp.com/support/knowledge-base/vik-restaurants/hooks/api/init-framework.

Visit the Plugins List from the back-end of VikRestaurants and make sure the Rooms Tables plugin is visible.

The  icon is disabled because the EventAPIs::getDescription() method that we have initially defined is returning an empty string.

To test our new empty plugin, try to launch this URL (replace the ellipsis with your domain):

.../index.php?option=com_vikrestaurants&task=apis&event=rooms_tables&username=app&password=ABCD1234

and make sure the result is matching the one below:

{
	"errcode": 500,
	"error": ""
}

We are getting an error (this is normal) because we haven't verified yet the status of the response within the EventAPIs::doAction() method.

@see ResponseAPIs::setStatus() to understand how a plugin response can be confirmed.

Plugin Development

Now, we can proceed with the development of the event that the plugin should handle.

All the blocks of code described in this section have to be included within the EventAPIs::doAction() method of our plugin.

protected function doAction(array $args, ResponseAPIs &$response)
{
	/* insert code here */
}
Arguments

As mentioned in the Problem Description section of this tutorial, we should implement the code to retrieve the argument to accept or ignore the unpublished rooms and tables.

/* 0 to load all, 1 to load only published rooms and tables */
$published = isset($_REQUEST['published']) ? (int) $_REQUEST['published'] : 0;
MySQL Query

Before to retrieve the rooms and tables from the database, we can start thinking about the query to use.

SELECT `r`.`id`, `r`.`name`, `r`.`published`, `r`.`description`,
`t`.`id` AS `id_table`, `t`.`name` AS `table_name`, `t`.`min_capacity`, `t`.`max_capacity`, 
`t`.`published` AS `table_published`
FROM `#__vikrestaurants_room` AS `r`
LEFT JOIN `#__vikrestaurants_table` AS `t` ON `r`.`id`=`t`.`id_room`
WHERE `r`.`published`>=[PUBLISHED] AND `t`.`published`>=[PUBLISHED]
ORDER BY `r`.`ordering` ASC, `t`.`name` ASC;

Before to launch the query, we have to replace all the #__ occurrences with the real prefix of the database (e.g. xyz_).

It is also needed to replace the [PUBLISHED] parameter with 0 or 1 values.

The result of the query, launched from your MySQL Panel, should look like the one below.

Run PHP Query

Once the QUERY seems to return the proper result, we can implement its execution via PHP.

/* get database object */
$dbo = JFactory::getDbo();

/* get empty query */
$q = $dbo->getQuery(true);

/* build query */
$q->select('`r`.`id`, `r`.`name`, `r`.`published`, `r`.`description`')
	->select('`t`.`id` AS `id_table`, `t`.`name` AS `table_name`, `t`.`min_capacity`')
	->select('`t`.`max_capacity`, `t`.`published` AS `table_published`')
	->from($dbo->qn('#__vikrestaurants_room', 'r'))
	->join('LEFT', $dbo->qn('#__vikrestaurants_table', 't') . ' ON `r`.`id`=`t`.`id_room`')
	->where('`r`.`published` >= ' . $published . ' AND `t`.`published` >= ' . $published)
	->order('`r`.`ordering` ASC, `t`.`name` ASC');

/* setup query */
$dbo->setQuery($q);
/* run query */
$dbo->execute();

/* validate result */
if ($dbo->getNumRows() == 0) {
	/* verify the response */
	$response->setStatus(1);
	/* return empty result */
	echo "[]";
	return;
}

/* get fetched rows */
$rows = $dbo->loadObjectList();
Manipulate Response

To complete the plugin, we have to manipulate the result of the query and adapt it to the required JSON structure.

/* manipulate response */
$rooms = array();

$last_room_id = -1;

foreach ($rows as $row) {

	if ($last_room_id != $row['id']) {
		/* push room */
		$rooms[] = array(
			"id" => $row['id'],
			"name" => $row['name'],
			"published" => $row['published'],
			"description" => $row['description'],
			"tables" => array(),
		);

		/* store ID last room pushed */
		$last_room_id = $row['id'];
	}

	if (!empty($row['id_table'])) {
		/* push table in last room */
		$rooms[count($rooms)-1]['tables'][] = array(
			"id" => $row['id_table'],
			"name" => $row['table_name'],
			"min" => $row['min_capacity'],
			"max" => $row['max_capacity'],
			"published" => $row['table_published'],
		);
	}
}

/* verify the response */
$response->setStatus(1);
/* write some logs for the administrator */
$response->setContent('Fetched #' . count($rooms) . ' rooms.');

/* return fetched result */
echo json_encode($rooms);
return;
Plugin Response

The plugin seems to be ready. We can start testing the response we get.

Client

The client that is calling the event should retrieve a JSON string like the one below.

[
	{
		"id": "1",
		"name": "Main Room",
		"published": "1",
		"description": "",
		"tables": [
			{
				"id": "1",
				"name": "t1",
				"min": "2",
				"max": "2",
				"published": "1"
			},
			{
				"id": "2",
				"name": "t2",
				"min": "2",
				"max": "4",
				"published": "0"
			},
			{
				"id": "3",
				"name": "t3",
				"min": "2",
				"max": "4",
				"published": "1"
			},
			{
				"id": "4",
				"name": "t4",
				"min": "2",
				"max": "4",
				"published": "1"
			},
			{
				"id": "5",
				"name": "t5",
				"min": "2",
				"max": "4",
				"published": "1"
			},
			{
				"id": "6",
				"name": "t6",
				"min": "2",
				"max": "4",
				"published": "1"
			},
			{
				"id": "7",
				"name": "t7",
				"min": "4",
				"max": "8",
				"published": "1"
			}
		]
	},
	{
		"id": "2",
		"name": "Garden",
		"published": "1",
		"description": "",
		"tables": [
			{
				"id": "9",
				"name": "g1",
				"min": "2",
				"max": "6",
				"published": "1"
			},
			{
				"id": "10",
				"name": "g2",
				"min": "2",
				"max": "10",
				"published": "1"
			}
		]
	},
	{
		"id": "4",
		"name": "Private",
		"published": "1",
		"description": "",
		"tables": [
			{
				"id": "11",
				"name": "p1",
				"min": "2",
				"max": "20",
				"published": "1"
			}
		]
	}
]
Admin

From the back-end of VikRestaurants it is possible to check the logs (if any) of the event called by the client.

By clicking the icon, it is possible to see the logs related to the performed event.

Application Usage

How should the plugins be handled from your Applications?

Here is a simple example that uses a cURL connection to retrieve the rooms and tables from a different website/server.

/* define params */
$params = array(
	"event" => "rooms_tables",
	"username" => "app",
	"password" => "ABCD1234",
);

/* specify your domain URL */
$ch = curl_init('http://domain.com/index.php?option=com_vikrestaurants&task=apis');

/* configure cURL connection */
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

/* connect to the URL and retrieve the JSON response */
$json = curl_exec($ch);

/* evaluate error */
if ($errno = curl_errno($ch)) {
	echo "Error ($errno) : " . curl_error($ch) . "\n";
	exit;
}

/* otherwise decode the response */
$rooms = json_decode($json);

echo print_r($rooms, true) . "\n";
Errors

Here is the list of all the possible errors that can be raised by the API Framework.

Authentication

All the errors raised during the authentication of the application.

Generic Authentication Error
100

Something gone wrong while it was authenticating the application.
You should see this error only if you are triggering an event (via code) without the authentication, such as the example below.

FrameworkAPIs::getInstance()->trigger('connection_ping');
Username Error
101

The username provided is empty or invalid. Make sure the connection URL contains the &username=[USERNAME] parameter.
@see also Credentials Requirements to check if your username matches the system requirements.

Password Error
102

The password provided is empty or invalid. Make sure the connection URL contains the &password=[PASSWORD] parameter.
@see also Credentials Requirements to check if your password matches the system requirements.

Invalid Credentials
103

The username and password do not match. Your application may not exist or the credentials may not be correct.

Account Blocked
104

The account is blocked. The application you are using is blocked, you need to re-enable it from the back-end of VikRestaurants.
Even if you are seeing this error, the username and password you are using are correct.

Otherwise, the IP Address from which you are trying to connect may be banned. In this case, check the Banned List from the back-end of VikRestaurants.

@see Banned List

Unauthorised Source IP
105

The IP Address from which you are trying to connect is not allowed. Make sure the list of allowed IPs for this application is empty or includes your origin address. Even if you are seeing this error, the credentials are correct.

@see Allowed IPs

Event Triggering

All the errors raised during the triggering of the event. 

File Not Found
201

The event requested does not exist. Make sure the event you are requesting is listed in the plugins folder.

 @see API Plugins Path

Event Not Valid
202

The event requested is not valid. Make sure the classname of the event follows the standard of the EventAPIs class.

 @see EventAPIs

Event Not Runnable
203

The event requested is not runnable. Make sure the event you are requesting inherits correctly the EventAPIs class.

 @see EventAPIs

Unauthorised Event
204

The event requested is not authorised. Make sure your application owns the permissions to run the event you are requesting.

 @see API Users Plugin Rules

Plugin Response

The errors raised during the plugin execution.

Generic Plugin Error
500

If you are seeing this error, it means that you are correctly running the plugin but there is still something wrong.

If the error message is empty, make sure you are verifying the response within the code.

@see ResponseAPIs::setStatus()

Otherwise it means that the plugin is throwing an own error.

Custom Plugin Error
xxx

Any other error code you see should be considered as a custom error thrown by the plugin.
In order to understand the reason of this error, you should read the description of the plugin that you are running.

 @see API Plugins Description

This site uses cookies. By continuing to browse you accept their use. Further information