mirror of
https://github.com/Dolibarr/dolibarr.git
synced 2026-01-06 00:53:00 +01:00
Merge remote-tracking branch 'Upstream/develop' into develop-md
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"ext-gd": "*",
|
||||
"ext-curl": "*"
|
||||
"ext-curl": "*",
|
||||
"restler/framework": "3.0.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mysqli": "*",
|
||||
|
||||
123
dev/skeletons/build_api_class.php
Executable file
123
dev/skeletons/build_api_class.php
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file dev/skeletons/build_api_class.php
|
||||
* \ingroup core
|
||||
* \brief Create a complete API class file from existant class file
|
||||
*/
|
||||
|
||||
$sapi_type = php_sapi_name();
|
||||
$script_file = basename(__FILE__);
|
||||
$path=dirname(__FILE__).'/';
|
||||
|
||||
// Test if batch mode
|
||||
if (substr($sapi_type, 0, 3) == 'cgi') {
|
||||
echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Include Dolibarr environment
|
||||
require_once($path."../../htdocs/master.inc.php");
|
||||
// After this $db is a defined handler to database.
|
||||
|
||||
// Main
|
||||
$version='1';
|
||||
@set_time_limit(0);
|
||||
$error=0;
|
||||
|
||||
$langs->load("main");
|
||||
|
||||
|
||||
print "***** $script_file ($version) *****\n";
|
||||
|
||||
|
||||
// -------------------- START OF BUILD_API_FROM_CLASS --------------------
|
||||
|
||||
// Check parameters
|
||||
if (! isset($argv[1]) && ! isset($argv[2]))
|
||||
{
|
||||
print "Usage: $script_file phpClassFile phpClassName\n";
|
||||
exit;
|
||||
}
|
||||
// Show parameters
|
||||
print 'Classfile='.$argv[1]."\n";
|
||||
print 'Classname='.$argv[2]."\n";
|
||||
|
||||
$classfile=$argv[1];
|
||||
$classname=$argv[2];
|
||||
$classmin=strtolower($classname);
|
||||
$classnameApi = $classname.'Api';
|
||||
$property=array();
|
||||
$targetcontent='';
|
||||
|
||||
// Load the class and read properties
|
||||
require_once($classfile);
|
||||
|
||||
$property=array();
|
||||
$class = new $classname($db);
|
||||
$values=get_class_vars($classname);
|
||||
|
||||
unset($values['db']);
|
||||
unset($values['error']);
|
||||
unset($values['errors']);
|
||||
unset($values['element']);
|
||||
unset($values['table_element']);
|
||||
unset($values['table_element_line']);
|
||||
unset($values['fk_element']);
|
||||
unset($values['ismultientitymanaged']);
|
||||
|
||||
// Read skeleton_api_class.class.php file
|
||||
$skeletonfile=$path.'skeleton_api_class.class.php';
|
||||
$sourcecontent=file_get_contents($skeletonfile);
|
||||
if (! $sourcecontent)
|
||||
{
|
||||
print "\n";
|
||||
print "Error: Failed to read skeleton sample '".$skeletonfile."'\n";
|
||||
print "Try to run script from skeletons directory.\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Define output variables
|
||||
$outfile='out.api_'.$classmin.'.class.php';
|
||||
$targetcontent=$sourcecontent;
|
||||
|
||||
// Substitute class name
|
||||
$targetcontent=preg_replace('/skeleton_api_class\.class\.php/', 'api_'.$classmin.'.class.php', $targetcontent);
|
||||
$targetcontent=preg_replace('/skeleton/', $classmin, $targetcontent);
|
||||
//$targetcontent=preg_replace('/\$table_element=\'skeleton\'/', '\$table_element=\''.$tablenoprefix.'\'', $targetcontent);
|
||||
$targetcontent=preg_replace('/SkeletonApi/', $classnameApi, $targetcontent);
|
||||
$targetcontent=preg_replace('/Skeleton/', $classname, $targetcontent);
|
||||
|
||||
// Build file
|
||||
$fp=fopen($outfile,"w");
|
||||
if ($fp)
|
||||
{
|
||||
fputs($fp, $targetcontent);
|
||||
fclose($fp);
|
||||
print "\n";
|
||||
print "File '".$outfile."' has been built in current directory.\n";
|
||||
}
|
||||
else $error++;
|
||||
|
||||
|
||||
|
||||
// -------------------- END OF BUILD_CLASS_FROM_TABLE SCRIPT --------------------
|
||||
|
||||
print "You can now rename generated files by removing the 'out.' prefix in their name and store them into directory /module/class.\n";
|
||||
return $error;
|
||||
288
dev/skeletons/skeleton_api_class.class.php
Normal file
288
dev/skeletons/skeleton_api_class.class.php
Normal file
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
|
||||
/**
|
||||
* API class for skeleton object
|
||||
*
|
||||
* @smart-auto-routing false
|
||||
* @access protected
|
||||
* @class DolibarrApiAccess {@requires user,external}
|
||||
*
|
||||
*
|
||||
*/
|
||||
class SkeletonApi extends DolibarrApi
|
||||
{
|
||||
/**
|
||||
* @var array $FIELDS Mandatory fields, checked when create and update object
|
||||
*/
|
||||
static $FIELDS = array(
|
||||
'name'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var Skeleton $skeleton {@type Skeleton}
|
||||
*/
|
||||
public $skeleton;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @url GET skeleton/
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
global $db, $conf;
|
||||
$this->db = $db;
|
||||
$this->skeleton = new Skeleton($this->db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properties of a skeleton object
|
||||
*
|
||||
* Return an array with skeleton informations
|
||||
*
|
||||
* @param int $id ID of skeleton
|
||||
* @return array|mixed data without useless information
|
||||
*
|
||||
* @url GET skeleton/{id}
|
||||
* @throws RestException
|
||||
*/
|
||||
function get($id)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->skeleton->read) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$result = $this->skeleton->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Skeleton not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('skeleton',$this->skeleton->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
return $this->_cleanObjectDatas($this->skeleton);
|
||||
}
|
||||
|
||||
/**
|
||||
* List skeletons
|
||||
*
|
||||
* Get a list of skeletons
|
||||
*
|
||||
* @param int $mode Use this param to filter list
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
*
|
||||
* @return array Array of skeleton objects
|
||||
*
|
||||
* @url GET /skeletons/
|
||||
*/
|
||||
function getList($mode, $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
global $db, $conf;
|
||||
|
||||
$obj_ret = array();
|
||||
|
||||
$socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : '';
|
||||
|
||||
// If the internal user must only see his customers, force searching by him
|
||||
if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
|
||||
|
||||
$sql = "SELECT s.rowid";
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."skeleton as s";
|
||||
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
|
||||
$sql.= ", ".MAIN_DB_PREFIX."c_stcomm as st";
|
||||
$sql.= " WHERE s.fk_stcomm = st.id";
|
||||
|
||||
// Example of use $mode
|
||||
//if ($mode == 1) $sql.= " AND s.client IN (1, 3)";
|
||||
//if ($mode == 2) $sql.= " AND s.client IN (2, 3)";
|
||||
|
||||
$sql.= ' AND s.entity IN ('.getEntity('skeleton', 1).')';
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= " AND s.fk_soc = sc.fk_soc";
|
||||
if ($socid) $sql.= " AND s.fk_soc = ".$socid;
|
||||
if ($search_sale > 0) $sql.= " AND s.rowid = sc.fk_soc"; // Join for the needed table to filter by sale
|
||||
|
||||
// Insert sale filter
|
||||
if ($search_sale > 0)
|
||||
{
|
||||
$sql .= " AND sc.fk_user = ".$search_sale;
|
||||
}
|
||||
|
||||
$nbtotalofrecords = 0;
|
||||
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
|
||||
{
|
||||
$result = $db->query($sql);
|
||||
$nbtotalofrecords = $db->num_rows($result);
|
||||
}
|
||||
|
||||
$sql.= $db->order($sortfield, $sortorder);
|
||||
if ($limit) {
|
||||
if ($page < 0)
|
||||
{
|
||||
$page = 0;
|
||||
}
|
||||
$offset = $limit * $page;
|
||||
|
||||
$sql.= $db->plimit($limit + 1, $offset);
|
||||
}
|
||||
|
||||
$result = $db->query($sql);
|
||||
if ($result)
|
||||
{
|
||||
$num = $db->num_rows($result);
|
||||
while ($i < $num)
|
||||
{
|
||||
$obj = $db->fetch_object($result);
|
||||
$skeleton_static = new Skeleton($db);
|
||||
if($skeleton_static->fetch($obj->rowid)) {
|
||||
$obj_ret[] = parent::_cleanObjectDatas($skeleton_static);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new RestException(503, 'Error when retrieve skeleton list');
|
||||
}
|
||||
if( ! count($obj_ret)) {
|
||||
throw new RestException(404, 'No skeleton found');
|
||||
}
|
||||
return $obj_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create skeleton object
|
||||
*
|
||||
* @param array $request_data Request datas
|
||||
* @return int ID of skeleton
|
||||
*
|
||||
* @url POST skeleton/
|
||||
*/
|
||||
function post($request_data = NULL)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->skeleton->create) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
// Check mandatory fields
|
||||
$result = $this->_validate($request_data);
|
||||
|
||||
foreach($request_data as $field => $value) {
|
||||
$this->skeleton->$field = $value;
|
||||
}
|
||||
if( ! $this->skeleton->create(DolibarrApiAccess::$user)) {
|
||||
throw new RestException(500);
|
||||
}
|
||||
return $this->skeleton->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update skeleton
|
||||
*
|
||||
* @param int $id Id of skeleton to update
|
||||
* @param array $request_data Datas
|
||||
* @return int
|
||||
*
|
||||
* @url PUT skeleton/{id}
|
||||
*/
|
||||
function put($id, $request_data = NULL)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->skeleton->create) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$result = $this->skeleton->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Skeleton not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('skeleton',$this->skeleton->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
foreach($request_data as $field => $value) {
|
||||
$this->skeleton->$field = $value;
|
||||
}
|
||||
|
||||
if($this->skeleton->update($id, DolibarrApiAccess::$user))
|
||||
return $this->get ($id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete skeleton
|
||||
*
|
||||
* @param int $id Skeleton ID
|
||||
* @return array
|
||||
*
|
||||
* @url DELETE skeleton/{id}
|
||||
*/
|
||||
function delete($id)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->skeleton->supprimer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$result = $this->skeleton->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Skeleton not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('skeleton',$this->skeleton->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
if( !$this->skeleton->delete($id))
|
||||
{
|
||||
throw new RestException(500);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => 'Skeleton deleted'
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate fields before create or update object
|
||||
*
|
||||
* @param array $data Data to validate
|
||||
* @return array
|
||||
*
|
||||
* @throws RestException
|
||||
*/
|
||||
function _validate($data)
|
||||
{
|
||||
$skeleton = array();
|
||||
foreach (SkeletonApi::$FIELDS as $field) {
|
||||
if (!isset($data[$field]))
|
||||
throw new RestException(400, "$field field missing");
|
||||
$skeleton[$field] = $data[$field];
|
||||
}
|
||||
return $skeleton;
|
||||
}
|
||||
}
|
||||
@@ -873,7 +873,7 @@ if ($rowid)
|
||||
}
|
||||
});
|
||||
';
|
||||
if (GETPOST('paymentsave')) print '$("#'.GETPOST('paymentsave').'").attr("checked",true);';
|
||||
if (GETPOST('paymentsave')) print '$("#'.GETPOST('paymentsave').'").prop("checked",true);';
|
||||
print '});';
|
||||
print '</script>'."\n";
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ jQuery(document).ready(function() {
|
||||
var row_num = field_id.split("_");
|
||||
jQuery("#updateconst").show();
|
||||
jQuery("#action").val('update');
|
||||
jQuery("#check_" + row_num[1]).attr("checked",true);
|
||||
jQuery("#check_" + row_num[1]).prop("checked",true);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -271,12 +271,12 @@ if ($action == 'edit')
|
||||
{
|
||||
jQuery(".drag").hide();
|
||||
jQuery("#MAIN_MAIL_EMAIL_TLS").val(0);
|
||||
jQuery("#MAIN_MAIL_EMAIL_TLS").attr(\'disabled\', \'disabled\');
|
||||
jQuery("#MAIN_MAIL_EMAIL_TLS").prop("disabled", true);
|
||||
';
|
||||
if ($linuxlike)
|
||||
{
|
||||
print ' jQuery("#MAIN_MAIL_SMTP_SERVER").attr(\'disabled\', \'disabled\');';
|
||||
print ' jQuery("#MAIN_MAIL_SMTP_PORT").attr(\'disabled\', \'disabled\');';
|
||||
print ' jQuery("#MAIN_MAIL_SMTP_SERVER").prop("disabled", true);';
|
||||
print ' jQuery("#MAIN_MAIL_SMTP_PORT").prop("disabled", true);';
|
||||
}
|
||||
print '
|
||||
}
|
||||
@@ -284,9 +284,9 @@ if ($action == 'edit')
|
||||
{
|
||||
jQuery(".drag").show();
|
||||
jQuery("#MAIN_MAIL_EMAIL_TLS").val('.$conf->global->MAIN_MAIL_EMAIL_TLS.');
|
||||
jQuery("#MAIN_MAIL_EMAIL_TLS").removeAttr(\'disabled\');
|
||||
jQuery("#MAIN_MAIL_SMTP_SERVER").removeAttr(\'disabled\');
|
||||
jQuery("#MAIN_MAIL_SMTP_PORT").removeAttr(\'disabled\');
|
||||
jQuery("#MAIN_MAIL_EMAIL_TLS").removeAttr("disabled");
|
||||
jQuery("#MAIN_MAIL_SMTP_SERVER").removeAttr("disabled");
|
||||
jQuery("#MAIN_MAIL_SMTP_PORT").removeAttr("disabled");
|
||||
}
|
||||
}
|
||||
initfields();
|
||||
|
||||
@@ -255,12 +255,12 @@ if ($action == 'create')
|
||||
{
|
||||
if (jQuery("#topleft").val() == \'top\')
|
||||
{
|
||||
jQuery("#menuId").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#menuId").prop("disabled", true);
|
||||
jQuery("#menuId").val(\'\');
|
||||
}
|
||||
else
|
||||
{
|
||||
jQuery("#menuId").removeAttr(\'disabled\');
|
||||
jQuery("#menuId").removeAttr("disabled");
|
||||
}
|
||||
}
|
||||
init_topleft();
|
||||
|
||||
@@ -118,7 +118,7 @@ foreach($sortorder as $numero=>$name)
|
||||
$idperms="";
|
||||
$var=!$var;
|
||||
// Module
|
||||
print "<tr ".$bc[$var]."><td width=\"300\" nowrap=\"nowrap\">";
|
||||
print "<tr ".$bc[$var].'><td width="300" class="nowrap">';
|
||||
$alt=$name.' - '.$modules_files[$numero];
|
||||
if (! empty($picto[$numero]))
|
||||
{
|
||||
|
||||
@@ -96,7 +96,7 @@ jQuery(document).ready(function() {
|
||||
jQuery("#select_sql_compat").click(function() {
|
||||
if (jQuery("#select_sql_compat").val() == 'POSTGRESQL')
|
||||
{
|
||||
jQuery("#checkbox_dump_disable-add-locks").attr('checked',true);
|
||||
jQuery("#checkbox_dump_disable-add-locks").prop('checked',true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
50
htdocs/api/README.md
Normal file
50
htdocs/api/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
API howto
|
||||
=========
|
||||
|
||||
Explore the api
|
||||
---------------
|
||||
|
||||
You can explore API method by using web interface : https://**yourdolibarr.tld**/htdocs/public/api/explorer/index.html (replace **yourdolibarr.tld** by real hostname of your Dolibarr installation)
|
||||
|
||||
Access to the API
|
||||
---------------
|
||||
|
||||
> **Warning : access to the API should (or better : must!) be secured with SSL connection**
|
||||
|
||||
To access to the API you need a token to identify. When you access the API for the first time, you need to log in with user name and password to get a token. **Only** this token will allow to access API with.
|
||||
|
||||
To log in with the API, use this uri : https://**yourdolibarr.tld**/htdocs/public/api/login?login=**username**&password=**password** (replace bold strings with real values)
|
||||
|
||||
The token will be saved by Dolibarr for next user accesses to the API and it **must** be put into request uri as **api_key** parameter.
|
||||
|
||||
Develop the API
|
||||
--------------
|
||||
|
||||
The API uses Lucarast Restler framework. Please check documentation https://www.luracast.com/products/restler and examples http://help.luracast.com/restler/examples/
|
||||
Github contains also usefull informations : https://github.com/Luracast/Restler
|
||||
|
||||
To implement it into Dolibarr, we need to create a specific class for object we want to use. A skeleton file is available into /dev directory : *skeleton_api_class.class.php*
|
||||
The API class file must be put into object class directory, with specific file name. By example, API class file for '*myobject*' must be put as : /htdocs/*myobject*/class/api_*myobject*.class.php. Class must be named **MyobjectApi**.
|
||||
|
||||
If a module provide several object, use a different name for '*myobject*' and put the file into the same directory.
|
||||
|
||||
**Define url for methods**
|
||||
|
||||
It is possible to specify url for API methods by simply use the PHPDoc tag **@url**. See examples :
|
||||
|
||||
/**
|
||||
* List contacts
|
||||
*
|
||||
* Get a list of contacts
|
||||
*
|
||||
* @url GET /contact/list
|
||||
* @url GET /contact/list/{socid}
|
||||
* @url GET /thirdparty/{socid}/contacts
|
||||
* [...]
|
||||
|
||||
**Other Annotations**
|
||||
Other annotations are used, you are encouraged to read them : https://github.com/Luracast/Restler/blob/master/ANNOTATIONS.md
|
||||
|
||||
PHPDoc tags can also be used to specify variables informations for API. Again, rtfm : https://github.com/Luracast/Restler/blob/master/PARAM.md
|
||||
|
||||
|
||||
138
htdocs/api/admin/api.php
Normal file
138
htdocs/api/admin/api.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/* Copyright (C) 2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
||||
* Copyright (C) 2005-2010 Laurent Destailleur <eldy@users.sourceforge.org>
|
||||
* Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
|
||||
* Copyright (C) 2012 Regis Houssin <regis.houssin@capnetworks.com>
|
||||
* Copyright (C) 2015 Regis Houssin <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file htdocs/api/admin/api.php
|
||||
* \ingroup api
|
||||
* \brief Page to setup api module
|
||||
*/
|
||||
|
||||
require '../../main.inc.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
|
||||
|
||||
$langs->load("admin");
|
||||
|
||||
if (! $user->admin)
|
||||
accessforbidden();
|
||||
|
||||
$actionsave=GETPOST("save");
|
||||
|
||||
// Sauvegardes parametres
|
||||
if ($actionsave)
|
||||
{
|
||||
$i=0;
|
||||
|
||||
$db->begin();
|
||||
|
||||
$i+=dolibarr_set_const($db,'API_KEY',trim(GETPOST("API_KEY")),'chaine',0,'',$conf->entity);
|
||||
|
||||
if ($i >= 1)
|
||||
{
|
||||
$db->commit();
|
||||
setEventMessage($langs->trans("SetupSaved"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$db->rollback();
|
||||
setEventMessage($langs->trans("Error"), 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* View
|
||||
*/
|
||||
|
||||
llxHeader();
|
||||
|
||||
$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
|
||||
print_fiche_titre($langs->trans("ApiSetup"),$linkback,'title_setup');
|
||||
|
||||
print $langs->trans("ApiDesc")."<br>\n";
|
||||
print "<br>\n";
|
||||
|
||||
print '<form name="apisetupform" action="'.$_SERVER["PHP_SELF"].'" method="post">';
|
||||
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
||||
print '<table class="noborder" width="100%">';
|
||||
|
||||
print '<tr class="liste_titre">';
|
||||
print "<td>".$langs->trans("Parameter")."</td>";
|
||||
print "<td>".$langs->trans("Value")."</td>";
|
||||
print "<td> </td>";
|
||||
print "</tr>";
|
||||
|
||||
print '<tr class="impair">';
|
||||
print '<td class="fieldrequired">'.$langs->trans("KeyForApiAccess").'</td>';
|
||||
print '<td><input type="text" class="flat" id="API_KEY" name="API_KEY" value="'. (GETPOST('API_KEY')?GETPOST('API_KEY'):(! empty($conf->global->API_KEY)?$conf->global->API_KEY:'')) . '" size="40">';
|
||||
if (! empty($conf->use_javascript_ajax))
|
||||
print ' '.img_picto($langs->trans('Generate'), 'refresh', 'id="generate_token" class="linkobject"');
|
||||
print '</td>';
|
||||
print '<td> </td>';
|
||||
print '</tr>';
|
||||
|
||||
print '</table>';
|
||||
|
||||
print '<br><div class="center">';
|
||||
print '<input type="submit" name="save" class="button" value="'.$langs->trans("Save").'">';
|
||||
print '</div>';
|
||||
|
||||
print '</form>';
|
||||
|
||||
print '<br><br>';
|
||||
|
||||
// API endpoint
|
||||
print '<u>'.$langs->trans("ApiEndPointIs").':</u><br>';
|
||||
$url=DOL_MAIN_URL_ROOT.'/public/api/';
|
||||
print img_picto('','object_globe.png').' <a href="'.$url.'" target="_blank">'.$url."</a><br>\n";
|
||||
$url=DOL_MAIN_URL_ROOT.'/public/api/.json';
|
||||
print img_picto('','object_globe.png').' <a href="'.$url.'" target="_blank">'.$url."</a><br>\n";
|
||||
|
||||
// Explorer
|
||||
print '<u>'.$langs->trans("ApiExporerIs").':</u><br>';
|
||||
$url=DOL_MAIN_URL_ROOT.'/public/api/explorer/index.html';
|
||||
print img_picto('','object_globe.png').' <a href="'.$url.'" target="_blank">'.$url."</a><br>\n";
|
||||
|
||||
print '<br>';
|
||||
|
||||
|
||||
print '<br>';
|
||||
print $langs->trans("OnlyActiveElementsAreExposed", DOL_URL_ROOT.'/admin/modules.php');
|
||||
|
||||
if (! empty($conf->use_javascript_ajax))
|
||||
{
|
||||
print "\n".'<script type="text/javascript">';
|
||||
print '$(document).ready(function () {
|
||||
$("#generate_token").click(function() {
|
||||
$.get( "'.DOL_URL_ROOT.'/core/ajax/security.php", {
|
||||
action: \'getrandompassword\',
|
||||
generic: true
|
||||
},
|
||||
function(token) {
|
||||
$("#API_KEY").val(token);
|
||||
});
|
||||
});
|
||||
});';
|
||||
print '</script>';
|
||||
}
|
||||
|
||||
|
||||
llxFooter();
|
||||
$db->close();
|
||||
215
htdocs/api/class/api.class.php
Normal file
215
htdocs/api/class/api.class.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Luracast\Restler\Restler;
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
||||
|
||||
/**
|
||||
* Class for API
|
||||
*
|
||||
*/
|
||||
class DolibarrApi
|
||||
{
|
||||
|
||||
/**
|
||||
* @var DoliDb $db Database object
|
||||
*/
|
||||
static protected $db;
|
||||
|
||||
/**
|
||||
* @var Restler $r Restler object
|
||||
*/
|
||||
var $r;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param DoliDb $db Database handler
|
||||
*/
|
||||
function __construct($db) {
|
||||
$this->db = $db;
|
||||
$this->r = new Restler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed method when API is called without parameter
|
||||
*
|
||||
* Display a short message an return a http code 200
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function index()
|
||||
{
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => __class__.' is up and running!'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clean sensible object datas
|
||||
*
|
||||
* @param object $object Object to clean
|
||||
* @return array Array of cleaned object properties
|
||||
*
|
||||
* @todo use an array for properties to clean
|
||||
*
|
||||
*/
|
||||
function _cleanObjectDatas($object) {
|
||||
|
||||
// Remove $db object property for object
|
||||
unset($object->db);
|
||||
|
||||
// If object has lines, remove $db property
|
||||
if(isset($object->lines) && count($object->lines) > 0) {
|
||||
for($i=0; $i < count($object->lines); $i++) {
|
||||
$this->_cleanObjectDatas($object->lines[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
// If object has linked objects, remove $db property
|
||||
if(isset($object->linkedObjects) && count($object->linkedObjects) > 0) {
|
||||
foreach($object->linkedObjects as $type_object => $linked_object) {
|
||||
foreach($linked_object as $object2clean) {
|
||||
$this->_cleanObjectDatas($object2clean);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check user access to a resource
|
||||
*
|
||||
* Check access by user to a given resource
|
||||
*
|
||||
* @param string $resource element to check
|
||||
* @param int $resource_id Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional).
|
||||
* @param type $dbtablename 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity. Not used if objectid is null (optional)
|
||||
* @param string $feature2 Feature to check, second level of permission (optional). Can be or check with 'level1|level2'.
|
||||
* @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional)
|
||||
* @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional)
|
||||
* @throws RestException
|
||||
*/
|
||||
static function _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid') {
|
||||
|
||||
// Features/modules to check
|
||||
$featuresarray = array($resource);
|
||||
if (preg_match('/&/', $resource)) {
|
||||
$featuresarray = explode("&", $resource);
|
||||
}
|
||||
else if (preg_match('/\|/', $resource)) {
|
||||
$featuresarray = explode("|", $resource);
|
||||
}
|
||||
|
||||
// More subfeatures to check
|
||||
if (! empty($feature2)) {
|
||||
$feature2 = explode("|", $feature2);
|
||||
}
|
||||
|
||||
return checkUserAccessToObject(DolibarrApiAccess::$user, $featuresarray,$resource_id,$dbtablename,$feature2,$dbt_keyfield,$dbt_select);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* API init
|
||||
*
|
||||
*/
|
||||
class DolibarrApiInit extends DolibarrApi
|
||||
{
|
||||
|
||||
function __construct() {
|
||||
global $db;
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login
|
||||
*
|
||||
* Log user with username and password
|
||||
*
|
||||
* @param string $login Username
|
||||
* @param string $password User password
|
||||
* @param int $entity User entity
|
||||
* @return array Response status and user token
|
||||
*
|
||||
* @throws RestException
|
||||
*/
|
||||
public function login($login, $password, $entity = 0) {
|
||||
|
||||
// Authentication mode
|
||||
if (empty($dolibarr_main_authentication))
|
||||
$dolibarr_main_authentication = 'http,dolibarr';
|
||||
// Authentication mode: forceuser
|
||||
if ($dolibarr_main_authentication == 'forceuser' && empty($dolibarr_auto_user))
|
||||
$dolibarr_auto_user = 'auto';
|
||||
// Set authmode
|
||||
$authmode = explode(',', $dolibarr_main_authentication);
|
||||
|
||||
include_once DOL_DOCUMENT_ROOT . '/core/lib/security2.lib.php';
|
||||
$login = checkLoginPassEntity($login, $password, $entity, $authmode);
|
||||
if (empty($login))
|
||||
{
|
||||
throw new RestException(403, 'Access denied');
|
||||
}
|
||||
|
||||
// Generate token for user
|
||||
$token = dol_hash($login.uniqid().$conf->global->MAIN_API_KEY,1);
|
||||
|
||||
// We store API token into database
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."user";
|
||||
$sql.= " SET api_key = '".$this->db->escape($token)."'";
|
||||
$sql.= " WHERE login = '".$this->db->escape($login)."'";
|
||||
|
||||
dol_syslog(get_class($this)."::login", LOG_DEBUG); // No log
|
||||
$result = $this->db->query($sql);
|
||||
if (!$result)
|
||||
{
|
||||
throw new RestException(500, 'Error when updating user :'.$this->db->error_msg);
|
||||
}
|
||||
|
||||
//return token
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'token' => $token,
|
||||
'message' => 'Welcome ' . $login
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status (Dolibarr version)
|
||||
*
|
||||
* @access protected
|
||||
* @class DolibarrApiAccess {@requires admin}
|
||||
*/
|
||||
function status() {
|
||||
require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php';
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'dolibarr_version' => DOL_VERSION
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
144
htdocs/api/class/api_access.class.php
Normal file
144
htdocs/api/class/api_access.class.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use \Luracast\Restler\iAuthenticate;
|
||||
use \Luracast\Restler\Resources;
|
||||
use \Luracast\Restler\Defaults;
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
|
||||
/**
|
||||
* Dolibarr API access class
|
||||
*
|
||||
*/
|
||||
class DolibarrApiAccess implements iAuthenticate
|
||||
{
|
||||
const REALM = 'Restricted Dolibarr API';
|
||||
|
||||
/**
|
||||
* @var array $requires role required by API method user / external / admin
|
||||
*/
|
||||
public static $requires = array('user','external','admin');
|
||||
|
||||
/**
|
||||
* @var string $role user role
|
||||
*/
|
||||
public static $role = 'user';
|
||||
|
||||
/**
|
||||
* @var User $user Loggued user
|
||||
*/
|
||||
public static $user = '';
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
|
||||
/**
|
||||
* @return string string to be used with WWW-Authenticate header
|
||||
* @example Basic
|
||||
* @example Digest
|
||||
* @example OAuth
|
||||
*/
|
||||
public function __getWWWAuthenticateString();
|
||||
|
||||
/**
|
||||
* Check access
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function _isAllowed()
|
||||
{
|
||||
// @codingStandardsIgnoreEnd
|
||||
global $db;
|
||||
|
||||
$stored_key = '';
|
||||
|
||||
$userClass = Defaults::$userIdentifierClass;
|
||||
|
||||
if (isset($_GET['api_key'])) {
|
||||
$sql = "SELECT u.login, u.datec, u.api_key, ";
|
||||
$sql.= " u.tms as date_modification, u.entity";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."user as u";
|
||||
$sql.= " WHERE u.api_key = '".$db->escape($_GET['api_key'])."'";
|
||||
|
||||
if ($db->query($sql))
|
||||
{
|
||||
if ($db->num_rows($result))
|
||||
{
|
||||
$obj = $db->fetch_object($result);
|
||||
$login = $obj->login;
|
||||
$stored_key = $obj->api_key;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new RestException(503, 'Error when fetching user api_key :'.$db->error_msg);
|
||||
}
|
||||
|
||||
if ( $stored_key != $_GET['api_key']) {
|
||||
$userClass::setCacheIdentifier($_GET['api_key']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$fuser = new User($db);
|
||||
if(! $fuser->fetch('',$login)) {
|
||||
throw new RestException(503, 'Error when fetching user :'.$fuser->error);
|
||||
}
|
||||
$fuser->getrights();
|
||||
static::$user = $fuser;
|
||||
|
||||
if($fuser->societe_id)
|
||||
static::$role = 'external';
|
||||
|
||||
if($fuser->admin)
|
||||
static::$role = 'admin';
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$userClass::setCacheIdentifier(static::$role);
|
||||
Resources::$accessControlFunction = 'DolibarrApiAccess::verifyAccess';
|
||||
return in_array(static::$role, (array) static::$requires) || static::$role == 'admin';
|
||||
}
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
public function __getWWWAuthenticateString()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
/**
|
||||
* Verify access
|
||||
*
|
||||
* @param array $m Properties of method
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
public static function verifyAccess(array $m)
|
||||
{
|
||||
$requires = isset($m['class']['DolibarrApiAccess']['properties']['requires'])
|
||||
? $m['class']['DolibarrApiAccess']['properties']['requires']
|
||||
: false;
|
||||
|
||||
|
||||
return $requires
|
||||
? static::$role == 'admin' || in_array(static::$role, (array) $requires)
|
||||
: true;
|
||||
|
||||
}
|
||||
}
|
||||
8
htdocs/api/index.php
Normal file
8
htdocs/api/index.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
include '../master.inc.php';
|
||||
|
||||
$phone = GETPOST('phone');
|
||||
|
||||
$notfound = "Not found";
|
||||
$error = "Error"
|
||||
|
||||
// Security check
|
||||
if (empty($conf->clicktodial->enabled)) {
|
||||
@@ -64,13 +65,15 @@ if ($resql)
|
||||
if ($obj)
|
||||
{
|
||||
$found = $obj->name;
|
||||
} else {
|
||||
$found = $notfound;
|
||||
}
|
||||
$db->free($resql);
|
||||
}
|
||||
else
|
||||
{
|
||||
dol_print_error($db,'Error');
|
||||
$found = $error;
|
||||
}
|
||||
|
||||
echo $found;
|
||||
|
||||
|
||||
@@ -313,28 +313,28 @@ jQuery(document).ready(function() {
|
||||
{
|
||||
if (jQuery("#fillmanually:checked").val() == "fillmanually")
|
||||
{
|
||||
jQuery("#submitproduct").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#submitthirdparty").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#search_productid").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#socid").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#submitproduct").prop("disabled", true);
|
||||
jQuery("#submitthirdparty").prop("disabled", true);
|
||||
jQuery("#search_productid").prop("disabled", true);
|
||||
jQuery("#socid").prop("disabled", true);
|
||||
jQuery(".showforproductselector").hide();
|
||||
jQuery(".showforthirdpartyselector").hide();
|
||||
}
|
||||
if (jQuery("#fillfromproduct:checked").val() == "fillfromproduct")
|
||||
{
|
||||
jQuery("#submitproduct").removeAttr(\'disabled\');
|
||||
jQuery("#submitthirdparty").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#search_productid").removeAttr(\'disabled\');
|
||||
jQuery("#socid").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#submitproduct").removeAttr("disabled");
|
||||
jQuery("#submitthirdparty").prop("disabled", true);
|
||||
jQuery("#search_productid").removeAttr("disabled");
|
||||
jQuery("#socid").prop("disabled", true);
|
||||
jQuery(".showforproductselector").show();
|
||||
jQuery(".showforthirdpartyselector").hide();
|
||||
}
|
||||
if (jQuery("#fillfromthirdparty:checked").val() == "fillfromthirdparty")
|
||||
{
|
||||
jQuery("#submitproduct").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#submitthirdparty").removeAttr(\'disabled\');
|
||||
jQuery("#search_productid").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#socid").removeAttr(\'disabled\');
|
||||
jQuery("#submitproduct").prop("disabled", true);
|
||||
jQuery("#submitthirdparty").removeAttr("disabled");
|
||||
jQuery("#search_productid").prop("disabled", true);
|
||||
jQuery("#socid").removeAttr("disabled");
|
||||
jQuery(".showforproductselector").hide();
|
||||
jQuery(".showforthirdpartyselector").show();
|
||||
}
|
||||
@@ -348,11 +348,11 @@ jQuery(document).ready(function() {
|
||||
{
|
||||
if (jQuery("#select_fk_barcode_type").val() > 0 && jQuery("#forbarcode").val())
|
||||
{
|
||||
jQuery("#submitformbarcodegen").removeAttr(\'disabled\');
|
||||
jQuery("#submitformbarcodegen").removeAttr("disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
jQuery("#submitformbarcodegen").attr(\'disabled\',\'disabled\');
|
||||
jQuery("#submitformbarcodegen").prop("disabled", true);
|
||||
}
|
||||
}
|
||||
init_gendoc_button();
|
||||
|
||||
355
htdocs/categories/class/api_category.class.php
Normal file
355
htdocs/categories/class/api_category.class.php
Normal file
@@ -0,0 +1,355 @@
|
||||
<?php
|
||||
/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
|
||||
|
||||
/**
|
||||
* API class for category object
|
||||
*
|
||||
* @smart-auto-routing false
|
||||
* @access protected
|
||||
* @class DolibarrApiAccess {@requires user,external}
|
||||
*
|
||||
*
|
||||
*/
|
||||
class CategoryApi extends DolibarrApi
|
||||
{
|
||||
/**
|
||||
* @var array $FIELDS Mandatory fields, checked when create and update object
|
||||
*/
|
||||
static $FIELDS = array(
|
||||
'label',
|
||||
'type'
|
||||
);
|
||||
|
||||
static $TYPES = array(
|
||||
0 => 'product',
|
||||
1 => 'supplier',
|
||||
2 => 'customer',
|
||||
3 => 'member',
|
||||
4 => 'contact',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var Categorie $category {@type Categorie}
|
||||
*/
|
||||
public $category;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @url GET category/
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
global $db, $conf;
|
||||
$this->db = $db;
|
||||
$this->category = new Categorie($this->db);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properties of a category object
|
||||
*
|
||||
* Return an array with category informations
|
||||
*
|
||||
* @param int $id ID of category
|
||||
* @return array|mixed data without useless information
|
||||
*
|
||||
* @url GET category/{id}
|
||||
* @throws RestException
|
||||
*/
|
||||
function get($id)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->categorie->lire) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$result = $this->category->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'category not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('category',$this->category->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
return $this->_cleanObjectDatas($this->category);
|
||||
}
|
||||
|
||||
/**
|
||||
* List categories
|
||||
*
|
||||
* Get a list of categories
|
||||
*
|
||||
* @param string $type Type of category ('member', 'customer', 'supplier', 'product', 'contact')
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
* @return array Array of category objects
|
||||
*
|
||||
* @url GET /category/list
|
||||
*/
|
||||
function getList($type='product', $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
global $db, $conf;
|
||||
|
||||
$obj_ret = array();
|
||||
|
||||
if(! DolibarrApiAccess::$user->rights->categorie->lire) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$sql = "SELECT s.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."categorie as s";
|
||||
$sql.= ' WHERE s.entity IN ('.getEntity('categorie', 1).')';
|
||||
$sql.= ' AND s.type='.array_search($type,CategoryApi::$TYPES);
|
||||
|
||||
$nbtotalofrecords = 0;
|
||||
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
|
||||
{
|
||||
$result = $db->query($sql);
|
||||
$nbtotalofrecords = $db->num_rows($result);
|
||||
}
|
||||
|
||||
$sql.= $db->order($sortfield, $sortorder);
|
||||
if ($limit) {
|
||||
if ($page < 0)
|
||||
{
|
||||
$page = 0;
|
||||
}
|
||||
$offset = $limit * $page;
|
||||
|
||||
$sql.= $db->plimit($limit + 1, $offset);
|
||||
}
|
||||
|
||||
$result = $db->query($sql);
|
||||
if ($result)
|
||||
{
|
||||
$num = $db->num_rows($result);
|
||||
while ($i < $num)
|
||||
{
|
||||
$obj = $db->fetch_object($result);
|
||||
$category_static = new Categorie($db);
|
||||
if($category_static->fetch($obj->rowid)) {
|
||||
$obj_ret[] = parent::_cleanObjectDatas($category_static);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new RestException(503, 'Error when retrieve category list : '.$category_static->error);
|
||||
}
|
||||
if( ! count($obj_ret)) {
|
||||
throw new RestException(404, 'No category found');
|
||||
}
|
||||
return $obj_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get member categories list
|
||||
*
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
* @return mixed
|
||||
*
|
||||
* @url GET /category/list/member
|
||||
*/
|
||||
function getListCategoryMember($sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
return $this->getList('member', $sortfield, $sortorder, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customer categories list
|
||||
*
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @url GET /category/list/customer
|
||||
*/
|
||||
function getListCategoryCustomer($sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
return $this->getList('customer', $sortfield, $sortorder, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get supplier categories list
|
||||
*
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @url GET /category/list/supplier
|
||||
*/
|
||||
function getListCategorySupplier($sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
return $this->getList('supplier', $sortfield, $sortorder, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product categories list
|
||||
*
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @url GET /category/list/product
|
||||
*/
|
||||
function getListCategoryProduct($sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
return $this->getList('product', $sortfield, $sortorder, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contact categories list
|
||||
*
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
* @return mixed
|
||||
*
|
||||
* @url GET /category/list/contact
|
||||
*/
|
||||
function getListCategoryContact($sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
return $this->getList('contact', $sortfield, $sortorder, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create category object
|
||||
*
|
||||
* @param array $request_data Request data
|
||||
* @return int ID of category
|
||||
*
|
||||
* @url POST category/
|
||||
*/
|
||||
function post($request_data = NULL)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->categorie->creer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
// Check mandatory fields
|
||||
$result = $this->_validate($request_data);
|
||||
|
||||
foreach($request_data as $field => $value) {
|
||||
$this->category->$field = $value;
|
||||
}
|
||||
if($this->category->create(DolibarrApiAccess::$user) < 0) {
|
||||
throw new RestException(503, 'Error when create category : '.$this->category->error);
|
||||
}
|
||||
return $this->category->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update category
|
||||
*
|
||||
* @param int $id Id of category to update
|
||||
* @param array $request_data Datas
|
||||
* @return int
|
||||
*
|
||||
* @url PUT category/{id}
|
||||
*/
|
||||
function put($id, $request_data = NULL)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->categorie->creer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$result = $this->category->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'category not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('category',$this->category->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
foreach($request_data as $field => $value) {
|
||||
$this->category->$field = $value;
|
||||
}
|
||||
|
||||
if($this->category->update(DolibarrApiAccess::$user))
|
||||
return $this->get ($id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete category
|
||||
*
|
||||
* @param int $id Category ID
|
||||
* @return array
|
||||
*
|
||||
* @url DELETE category/{id}
|
||||
*/
|
||||
function delete($id)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->categorie->supprimer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$result = $this->category->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'category not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('category',$this->category->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
if (! $this->category->delete(DolibarrApiAccess::$user)) {
|
||||
throw new RestException(401,'error when delete category');
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => 'Category deleted'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate fields before create or update object
|
||||
*
|
||||
* @param array $data Data to validate
|
||||
* @return array
|
||||
*
|
||||
* @throws RestException
|
||||
*/
|
||||
function _validate($data)
|
||||
{
|
||||
$category = array();
|
||||
foreach (CategoryApi::$FIELDS as $field) {
|
||||
if (!isset($data[$field]))
|
||||
throw new RestException(400, "$field field missing");
|
||||
$category[$field] = $data[$field];
|
||||
}
|
||||
return $category;
|
||||
}
|
||||
}
|
||||
@@ -254,7 +254,7 @@ else
|
||||
{
|
||||
$var=!$var;
|
||||
print "\t<tr ".$bc[$var].">\n";
|
||||
print "\t\t<td nowrap=\"nowrap\">";
|
||||
print "\t\t".'<td class="nowrap">';
|
||||
print "<a href='viewcat.php?id=".$cat->id."&type=".$type."'>".$cat->label."</a>";
|
||||
print "</td>\n";
|
||||
print "\t\t".'<td colspan="2">'.$cat->description."</td>\n";
|
||||
|
||||
@@ -570,11 +570,11 @@ if ($action == 'create')
|
||||
$(".fulldayendmin").removeAttr("disabled");
|
||||
$("#p2").removeAttr("disabled");
|
||||
} else {
|
||||
$(".fulldaystarthour").attr("disabled","disabled").val("00");
|
||||
$(".fulldaystartmin").attr("disabled","disabled").val("00");
|
||||
$(".fulldayendhour").attr("disabled","disabled").val("23");
|
||||
$(".fulldayendmin").attr("disabled","disabled").val("59");
|
||||
$("#p2").removeAttr("disabled");
|
||||
$(".fulldaystarthour").prop("disabled", true).val("00");
|
||||
$(".fulldaystartmin").prop("disabled", true).val("00");
|
||||
$(".fulldayendhour").prop("disabled", true).val("23");
|
||||
$(".fulldayendmin").prop("disabled", true).val("59");
|
||||
$("#p2").removeAttr("disabled");
|
||||
}
|
||||
}
|
||||
setdatefields();
|
||||
@@ -841,10 +841,10 @@ if ($id > 0)
|
||||
$(".fulldayendhour").removeAttr("disabled");
|
||||
$(".fulldayendmin").removeAttr("disabled");
|
||||
} else {
|
||||
$(".fulldaystarthour").attr("disabled","disabled").val("00");
|
||||
$(".fulldaystartmin").attr("disabled","disabled").val("00");
|
||||
$(".fulldayendhour").attr("disabled","disabled").val("23");
|
||||
$(".fulldayendmin").attr("disabled","disabled").val("59");
|
||||
$(".fulldaystarthour").prop("disabled", true).val("00");
|
||||
$(".fulldaystartmin").prop("disabled", true).val("00");
|
||||
$(".fulldayendhour").prop("disabled", true).val("23");
|
||||
$(".fulldayendmin").prop("disabled", true).val("59");
|
||||
}
|
||||
}
|
||||
setdatefields();
|
||||
@@ -986,7 +986,7 @@ if ($id > 0)
|
||||
}
|
||||
|
||||
// Priority
|
||||
print '<tr><td nowrap width="30%">'.$langs->trans("Priority").'</td><td colspan="3">';
|
||||
print '<tr><td class="nowrap" width="30%">'.$langs->trans("Priority").'</td><td colspan="3">';
|
||||
print '<input type="text" name="priority" value="'.($object->priority?$object->priority:'').'" size="5">';
|
||||
print '</td></tr>';
|
||||
|
||||
@@ -1174,7 +1174,7 @@ if ($id > 0)
|
||||
}
|
||||
|
||||
// Priority
|
||||
print '<tr><td nowrap width="30%">'.$langs->trans("Priority").'</td><td colspan="3">';
|
||||
print '<tr><td class="nowrap" width="30%">'.$langs->trans("Priority").'</td><td colspan="3">';
|
||||
print ($object->priority?$object->priority:'');
|
||||
print '</td></tr>';
|
||||
|
||||
|
||||
335
htdocs/commande/class/api_commande.class.php
Normal file
335
htdocs/commande/class/api_commande.class.php
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
|
||||
|
||||
/**
|
||||
* API class for commande object
|
||||
*
|
||||
* @smart-auto-routing false
|
||||
* @access protected
|
||||
* @class DolibarrApiAccess {@requires user,external}
|
||||
*
|
||||
* @category Api
|
||||
* @package Api
|
||||
*
|
||||
*
|
||||
*/
|
||||
class CommandeApi extends DolibarrApi
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array $FIELDS Mandatory fields, checked when create and update object
|
||||
*/
|
||||
static $FIELDS = array(
|
||||
'socid'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var Commande $commande {@type Commande}
|
||||
*/
|
||||
public $commande;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @url GET order/
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
global $db, $conf;
|
||||
$this->db = $db;
|
||||
$this->commande = new Commande($this->db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properties of a commande object
|
||||
*
|
||||
* Return an array with commande informations
|
||||
*
|
||||
* @param int $id ID of order
|
||||
* @param string $ref Ref of object
|
||||
* @param string $ref_ext External reference of object
|
||||
* @param string $ref_int Internal reference of other object
|
||||
* @return array|mixed data without useless information
|
||||
*
|
||||
* @url GET order/{id}
|
||||
* @throws RestException
|
||||
*/
|
||||
function get($id='',$ref='', $ref_ext='', $ref_int='')
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->commande->lire) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$result = $this->commande->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Order not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('commande',$this->commande->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
$this->commande->fetchObjectLinked();
|
||||
return $this->_cleanObjectDatas($this->commande);
|
||||
}
|
||||
|
||||
/**
|
||||
* List orders
|
||||
*
|
||||
* Get a list of orders
|
||||
*
|
||||
* @param int $mode Use this param to filter list
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
*
|
||||
* @url GET /order/list
|
||||
* @return array Array of order objects
|
||||
*/
|
||||
function getList($mode=0, $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
global $db, $conf;
|
||||
|
||||
$obj_ret = array();
|
||||
|
||||
$socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : '';
|
||||
|
||||
// If the internal user must only see his customers, force searching by him
|
||||
if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
|
||||
|
||||
$sql = "SELECT s.rowid";
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."commande as s";
|
||||
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
|
||||
|
||||
// Example of use $mode
|
||||
//if ($mode == 1) $sql.= " AND s.client IN (1, 3)";
|
||||
//if ($mode == 2) $sql.= " AND s.client IN (2, 3)";
|
||||
|
||||
$sql.= ' WHERE s.entity IN ('.getEntity('commande', 1).')';
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= " AND s.fk_soc = sc.fk_soc";
|
||||
if ($socid) $sql.= " AND s.fk_soc = ".$socid;
|
||||
if ($search_sale > 0) $sql.= " AND s.rowid = sc.fk_soc"; // Join for the needed table to filter by sale
|
||||
|
||||
// Insert sale filter
|
||||
if ($search_sale > 0)
|
||||
{
|
||||
$sql .= " AND sc.fk_user = ".$search_sale;
|
||||
}
|
||||
|
||||
$nbtotalofrecords = 0;
|
||||
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
|
||||
{
|
||||
$result = $db->query($sql);
|
||||
$nbtotalofrecords = $db->num_rows($result);
|
||||
}
|
||||
|
||||
$sql.= $db->order($sortfield, $sortorder);
|
||||
if ($limit) {
|
||||
if ($page < 0)
|
||||
{
|
||||
$page = 0;
|
||||
}
|
||||
$offset = $limit * $page;
|
||||
|
||||
$sql.= $db->plimit($limit + 1, $offset);
|
||||
}
|
||||
|
||||
$result = $db->query($sql);
|
||||
|
||||
if ($result)
|
||||
{
|
||||
$num = $db->num_rows($result);
|
||||
while ($i < $num)
|
||||
{
|
||||
$obj = $db->fetch_object($result);
|
||||
$commande_static = new Commande($db);
|
||||
if($commande_static->fetch($obj->rowid)) {
|
||||
$obj_ret[] = parent::_cleanObjectDatas($commande_static);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new RestException(503, 'Error when retrieve commande list');
|
||||
}
|
||||
if( ! count($obj_ret)) {
|
||||
throw new RestException(404, 'No commande found');
|
||||
}
|
||||
return $obj_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create order object
|
||||
*
|
||||
* @param array $request_data Request datas
|
||||
*
|
||||
* @url POST order/
|
||||
*
|
||||
* @return int ID of commande
|
||||
*/
|
||||
function post($request_data = NULL)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->commande->creer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
// Check mandatory fields
|
||||
$result = $this->_validate($request_data);
|
||||
|
||||
foreach($request_data as $field => $value) {
|
||||
$this->commande->$field = $value;
|
||||
}
|
||||
if(! $this->commande->create(DolibarrApiAccess::$user) ) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
return $this->commande->ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update order
|
||||
*
|
||||
* @param int $id Id of commande to update
|
||||
* @param array $request_data Datas
|
||||
*
|
||||
* @url PUT order/{id}
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function put($id, $request_data = NULL)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->commande->creer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$result = $this->commande->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Commande not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('commande',$this->commande->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
foreach($request_data as $field => $value) {
|
||||
$this->commande->$field = $value;
|
||||
}
|
||||
|
||||
if($this->commande->update($id, DolibarrApiAccess::$user,1,'','','update'))
|
||||
return $this->get ($id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete order
|
||||
*
|
||||
* @param int $id Order ID
|
||||
*
|
||||
* @url DELETE order/{id}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function delete($id)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->commande->supprimer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$result = $this->commande->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Order not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('commande',$this->commande->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
if( ! $this->commande->delete(DolibarrApiAccess::$user)) {
|
||||
throw new RestException(500, 'Error when delete order : '.$this->commande->error);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => 'Order deleted'
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an order
|
||||
*
|
||||
* @param int $id Order ID
|
||||
* @param int $idwarehouse Warehouse ID
|
||||
*
|
||||
* @url GET order/{id}/validate
|
||||
* @url POST order/{id}/validate
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
function validOrder($id, $idwarehouse=0)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->commande->creer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$result = $this->commande->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Order not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('commande',$this->commande->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
if( ! $this->commande->valid(DolibarrApiAccess::$user, $idwarehouse)) {
|
||||
throw new RestException(500, 'Error when validate order');
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => 'Order validated'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate fields before create or update object
|
||||
*
|
||||
* @param array $data Array with data to verify
|
||||
* @return array
|
||||
* @throws RestException
|
||||
*/
|
||||
function _validate($data)
|
||||
{
|
||||
$commande = array();
|
||||
foreach (CommandeApi::$FIELDS as $field) {
|
||||
if (!isset($data[$field]))
|
||||
throw new RestException(400, "$field field missing");
|
||||
$commande[$field] = $data[$field];
|
||||
}
|
||||
return $commande;
|
||||
}
|
||||
}
|
||||
@@ -512,10 +512,10 @@ if (($action != 'create' && $action != 'add') || !$error)
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function() {
|
||||
jQuery("#checkall").click(function() {
|
||||
jQuery(".checkformerge").attr('checked', true);
|
||||
jQuery(".checkformerge").prop('checked', true);
|
||||
});
|
||||
jQuery("#checknone").click(function() {
|
||||
jQuery(".checkformerge").attr('checked', false);
|
||||
jQuery(".checkformerge").prop('checked', false);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -655,12 +655,12 @@ if (($action != 'create' && $action != 'add') || !$error)
|
||||
print '<td>'.$objp->ref_client.'</td>';
|
||||
|
||||
// Order date
|
||||
print '<td align="center" nowrap>';
|
||||
print '<td align="center" class="nowrap">';
|
||||
print dol_print_date($db->jdate($objp->date_commande),'day');
|
||||
print '</td>';
|
||||
|
||||
//Delivery date
|
||||
print '<td align="center" nowrap>';
|
||||
print '<td align="center" class="nowrap">';
|
||||
print dol_print_date($db->jdate($objp->date_livraison),'day');
|
||||
print '</td>';
|
||||
|
||||
|
||||
@@ -776,11 +776,11 @@ if ($id > 0 || ! empty($ref))
|
||||
{
|
||||
if ($total >= 0)
|
||||
{
|
||||
print '<td align="right" nowrap> '.price($total).'</td>';
|
||||
print '<td align="right" class="nowrap"> '.price($total).'</td>';
|
||||
}
|
||||
else
|
||||
{
|
||||
print '<td align="right" class="error" nowrap> '.price($total).'</td>';
|
||||
print '<td align="right" class="error nowrap"> '.price($total).'</td>';
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -791,7 +791,7 @@ if ($id > 0 || ! empty($ref))
|
||||
// Transaction reconciliated or edit link
|
||||
if ($objp->rappro && $object->canBeConciliated() > 0) // If line not conciliated and account can be conciliated
|
||||
{
|
||||
print '<td align="center" nowrap>';
|
||||
print '<td align="center" class="nowrap">';
|
||||
print '<a href="'.DOL_URL_ROOT.'/compta/bank/ligne.php?rowid='.$objp->rowid.'&account='.$object->id.'&page='.$page.'">';
|
||||
print img_edit();
|
||||
print '</a>';
|
||||
@@ -844,7 +844,7 @@ if ($id > 0 || ! empty($ref))
|
||||
if ($sep > 0) print ' '; // If we had at least one line in future
|
||||
else print $langs->trans("CurrentBalance");
|
||||
print ' '.$object->currency_code.'</td>';
|
||||
print '<td align="right" nowrap><b>'.price($total, 0, $langs, 0, 0, -1, $object->currency_code).'</b></td>';
|
||||
print '<td align="right" class="nowrap"><b>'.price($total, 0, $langs, 0, 0, -1, $object->currency_code).'</b></td>';
|
||||
print '<td> </td>';
|
||||
print '</tr>';
|
||||
}
|
||||
|
||||
@@ -489,15 +489,15 @@ else
|
||||
if ($objp->amount < 0)
|
||||
{
|
||||
$totald = $totald + abs($objp->amount);
|
||||
print '<td align="right" nowrap=\"nowrap\">'.price($objp->amount * -1)."</td><td> </td>\n";
|
||||
print '<td align="right" class="nowrap">'.price($objp->amount * -1)."</td><td> </td>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$totalc = $totalc + abs($objp->amount);
|
||||
print "<td> </td><td align=\"right\" nowrap=\"nowrap\">".price($objp->amount)."</td>\n";
|
||||
print '<td> </td><td align="right" class="nowrap">'.price($objp->amount)."</td>\n";
|
||||
}
|
||||
|
||||
print "<td align=\"right\" nowrap=\"nowrap\">".price($total)."</td>\n";
|
||||
print '<td align="right" class="nowrap">'.price($total)."</td>\n";
|
||||
|
||||
if ($user->rights->banque->modifier || $user->rights->banque->consolidate)
|
||||
{
|
||||
|
||||
@@ -134,13 +134,13 @@ if ($_REQUEST["account"] || $_REQUEST["ref"])
|
||||
$var=!$var;
|
||||
print '<tr class="liste_total">';
|
||||
print '<td align="left" colspan="5">'.$langs->trans("CurrentBalance").'</td>';
|
||||
print '<td align="right" nowrap>'.price($solde).'</td>';
|
||||
print '<td align="right" class="nowrap">'.price($solde).'</td>';
|
||||
print '</tr>';
|
||||
|
||||
$var=!$var;
|
||||
print '<tr class="liste_total">';
|
||||
print '<td align="left" colspan="5">'.$langs->trans("RemainderToPay").'</td>';
|
||||
print '<td align="right" nowrap> </td>';
|
||||
print '<td align="right" class="nowrap"> </td>';
|
||||
print '</tr>';
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ if ($_REQUEST["account"] || $_REQUEST["ref"])
|
||||
$var=!$var;
|
||||
print '<tr class="liste_total">';
|
||||
print '<td align="left" colspan="5">'.$langs->trans("FutureBalance").' ('.$acct->currency_code.')</td>';
|
||||
print '<td align="right" nowrap>'.price($solde, 0, $langs, 0, 0, -1, $acct->currency_code).'</td>';
|
||||
print '<td align="right" class="nowrap">'.price($solde, 0, $langs, 0, 0, -1, $acct->currency_code).'</td>';
|
||||
print '</tr>';
|
||||
|
||||
print "</table>";
|
||||
|
||||
@@ -2099,7 +2099,7 @@ if ($action == 'create')
|
||||
print '<script type="text/javascript" language="javascript">
|
||||
jQuery(document).ready(function() {
|
||||
jQuery("#typedeposit, #valuedeposit").click(function() {
|
||||
jQuery("#radio_deposit").attr(\'checked\',\'checked\');
|
||||
jQuery("#radio_deposit").prop("checked", true);
|
||||
});
|
||||
});
|
||||
</script>';
|
||||
@@ -2154,7 +2154,7 @@ if ($action == 'create')
|
||||
print '<script type="text/javascript" language="javascript">
|
||||
jQuery(document).ready(function() {
|
||||
jQuery("#fac_replacement").change(function() {
|
||||
jQuery("#radio_replacement").attr(\'checked\',\'checked\');
|
||||
jQuery("#radio_replacement").prop("checked", true);
|
||||
});
|
||||
});
|
||||
</script>';
|
||||
@@ -2200,7 +2200,7 @@ if ($action == 'create')
|
||||
// Show credit note options only if we checked credit note
|
||||
print '<script type="text/javascript" language="javascript">
|
||||
jQuery(document).ready(function() {
|
||||
if (! jQuery("#radio_creditnote").attr(\'checked\'))
|
||||
if (! jQuery("#radio_creditnote").is(":checked"))
|
||||
{
|
||||
jQuery("#credit_note_options").hide();
|
||||
}
|
||||
@@ -2229,8 +2229,8 @@ if ($action == 'create')
|
||||
print $desc;
|
||||
|
||||
print '<div id="credit_note_options">';
|
||||
print ' <input type="checkbox" name="invoiceAvoirWithLines" id="invoiceAvoirWithLines" value="1" onclick="if($(this).is(\':checked\') ) { $(\'#radio_creditnote\').attr(\'checked\',\'checked\'); $(\'#invoiceAvoirWithPaymentRestAmount\').removeAttr(\'checked\'); }" '.(GETPOST('invoiceAvoirWithLines','int')>0 ? 'checked':'').' /> <label for="invoiceAvoirWithLines">'.$langs->trans('invoiceAvoirWithLines')."</label>";
|
||||
print '<br> <input type="checkbox" name="invoiceAvoirWithPaymentRestAmount" id="invoiceAvoirWithPaymentRestAmount" value="1" onclick="if($(this).is(\':checked\') ) { $(\'#radio_creditnote\').attr(\'checked\',\'checked\'); $(\'#invoiceAvoirWithLines\').removeAttr(\'checked\'); }" '.(GETPOST('invoiceAvoirWithPaymentRestAmount','int')>0 ? 'checked':'').' /> <label for="invoiceAvoirWithPaymentRestAmount">'.$langs->trans('invoiceAvoirWithPaymentRestAmount')."</label>";
|
||||
print ' <input type="checkbox" name="invoiceAvoirWithLines" id="invoiceAvoirWithLines" value="1" onclick="if($(this).is(\':checked\') ) { $(\'#radio_creditnote\').prop("checked", true); $(\'#invoiceAvoirWithPaymentRestAmount\').removeAttr(\'checked\'); }" '.(GETPOST('invoiceAvoirWithLines','int')>0 ? 'checked':'').' /> <label for="invoiceAvoirWithLines">'.$langs->trans('invoiceAvoirWithLines')."</label>";
|
||||
print '<br> <input type="checkbox" name="invoiceAvoirWithPaymentRestAmount" id="invoiceAvoirWithPaymentRestAmount" value="1" onclick="if($(this).is(\':checked\') ) { $(\'#radio_creditnote\').prop("checked", true); $(\'#invoiceAvoirWithLines\').removeAttr(\'checked\'); }" '.(GETPOST('invoiceAvoirWithPaymentRestAmount','int')>0 ? 'checked':'').' /> <label for="invoiceAvoirWithPaymentRestAmount">'.$langs->trans('invoiceAvoirWithPaymentRestAmount')."</label>";
|
||||
print '</div>';
|
||||
|
||||
print '</td></tr>' . "\n";
|
||||
@@ -3137,28 +3137,28 @@ if ($action == 'create')
|
||||
|
||||
// Paye partiellement 'escompte'
|
||||
if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'discount_vat') {
|
||||
print '<tr><td colspan="' . $nbcols . '" align="right" nowrap="1">';
|
||||
print '<tr><td colspan="' . $nbcols . '" align="right" class="nowrap">';
|
||||
print $form->textwithpicto($langs->trans("Discount") . ':', $langs->trans("HelpEscompte"), - 1);
|
||||
print '</td><td align="right">' . price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye) . '</td><td> </td></tr>';
|
||||
$resteapayeraffiche = 0;
|
||||
}
|
||||
// Paye partiellement ou Abandon 'badcustomer'
|
||||
if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'badcustomer') {
|
||||
print '<tr><td colspan="' . $nbcols . '" align="right" nowrap="1">';
|
||||
print '<tr><td colspan="' . $nbcols . '" align="right" class="nowrap">';
|
||||
print $form->textwithpicto($langs->trans("Abandoned") . ':', $langs->trans("HelpAbandonBadCustomer"), - 1);
|
||||
print '</td><td align="right">' . price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye) . '</td><td> </td></tr>';
|
||||
// $resteapayeraffiche=0;
|
||||
}
|
||||
// Paye partiellement ou Abandon 'product_returned'
|
||||
if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'product_returned') {
|
||||
print '<tr><td colspan="' . $nbcols . '" align="right" nowrap="1">';
|
||||
print '<tr><td colspan="' . $nbcols . '" align="right" class="nowrap">';
|
||||
print $form->textwithpicto($langs->trans("ProductReturned") . ':', $langs->trans("HelpAbandonProductReturned"), - 1);
|
||||
print '</td><td align="right">' . price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye) . '</td><td> </td></tr>';
|
||||
$resteapayeraffiche = 0;
|
||||
}
|
||||
// Paye partiellement ou Abandon 'abandon'
|
||||
if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'abandon') {
|
||||
print '<tr><td colspan="' . $nbcols . '" align="right" nowrap="1">';
|
||||
print '<tr><td colspan="' . $nbcols . '" align="right" class="nowrap">';
|
||||
$text = $langs->trans("HelpAbandonOther");
|
||||
if ($object->close_note)
|
||||
$text .= '<br><br><b>' . $langs->trans("Reason") . '</b>:' . $object->close_note;
|
||||
@@ -3319,7 +3319,7 @@ if ($action == 'create')
|
||||
print $object->situation_counter;
|
||||
|
||||
print '</td>';
|
||||
print '<td align="right" colspan="2" nowrap>';
|
||||
print '<td align="right" colspan="2" class="nowrap">';
|
||||
|
||||
$prevsits_total_amount = 0;
|
||||
foreach ($prevsits as $situation) {
|
||||
@@ -3340,7 +3340,7 @@ if ($action == 'create')
|
||||
print $prevsits[$i]->situation_counter;
|
||||
print '</a></td>';
|
||||
|
||||
print '<td align="right" colspan="2" nowrap>';
|
||||
print '<td align="right" colspan="2" class="nowrap">';
|
||||
print '- ' . price($prevsits[$i]->total_ht);
|
||||
print '</td>';
|
||||
print '<td>' . $langs->trans('Currency' . $conf->currency) . '</td></tr>';
|
||||
@@ -3350,20 +3350,20 @@ if ($action == 'create')
|
||||
|
||||
// Amount
|
||||
print '<tr><td>' . $langs->trans('AmountHT') . '</td>';
|
||||
print '<td colspan="3" nowrap>' . price($object->total_ht, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>';
|
||||
print '<tr><td>' . $langs->trans('AmountVAT') . '</td><td colspan="3" nowrap>' . price($object->total_tva, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>';
|
||||
print '<td colspan="3" class="nowrap">' . price($object->total_ht, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>';
|
||||
print '<tr><td>' . $langs->trans('AmountVAT') . '</td><td colspan="3" class="nowrap">' . price($object->total_tva, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>';
|
||||
print '</tr>';
|
||||
|
||||
// Amount Local Taxes
|
||||
if (($mysoc->localtax1_assuj == "1" && $mysoc->useLocalTax(1)) || $object->total_localtax1 != 0) // Localtax1
|
||||
{
|
||||
print '<tr><td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
|
||||
print '<td colspan="3" nowrap>' . price($object->total_localtax1, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>';
|
||||
print '<td colspan="3" class="nowrap">' . price($object->total_localtax1, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>';
|
||||
}
|
||||
if (($mysoc->localtax2_assuj == "1" && $mysoc->useLocalTax(2)) || $object->total_localtax2 != 0) // Localtax2
|
||||
{
|
||||
print '<tr><td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
|
||||
print '<td colspan="3" nowrap>' . price($object->total_localtax2, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>';
|
||||
print '<td colspan="3" class=nowrap">' . price($object->total_localtax2, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>';
|
||||
}
|
||||
|
||||
// Revenue stamp
|
||||
|
||||
297
htdocs/compta/facture/class/api_invoice.class.php
Normal file
297
htdocs/compta/facture/class/api_invoice.class.php
Normal file
@@ -0,0 +1,297 @@
|
||||
<?php
|
||||
/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
|
||||
|
||||
/**
|
||||
* API class for invoice object
|
||||
*
|
||||
* @smart-auto-routing false
|
||||
* @access protected
|
||||
* @class DolibarrApiAccess {@requires user,external}
|
||||
*
|
||||
*/
|
||||
class InvoiceApi extends DolibarrApi
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var array $FIELDS Mandatory fields, checked when create and update object
|
||||
*/
|
||||
static $FIELDS = array(
|
||||
'socid'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var Facture $invoice {@type Facture}
|
||||
*/
|
||||
public $invoice;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @url GET invoice/
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
global $db, $conf;
|
||||
$this->db = $db;
|
||||
$this->invoice = new Facture($this->db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properties of a invoice object
|
||||
*
|
||||
* Return an array with invoice informations
|
||||
*
|
||||
* @param int $id ID of invoice
|
||||
* @return array|mixed data without useless information
|
||||
*
|
||||
* @url GET invoice/{id}
|
||||
* @throws RestException
|
||||
*/
|
||||
function get($id)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->facture->lire) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$result = $this->invoice->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Facture not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
return $this->_cleanObjectDatas($this->invoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* List invoices
|
||||
*
|
||||
* Get a list of invoices
|
||||
*
|
||||
* @param int $socid Filter list with thirdparty ID
|
||||
* @param string $mode Filter by invoice status : draft | unpaid | paid | cancelled
|
||||
* @param string $sortfield Sort field
|
||||
* @param string $sortorder Sort order
|
||||
* @param int $limit Limit for list
|
||||
* @param int $page Page number
|
||||
*
|
||||
* @return array Array of invoice objects
|
||||
*
|
||||
* @url GET invoice/list
|
||||
* @url GET invoice/list/{mode}
|
||||
* @url GET thirdparty/{socid}/invoice/list
|
||||
* @url GET thirdparty/{socid}/invoice/list/{mode}
|
||||
*/
|
||||
function getList($socid=0, $mode='', $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) {
|
||||
global $db, $conf;
|
||||
|
||||
$obj_ret = array();
|
||||
|
||||
$socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : '';
|
||||
|
||||
// If the internal user must only see his customers, force searching by him
|
||||
if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
|
||||
|
||||
$sql = "SELECT s.rowid";
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."facture as s";
|
||||
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
|
||||
|
||||
$sql.= ' WHERE s.entity IN ('.getEntity('facture', 1).')';
|
||||
if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= " AND s.fk_soc = sc.fk_soc";
|
||||
if ($socid) $sql.= " AND s.fk_soc = ".$socid;
|
||||
if ($search_sale > 0) $sql.= " AND s.rowid = sc.fk_soc"; // Join for the needed table to filter by sale
|
||||
|
||||
|
||||
// Example of use $mode
|
||||
if ($mode == 'draft') $sql.= " AND s.fk_statut IN (0)";
|
||||
if ($mode == 'unpaid') $sql.= " AND s.fk_statut IN (1)";
|
||||
if ($mode == 'paid') $sql.= " AND s.fk_statut IN (2)";
|
||||
if ($mode == 'cancelled') $sql.= " AND s.fk_statut IN (3)";
|
||||
|
||||
// Insert sale filter
|
||||
if ($search_sale > 0)
|
||||
{
|
||||
$sql .= " AND sc.fk_user = ".$search_sale;
|
||||
}
|
||||
|
||||
$nbtotalofrecords = 0;
|
||||
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
|
||||
{
|
||||
$result = $db->query($sql);
|
||||
$nbtotalofrecords = $db->num_rows($result);
|
||||
}
|
||||
|
||||
$sql.= $db->order($sortfield, $sortorder);
|
||||
if ($limit) {
|
||||
if ($page < 0)
|
||||
{
|
||||
$page = 0;
|
||||
}
|
||||
$offset = $limit * $page;
|
||||
|
||||
$sql.= $db->plimit($limit + 1, $offset);
|
||||
}
|
||||
|
||||
$result = $db->query($sql);
|
||||
if ($result)
|
||||
{
|
||||
$num = $db->num_rows($result);
|
||||
while ($i < $num)
|
||||
{
|
||||
$obj = $db->fetch_object($result);
|
||||
$invoice_static = new Facture($db);
|
||||
if($invoice_static->fetch($obj->rowid)) {
|
||||
$obj_ret[] = parent::_cleanObjectDatas($invoice_static);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new RestException(503, 'Error when retrieve invoice list');
|
||||
}
|
||||
if( ! count($obj_ret)) {
|
||||
throw new RestException(404, 'No invoice found');
|
||||
}
|
||||
return $obj_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create invoice object
|
||||
*
|
||||
* @param array $request_data Request datas
|
||||
* @return int ID of invoice
|
||||
*
|
||||
* @url POST invoice/
|
||||
*/
|
||||
function post($request_data = NULL)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->facture->creer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
// Check mandatory fields
|
||||
$result = $this->_validate($request_data);
|
||||
|
||||
foreach($request_data as $field => $value) {
|
||||
$this->invoice->$field = $value;
|
||||
}
|
||||
if(! array_keys($request_data,'date')) {
|
||||
$this->invoice->date = dol_now();
|
||||
}
|
||||
if( ! $this->invoice->create(DolibarrApiAccess::$user)) {
|
||||
throw new RestException(500);
|
||||
}
|
||||
return $this->invoice->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update invoice
|
||||
*
|
||||
* @param int $id Id of invoice to update
|
||||
* @param array $request_data Datas
|
||||
* @return int
|
||||
*
|
||||
* @url PUT invoice/{id}
|
||||
*/
|
||||
function put($id, $request_data = NULL)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->facture->creer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
|
||||
$result = $this->invoice->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Facture not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
foreach($request_data as $field => $value) {
|
||||
$this->invoice->$field = $value;
|
||||
}
|
||||
|
||||
if($this->invoice->update($id, DolibarrApiAccess::$user))
|
||||
return $this->get ($id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete invoice
|
||||
*
|
||||
* @param int $id Invoice ID
|
||||
* @return type
|
||||
*
|
||||
* @url DELETE invoice/{id}
|
||||
*/
|
||||
function delete($id)
|
||||
{
|
||||
if(! DolibarrApiAccess::$user->rights->facture->supprimer) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$result = $this->invoice->fetch($id);
|
||||
if( ! $result ) {
|
||||
throw new RestException(404, 'Facture not found');
|
||||
}
|
||||
|
||||
if( ! DolibarrApi::_checkAccessToResource('facture',$this->facture->id)) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
if( !$this->invoice->delete($id))
|
||||
{
|
||||
throw new RestException(500);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => 'Facture deleted'
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate fields before create or update object
|
||||
*
|
||||
* @param array $data Datas to validate
|
||||
* @return array
|
||||
*
|
||||
* @throws RestException
|
||||
*/
|
||||
function _validate($data)
|
||||
{
|
||||
$invoice = array();
|
||||
foreach (InvoiceApi::$FIELDS as $field) {
|
||||
if (!isset($data[$field]))
|
||||
throw new RestException(400, "$field field missing");
|
||||
$invoice[$field] = $data[$field];
|
||||
}
|
||||
return $invoice;
|
||||
}
|
||||
}
|
||||
@@ -393,16 +393,16 @@ llxHeader('',$title);
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$("#checkall").click(function() {
|
||||
$(".checkformerge").attr('checked', true);
|
||||
$(".checkformerge").prop('checked', true);
|
||||
});
|
||||
$("#checknone").click(function() {
|
||||
$(".checkformerge").attr('checked', false);
|
||||
$(".checkformerge").prop('checked', false);
|
||||
});
|
||||
$("#checkallsend").click(function() {
|
||||
$(".checkforsend").attr('checked', true);
|
||||
$(".checkforsend").prop('checked', true);
|
||||
});
|
||||
$("#checknonesend").click(function() {
|
||||
$(".checkforsend").attr('checked', false);
|
||||
$(".checkforsend").prop('checked', false);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -399,27 +399,27 @@ if ($object->id > 0)
|
||||
|
||||
// Montants
|
||||
print '<tr><td>'.$langs->trans('AmountHT').'</td>';
|
||||
print '<td align="right" colspan="2" nowrap>'.price($object->total_ht).'</td>';
|
||||
print '<td align="right" colspan="2" class="nowrap">'.price($object->total_ht).'</td>';
|
||||
print '<td>'.$langs->trans('Currency'.$conf->currency).'</td></tr>';
|
||||
print '<tr><td>'.$langs->trans('AmountVAT').'</td><td align="right" colspan="2" nowrap>'.price($object->total_tva).'</td>';
|
||||
print '<tr><td>'.$langs->trans('AmountVAT').'</td><td align="right" colspan="2" class="nowrap">'.price($object->total_tva).'</td>';
|
||||
print '<td>'.$langs->trans('Currency'.$conf->currency).'</td></tr>';
|
||||
|
||||
// Amount Local Taxes
|
||||
if ($mysoc->localtax1_assuj=="1") //Localtax1
|
||||
{
|
||||
print '<tr><td>'.$langs->transcountry("AmountLT1",$mysoc->country_code).'</td>';
|
||||
print '<td align="right" colspan="2" nowrap>'.price($object->total_localtax1).'</td>';
|
||||
print '<td align="right" colspan="2" class="nowrap">'.price($object->total_localtax1).'</td>';
|
||||
print '<td>'.$langs->trans("Currency".$conf->currency).'</td></tr>';
|
||||
}
|
||||
if ($mysoc->localtax2_assuj=="1") //Localtax2
|
||||
{
|
||||
print '<tr><td>'.$langs->transcountry("AmountLT2",$mysoc->country_code).'</td>';
|
||||
print '<td align="right" colspan="2" nowrap>'.price($object->total_localtax2).'</td>';
|
||||
print '<td align="right" colspan="2" class="nowrap">'.price($object->total_localtax2).'</td>';
|
||||
print '<td>'.$langs->trans("Currency".$conf->currency).'</td></tr>';
|
||||
}
|
||||
|
||||
|
||||
print '<tr><td>'.$langs->trans('AmountTTC').'</td><td align="right" colspan="2" nowrap>'.price($object->total_ttc).'</td>';
|
||||
print '<tr><td>'.$langs->trans('AmountTTC').'</td><td align="right" colspan="2" class="nowrap">'.price($object->total_ttc).'</td>';
|
||||
print '<td>'.$langs->trans('Currency'.$conf->currency).'</td></tr>';
|
||||
|
||||
// We can also use bcadd to avoid pb with floating points
|
||||
@@ -428,7 +428,7 @@ if ($object->id > 0)
|
||||
//$resteapayer=bcadd($resteapayer,$totalavoir,$conf->global->MAIN_MAX_DECIMALS_TOT);
|
||||
$resteapayer = price2num($object->total_ttc - $totalpaye - $totalcreditnotes - $totaldeposits,'MT');
|
||||
|
||||
print '<tr><td>'.$langs->trans('RemainderToPay').'</td><td align="right" colspan="2" nowrap>'.price($resteapayer).'</td>';
|
||||
print '<tr><td>'.$langs->trans('RemainderToPay').'</td><td align="right" colspan="2" class="nowrap">'.price($resteapayer).'</td>';
|
||||
print '<td>'.$langs->trans('Currency'.$conf->currency).'</td></tr>';
|
||||
|
||||
// Statut
|
||||
|
||||
@@ -86,7 +86,7 @@ function pt ($db, $sql, $date)
|
||||
|
||||
$i++;
|
||||
}
|
||||
print '<tr class="liste_total"><td align="right">'.$langs->trans("Total")." :</td><td nowrap=\"nowrap\" align=\"right\"><b>".price($total)."</b></td><td> </td></tr>";
|
||||
print '<tr class="liste_total"><td align="right">'.$langs->trans("Total")." :</td><td class=\"nowrap\" align=\"right\"><b>".price($total)."</b></td><td> </td></tr>";
|
||||
|
||||
print "</table>";
|
||||
$db->free($result);
|
||||
@@ -253,7 +253,7 @@ for ($m = 1 ; $m < 13 ; $m++ ) {
|
||||
$subtotalcoll=0; $subtotalpaye=0; $subtotal=0;
|
||||
}
|
||||
}
|
||||
print '<tr class="liste_total"><td align="right" colspan="3">'.$langs->trans("TotalToPay").':</td><td nowrap align="right">'.price($total).'</td>';
|
||||
print '<tr class="liste_total"><td align="right" colspan="3">'.$langs->trans("TotalToPay").':</td><td class="nowrap" align="right">'.price($total).'</td>';
|
||||
print "<td> </td>\n";
|
||||
print '</tr>';
|
||||
|
||||
|
||||
@@ -414,11 +414,11 @@ if ($action == 'new')
|
||||
{
|
||||
jQuery("#checkall_'.$bid.'").click(function()
|
||||
{
|
||||
jQuery(".checkforremise_'.$bid.'").attr(\'checked\', true);
|
||||
jQuery(".checkforremise_'.$bid.'").prop(\'checked\', true);
|
||||
});
|
||||
jQuery("#checknone_'.$bid.'").click(function()
|
||||
{
|
||||
jQuery(".checkforremise_'.$bid.'").attr(\'checked\', false);
|
||||
jQuery(".checkforremise_'.$bid.'").prop(\'checked\', false);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -93,7 +93,7 @@ function pt ($db, $sql, $date)
|
||||
|
||||
$i++;
|
||||
}
|
||||
print '<tr class="liste_total"><td align="right">'.$langs->trans("Total")." :</td><td nowrap=\"nowrap\" align=\"right\"><b>".price($total)."</b></td><td> </td></tr>";
|
||||
print '<tr class="liste_total"><td align="right">'.$langs->trans("Total")." :</td><td class=\"nowrap\" align=\"right\"><b>".price($total)."</b></td><td> </td></tr>";
|
||||
|
||||
print "</table>";
|
||||
$db->free($result);
|
||||
@@ -216,7 +216,7 @@ for ($m = 1 ; $m < 13 ; $m++ )
|
||||
$subtotalcoll=0; $subtotalpaye=0; $subtotal=0;
|
||||
}
|
||||
}
|
||||
print '<tr class="liste_total"><td align="right" colspan="3">'.$langs->trans("TotalToPay").':</td><td nowrap align="right">'.price($total).'</td>';
|
||||
print '<tr class="liste_total"><td align="right" colspan="3">'.$langs->trans("TotalToPay").':</td><td class="nowrap" align="right">'.price($total).'</td>';
|
||||
print "<td> </td>\n";
|
||||
print '</tr>';
|
||||
|
||||
|
||||
@@ -437,7 +437,7 @@ if ($result)
|
||||
|
||||
print '</form>';
|
||||
|
||||
if ($num > $limit) print_barre_liste('', $page, $_SERVER["PHP_SELF"], '&begin='.$begin.'&view='.$view.'&userid='.$userid, $sortfield, $sortorder, '', $num, $nbtotalofrecords, '');
|
||||
if ($num > $limit) print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, '');
|
||||
|
||||
$db->free($result);
|
||||
}
|
||||
|
||||
@@ -1021,12 +1021,12 @@ if ($action == 'create')
|
||||
}
|
||||
|
||||
// Commercial suivi
|
||||
print '<tr><td width="20%" nowrap><span class="fieldrequired">'.$langs->trans("TypeContact_contrat_internal_SALESREPFOLL").'</span></td><td>';
|
||||
print '<tr><td width="20%" class="nowrap"><span class="fieldrequired">'.$langs->trans("TypeContact_contrat_internal_SALESREPFOLL").'</span></td><td>';
|
||||
print $form->select_dolusers(GETPOST("commercial_suivi_id")?GETPOST("commercial_suivi_id"):$user->id,'commercial_suivi_id',1,'');
|
||||
print '</td></tr>';
|
||||
|
||||
// Commercial signature
|
||||
print '<tr><td width="20%" nowrap><span class="fieldrequired">'.$langs->trans("TypeContact_contrat_internal_SALESREPSIGN").'</span></td><td>';
|
||||
print '<tr><td width="20%" class="nowrap"><span class="fieldrequired">'.$langs->trans("TypeContact_contrat_internal_SALESREPSIGN").'</span></td><td>';
|
||||
print $form->select_dolusers(GETPOST("commercial_signature_id")?GETPOST("commercial_signature_id"):$user->id,'commercial_signature_id',1,'');
|
||||
print '</td></tr>';
|
||||
|
||||
|
||||
@@ -1124,7 +1124,7 @@ class ExtraFields
|
||||
if (!empty($value)) {
|
||||
$checked=' checked ';
|
||||
}
|
||||
$value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly="readonly" disabled>';
|
||||
$value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
|
||||
}
|
||||
elseif ($type == 'mail')
|
||||
{
|
||||
|
||||
@@ -4356,7 +4356,7 @@ class Form
|
||||
</script>';
|
||||
}
|
||||
|
||||
$out.='<select id="'.preg_replace('/^\./','',$htmlname).'" '.($disabled?'disabled="disabled" ':'').'class="flat '.(preg_replace('/^\./','',$htmlname)).($morecss?' '.$morecss:'').'" name="'.preg_replace('/^\./','',$htmlname).'" '.($moreparam?$moreparam:'').'>';
|
||||
$out.='<select id="'.preg_replace('/^\./','',$htmlname).'" '.($disabled?'disabled ':'').'class="flat '.(preg_replace('/^\./','',$htmlname)).($morecss?' '.$morecss:'').'" name="'.preg_replace('/^\./','',$htmlname).'" '.($moreparam?$moreparam:'').'>';
|
||||
|
||||
if ($show_empty)
|
||||
{
|
||||
@@ -4539,7 +4539,7 @@ class Form
|
||||
// Try also magic suggest
|
||||
|
||||
// Add data-role="none" to disable jmobile decoration
|
||||
$out = '<select data-role="none" id="'.$htmlname.'" class="multiselect'.($morecss?' '.$morecss:'').'" multiple="multiple" name="'.$htmlname.'[]"'.($moreattrib?' '.$moreattrib:'').($width?' style="width: '.(preg_match('/%/',$width)?$width:$width.'px').'"':'').'>'."\n";
|
||||
$out = '<select data-role="none" id="'.$htmlname.'" class="multiselect'.($morecss?' '.$morecss:'').'" multiple name="'.$htmlname.'[]"'.($moreattrib?' '.$moreattrib:'').($width?' style="width: '.(preg_match('/%/',$width)?$width:$width.'px').'"':'').'>'."\n";
|
||||
if (is_array($array) && ! empty($array))
|
||||
{
|
||||
if ($value_as_key) $array=array_combine($array, $array);
|
||||
|
||||
@@ -95,17 +95,17 @@ class FormActions
|
||||
percentage.val(value);
|
||||
|
||||
if (defaultvalue == -1) {
|
||||
percentage.attr('disabled', 'disabled');
|
||||
percentage.prop('disabled', true);
|
||||
$('.hideifna').hide();
|
||||
}
|
||||
else if (defaultvalue == 0) {
|
||||
percentage.val(0);
|
||||
percentage.attr('disabled', 'disabled');
|
||||
percentage.prop('disabled', true);
|
||||
$('.hideifna').show();
|
||||
}
|
||||
else if (defaultvalue == 100) {
|
||||
percentage.val(100);
|
||||
percentage.attr('disabled', 'disabled');
|
||||
percentage.prop('disabled', true);
|
||||
$('.hideifna').show();
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
* Copyright (C) 2013 Charles-Fr BENKE <charles.fr@benke.fr>
|
||||
* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
|
||||
* Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
|
||||
*
|
||||
* Copyright (C) 2015 Bahfir Abbes <bafbes@gmail.com>
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||
* Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
|
||||
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
|
||||
* Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||
* Copyright (C) 2014-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to manage Dolibarr database access for a Mysql database
|
||||
* Class to manage Dolibarr database access for an SQL database
|
||||
*/
|
||||
interface Database
|
||||
{
|
||||
@@ -111,13 +111,6 @@ interface Database
|
||||
*/
|
||||
function error();
|
||||
|
||||
/**
|
||||
* Return label of manager
|
||||
*
|
||||
* @return string Label
|
||||
*/
|
||||
function getLabel();
|
||||
|
||||
/**
|
||||
* List tables into a database
|
||||
*
|
||||
@@ -141,7 +134,7 @@ interface Database
|
||||
* @param string $sortorder Sort order
|
||||
* @return string String to provide syntax of a sort sql string
|
||||
*/
|
||||
function order($sortfield = 0, $sortorder = 0);
|
||||
function order($sortfield = null, $sortorder = null);
|
||||
|
||||
/**
|
||||
* Decrypt sensitive data in database
|
||||
@@ -216,7 +209,7 @@ interface Database
|
||||
* @param string $login login
|
||||
* @param string $passwd password
|
||||
* @param string $name name of database (not used for mysql, used for pgsql)
|
||||
* @param string $port Port of database server
|
||||
* @param int $port Port of database server
|
||||
* @return resource Database access handler
|
||||
* @see close
|
||||
*/
|
||||
@@ -293,10 +286,10 @@ interface Database
|
||||
* @param string $type Type de la table
|
||||
* @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
|
||||
* @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
|
||||
* @param string $keys Tableau des champs cles noms => valeur
|
||||
* @param array $keys Tableau des champs cles noms => valeur
|
||||
* @return int <0 if KO, >=0 if OK
|
||||
*/
|
||||
function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = "", $fulltext_keys = "", $keys = "");
|
||||
function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null);
|
||||
|
||||
/**
|
||||
* Return list of available charset that can be used to store data in database
|
||||
@@ -382,15 +375,15 @@ interface Database
|
||||
);
|
||||
|
||||
/**
|
||||
* Convert (by PHP) a PHP server TZ string date into a Timestamps date (GMT if gm=true)
|
||||
* 19700101020000 -> 3600 with TZ+1 and gmt=0
|
||||
* 19700101020000 -> 7200 whaterver is TZ if gmt=1
|
||||
*
|
||||
* Convert (by PHP) a PHP server TZ string date into a Timestamps date (GMT if gm=true)
|
||||
* 19700101020000 -> 3600 with TZ+1 and gmt=0
|
||||
* 19700101020000 -> 7200 whaterver is TZ if gmt=1
|
||||
*
|
||||
* @param string $string Date in a string (YYYYMMDDHHMMSS, YYYYMMDD, YYYY-MM-DD HH:MM:SS)
|
||||
* @param int $gm 1=Input informations are GMT values, otherwise local to server TZ
|
||||
* @param bool $gm 1=Input informations are GMT values, otherwise local to server TZ
|
||||
* @return int|string Date TMS or ''
|
||||
*/
|
||||
function jdate($string, $gm=false);
|
||||
*/
|
||||
function jdate($string, $gm=false);
|
||||
|
||||
/**
|
||||
* Encrypt sensitive data in database
|
||||
@@ -424,7 +417,7 @@ interface Database
|
||||
* @param resource $resultset Fre cursor
|
||||
* @return void
|
||||
*/
|
||||
function free($resultset = 0);
|
||||
function free($resultset = null);
|
||||
|
||||
/**
|
||||
* Close database connexion
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2013-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||
* Copyright (C) 2013-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||
* Copyright (C) 2014-2015 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -29,41 +29,43 @@ require_once DOL_DOCUMENT_ROOT .'/core/db/Database.interface.php';
|
||||
*/
|
||||
abstract class DoliDB implements Database
|
||||
{
|
||||
//! Database handler
|
||||
public $db;
|
||||
//! Database type
|
||||
public $type;
|
||||
//! Charset used to force charset when creating database
|
||||
public $forcecharset='utf8';
|
||||
//! Collate used to force collate when creating database
|
||||
public $forcecollate='utf8_general_ci';
|
||||
//! Resultset of last query
|
||||
private $_results;
|
||||
//! 1 if connected, else 0
|
||||
public $connected;
|
||||
//! 1 if database selected, else 0
|
||||
public $database_selected;
|
||||
//! Selected database name
|
||||
public $database_name;
|
||||
//! Database username
|
||||
public $database_user;
|
||||
//! Database host
|
||||
public $database_host;
|
||||
//! Database port
|
||||
public $database_port;
|
||||
//! >=1 if a transaction is opened, 0 otherwise
|
||||
public $transaction_opened;
|
||||
//! Last successful query
|
||||
public $lastquery;
|
||||
//! Last failed query
|
||||
public $lastqueryerror;
|
||||
//! Last error message
|
||||
public $lasterror;
|
||||
//! Last error number
|
||||
public $lasterrno;
|
||||
/** @var resource Database handler */
|
||||
public $db;
|
||||
/** @var string Database type */
|
||||
public $type;
|
||||
/** @var string Charset used to force charset when creating database */
|
||||
public $forcecharset='utf8';
|
||||
/** @var string Collate used to force collate when creating database */
|
||||
public $forcecollate='utf8_general_ci';
|
||||
/** @var resource Resultset of last query */
|
||||
private $_results;
|
||||
/** @var bool true if connected, else false */
|
||||
public $connected;
|
||||
/** @var bool true if database selected, else false */
|
||||
public $database_selected;
|
||||
/** @var string Selected database name */
|
||||
public $database_name;
|
||||
/** @var string Database username */
|
||||
public $database_user;
|
||||
/** @var string Database host */
|
||||
public $database_host;
|
||||
/** @var int Database port */
|
||||
public $database_port;
|
||||
/** @var int >=1 if a transaction is opened, 0 otherwise */
|
||||
public $transaction_opened;
|
||||
/** @var string Last successful query */
|
||||
public $lastquery;
|
||||
/** @ar string Last failed query */
|
||||
public $lastqueryerror;
|
||||
/** @var string Last error message */
|
||||
public $lasterror;
|
||||
/** @var int Last error number */
|
||||
public $lasterrno;
|
||||
|
||||
public $ok;
|
||||
public $error;
|
||||
/** @var bool Status */
|
||||
public $ok;
|
||||
/** @var string */
|
||||
public $error;
|
||||
|
||||
/**
|
||||
* Format a SQL IF
|
||||
@@ -205,16 +207,6 @@ abstract class DoliDB implements Database
|
||||
return preg_split("/[\.,-]/",$this->getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return label of manager
|
||||
*
|
||||
* @return string Label
|
||||
*/
|
||||
function getLabel()
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last request executed with query()
|
||||
*
|
||||
@@ -232,9 +224,9 @@ abstract class DoliDB implements Database
|
||||
* @param string $sortorder Sort order
|
||||
* @return string String to provide syntax of a sort sql string
|
||||
*/
|
||||
function order($sortfield=0,$sortorder=0)
|
||||
function order($sortfield=null,$sortorder=null)
|
||||
{
|
||||
if ($sortfield)
|
||||
if (isset($sortfield))
|
||||
{
|
||||
$return='';
|
||||
$fields=explode(',',$sortfield);
|
||||
@@ -244,7 +236,9 @@ abstract class DoliDB implements Database
|
||||
else $return.=',';
|
||||
|
||||
$return.=preg_replace('/[^0-9a-z_\.]/i','',$val);
|
||||
if ($sortorder) $return.=' '.preg_replace('/[^0-9a-z]/i','',$sortorder);
|
||||
if (isset($sortorder)) {
|
||||
$return.=' '.preg_replace('/[^0-9a-z]/i','',$sortorder);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
@@ -270,7 +264,7 @@ abstract class DoliDB implements Database
|
||||
* 19700101020000 -> 7200 whaterver is TZ if gmt=1
|
||||
*
|
||||
* @param string $string Date in a string (YYYYMMDDHHMMSS, YYYYMMDD, YYYY-MM-DD HH:MM:SS)
|
||||
* @param int $gm 1=Input informations are GMT values, otherwise local to server TZ
|
||||
* @param bool $gm 1=Input informations are GMT values, otherwise local to server TZ
|
||||
* @return int|string Date TMS or ''
|
||||
*/
|
||||
function jdate($string, $gm=false)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
/**
|
||||
* \file htdocs/core/db/mssql.class.php
|
||||
* \brief Fichier de la classe permettant de gerer une base mssql
|
||||
* \brief Fichier de la classe permettant de gerer une base MSSQL
|
||||
*/
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT .'/core/db/DoliDB.class.php';
|
||||
@@ -41,7 +41,7 @@ class DoliDBMssql extends DoliDB
|
||||
var $forcecollate='latin1_swedish_ci'; // Can't be static as it may be forced with a dynamic value
|
||||
//! Version min database
|
||||
const VERSIONMIN='2000';
|
||||
//! Resultset of last query
|
||||
/** @var resource Resultset of last query */
|
||||
private $_results;
|
||||
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ class DoliDBMssql extends DoliDB
|
||||
*/
|
||||
function __construct($type, $host, $user, $pass, $name='', $port=0)
|
||||
{
|
||||
global $conf,$langs;
|
||||
global $langs;
|
||||
|
||||
$this->database_user=$user;
|
||||
$this->database_host=$host;
|
||||
@@ -66,8 +66,8 @@ class DoliDBMssql extends DoliDB
|
||||
|
||||
if (! function_exists("mssql_connect"))
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error="Mssql PHP functions for using MSSql driver are not available in this version of PHP";
|
||||
dol_syslog(get_class($this)."::DoliDBMssql : MSsql PHP functions for using MSsql driver are not available in this version of PHP",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -75,8 +75,8 @@ class DoliDBMssql extends DoliDB
|
||||
|
||||
if (! $host)
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=$langs->trans("ErrorWrongHostParameter");
|
||||
dol_syslog(get_class($this)."::DoliDBMssql : Erreur Connect, wrong host parameters",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -88,14 +88,14 @@ class DoliDBMssql extends DoliDB
|
||||
{
|
||||
// Si client connecte avec charset different de celui de la base Dolibarr
|
||||
// (La base Dolibarr a ete forcee en this->forcecharset a l'install)
|
||||
$this->connected = 1;
|
||||
$this->ok = 1;
|
||||
$this->connected = true;
|
||||
$this->ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// host, login ou password incorrect
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=mssql_get_last_message();
|
||||
dol_syslog(get_class($this)."::DoliDBMssql : Erreur Connect mssql_get_last_message=".$this->error,LOG_ERR);
|
||||
}
|
||||
@@ -105,15 +105,15 @@ class DoliDBMssql extends DoliDB
|
||||
{
|
||||
if ($this->select_db($name))
|
||||
{
|
||||
$this->database_selected = 1;
|
||||
$this->database_selected = true;
|
||||
$this->database_name = $name;
|
||||
$this->ok = 1;
|
||||
$this->ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->database_selected = 0;
|
||||
$this->database_selected = false;
|
||||
$this->database_name = '';
|
||||
$this->ok = 0;
|
||||
$this->ok = false;
|
||||
$this->error=$this->error();
|
||||
dol_syslog(get_class($this)."::DoliDBMssql : Erreur Select_db ".$this->error,LOG_ERR);
|
||||
}
|
||||
@@ -121,7 +121,7 @@ class DoliDBMssql extends DoliDB
|
||||
else
|
||||
{
|
||||
// Pas de selection de base demandee, ok ou ko
|
||||
$this->database_selected = 0;
|
||||
$this->database_selected = false;
|
||||
}
|
||||
|
||||
return $this->ok;
|
||||
@@ -157,8 +157,8 @@ class DoliDBMssql extends DoliDB
|
||||
* @param string $login login
|
||||
* @param string $passwd password
|
||||
* @param string $name name of database (not used for mysql, used for pgsql)
|
||||
* @param string $port Port of database server
|
||||
* @return resource Database access handler
|
||||
* @param int $port Port of database server
|
||||
* @return false|resource|true Database access handler
|
||||
* @see close
|
||||
*/
|
||||
function connect($host, $login, $passwd, $name, $port=0)
|
||||
@@ -212,7 +212,7 @@ class DoliDBMssql extends DoliDB
|
||||
/**
|
||||
* Close database connexion
|
||||
*
|
||||
* @return boolean True if disconnect successfull, false otherwise
|
||||
* @return bool True if disconnect successfull, false otherwise
|
||||
* @see connect
|
||||
*/
|
||||
function close()
|
||||
@@ -220,7 +220,7 @@ class DoliDBMssql extends DoliDB
|
||||
if ($this->db)
|
||||
{
|
||||
if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR);
|
||||
$this->connected=0;
|
||||
$this->connected=false;
|
||||
return mssql_close($this->db);
|
||||
}
|
||||
return false;
|
||||
@@ -230,7 +230,7 @@ class DoliDBMssql extends DoliDB
|
||||
/**
|
||||
* Start transaction
|
||||
*
|
||||
* @return int 1 if transaction successfuly opened or already opened, 0 if error
|
||||
* @return bool true if transaction successfuly opened or already opened, false if error
|
||||
*/
|
||||
function begin()
|
||||
{
|
||||
@@ -250,7 +250,7 @@ class DoliDBMssql extends DoliDB
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ class DoliDBMssql extends DoliDB
|
||||
* Validate a database transaction
|
||||
*
|
||||
* @param string $log Add more log to default log line
|
||||
* @return int 1 if validation is OK or transaction level no started, 0 if ERROR
|
||||
* @return bool true if validation is OK or transaction level no started, false if ERROR
|
||||
*/
|
||||
function commit($log='')
|
||||
{
|
||||
@@ -272,25 +272,26 @@ class DoliDBMssql extends DoliDB
|
||||
if ($ret)
|
||||
{
|
||||
dol_syslog("COMMIT Transaction",LOG_DEBUG);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif ($this->transaction_opened > 1)
|
||||
{
|
||||
return 1;
|
||||
} else
|
||||
trigger_error("Commit requested but no transaction remain");
|
||||
return true;
|
||||
}
|
||||
trigger_error("Commit requested but no transaction remain");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annulation d'une transaction et retour aux anciennes valeurs
|
||||
*
|
||||
* @param string $log Add more log to default log line
|
||||
* @return int 1 si annulation ok ou transaction non ouverte, 0 en cas d'erreur
|
||||
* @return bool true si annulation ok ou transaction non ouverte, false en cas d'erreur
|
||||
*/
|
||||
function rollback($log='')
|
||||
{
|
||||
@@ -305,9 +306,10 @@ class DoliDBMssql extends DoliDB
|
||||
}
|
||||
elseif ($this->transaction_opened > 1)
|
||||
{
|
||||
return 1;
|
||||
} else
|
||||
trigger_error("Rollback requested but no transaction remain");
|
||||
return true;
|
||||
}
|
||||
trigger_error("Rollback requested but no transaction remain");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,7 +319,7 @@ class DoliDBMssql extends DoliDB
|
||||
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
|
||||
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
|
||||
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
|
||||
* @return resource Resultset of answer
|
||||
* @return false|resource|true Resultset of answer
|
||||
*/
|
||||
function query($query,$usesavepoint=0,$type='auto')
|
||||
{
|
||||
@@ -459,8 +461,8 @@ class DoliDBMssql extends DoliDB
|
||||
/**
|
||||
* Renvoie la ligne courante (comme un objet) pour le curseur resultset
|
||||
*
|
||||
* @param Resultset $resultset Curseur de la requete voulue
|
||||
* @return Object Object result line or false if KO or end of cursor
|
||||
* @param resource $resultset Curseur de la requete voulue
|
||||
* @return object|false Object result line or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_object($resultset)
|
||||
{
|
||||
@@ -472,8 +474,8 @@ class DoliDBMssql extends DoliDB
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param Resultset $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @param resource $resultset Resultset of request
|
||||
* @return array|false Array or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_array($resultset)
|
||||
{
|
||||
@@ -486,8 +488,8 @@ class DoliDBMssql extends DoliDB
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param Resultset $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @param resource $resultset Resultset of request
|
||||
* @return array|false Array or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_row($resultset)
|
||||
{
|
||||
@@ -499,7 +501,7 @@ class DoliDBMssql extends DoliDB
|
||||
/**
|
||||
* Return number of lines for result of a SELECT
|
||||
*
|
||||
* @param Resultset $resultset Resulset of requests
|
||||
* @param resource $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @see affected_rows
|
||||
*/
|
||||
@@ -513,7 +515,7 @@ class DoliDBMssql extends DoliDB
|
||||
/**
|
||||
* Renvoie le nombre de lignes dans le resultat d'une requete INSERT, DELETE ou UPDATE
|
||||
*
|
||||
* @param resultset $resultset Curseur de la requete voulue
|
||||
* @param resource $resultset Curseur de la requete voulue
|
||||
* @return int Nombre de lignes
|
||||
* @see num_rows
|
||||
*/
|
||||
@@ -532,10 +534,10 @@ class DoliDBMssql extends DoliDB
|
||||
/**
|
||||
* Free last resultset used.
|
||||
*
|
||||
* @param resultset $resultset Curseur de la requete voulue
|
||||
* @return void
|
||||
* @param resource $resultset Curseur de la requete voulue
|
||||
* @return bool
|
||||
*/
|
||||
function free($resultset=0)
|
||||
function free($resultset=null)
|
||||
{
|
||||
// Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
|
||||
if (! is_resource($resultset)) { $resultset=$this->_results; }
|
||||
@@ -641,7 +643,7 @@ class DoliDBMssql extends DoliDB
|
||||
*
|
||||
* @param string $tab Table name concerned by insert. Ne sert pas sous MySql mais requis pour compatibilite avec Postgresql
|
||||
* @param string $fieldid Field name
|
||||
* @return int Id of row
|
||||
* @return int Id of row or -1 on error
|
||||
*/
|
||||
function last_insert_id($tab,$fieldid='rowid')
|
||||
{
|
||||
@@ -662,7 +664,7 @@ class DoliDBMssql extends DoliDB
|
||||
*
|
||||
* @param string $fieldorvalue Field name or value to encrypt
|
||||
* @param int $withQuotes Return string with quotes
|
||||
* @return return XXX(field) or XXX('value') or field or 'value'
|
||||
* @return string XXX(field) or XXX('value') or field or 'value'
|
||||
*/
|
||||
function encrypt($fieldorvalue, $withQuotes=0)
|
||||
{
|
||||
@@ -720,7 +722,7 @@ class DoliDBMssql extends DoliDB
|
||||
* @param string $charset Charset used to store data
|
||||
* @param string $collation Charset used to sort data
|
||||
* @param string $owner Username of database owner
|
||||
* @return resource resource defined if OK, null if KO
|
||||
* @return false|resource|true resource defined if OK, false if KO
|
||||
*/
|
||||
function DDLCreateDb($database,$charset='',$collation='',$owner='')
|
||||
{
|
||||
@@ -786,11 +788,13 @@ class DoliDBMssql extends DoliDB
|
||||
* @param string $type Type de la table
|
||||
* @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
|
||||
* @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
|
||||
* @param string $keys Tableau des champs cles noms => valeur
|
||||
* @param array $keys Tableau des champs cles noms => valeur
|
||||
* @return int <0 if KO, >=0 if OK
|
||||
*/
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys="",$fulltext_keys="",$keys="")
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys=null,$fulltext_keys=null,$keys=null)
|
||||
{
|
||||
// FIXME: $fulltext_keys parameter is unused
|
||||
|
||||
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
|
||||
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
|
||||
$sql = "create table ".$table."(";
|
||||
@@ -820,7 +824,7 @@ class DoliDBMssql extends DoliDB
|
||||
if($primary_key != "")
|
||||
$pk = "primary key(".$primary_key.")";
|
||||
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($unique_keys as $key => $value)
|
||||
@@ -829,7 +833,7 @@ class DoliDBMssql extends DoliDB
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($keys as $key => $value)
|
||||
@@ -841,9 +845,9 @@ class DoliDBMssql extends DoliDB
|
||||
$sql .= implode(',',$sqlfields);
|
||||
if($primary_key != "")
|
||||
$sql .= ",".$pk;
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
$sql .= ",".implode(',',$sqluq);
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
$sql .= ",".implode(',',$sqlk);
|
||||
$sql .=") type=".$type;
|
||||
|
||||
@@ -859,7 +863,7 @@ class DoliDBMssql extends DoliDB
|
||||
*
|
||||
* @param string $table Name of table
|
||||
* @param string $field Optionnel : Name of field if we want description of field
|
||||
* @return resource Resource
|
||||
* @return false|resource|true Resource
|
||||
*/
|
||||
function DDLDescTable($table,$field="")
|
||||
{
|
||||
@@ -1047,7 +1051,7 @@ class DoliDBMssql extends DoliDB
|
||||
// FIXME: Dummy method
|
||||
// TODO: Implement
|
||||
|
||||
return '';
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1123,7 +1127,7 @@ class DoliDBMssql extends DoliDB
|
||||
*
|
||||
* @param string $table Table name which contains fields
|
||||
* @param mixed $fields String for one field or array of string for multiple field
|
||||
* @return boolean|multitype:object
|
||||
* @return false|object
|
||||
*/
|
||||
function GetFieldInformation($table,$fields) {
|
||||
$sql="SELECT * from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='".$this->escape($table)."' AND COLUMN_NAME";
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
|
||||
/**
|
||||
* \file htdocs/core/db/mysql.class.php
|
||||
* \brief Class file to manage Dolibarr database access for a Mysql database
|
||||
* \brief Class file to manage Dolibarr database access for a MySQL database
|
||||
*/
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT .'/core/db/DoliDB.class.php';
|
||||
|
||||
/**
|
||||
* Class to manage Dolibarr database access for a Mysql database
|
||||
* Class to manage Dolibarr database access for a MySQL database using the mysql extension
|
||||
*/
|
||||
class DoliDBMysql extends DoliDB
|
||||
{
|
||||
@@ -37,7 +37,7 @@ class DoliDBMysql extends DoliDB
|
||||
const LABEL='MySQL';
|
||||
//! Version min database
|
||||
const VERSIONMIN='4.1.0';
|
||||
//! Resultset of last query
|
||||
/** @var resource Resultset of last query */
|
||||
private $_results;
|
||||
|
||||
/**
|
||||
@@ -69,8 +69,8 @@ class DoliDBMysql extends DoliDB
|
||||
|
||||
if (! function_exists("mysql_connect"))
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error="Mysql PHP functions for using MySql driver are not available in this version of PHP. Try to use another driver.";
|
||||
dol_syslog(get_class($this)."::DoliDBMysql : Mysql PHP functions for using Mysql driver are not available in this version of PHP. Try to use another driver.",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -78,8 +78,8 @@ class DoliDBMysql extends DoliDB
|
||||
|
||||
if (! $host)
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=$langs->trans("ErrorWrongHostParameter");
|
||||
dol_syslog(get_class($this)."::DoliDBMysql : Erreur Connect, wrong host parameters",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -89,14 +89,14 @@ class DoliDBMysql extends DoliDB
|
||||
$this->db = $this->connect($host, $user, $pass, $name, $port);
|
||||
if ($this->db)
|
||||
{
|
||||
$this->connected = 1;
|
||||
$this->ok = 1;
|
||||
$this->connected = true;
|
||||
$this->ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// host, login ou password incorrect
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=mysql_error();
|
||||
dol_syslog(get_class($this)."::DoliDBMysql : Erreur Connect mysql_error=".$this->error,LOG_ERR);
|
||||
}
|
||||
@@ -106,9 +106,9 @@ class DoliDBMysql extends DoliDB
|
||||
{
|
||||
if ($this->select_db($name))
|
||||
{
|
||||
$this->database_selected = 1;
|
||||
$this->database_selected = true;
|
||||
$this->database_name = $name;
|
||||
$this->ok = 1;
|
||||
$this->ok = true;
|
||||
|
||||
// If client connected with different charset than Dolibarr HTML output
|
||||
$clientmustbe='';
|
||||
@@ -122,9 +122,9 @@ class DoliDBMysql extends DoliDB
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->database_selected = 0;
|
||||
$this->database_selected = false;
|
||||
$this->database_name = '';
|
||||
$this->ok = 0;
|
||||
$this->ok = false;
|
||||
$this->error=$this->error();
|
||||
dol_syslog(get_class($this)."::DoliDBMysql : Erreur Select_db ".$this->error,LOG_ERR);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ class DoliDBMysql extends DoliDB
|
||||
else
|
||||
{
|
||||
// Pas de selection de base demandee, ok ou ko
|
||||
$this->database_selected = 0;
|
||||
$this->database_selected = false;
|
||||
|
||||
if ($this->connected)
|
||||
{
|
||||
@@ -177,14 +177,14 @@ class DoliDBMysql extends DoliDB
|
||||
}
|
||||
|
||||
/**
|
||||
* Connexion to server
|
||||
* Connection to server
|
||||
*
|
||||
* @param string $host database server host
|
||||
* @param string $login login
|
||||
* @param string $passwd password
|
||||
* @param string $name name of database (not used for mysql, used for pgsql)
|
||||
* @param integer $port Port of database server
|
||||
* @return resource Database access handler
|
||||
* @return resource|false Database access handler
|
||||
* @see close
|
||||
*/
|
||||
function connect($host, $login, $passwd, $name, $port=0)
|
||||
@@ -219,7 +219,7 @@ class DoliDBMysql extends DoliDB
|
||||
*/
|
||||
function getDriverInfo()
|
||||
{
|
||||
return mysqli_get_client_info();
|
||||
return mysql_get_client_info();
|
||||
}
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ class DoliDBMysql extends DoliDB
|
||||
if ($this->db)
|
||||
{
|
||||
if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR);
|
||||
$this->connected=0;
|
||||
$this->connected=false;
|
||||
return mysql_close($this->db);
|
||||
}
|
||||
return false;
|
||||
@@ -247,7 +247,7 @@ class DoliDBMysql extends DoliDB
|
||||
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
|
||||
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
|
||||
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
|
||||
* @return resource Resultset of answer
|
||||
* @return resource|true|false Resultset of answer
|
||||
*/
|
||||
function query($query,$usesavepoint=0,$type='auto')
|
||||
{
|
||||
@@ -287,8 +287,8 @@ class DoliDBMysql extends DoliDB
|
||||
/**
|
||||
* Renvoie la ligne courante (comme un objet) pour le curseur resultset
|
||||
*
|
||||
* @param Resultset $resultset Curseur de la requete voulue
|
||||
* @return Object Object result line or false if KO or end of cursor
|
||||
* @param resource $resultset Curseur de la requete voulue
|
||||
* @return resource|false Object result line or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_object($resultset)
|
||||
{
|
||||
@@ -300,7 +300,7 @@ class DoliDBMysql extends DoliDB
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param Resultset $resultset Resultset of request
|
||||
* @param resource $resultset Resultset of request
|
||||
* @return array Array
|
||||
*/
|
||||
function fetch_array($resultset)
|
||||
@@ -327,7 +327,7 @@ class DoliDBMysql extends DoliDB
|
||||
/**
|
||||
* Return number of lines for result of a SELECT
|
||||
*
|
||||
* @param Resultset $resultset Resulset of requests
|
||||
* @param resource $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @see affected_rows
|
||||
*/
|
||||
@@ -341,7 +341,7 @@ class DoliDBMysql extends DoliDB
|
||||
/**
|
||||
* Renvoie le nombre de lignes dans le resultat d'une requete INSERT, DELETE ou UPDATE
|
||||
*
|
||||
* @param resultset $resultset Curseur de la requete voulue
|
||||
* @param resource $resultset Curseur de la requete voulue
|
||||
* @return int Nombre de lignes
|
||||
* @see num_rows
|
||||
*/
|
||||
@@ -358,10 +358,10 @@ class DoliDBMysql extends DoliDB
|
||||
/**
|
||||
* Free last resultset used.
|
||||
*
|
||||
* @param resultset $resultset Curseur de la requete voulue
|
||||
* @param resource $resultset Curseur de la requete voulue
|
||||
* @return void
|
||||
*/
|
||||
function free($resultset=0)
|
||||
function free($resultset=null)
|
||||
{
|
||||
// If resultset not provided, we take the last used by connexion
|
||||
if (! is_resource($resultset)) { $resultset=$this->_results; }
|
||||
@@ -558,7 +558,7 @@ class DoliDBMysql extends DoliDB
|
||||
* @param string $charset Charset used to store data
|
||||
* @param string $collation Charset used to sort data
|
||||
* @param string $owner Username of database owner
|
||||
* @return resource resource defined if OK, null if KO
|
||||
* @return false|resource|true resource defined if OK, null if KO
|
||||
*/
|
||||
function DDLCreateDb($database,$charset='',$collation='',$owner='')
|
||||
{
|
||||
@@ -634,11 +634,13 @@ class DoliDBMysql extends DoliDB
|
||||
* @param string $type Type de la table
|
||||
* @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
|
||||
* @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
|
||||
* @param string $keys Tableau des champs cles noms => valeur
|
||||
* @param array $keys Tableau des champs cles noms => valeur
|
||||
* @return int <0 if KO, >=0 if OK
|
||||
*/
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys="",$fulltext_keys="",$keys="")
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys=null,$fulltext_keys=null,$keys=null)
|
||||
{
|
||||
// FIXME: $fulltext_keys parameter is unused
|
||||
|
||||
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
|
||||
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
|
||||
$sql = "CREATE TABLE ".$table."(";
|
||||
@@ -673,7 +675,7 @@ class DoliDBMysql extends DoliDB
|
||||
if($primary_key != "")
|
||||
$pk = "primary key(".$primary_key.")";
|
||||
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($unique_keys as $key => $value)
|
||||
@@ -682,7 +684,7 @@ class DoliDBMysql extends DoliDB
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($keys as $key => $value)
|
||||
@@ -694,9 +696,9 @@ class DoliDBMysql extends DoliDB
|
||||
$sql .= implode(',',$sqlfields);
|
||||
if($primary_key != "")
|
||||
$sql .= ",".$pk;
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
$sql .= ",".implode(',',$sqluq);
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
$sql .= ",".implode(',',$sqlk);
|
||||
$sql .=") engine=".$type;
|
||||
|
||||
@@ -712,7 +714,7 @@ class DoliDBMysql extends DoliDB
|
||||
*
|
||||
* @param string $table Name of table
|
||||
* @param string $field Optionnel : Name of field if we want description of field
|
||||
* @return resource Resource
|
||||
* @return false|resource|true Resource
|
||||
*/
|
||||
function DDLDescTable($table,$field="")
|
||||
{
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
|
||||
/**
|
||||
* \file htdocs/core/db/mysqli.class.php
|
||||
* \brief Class file to manage Dolibarr database access for a Mysql database
|
||||
* \brief Class file to manage Dolibarr database access for a MySQL database
|
||||
*/
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT .'/core/db/DoliDB.class.php';
|
||||
|
||||
/**
|
||||
* Class to manage Dolibarr database access for a Mysql database
|
||||
* Class to manage Dolibarr database access for a MySQL database using the MySQLi extension
|
||||
*/
|
||||
class DoliDBMysqli extends DoliDB
|
||||
{
|
||||
@@ -36,8 +36,8 @@ class DoliDBMysqli extends DoliDB
|
||||
//! Database label
|
||||
const LABEL='MySQL';
|
||||
//! Version min database
|
||||
const VERSIONMIN='4.1.0';
|
||||
//! Resultset of last query
|
||||
const VERSIONMIN='4.1.3';
|
||||
/** @var mysqli_result Resultset of last query */
|
||||
private $_results;
|
||||
|
||||
/**
|
||||
@@ -69,8 +69,8 @@ class DoliDBMysqli extends DoliDB
|
||||
|
||||
if (! function_exists("mysqli_connect"))
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error="Mysqli PHP functions for using Mysqli driver are not available in this version of PHP. Try to use another driver.";
|
||||
dol_syslog(get_class($this)."::DoliDBMysqli : Mysqli PHP functions for using Mysqli driver are not available in this version of PHP. Try to use another driver.",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -78,8 +78,8 @@ class DoliDBMysqli extends DoliDB
|
||||
|
||||
if (! $host)
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=$langs->trans("ErrorWrongHostParameter");
|
||||
dol_syslog(get_class($this)."::DoliDBMysqli : Erreur Connect, wrong host parameters",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -91,14 +91,14 @@ class DoliDBMysqli extends DoliDB
|
||||
|
||||
if ($this->db)
|
||||
{
|
||||
$this->connected = 1;
|
||||
$this->ok = 1;
|
||||
$this->connected = true;
|
||||
$this->ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// host, login ou password incorrect
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=mysqli_connect_error();
|
||||
dol_syslog(get_class($this)."::DoliDBMysqli : Erreur Connect mysqli_connect_error=".$this->error,LOG_ERR);
|
||||
}
|
||||
@@ -108,9 +108,9 @@ class DoliDBMysqli extends DoliDB
|
||||
{
|
||||
if ($this->select_db($name))
|
||||
{
|
||||
$this->database_selected = 1;
|
||||
$this->database_selected = true;
|
||||
$this->database_name = $name;
|
||||
$this->ok = 1;
|
||||
$this->ok = true;
|
||||
|
||||
// If client connected with different charset than Dolibarr HTML output
|
||||
$clientmustbe='';
|
||||
@@ -124,9 +124,9 @@ class DoliDBMysqli extends DoliDB
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->database_selected = 0;
|
||||
$this->database_selected = false;
|
||||
$this->database_name = '';
|
||||
$this->ok = 0;
|
||||
$this->ok = false;
|
||||
$this->error=$this->error();
|
||||
dol_syslog(get_class($this)."::DoliDBMysqli : Erreur Select_db ".$this->error,LOG_ERR);
|
||||
}
|
||||
@@ -134,7 +134,7 @@ class DoliDBMysqli extends DoliDB
|
||||
else
|
||||
{
|
||||
// Pas de selection de base demandee, ok ou ko
|
||||
$this->database_selected = 0;
|
||||
$this->database_selected = false;
|
||||
|
||||
if ($this->connected)
|
||||
{
|
||||
@@ -187,7 +187,7 @@ class DoliDBMysqli extends DoliDB
|
||||
* @param string $passwd password
|
||||
* @param string $name name of database (not used for mysql, used for pgsql)
|
||||
* @param integer $port Port of database server
|
||||
* @return resource Database access handler
|
||||
* @return mysqli Database access handler
|
||||
* @see close
|
||||
*/
|
||||
function connect($host, $login, $passwd, $name, $port=0)
|
||||
@@ -230,7 +230,7 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Close database connexion
|
||||
*
|
||||
* @return boolean True if disconnect successfull, false otherwise
|
||||
* @return bool True if disconnect successfull, false otherwise
|
||||
* @see connect
|
||||
*/
|
||||
function close()
|
||||
@@ -238,7 +238,7 @@ class DoliDBMysqli extends DoliDB
|
||||
if ($this->db)
|
||||
{
|
||||
if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR);
|
||||
$this->connected=0;
|
||||
$this->connected=false;
|
||||
return mysqli_close($this->db);
|
||||
}
|
||||
return false;
|
||||
@@ -251,7 +251,7 @@ class DoliDBMysqli extends DoliDB
|
||||
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
|
||||
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
|
||||
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
|
||||
* @return resource Resultset of answer
|
||||
* @return bool|mysqli_result Resultset of answer
|
||||
*/
|
||||
function query($query,$usesavepoint=0,$type='auto')
|
||||
{
|
||||
@@ -290,8 +290,8 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Renvoie la ligne courante (comme un objet) pour le curseur resultset
|
||||
*
|
||||
* @param Resultset $resultset Curseur de la requete voulue
|
||||
* @return Object Object result line or false if KO or end of cursor
|
||||
* @param mysqli_result $resultset Curseur de la requete voulue
|
||||
* @return object|null Object result line or null if KO or end of cursor
|
||||
*/
|
||||
function fetch_object($resultset)
|
||||
{
|
||||
@@ -304,8 +304,8 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param Resultset $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @param mysqli_result $resultset Resultset of request
|
||||
* @return array|null Array or null if KO or end of cursor
|
||||
*/
|
||||
function fetch_array($resultset)
|
||||
{
|
||||
@@ -317,8 +317,8 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param resource $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @param mysqli_result $resultset Resultset of request
|
||||
* @return array|null|0 Array or null if KO or end of cursor or 0 if resultset is bool
|
||||
*/
|
||||
function fetch_row($resultset)
|
||||
{
|
||||
@@ -338,8 +338,8 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Return number of lines for result of a SELECT
|
||||
*
|
||||
* @param Resultset $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @param mysqli_result $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @see affected_rows
|
||||
*/
|
||||
function num_rows($resultset)
|
||||
@@ -352,8 +352,8 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Renvoie le nombre de lignes dans le resultat d'une requete INSERT, DELETE ou UPDATE
|
||||
*
|
||||
* @param resultset $resultset Curseur de la requete voulue
|
||||
* @return int Nombre de lignes
|
||||
* @param mysqli_result $resultset Curseur de la requete voulue
|
||||
* @return int Nombre de lignes
|
||||
* @see num_rows
|
||||
*/
|
||||
function affected_rows($resultset)
|
||||
@@ -369,10 +369,10 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Libere le dernier resultset utilise sur cette connexion
|
||||
*
|
||||
* @param resultset $resultset Curseur de la requete voulue
|
||||
* @param mysqli_result $resultset Curseur de la requete voulue
|
||||
* @return void
|
||||
*/
|
||||
function free($resultset=0)
|
||||
function free($resultset=null)
|
||||
{
|
||||
// If resultset not provided, we take the last used by connexion
|
||||
if (! is_object($resultset)) { $resultset=$this->_results; }
|
||||
@@ -401,8 +401,7 @@ class DoliDBMysqli extends DoliDB
|
||||
if (! $this->connected) {
|
||||
// Si il y a eu echec de connexion, $this->db n'est pas valide.
|
||||
return 'DB_ERROR_FAILED_TO_CONNECT';
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Constants to convert a MySql error code to a generic Dolibarr error code
|
||||
$errorcode_map = array(
|
||||
1004 => 'DB_ERROR_CANNOT_CREATE',
|
||||
@@ -434,8 +433,7 @@ class DoliDBMysqli extends DoliDB
|
||||
1451 => 'DB_ERROR_CHILD_EXISTS'
|
||||
);
|
||||
|
||||
if (isset($errorcode_map[mysqli_errno($this->db)]))
|
||||
{
|
||||
if (isset($errorcode_map[mysqli_errno($this->db)])) {
|
||||
return $errorcode_map[mysqli_errno($this->db)];
|
||||
}
|
||||
$errno=mysqli_errno($this->db);
|
||||
@@ -464,7 +462,7 @@ class DoliDBMysqli extends DoliDB
|
||||
*
|
||||
* @param string $tab Table name concerned by insert. Ne sert pas sous MySql mais requis pour compatibilite avec Postgresql
|
||||
* @param string $fieldid Field name
|
||||
* @return int Id of row
|
||||
* @return int|string Id of row
|
||||
*/
|
||||
function last_insert_id($tab,$fieldid='rowid')
|
||||
{
|
||||
@@ -562,7 +560,7 @@ class DoliDBMysqli extends DoliDB
|
||||
* @param string $charset Charset used to store data
|
||||
* @param string $collation Charset used to sort data
|
||||
* @param string $owner Username of database owner
|
||||
* @return resource resource defined if OK, null if KO
|
||||
* @return bool|mysqli_result resource defined if OK, null if KO
|
||||
*/
|
||||
function DDLCreateDb($database,$charset='',$collation='',$owner='')
|
||||
{
|
||||
@@ -638,11 +636,13 @@ class DoliDBMysqli extends DoliDB
|
||||
* @param string $type Type de la table
|
||||
* @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
|
||||
* @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
|
||||
* @param string $keys Tableau des champs cles noms => valeur
|
||||
* @param array $keys Tableau des champs cles noms => valeur
|
||||
* @return int <0 if KO, >=0 if OK
|
||||
*/
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys="",$fulltext_keys="",$keys="")
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys=null,$fulltext_keys=null,$keys=null)
|
||||
{
|
||||
// FIXME: $fulltext_keys parameter is unused
|
||||
|
||||
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
|
||||
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
|
||||
$sql = "CREATE TABLE ".$table."(";
|
||||
@@ -677,8 +677,7 @@ class DoliDBMysqli extends DoliDB
|
||||
if($primary_key != "")
|
||||
$pk = "primary key(".$primary_key.")";
|
||||
|
||||
if($unique_keys != "")
|
||||
{
|
||||
if(is_array($unique_keys)) {
|
||||
$i = 0;
|
||||
foreach($unique_keys as $key => $value)
|
||||
{
|
||||
@@ -686,7 +685,7 @@ class DoliDBMysqli extends DoliDB
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($keys as $key => $value)
|
||||
@@ -700,7 +699,7 @@ class DoliDBMysqli extends DoliDB
|
||||
$sql .= ",".$pk;
|
||||
if($unique_keys != "")
|
||||
$sql .= ",".implode(',',$sqluq);
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
$sql .= ",".implode(',',$sqlk);
|
||||
$sql .=") engine=".$type;
|
||||
|
||||
@@ -716,7 +715,7 @@ class DoliDBMysqli extends DoliDB
|
||||
*
|
||||
* @param string $table Name of table
|
||||
* @param string $field Optionnel : Name of field if we want description of field
|
||||
* @return resource Resultset x (x->Field, x->Type, ...)
|
||||
* @return bool|mysqli_result Resultset x (x->Field, x->Type, ...)
|
||||
*/
|
||||
function DDLDescTable($table,$field="")
|
||||
{
|
||||
@@ -763,14 +762,10 @@ class DoliDBMysqli extends DoliDB
|
||||
$sql.= " ".$field_position;
|
||||
|
||||
dol_syslog(get_class($this)."::DDLAddField ".$sql,LOG_DEBUG);
|
||||
if(! $this->query($sql))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($this->query($sql)) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -808,12 +803,11 @@ class DoliDBMysqli extends DoliDB
|
||||
{
|
||||
$sql= "ALTER TABLE ".$table." DROP COLUMN `".$field_name."`";
|
||||
dol_syslog(get_class($this)."::DDLDropField ".$sql,LOG_DEBUG);
|
||||
if (! $this->query($sql))
|
||||
{
|
||||
$this->error=$this->lasterror();
|
||||
return -1;
|
||||
if ($this->query($sql)) {
|
||||
return 1;
|
||||
}
|
||||
else return 1;
|
||||
$this->error=$this->lasterror();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -883,7 +877,7 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Return list of available charset that can be used to store data in database
|
||||
*
|
||||
* @return array List of Charset
|
||||
* @return array|null List of Charset
|
||||
*/
|
||||
function getListOfCharacterSet()
|
||||
{
|
||||
@@ -926,7 +920,7 @@ class DoliDBMysqli extends DoliDB
|
||||
/**
|
||||
* Return list of available collation that can be used for database
|
||||
*
|
||||
* @return array Liste of Collation
|
||||
* @return array|null Liste of Collation
|
||||
*/
|
||||
function getListOfCollation()
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@ class DoliDBPgsql extends DoliDB
|
||||
var $forcecollate=''; // Can't be static as it may be forced with a dynamic value
|
||||
//! Version min database
|
||||
const VERSIONMIN='8.4.0'; // Version min database
|
||||
//! Resultset of last query
|
||||
/** @var resource Resultset of last query */
|
||||
private $_results;
|
||||
|
||||
public $unescapeslashquot;
|
||||
@@ -80,8 +80,8 @@ class DoliDBPgsql extends DoliDB
|
||||
|
||||
if (! function_exists("pg_connect"))
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error="Pgsql PHP functions are not available in this version of PHP";
|
||||
dol_syslog(get_class($this)."::DoliDBPgsql : Pgsql PHP functions are not available in this version of PHP",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -89,8 +89,8 @@ class DoliDBPgsql extends DoliDB
|
||||
|
||||
if (! $host)
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=$langs->trans("ErrorWrongHostParameter");
|
||||
dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Connect, wrong host parameters",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -102,14 +102,14 @@ class DoliDBPgsql extends DoliDB
|
||||
|
||||
if ($this->db)
|
||||
{
|
||||
$this->connected = 1;
|
||||
$this->ok = 1;
|
||||
$this->connected = true;
|
||||
$this->ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// host, login ou password incorrect
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error='Host, login or password incorrect';
|
||||
dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Connect ".$this->error,LOG_ERR);
|
||||
}
|
||||
@@ -119,15 +119,15 @@ class DoliDBPgsql extends DoliDB
|
||||
{
|
||||
if ($this->select_db($name))
|
||||
{
|
||||
$this->database_selected = 1;
|
||||
$this->database_selected = true;
|
||||
$this->database_name = $name;
|
||||
$this->ok = 1;
|
||||
$this->ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->database_selected = 0;
|
||||
$this->database_selected = false;
|
||||
$this->database_name = '';
|
||||
$this->ok = 0;
|
||||
$this->ok = false;
|
||||
$this->error=$this->error();
|
||||
dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Select_db ".$this->error,LOG_ERR);
|
||||
}
|
||||
@@ -135,7 +135,7 @@ class DoliDBPgsql extends DoliDB
|
||||
else
|
||||
{
|
||||
// Pas de selection de base demandee, ok ou ko
|
||||
$this->database_selected = 0;
|
||||
$this->database_selected = false;
|
||||
}
|
||||
|
||||
return $this->ok;
|
||||
@@ -147,10 +147,10 @@ class DoliDBPgsql extends DoliDB
|
||||
*
|
||||
* @param string $line SQL request line to convert
|
||||
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
|
||||
* @param string $unescapeslashquot Unescape slash quote with quote quote
|
||||
* @param bool $unescapeslashquot Unescape slash quote with quote quote
|
||||
* @return string SQL request line converted
|
||||
*/
|
||||
static function convertSQLFromMysql($line,$type='auto',$unescapeslashquot=0)
|
||||
static function convertSQLFromMysql($line,$type='auto',$unescapeslashquot=false)
|
||||
{
|
||||
// Removed empty line if this is a comment line for SVN tagging
|
||||
if (preg_match('/^--\s\$Id/i',$line)) {
|
||||
@@ -353,7 +353,7 @@ class DoliDBPgsql extends DoliDB
|
||||
* On compare juste manuellement si la database choisie est bien celle activee par la connexion
|
||||
*
|
||||
* @param string $database Name of database
|
||||
* @return boolean true if OK, false if KO
|
||||
* @return bool true if OK, false if KO
|
||||
*/
|
||||
function select_db($database)
|
||||
{
|
||||
@@ -369,7 +369,7 @@ class DoliDBPgsql extends DoliDB
|
||||
* @param string $passwd Password
|
||||
* @param string $name Name of database (not used for mysql, used for pgsql)
|
||||
* @param integer $port Port of database server
|
||||
* @return resource Database access handler
|
||||
* @return false|resource Database access handler
|
||||
* @see close
|
||||
*/
|
||||
function connect($host, $login, $passwd, $name, $port=0)
|
||||
@@ -451,7 +451,7 @@ class DoliDBPgsql extends DoliDB
|
||||
if ($this->db)
|
||||
{
|
||||
if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR);
|
||||
$this->connected=0;
|
||||
$this->connected=false;
|
||||
return pg_close($this->db);
|
||||
}
|
||||
return false;
|
||||
@@ -463,7 +463,7 @@ class DoliDBPgsql extends DoliDB
|
||||
* @param string $query SQL query string
|
||||
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions).
|
||||
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
|
||||
* @return resource Resultset of answer
|
||||
* @return false|resource Resultset of answer
|
||||
*/
|
||||
function query($query,$usesavepoint=0,$type='auto')
|
||||
{
|
||||
@@ -530,8 +530,8 @@ class DoliDBPgsql extends DoliDB
|
||||
/**
|
||||
* Renvoie la ligne courante (comme un objet) pour le curseur resultset
|
||||
*
|
||||
* @param Resultset $resultset Curseur de la requete voulue
|
||||
* @return Object Object result line or false if KO or end of cursor
|
||||
* @param resource $resultset Curseur de la requete voulue
|
||||
* @return false|object Object result line or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_object($resultset)
|
||||
{
|
||||
@@ -544,7 +544,7 @@ class DoliDBPgsql extends DoliDB
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param resource $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @return false|array Array
|
||||
*/
|
||||
function fetch_array($resultset)
|
||||
{
|
||||
@@ -557,7 +557,7 @@ class DoliDBPgsql extends DoliDB
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param resource $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @return false|array Array
|
||||
*/
|
||||
function fetch_row($resultset)
|
||||
{
|
||||
@@ -569,8 +569,8 @@ class DoliDBPgsql extends DoliDB
|
||||
/**
|
||||
* Return number of lines for result of a SELECT
|
||||
*
|
||||
* @param Resultset $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @param resourse $resultset Resulset of requests
|
||||
* @return int Nb of lines, -1 on error
|
||||
* @see affected_rows
|
||||
*/
|
||||
function num_rows($resultset)
|
||||
@@ -583,7 +583,7 @@ class DoliDBPgsql extends DoliDB
|
||||
/**
|
||||
* Renvoie le nombre de lignes dans le resultat d'une requete INSERT, DELETE ou UPDATE
|
||||
*
|
||||
* @param Resultset $resultset Result set of request
|
||||
* @param resource $resultset Result set of request
|
||||
* @return int Nb of lines
|
||||
* @see num_rows
|
||||
*/
|
||||
@@ -600,10 +600,10 @@ class DoliDBPgsql extends DoliDB
|
||||
/**
|
||||
* Libere le dernier resultset utilise sur cette connexion
|
||||
*
|
||||
* @param Resultset $resultset Result set of request
|
||||
* @param resource $resultset Result set of request
|
||||
* @return void
|
||||
*/
|
||||
function free($resultset=0)
|
||||
function free($resultset=null)
|
||||
{
|
||||
// If resultset not provided, we take the last used by connexion
|
||||
if (! is_resource($resultset)) { $resultset=$this->_results; }
|
||||
@@ -746,7 +746,7 @@ class DoliDBPgsql extends DoliDB
|
||||
*
|
||||
* @param string $tab Table name concerned by insert. Ne sert pas sous MySql mais requis pour compatibilite avec Postgresql
|
||||
* @param string $fieldid Field name
|
||||
* @return int Id of row
|
||||
* @return string Id of row
|
||||
*/
|
||||
function last_insert_id($tab,$fieldid='rowid')
|
||||
{
|
||||
@@ -827,7 +827,7 @@ class DoliDBPgsql extends DoliDB
|
||||
* @param string $charset Charset used to store data
|
||||
* @param string $collation Charset used to sort data
|
||||
* @param string $owner Username of database owner
|
||||
* @return resource resource defined if OK, null if KO
|
||||
* @return false|resource resource defined if OK, null if KO
|
||||
*/
|
||||
function DDLCreateDb($database,$charset='',$collation='',$owner='')
|
||||
{
|
||||
@@ -910,11 +910,13 @@ class DoliDBPgsql extends DoliDB
|
||||
* @param string $type Type de la table
|
||||
* @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
|
||||
* @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
|
||||
* @param string $keys Tableau des champs cles noms => valeur
|
||||
* @param array $keys Tableau des champs cles noms => valeur
|
||||
* @return int <0 if KO, >=0 if OK
|
||||
*/
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys="",$fulltext_keys="",$keys="")
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys=null,$fulltext_keys=null,$keys=null)
|
||||
{
|
||||
// FIXME: $fulltext_keys parameter is unused
|
||||
|
||||
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
|
||||
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
|
||||
$sql = "create table ".$table."(";
|
||||
@@ -944,7 +946,7 @@ class DoliDBPgsql extends DoliDB
|
||||
if($primary_key != "")
|
||||
$pk = "primary key(".$primary_key.")";
|
||||
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($unique_keys as $key => $value)
|
||||
@@ -953,7 +955,7 @@ class DoliDBPgsql extends DoliDB
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($keys as $key => $value)
|
||||
@@ -965,9 +967,9 @@ class DoliDBPgsql extends DoliDB
|
||||
$sql .= implode(',',$sqlfields);
|
||||
if($primary_key != "")
|
||||
$sql .= ",".$pk;
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
$sql .= ",".implode(',',$sqluq);
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
$sql .= ",".implode(',',$sqlk);
|
||||
$sql .=") type=".$type;
|
||||
|
||||
@@ -1007,7 +1009,7 @@ class DoliDBPgsql extends DoliDB
|
||||
*
|
||||
* @param string $table Name of table
|
||||
* @param string $field Optionnel : Name of field if we want description of field
|
||||
* @return resource Resultset x (x->attname)
|
||||
* @return false|resource Resultset x (x->attname)
|
||||
*/
|
||||
function DDLDescTable($table,$field="")
|
||||
{
|
||||
@@ -1052,8 +1054,7 @@ class DoliDBPgsql extends DoliDB
|
||||
|
||||
dol_syslog($sql,LOG_DEBUG);
|
||||
if(! $this -> query($sql))
|
||||
return -1;
|
||||
else
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1078,8 +1079,7 @@ class DoliDBPgsql extends DoliDB
|
||||
|
||||
dol_syslog($sql,LOG_DEBUG);
|
||||
if (! $this->query($sql))
|
||||
return -1;
|
||||
else
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1099,7 +1099,7 @@ class DoliDBPgsql extends DoliDB
|
||||
$this->error=$this->lasterror();
|
||||
return -1;
|
||||
}
|
||||
else return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,7 @@ class DoliDBSqlite extends DoliDB
|
||||
const LABEL='PDO Sqlite';
|
||||
//! Version min database
|
||||
const VERSIONMIN='3.0.0';
|
||||
//! Resultset of last query
|
||||
/** @var PDOStatement Resultset of last query */
|
||||
private $_results;
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ class DoliDBSqlite extends DoliDB
|
||||
*/
|
||||
function __construct($type, $host, $user, $pass, $name='', $port=0)
|
||||
{
|
||||
global $conf,$langs;
|
||||
global $conf;
|
||||
|
||||
// Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
|
||||
if (! empty($conf->db->character_set)) $this->forcecharset=$conf->db->character_set;
|
||||
@@ -70,8 +70,8 @@ class DoliDBSqlite extends DoliDB
|
||||
|
||||
/*if (! function_exists("sqlite_query"))
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.";
|
||||
dol_syslog(get_class($this)."::DoliDBSqlite : Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -79,8 +79,8 @@ class DoliDBSqlite extends DoliDB
|
||||
|
||||
/*if (! $host)
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=$langs->trans("ErrorWrongHostParameter");
|
||||
dol_syslog(get_class($this)."::DoliDBSqlite : Erreur Connect, wrong host parameters",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -92,9 +92,9 @@ class DoliDBSqlite extends DoliDB
|
||||
|
||||
if ($this->db)
|
||||
{
|
||||
$this->connected = 1;
|
||||
$this->ok = 1;
|
||||
$this->database_selected = 1;
|
||||
$this->connected = true;
|
||||
$this->ok = true;
|
||||
$this->database_selected = true;
|
||||
$this->database_name = $name;
|
||||
|
||||
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
@@ -102,15 +102,15 @@ class DoliDBSqlite extends DoliDB
|
||||
else
|
||||
{
|
||||
// host, login ou password incorrect
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->database_selected = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->database_selected = false;
|
||||
$this->database_name = '';
|
||||
//$this->error=sqlite_connect_error();
|
||||
dol_syslog(get_class($this)."::DoliDBSqlite : Erreur Connect ".$this->error,LOG_ERR);
|
||||
}
|
||||
|
||||
return $this->ok;
|
||||
return (int) $this->ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,7 @@ class DoliDBSqlite extends DoliDB
|
||||
function select_db($database)
|
||||
{
|
||||
dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
|
||||
// FIXME: sqlite_select_db() does not exist
|
||||
return sqlite_select_db($this->db,$database);
|
||||
}
|
||||
|
||||
@@ -297,12 +298,12 @@ class DoliDBSqlite extends DoliDB
|
||||
* @param string $passwd password
|
||||
* @param string $name name of database (not used for mysql, used for pgsql)
|
||||
* @param integer $port Port of database server
|
||||
* @return resource Database access handler
|
||||
* @return PDO Database access handler
|
||||
* @see close
|
||||
*/
|
||||
function connect($host, $login, $passwd, $name, $port=0)
|
||||
{
|
||||
global $conf,$main_data_dir;
|
||||
global $main_data_dir;
|
||||
|
||||
dol_syslog(get_class($this)."::connect name=".$name,LOG_DEBUG);
|
||||
|
||||
@@ -352,7 +353,7 @@ class DoliDBSqlite extends DoliDB
|
||||
/**
|
||||
* Close database connexion
|
||||
*
|
||||
* @return boolean True if disconnect successfull, false otherwise
|
||||
* @return bool True if disconnect successfull, false otherwise
|
||||
* @see connect
|
||||
*/
|
||||
function close()
|
||||
@@ -360,7 +361,7 @@ class DoliDBSqlite extends DoliDB
|
||||
if ($this->db)
|
||||
{
|
||||
if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR);
|
||||
$this->connected=0;
|
||||
$this->connected=false;
|
||||
$this->db=null; // Clean this->db
|
||||
return true;
|
||||
}
|
||||
@@ -374,13 +375,11 @@ class DoliDBSqlite extends DoliDB
|
||||
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
|
||||
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
|
||||
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
|
||||
* @return resource Resultset of answer
|
||||
* @return PDOStatement Resultset of answer
|
||||
*/
|
||||
function query($query,$usesavepoint=0,$type='auto')
|
||||
{
|
||||
$errmsg='';
|
||||
|
||||
$ret='';
|
||||
$ret=null;
|
||||
$query = trim($query);
|
||||
$this->error = 0;
|
||||
|
||||
@@ -429,8 +428,8 @@ class DoliDBSqlite extends DoliDB
|
||||
/**
|
||||
* Renvoie la ligne courante (comme un objet) pour le curseur resultset
|
||||
*
|
||||
* @param Resultset $resultset Curseur de la requete voulue
|
||||
* @return Object Object result line or false if KO or end of cursor
|
||||
* @param PDOStatement $resultset Curseur de la requete voulue
|
||||
* @return false|object Object result line or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_object($resultset)
|
||||
{
|
||||
@@ -443,8 +442,8 @@ class DoliDBSqlite extends DoliDB
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param Resultset $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @param PDOStatement $resultset Resultset of request
|
||||
* @return false|array Array or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_array($resultset)
|
||||
{
|
||||
@@ -456,8 +455,8 @@ class DoliDBSqlite extends DoliDB
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param resource $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @param PDOStatement $resultset Resultset of request
|
||||
* @return false|array Array or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_row($resultset)
|
||||
{
|
||||
@@ -477,7 +476,7 @@ class DoliDBSqlite extends DoliDB
|
||||
/**
|
||||
* Return number of lines for result of a SELECT
|
||||
*
|
||||
* @param Resultset $resultset Resulset of requests
|
||||
* @param PDOStatement $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @see affected_rows
|
||||
*/
|
||||
@@ -491,7 +490,7 @@ class DoliDBSqlite extends DoliDB
|
||||
/**
|
||||
* Return number of lines for result of a SELECT
|
||||
*
|
||||
* @param Resultset $resultset Resulset of requests
|
||||
* @param PDOStatement $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @see affected_rows
|
||||
*/
|
||||
@@ -508,10 +507,10 @@ class DoliDBSqlite extends DoliDB
|
||||
/**
|
||||
* Free last resultset used.
|
||||
*
|
||||
* @param integer $resultset Curseur de la requete voulue
|
||||
* @param PDOStatement $resultset Curseur de la requete voulue
|
||||
* @return void
|
||||
*/
|
||||
function free($resultset=0)
|
||||
function free($resultset=null)
|
||||
{
|
||||
// If resultset not provided, we take the last used by connexion
|
||||
if (! is_object($resultset)) { $resultset=$this->_results; }
|
||||
@@ -709,7 +708,7 @@ class DoliDBSqlite extends DoliDB
|
||||
* @param string $charset Charset used to store data
|
||||
* @param string $collation Charset used to sort data
|
||||
* @param string $owner Username of database owner
|
||||
* @return resource resource defined if OK, null if KO
|
||||
* @return PDOStatement resource defined if OK, null if KO
|
||||
*/
|
||||
function DDLCreateDb($database,$charset='',$collation='',$owner='')
|
||||
{
|
||||
@@ -786,11 +785,13 @@ class DoliDBSqlite extends DoliDB
|
||||
* @param string $type Type de la table
|
||||
* @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
|
||||
* @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
|
||||
* @param string $keys Tableau des champs cles noms => valeur
|
||||
* @param array $keys Tableau des champs cles noms => valeur
|
||||
* @return int <0 if KO, >=0 if OK
|
||||
*/
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys="",$fulltext_keys="",$keys="")
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys=null,$fulltext_keys=null,$keys=null)
|
||||
{
|
||||
// FIXME: $fulltext_keys parameter is unused
|
||||
|
||||
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
|
||||
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
|
||||
$sql = "create table ".$table."(";
|
||||
@@ -820,7 +821,7 @@ class DoliDBSqlite extends DoliDB
|
||||
if($primary_key != "")
|
||||
$pk = "primary key(".$primary_key.")";
|
||||
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($unique_keys as $key => $value)
|
||||
@@ -829,7 +830,7 @@ class DoliDBSqlite extends DoliDB
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($keys as $key => $value)
|
||||
@@ -841,9 +842,9 @@ class DoliDBSqlite extends DoliDB
|
||||
$sql .= implode(',',$sqlfields);
|
||||
if($primary_key != "")
|
||||
$sql .= ",".$pk;
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
$sql .= ",".implode(',',$sqluq);
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
$sql .= ",".implode(',',$sqlk);
|
||||
$sql .=") type=".$type;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||
* Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
|
||||
* Copyright (C) 2005-2009 Regis Houssin <regis.houssin@capnetworks.com>
|
||||
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,13 +22,13 @@
|
||||
|
||||
/**
|
||||
* \file htdocs/core/db/sqlite.class.php
|
||||
* \brief Class file to manage Dolibarr database access for a Sqlite database
|
||||
* \brief Class file to manage Dolibarr database access for a SQLite database
|
||||
*/
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT .'/core/db/DoliDB.class.php';
|
||||
|
||||
/**
|
||||
* Class to manage Dolibarr database access for a Sqlite database
|
||||
* Class to manage Dolibarr database access for a SQLite database
|
||||
*/
|
||||
class DoliDBSqlite3 extends DoliDB
|
||||
{
|
||||
@@ -37,8 +38,8 @@ class DoliDBSqlite3 extends DoliDB
|
||||
const LABEL='Sqlite3';
|
||||
//! Version min database
|
||||
const VERSIONMIN='3.0.0';
|
||||
//! Resultset of last query
|
||||
private $_results;
|
||||
/** @var SQLite3Result Resultset of last query */
|
||||
private $_results;
|
||||
|
||||
const WEEK_MONDAY_FIRST=1;
|
||||
const WEEK_YEAR = 2;
|
||||
@@ -58,7 +59,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
*/
|
||||
function __construct($type, $host, $user, $pass, $name='', $port=0)
|
||||
{
|
||||
global $conf,$langs;
|
||||
global $conf;
|
||||
|
||||
// Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
|
||||
if (! empty($conf->db->character_set)) $this->forcecharset=$conf->db->character_set;
|
||||
@@ -74,8 +75,8 @@ class DoliDBSqlite3 extends DoliDB
|
||||
|
||||
/*if (! function_exists("sqlite_query"))
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.";
|
||||
dol_syslog(get_class($this)."::DoliDBSqlite3 : Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -83,8 +84,8 @@ class DoliDBSqlite3 extends DoliDB
|
||||
|
||||
/*if (! $host)
|
||||
{
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->error=$langs->trans("ErrorWrongHostParameter");
|
||||
dol_syslog(get_class($this)."::DoliDBSqlite3 : Erreur Connect, wrong host parameters",LOG_ERR);
|
||||
return $this->ok;
|
||||
@@ -96,9 +97,9 @@ class DoliDBSqlite3 extends DoliDB
|
||||
|
||||
if ($this->db)
|
||||
{
|
||||
$this->connected = 1;
|
||||
$this->ok = 1;
|
||||
$this->database_selected = 1;
|
||||
$this->connected = true;
|
||||
$this->ok = true;
|
||||
$this->database_selected = true;
|
||||
$this->database_name = $name;
|
||||
|
||||
$this->addCustomFunction('IF');
|
||||
@@ -114,9 +115,9 @@ class DoliDBSqlite3 extends DoliDB
|
||||
else
|
||||
{
|
||||
// host, login ou password incorrect
|
||||
$this->connected = 0;
|
||||
$this->ok = 0;
|
||||
$this->database_selected = 0;
|
||||
$this->connected = false;
|
||||
$this->ok = false;
|
||||
$this->database_selected = false;
|
||||
$this->database_name = '';
|
||||
//$this->error=sqlite_connect_error();
|
||||
dol_syslog(get_class($this)."::DoliDBSqlite3 : Error Connect ".$this->error,LOG_ERR);
|
||||
@@ -304,6 +305,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
function select_db($database)
|
||||
{
|
||||
dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
|
||||
// FIXME: sqlite_select_db() does not exist
|
||||
return sqlite_select_db($this->db,$database);
|
||||
}
|
||||
|
||||
@@ -316,12 +318,12 @@ class DoliDBSqlite3 extends DoliDB
|
||||
* @param string $passwd password
|
||||
* @param string $name name of database (not used for mysql, used for pgsql)
|
||||
* @param integer $port Port of database server
|
||||
* @return resource Database access handler
|
||||
* @return SQLite3 Database access handler
|
||||
* @see close
|
||||
*/
|
||||
function connect($host, $login, $passwd, $name, $port=0)
|
||||
{
|
||||
global $conf,$main_data_dir;
|
||||
global $main_data_dir;
|
||||
|
||||
dol_syslog(get_class($this)."::connect name=".$name,LOG_DEBUG);
|
||||
|
||||
@@ -372,7 +374,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
/**
|
||||
* Close database connexion
|
||||
*
|
||||
* @return boolean True if disconnect successfull, false otherwise
|
||||
* @return bool True if disconnect successfull, false otherwise
|
||||
* @see connect
|
||||
*/
|
||||
function close()
|
||||
@@ -380,9 +382,9 @@ class DoliDBSqlite3 extends DoliDB
|
||||
if ($this->db)
|
||||
{
|
||||
if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR);
|
||||
$this->connected=0;
|
||||
$this->connected=false;
|
||||
$this->db->close();
|
||||
$this->db=null; // Clean this->db
|
||||
unset($this->db); // Clean this->db
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -395,13 +397,11 @@ class DoliDBSqlite3 extends DoliDB
|
||||
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
|
||||
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
|
||||
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
|
||||
* @return resource Resultset of answer
|
||||
* @return SQLite3Result Resultset of answer
|
||||
*/
|
||||
function query($query,$usesavepoint=0,$type='auto')
|
||||
{
|
||||
$errmsg='';
|
||||
|
||||
$ret='';
|
||||
$ret=null;
|
||||
$query = trim($query);
|
||||
$this->error = 0;
|
||||
|
||||
@@ -492,8 +492,8 @@ class DoliDBSqlite3 extends DoliDB
|
||||
/**
|
||||
* Renvoie la ligne courante (comme un objet) pour le curseur resultset
|
||||
*
|
||||
* @param Resultset $resultset Curseur de la requete voulue
|
||||
* @return Object Object result line or false if KO or end of cursor
|
||||
* @param SQLite3Result $resultset Curseur de la requete voulue
|
||||
* @return false|object Object result line or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_object($resultset)
|
||||
{
|
||||
@@ -504,14 +504,15 @@ class DoliDBSqlite3 extends DoliDB
|
||||
if ($ret) {
|
||||
return (object) $ret;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param Resultset $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @param SQLite3Result $resultset Resultset of request
|
||||
* @return false|array Array or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_array($resultset)
|
||||
{
|
||||
@@ -519,16 +520,14 @@ class DoliDBSqlite3 extends DoliDB
|
||||
if (! is_object($resultset)) { $resultset=$this->_results; }
|
||||
//return $resultset->fetch(PDO::FETCH_ASSOC);
|
||||
$ret = $resultset->fetchArray(SQLITE3_ASSOC);
|
||||
if ($ret) {
|
||||
return (array) $ret;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return datas as an array
|
||||
*
|
||||
* @param resource $resultset Resultset of request
|
||||
* @return array Array
|
||||
* @param SQLite3Result $resultset Resultset of request
|
||||
* @return false|array Array or false if KO or end of cursor
|
||||
*/
|
||||
function fetch_row($resultset)
|
||||
{
|
||||
@@ -541,19 +540,21 @@ class DoliDBSqlite3 extends DoliDB
|
||||
else
|
||||
{
|
||||
// si le curseur est un booleen on retourne la valeur 0
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of lines for result of a SELECT
|
||||
*
|
||||
* @param Resultset $resultset Resulset of requests
|
||||
* @param SQLite3Result $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @see affected_rows
|
||||
*/
|
||||
function num_rows($resultset)
|
||||
{
|
||||
// FIXME: SQLite3Result does not have a queryString member
|
||||
|
||||
// If resultset not provided, we take the last used by connexion
|
||||
if (! is_object($resultset)) { $resultset=$this->_results; }
|
||||
if (preg_match("/^SELECT/i", $resultset->queryString)) {
|
||||
@@ -565,12 +566,14 @@ class DoliDBSqlite3 extends DoliDB
|
||||
/**
|
||||
* Return number of lines for result of a SELECT
|
||||
*
|
||||
* @param Resultset $resultset Resulset of requests
|
||||
* @param SQLite3Result $resultset Resulset of requests
|
||||
* @return int Nb of lines
|
||||
* @see affected_rows
|
||||
*/
|
||||
function affected_rows($resultset)
|
||||
{
|
||||
// FIXME: SQLite3Result does not have a queryString member
|
||||
|
||||
// If resultset not provided, we take the last used by connexion
|
||||
if (! is_object($resultset)) { $resultset=$this->_results; }
|
||||
if (preg_match("/^SELECT/i", $resultset->queryString)) {
|
||||
@@ -585,10 +588,10 @@ class DoliDBSqlite3 extends DoliDB
|
||||
/**
|
||||
* Free last resultset used.
|
||||
*
|
||||
* @param integer $resultset Curseur de la requete voulue
|
||||
* @param SQLite3Result $resultset Curseur de la requete voulue
|
||||
* @return void
|
||||
*/
|
||||
function free($resultset=0)
|
||||
function free($resultset=null)
|
||||
{
|
||||
// If resultset not provided, we take the last used by connexion
|
||||
if (! is_object($resultset)) { $resultset=$this->_results; }
|
||||
@@ -789,7 +792,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
* @param string $charset Charset used to store data
|
||||
* @param string $collation Charset used to sort data
|
||||
* @param string $owner Username of database owner
|
||||
* @return resource resource defined if OK, null if KO
|
||||
* @return SQLite3Result resource defined if OK, null if KO
|
||||
*/
|
||||
function DDLCreateDb($database,$charset='',$collation='',$owner='')
|
||||
{
|
||||
@@ -866,11 +869,13 @@ class DoliDBSqlite3 extends DoliDB
|
||||
* @param string $type Type de la table
|
||||
* @param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
|
||||
* @param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
|
||||
* @param string $keys Tableau des champs cles noms => valeur
|
||||
* @param array $keys Tableau des champs cles noms => valeur
|
||||
* @return int <0 if KO, >=0 if OK
|
||||
*/
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys="",$fulltext_keys="",$keys="")
|
||||
function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys=null,$fulltext_keys=null,$keys=null)
|
||||
{
|
||||
// FIXME: $fulltext_keys parameter is unused
|
||||
|
||||
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
|
||||
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
|
||||
$sql = "create table ".$table."(";
|
||||
@@ -900,7 +905,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
if($primary_key != "")
|
||||
$pk = "primary key(".$primary_key.")";
|
||||
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($unique_keys as $key => $value)
|
||||
@@ -909,7 +914,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
{
|
||||
$i = 0;
|
||||
foreach($keys as $key => $value)
|
||||
@@ -921,16 +926,15 @@ class DoliDBSqlite3 extends DoliDB
|
||||
$sql .= implode(',',$sqlfields);
|
||||
if($primary_key != "")
|
||||
$sql .= ",".$pk;
|
||||
if($unique_keys != "")
|
||||
if(is_array($unique_keys))
|
||||
$sql .= ",".implode(',',$sqluq);
|
||||
if($keys != "")
|
||||
if(is_array($keys))
|
||||
$sql .= ",".implode(',',$sqlk);
|
||||
$sql .=") type=".$type;
|
||||
|
||||
dol_syslog($sql,LOG_DEBUG);
|
||||
if(! $this -> query($sql))
|
||||
return -1;
|
||||
else
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -939,7 +943,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
*
|
||||
* @param string $table Name of table
|
||||
* @param string $field Optionnel : Name of field if we want description of field
|
||||
* @return resource Resource
|
||||
* @return SQLite3Result Resource
|
||||
*/
|
||||
function DDLDescTable($table,$field="")
|
||||
{
|
||||
@@ -990,10 +994,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1014,8 +1015,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
|
||||
dol_syslog(get_class($this)."::DDLUpdateField ".$sql,LOG_DEBUG);
|
||||
if (! $this->query($sql))
|
||||
return -1;
|
||||
else
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1035,7 +1035,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
$this->error=$this->lasterror();
|
||||
return -1;
|
||||
}
|
||||
else return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1082,7 +1082,6 @@ class DoliDBSqlite3 extends DoliDB
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1141,6 +1140,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
*/
|
||||
function getPathOfDump()
|
||||
{
|
||||
// FIXME: not for SQLite
|
||||
$fullpathofdump='/pathtomysqldump/mysqldump';
|
||||
|
||||
$resql=$this->query('SHOW VARIABLES LIKE \'basedir\'');
|
||||
@@ -1160,6 +1160,7 @@ class DoliDBSqlite3 extends DoliDB
|
||||
*/
|
||||
function getPathOfRestore()
|
||||
{
|
||||
// FIXME: not for SQLite
|
||||
$fullpathofimport='/pathtomysql/mysql';
|
||||
|
||||
$resql=$this->query('SHOW VARIABLES LIKE \'basedir\'');
|
||||
@@ -1425,10 +1426,10 @@ class DoliDBSqlite3 extends DoliDB
|
||||
/**
|
||||
* calc_daynr
|
||||
*
|
||||
* @param string $year Year
|
||||
* @param string $month Month
|
||||
* @param string $day Day
|
||||
* @return string La date formatee.
|
||||
* @param int $year Year
|
||||
* @param int $month Month
|
||||
* @param int $day Day
|
||||
* @return int Formatted date
|
||||
*/
|
||||
private static function calc_daynr($year, $month, $day) {
|
||||
$y = $year;
|
||||
@@ -1446,8 +1447,9 @@ class DoliDBSqlite3 extends DoliDB
|
||||
/**
|
||||
* calc_weekday
|
||||
*
|
||||
* @param string $daynr ???
|
||||
* @param string $sunday_first_day_of_week ???
|
||||
* @param int $daynr ???
|
||||
* @param bool $sunday_first_day_of_week ???
|
||||
* @return int
|
||||
*/
|
||||
private static function calc_weekday($daynr, $sunday_first_day_of_week) {
|
||||
$ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
|
||||
|
||||
@@ -106,7 +106,7 @@ window.onload = function()
|
||||
<tr>
|
||||
<td><?php echo img_picto_common('','treemenu/folder.gif','width="16" height="16"'); ?></td>
|
||||
<td> </td>
|
||||
<td id="tdName" width="100%" nowrap class="ActualFolder">/</td>
|
||||
<td id="tdName" width="100%" class="ActualFolder nowrap">/</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
|
||||
@@ -220,7 +220,7 @@ window.onload = function()
|
||||
<table id="tableFiles" cellSpacing="0" cellPadding="0" width="100%" border="0">
|
||||
<tr id="trUp" style="DISPLAY: none">
|
||||
<td width="16"><a id="linkUpIcon" href="#"><img alt="" src="images/FolderUp.gif" width="16" height="16" border="0"></a></td>
|
||||
<td nowrap width="100%"> <a id="linkUp" href="#">..</a></td>
|
||||
<td class="nowrap" width="100%"> <a id="linkUp" href="#">..</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
@@ -77,7 +77,7 @@ oListManager.GetFolderRowHtml = function( folderName, folderPath )
|
||||
'<td width="16">' +
|
||||
sLink +
|
||||
'<img alt="" src="images/Folder.gif" width="16" height="16" border="0"><\/a>' +
|
||||
'<\/td><td nowrap colspan="2"> ' +
|
||||
'<\/td><td class="nowrap" colspan="2"> ' +
|
||||
sLink +
|
||||
folderName +
|
||||
'<\/a>' +
|
||||
@@ -100,7 +100,7 @@ oListManager.GetFileRowHtml = function( fileName, fileUrl, fileSize )
|
||||
sLink +
|
||||
fileName +
|
||||
'<\/a>' +
|
||||
'<\/td><td align="right" nowrap> ' +
|
||||
'<\/td><td align="right" class="nowrap"> ' +
|
||||
fileSize +
|
||||
' KB' +
|
||||
'<\/td><\/tr>' ;
|
||||
|
||||
@@ -132,7 +132,7 @@ function ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLengt
|
||||
// Disable an element
|
||||
if (options.option_disabled) {
|
||||
if (ui.item.disabled) {
|
||||
$("#" + options.option_disabled).attr("disabled", "disabled");
|
||||
$("#" + options.option_disabled).prop("disabled", true);
|
||||
if (options.error) {
|
||||
$.jnotify(options.error, "error", true); // Output with jnotify the error message
|
||||
}
|
||||
@@ -145,7 +145,7 @@ function ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLengt
|
||||
}
|
||||
if (options.disabled) {
|
||||
$.each(options.disabled, function(key, value) {
|
||||
$("#" + value).attr("disabled", "disabled");
|
||||
$("#" + value).prop("disabled", true);
|
||||
});
|
||||
}
|
||||
if (options.show) {
|
||||
@@ -524,7 +524,7 @@ function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input=a
|
||||
// Disable another element
|
||||
if (input.disabled && input.disabled.length > 0) {
|
||||
$.each(input.disabled, function(key,value) {
|
||||
$("#" + value).attr("disabled", true);
|
||||
$("#" + value).prop("disabled", true);
|
||||
if ($("#" + value).hasClass("butAction") == true) {
|
||||
$("#" + value).removeClass("butAction");
|
||||
$("#" + value).addClass("butActionRefused");
|
||||
|
||||
@@ -331,163 +331,189 @@ function restrictedArea($user, $features, $objectid=0, $dbtablename='', $feature
|
||||
// is linked to a company allowed to $user.
|
||||
if (! empty($objectid) && $objectid > 0)
|
||||
{
|
||||
foreach ($featuresarray as $feature)
|
||||
{
|
||||
$sql='';
|
||||
|
||||
$check = array('adherent','banque','user','usergroup','produit','service','produit|service','categorie'); // Test on entity only (Objects with no link to company)
|
||||
$checksoc = array('societe'); // Test for societe object
|
||||
$checkother = array('contact'); // Test on entity and link to societe. Allowed if link is empty (Ex: contacts...).
|
||||
$checkproject = array('projet'); // Test for project object
|
||||
$nocheck = array('barcode','stock','fournisseur'); // No test
|
||||
$checkdefault = 'all other not already defined'; // Test on entity and link to third party. Not allowed if link is empty (Ex: invoice, orders...).
|
||||
|
||||
// If dbtable not defined, we use same name for table than module name
|
||||
if (empty($dbtablename)) $dbtablename = $feature;
|
||||
|
||||
// Check permission for object with entity
|
||||
if (in_array($feature,$check))
|
||||
{
|
||||
$sql = "SELECT dbt.".$dbt_select;
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
|
||||
if (($feature == 'user' || $feature == 'usergroup') && ! empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && ! $user->entity)
|
||||
{
|
||||
$sql.= " AND dbt.entity IS NOT NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
else if (in_array($feature,$checksoc)) // We check feature = checksoc
|
||||
{
|
||||
// If external user: Check permission for external users
|
||||
if ($user->societe_id > 0)
|
||||
{
|
||||
if ($user->societe_id <> $objectid) accessforbidden();
|
||||
}
|
||||
// If internal user: Check permission for internal users that are restricted on their objects
|
||||
else if (! empty($conf->societe->enabled) && ($user->rights->societe->lire && ! $user->rights->societe->client->voir))
|
||||
{
|
||||
$sql = "SELECT sc.fk_soc";
|
||||
$sql.= " FROM (".MAIN_DB_PREFIX."societe_commerciaux as sc";
|
||||
$sql.= ", ".MAIN_DB_PREFIX."societe as s)";
|
||||
$sql.= " WHERE sc.fk_soc = ".$objectid;
|
||||
$sql.= " AND sc.fk_user = ".$user->id;
|
||||
$sql.= " AND sc.fk_soc = s.rowid";
|
||||
$sql.= " AND s.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
// If multicompany and internal users with all permissions, check user is in correct entity
|
||||
else if (! empty($conf->multicompany->enabled))
|
||||
{
|
||||
$sql = "SELECT s.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."societe as s";
|
||||
$sql.= " WHERE s.rowid = ".$objectid;
|
||||
$sql.= " AND s.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
else if (in_array($feature,$checkother))
|
||||
{
|
||||
// If external user: Check permission for external users
|
||||
if ($user->societe_id > 0)
|
||||
{
|
||||
$sql = "SELECT dbt.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.rowid = ".$objectid;
|
||||
$sql.= " AND dbt.fk_soc = ".$user->societe_id;
|
||||
}
|
||||
// If internal user: Check permission for internal users that are restricted on their objects
|
||||
else if (! empty($conf->societe->enabled) && ($user->rights->societe->lire && ! $user->rights->societe->client->voir))
|
||||
{
|
||||
$sql = "SELECT dbt.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON dbt.fk_soc = sc.fk_soc AND sc.fk_user = '".$user->id."'";
|
||||
$sql.= " WHERE dbt.rowid = ".$objectid;
|
||||
$sql.= " AND (dbt.fk_soc IS NULL OR sc.fk_soc IS NOT NULL)"; // Contact not linked to a company or to a company of user
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
// If multicompany and internal users with all permissions, check user is in correct entity
|
||||
else if (! empty($conf->multicompany->enabled))
|
||||
{
|
||||
$sql = "SELECT dbt.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.rowid = ".$objectid;
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
else if (in_array($feature,$checkproject))
|
||||
{
|
||||
if (! empty($conf->projet->enabled) && ! $user->rights->projet->all->lire)
|
||||
{
|
||||
include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
|
||||
$projectstatic=new Project($db);
|
||||
$tmps=$projectstatic->getProjectsAuthorizedForUser($user,0,1,0);
|
||||
$tmparray=explode(',',$tmps);
|
||||
if (! in_array($objectid,$tmparray)) accessforbidden();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = "SELECT dbt.".$dbt_select;
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
else if (! in_array($feature,$nocheck)) // By default we check with link to third party
|
||||
{
|
||||
// If external user: Check permission for external users
|
||||
if ($user->societe_id > 0)
|
||||
{
|
||||
if (empty($dbt_keyfield)) dol_print_error('','Param dbt_keyfield is required but not defined');
|
||||
$sql = "SELECT dbt.".$dbt_keyfield;
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.rowid = ".$objectid;
|
||||
$sql.= " AND dbt.".$dbt_keyfield." = ".$user->societe_id;
|
||||
}
|
||||
// If internal user: Check permission for internal users that are restricted on their objects
|
||||
else if (! empty($conf->societe->enabled) && ($user->rights->societe->lire && ! $user->rights->societe->client->voir))
|
||||
{
|
||||
if (empty($dbt_keyfield)) dol_print_error('','Param dbt_keyfield is required but not defined');
|
||||
$sql = "SELECT sc.fk_soc";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= ", ".MAIN_DB_PREFIX."societe as s";
|
||||
$sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
|
||||
$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
|
||||
$sql.= " AND sc.fk_soc = dbt.".$dbt_keyfield;
|
||||
$sql.= " AND dbt.".$dbt_keyfield." = s.rowid";
|
||||
$sql.= " AND s.entity IN (".getEntity($sharedelement, 1).")";
|
||||
$sql.= " AND sc.fk_user = ".$user->id;
|
||||
}
|
||||
// If multicompany and internal users with all permissions, check user is in correct entity
|
||||
else if (! empty($conf->multicompany->enabled))
|
||||
{
|
||||
$sql = "SELECT dbt.".$dbt_select;
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
|
||||
//print "sql=".$sql."<br>";
|
||||
if ($sql)
|
||||
{
|
||||
$resql=$db->query($sql);
|
||||
if ($resql)
|
||||
{
|
||||
if ($db->num_rows($resql) == 0) accessforbidden();
|
||||
}
|
||||
else
|
||||
{
|
||||
accessforbidden();
|
||||
}
|
||||
}
|
||||
}
|
||||
$ok = checkUserAccessToObject($user, $featuresarray,$objectid,$dbtablename,$feature2,$dbt_keyfield,$dbt_select);
|
||||
return $ok ? 1 : accessforbidden();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access by user to object
|
||||
*
|
||||
* @param User $user User to check
|
||||
* @param array $featuresarray Features/modules to check
|
||||
* @param int $objectid Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional).
|
||||
* @param string $dbtablename 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity. Not used if objectid is null (optional)
|
||||
* @param string $feature2 Feature to check, second level of permission (optional). Can be or check with 'level1|level2'.
|
||||
* @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional)
|
||||
* @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional)
|
||||
*
|
||||
* @return bool True if user has access, False otherwise
|
||||
*/
|
||||
function checkUserAccessToObject($user, $featuresarray, $objectid=0, $dbtablename='', $feature2='', $dbt_keyfield='', $dbt_select='')
|
||||
{
|
||||
global $db, $conf;
|
||||
|
||||
// More parameters
|
||||
$params = explode('&', $dbtablename);
|
||||
$dbtablename=(! empty($params[0]) ? $params[0] : '');
|
||||
$sharedelement=(! empty($params[1]) ? $params[1] : $dbtablename);
|
||||
|
||||
foreach ($featuresarray as $feature)
|
||||
{
|
||||
$sql='';
|
||||
|
||||
$check = array('adherent','banque','user','usergroup','produit','service','produit|service','categorie'); // Test on entity only (Objects with no link to company)
|
||||
$checksoc = array('societe'); // Test for societe object
|
||||
$checkother = array('contact'); // Test on entity and link to societe. Allowed if link is empty (Ex: contacts...).
|
||||
$checkproject = array('projet'); // Test for project object
|
||||
$nocheck = array('barcode','stock','fournisseur'); // No test
|
||||
$checkdefault = 'all other not already defined'; // Test on entity and link to third party. Not allowed if link is empty (Ex: invoice, orders...).
|
||||
|
||||
// If dbtable not defined, we use same name for table than module name
|
||||
if (empty($dbtablename)) $dbtablename = $feature;
|
||||
|
||||
// Check permission for object with entity
|
||||
if (in_array($feature,$check))
|
||||
{
|
||||
$sql = "SELECT dbt.".$dbt_select;
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
|
||||
if (($feature == 'user' || $feature == 'usergroup') && ! empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && ! $user->entity)
|
||||
{
|
||||
$sql.= " AND dbt.entity IS NOT NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
else if (in_array($feature,$checksoc)) // We check feature = checksoc
|
||||
{
|
||||
// If external user: Check permission for external users
|
||||
if ($user->societe_id > 0)
|
||||
{
|
||||
if ($user->societe_id <> $objectid) return false;
|
||||
}
|
||||
// If internal user: Check permission for internal users that are restricted on their objects
|
||||
else if (! empty($conf->societe->enabled) && ($user->rights->societe->lire && ! $user->rights->societe->client->voir))
|
||||
{
|
||||
$sql = "SELECT sc.fk_soc";
|
||||
$sql.= " FROM (".MAIN_DB_PREFIX."societe_commerciaux as sc";
|
||||
$sql.= ", ".MAIN_DB_PREFIX."societe as s)";
|
||||
$sql.= " WHERE sc.fk_soc = ".$objectid;
|
||||
$sql.= " AND sc.fk_user = ".$user->id;
|
||||
$sql.= " AND sc.fk_soc = s.rowid";
|
||||
$sql.= " AND s.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
// If multicompany and internal users with all permissions, check user is in correct entity
|
||||
else if (! empty($conf->multicompany->enabled))
|
||||
{
|
||||
$sql = "SELECT s.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."societe as s";
|
||||
$sql.= " WHERE s.rowid = ".$objectid;
|
||||
$sql.= " AND s.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
else if (in_array($feature,$checkother))
|
||||
{
|
||||
// If external user: Check permission for external users
|
||||
if ($user->societe_id > 0)
|
||||
{
|
||||
$sql = "SELECT dbt.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.rowid = ".$objectid;
|
||||
$sql.= " AND dbt.fk_soc = ".$user->societe_id;
|
||||
}
|
||||
// If internal user: Check permission for internal users that are restricted on their objects
|
||||
else if (! empty($conf->societe->enabled) && ($user->rights->societe->lire && ! $user->rights->societe->client->voir))
|
||||
{
|
||||
$sql = "SELECT dbt.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON dbt.fk_soc = sc.fk_soc AND sc.fk_user = '".$user->id."'";
|
||||
$sql.= " WHERE dbt.rowid = ".$objectid;
|
||||
$sql.= " AND (dbt.fk_soc IS NULL OR sc.fk_soc IS NOT NULL)"; // Contact not linked to a company or to a company of user
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
// If multicompany and internal users with all permissions, check user is in correct entity
|
||||
else if (! empty($conf->multicompany->enabled))
|
||||
{
|
||||
$sql = "SELECT dbt.rowid";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.rowid = ".$objectid;
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
else if (in_array($feature,$checkproject))
|
||||
{
|
||||
if (! empty($conf->projet->enabled) && ! $user->rights->projet->all->lire)
|
||||
{
|
||||
include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
|
||||
$projectstatic=new Project($db);
|
||||
$tmps=$projectstatic->getProjectsAuthorizedForUser($user,0,1,0);
|
||||
$tmparray=explode(',',$tmps);
|
||||
if (! in_array($objectid,$tmparray)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = "SELECT dbt.".$dbt_select;
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
else if (! in_array($feature,$nocheck)) // By default we check with link to third party
|
||||
{
|
||||
// If external user: Check permission for external users
|
||||
if ($user->societe_id > 0)
|
||||
{
|
||||
if (empty($dbt_keyfield)) dol_print_error('','Param dbt_keyfield is required but not defined');
|
||||
$sql = "SELECT dbt.".$dbt_keyfield;
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.rowid = ".$objectid;
|
||||
$sql.= " AND dbt.".$dbt_keyfield." = ".$user->societe_id;
|
||||
}
|
||||
// If internal user: Check permission for internal users that are restricted on their objects
|
||||
else if (! empty($conf->societe->enabled) && ($user->rights->societe->lire && ! $user->rights->societe->client->voir))
|
||||
{
|
||||
if (empty($dbt_keyfield)) dol_print_error('','Param dbt_keyfield is required but not defined');
|
||||
$sql = "SELECT sc.fk_soc";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= ", ".MAIN_DB_PREFIX."societe as s";
|
||||
$sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
|
||||
$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
|
||||
$sql.= " AND sc.fk_soc = dbt.".$dbt_keyfield;
|
||||
$sql.= " AND dbt.".$dbt_keyfield." = s.rowid";
|
||||
$sql.= " AND s.entity IN (".getEntity($sharedelement, 1).")";
|
||||
$sql.= " AND sc.fk_user = ".$user->id;
|
||||
}
|
||||
// If multicompany and internal users with all permissions, check user is in correct entity
|
||||
else if (! empty($conf->multicompany->enabled))
|
||||
{
|
||||
$sql = "SELECT dbt.".$dbt_select;
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
|
||||
$sql.= " WHERE dbt.".$dbt_select." = ".$objectid;
|
||||
$sql.= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
|
||||
}
|
||||
}
|
||||
|
||||
//print "sql=".$sql."<br>";
|
||||
if ($sql)
|
||||
{
|
||||
$resql=$db->query($sql);
|
||||
if ($resql)
|
||||
{
|
||||
if ($db->num_rows($resql) == 0) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a message to say access is forbidden and stop program
|
||||
|
||||
252
htdocs/core/modules/modApi.class.php
Normal file
252
htdocs/core/modules/modApi.class.php
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
/* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
||||
* Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||
* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup api Module Api
|
||||
* \brief Descriptor file for Api modulee
|
||||
* \file htdocs/api/core/modules/modApi.class.php
|
||||
* \ingroup api
|
||||
* \brief Description and activation file for module Api
|
||||
*/
|
||||
include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php';
|
||||
|
||||
|
||||
/**
|
||||
* Description and activation class for module Api
|
||||
*/
|
||||
class modApi extends DolibarrModules
|
||||
{
|
||||
/**
|
||||
* Constructor. Define names, constants, directories, boxes, permissions
|
||||
*
|
||||
* @param DoliDB $db Database handler
|
||||
*/
|
||||
function __construct($db)
|
||||
{
|
||||
global $langs,$conf;
|
||||
|
||||
$this->db = $db;
|
||||
|
||||
// Id for module (must be unique).
|
||||
// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
|
||||
$this->numero = 2610;
|
||||
// Key text used to identify module (for permissions, menus, etc...)
|
||||
$this->rights_class = 'api';
|
||||
|
||||
// Family can be 'crm','financial','hr','projects','products','ecm','technic','other'
|
||||
// It is used to group modules in module setup page
|
||||
$this->family = "technic";
|
||||
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
|
||||
$this->name = preg_replace('/^mod/i','',get_class($this));
|
||||
// Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module)
|
||||
$this->description = "REST interface";
|
||||
// Possible values for version are: 'development', 'experimental', 'dolibarr' or 'dolibarr_deprecated' or version
|
||||
$this->version = 'development';
|
||||
// Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase)
|
||||
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
|
||||
// Where to store the module in setup page (0=common,1=interface,2=others,3=very specific)
|
||||
$this->special = 1;
|
||||
// Name of image file used for this module.
|
||||
// If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
|
||||
// If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
|
||||
$this->picto='technic';
|
||||
|
||||
|
||||
$this->module_parts = array();
|
||||
|
||||
// Data directories to create when module is enabled.
|
||||
// Example: this->dirs = array("/api/temp");
|
||||
$this->dirs = array();
|
||||
|
||||
// Config pages. Put here list of php page, stored into api/admin directory, to use to setup module.
|
||||
$this->config_page_url = array("api.php@api");
|
||||
|
||||
// Dependencies
|
||||
$this->hidden = false; // A condition to hide module
|
||||
$this->depends = array(); // List of modules id that must be enabled if this module is enabled
|
||||
$this->requiredby = array(); // List of modules id to disable if this one is disabled
|
||||
$this->conflictwith = array(); // List of modules id this module is in conflict with
|
||||
$this->phpmin = array(5,3); // Minimum version of PHP required by module
|
||||
$this->langfiles = array("other");
|
||||
|
||||
// Constants
|
||||
// List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive)
|
||||
// Example: $this->const=array(0=>array('MYMODULE_MYNEWCONST1','chaine','myvalue','This is a constant to add',1),
|
||||
// 1=>array('MYMODULE_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1)
|
||||
// );
|
||||
$this->const = array();
|
||||
|
||||
// Array to add new pages in new tabs
|
||||
// Example: $this->tabs = array('objecttype:+tabname1:Title1:mylangfile@api:$user->rights->api->read:/api/mynewtab1.php?id=__ID__', // To add a new tab identified by code tabname1
|
||||
// 'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@api:$user->rights->othermodule->read:/api/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
|
||||
// 'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname
|
||||
// where objecttype can be
|
||||
// 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member)
|
||||
// 'contact' to add a tab in contact view
|
||||
// 'contract' to add a tab in contract view
|
||||
// 'group' to add a tab in group view
|
||||
// 'intervention' to add a tab in intervention view
|
||||
// 'invoice' to add a tab in customer invoice view
|
||||
// 'invoice_supplier' to add a tab in supplier invoice view
|
||||
// 'member' to add a tab in fundation member view
|
||||
// 'opensurveypoll' to add a tab in opensurvey poll view
|
||||
// 'order' to add a tab in customer order view
|
||||
// 'order_supplier' to add a tab in supplier order view
|
||||
// 'payment' to add a tab in payment view
|
||||
// 'payment_supplier' to add a tab in supplier payment view
|
||||
// 'product' to add a tab in product view
|
||||
// 'propal' to add a tab in propal view
|
||||
// 'project' to add a tab in project view
|
||||
// 'stock' to add a tab in stock view
|
||||
// 'thirdparty' to add a tab in third party view
|
||||
// 'user' to add a tab in user view
|
||||
$this->tabs = array();
|
||||
|
||||
// Dictionaries
|
||||
if (! isset($conf->api->enabled))
|
||||
{
|
||||
$conf->api=new stdClass();
|
||||
$conf->api->enabled=0;
|
||||
}
|
||||
$this->dictionaries=array();
|
||||
/* Example:
|
||||
if (! isset($conf->api->enabled)) $conf->api->enabled=0; // This is to avoid warnings
|
||||
$this->dictionaries=array(
|
||||
'langs'=>'mylangfile@api',
|
||||
'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor
|
||||
'tablib'=>array("Table1","Table2","Table3"), // Label of tables
|
||||
'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields
|
||||
'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order
|
||||
'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary)
|
||||
'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record)
|
||||
'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert)
|
||||
'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid')
|
||||
'tabcond'=>array($conf->api->enabled,$conf->api->enabled,$conf->api->enabled) // Condition to show each dictionary
|
||||
);
|
||||
*/
|
||||
|
||||
// Boxes
|
||||
// Add here list of php file(s) stored in core/boxes that contains class to show a box.
|
||||
$this->boxes = array(); // List of boxes
|
||||
// Example:
|
||||
//$this->boxes=array(array(0=>array('file'=>'myboxa.php','note'=>'','enabledbydefaulton'=>'Home'),1=>array('file'=>'myboxb.php','note'=>''),2=>array('file'=>'myboxc.php','note'=>'')););
|
||||
|
||||
// Permissions
|
||||
$this->rights = array(); // Permission array used by this module
|
||||
$r=0;
|
||||
|
||||
// Add here list of permission defined by an id, a label, a boolean and two constant strings.
|
||||
// Example:
|
||||
// $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used)
|
||||
// $this->rights[$r][1] = 'Permision label'; // Permission label
|
||||
// $this->rights[$r][3] = 1; // Permission by default for new user (0/1)
|
||||
// $this->rights[$r][4] = 'level1'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2)
|
||||
// $this->rights[$r][5] = 'level2'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2)
|
||||
// $r++;
|
||||
|
||||
|
||||
// Main menu entries
|
||||
$this->menu = array(); // List of menus to add
|
||||
$r=0;
|
||||
|
||||
// Add here entries to declare new menus
|
||||
//
|
||||
// Example to declare a new Top Menu entry and its Left menu entry:
|
||||
// $this->menu[$r]=array( 'fk_menu'=>0, // Put 0 if this is a top menu
|
||||
// 'type'=>'top', // This is a Top menu entry
|
||||
// 'titre'=>'Api top menu',
|
||||
// 'mainmenu'=>'api',
|
||||
// 'leftmenu'=>'api',
|
||||
// 'url'=>'/api/pagetop.php',
|
||||
// 'langs'=>'mylangfile@api', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
|
||||
// 'position'=>100,
|
||||
// 'enabled'=>'$conf->api->enabled', // Define condition to show or hide menu entry. Use '$conf->api->enabled' if entry must be visible if module is enabled.
|
||||
// 'perms'=>'1', // Use 'perms'=>'$user->rights->api->level1->level2' if you want your menu with a permission rules
|
||||
// 'target'=>'',
|
||||
// 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both
|
||||
// $r++;
|
||||
//
|
||||
// Example to declare a Left Menu entry into an existing Top menu entry:
|
||||
// $this->menu[$r]=array( 'fk_menu'=>'fk_mainmenu=xxx', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
|
||||
// 'type'=>'left', // This is a Left menu entry
|
||||
// 'titre'=>'Api left menu',
|
||||
// 'mainmenu'=>'xxx',
|
||||
// 'leftmenu'=>'api',
|
||||
// 'url'=>'/api/pagelevel2.php',
|
||||
// 'langs'=>'mylangfile@api', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
|
||||
// 'position'=>100,
|
||||
// 'enabled'=>'$conf->api->enabled', // Define condition to show or hide menu entry. Use '$conf->api->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
|
||||
// 'perms'=>'1', // Use 'perms'=>'$user->rights->api->level1->level2' if you want your menu with a permission rules
|
||||
// 'target'=>'',
|
||||
// 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both
|
||||
// $r++;
|
||||
|
||||
|
||||
// Exports
|
||||
$r=1;
|
||||
|
||||
// Example:
|
||||
// $this->export_code[$r]=$this->rights_class.'_'.$r;
|
||||
// $this->export_label[$r]='CustomersInvoicesAndInvoiceLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
|
||||
// $this->export_enabled[$r]='1'; // Condition to show export in list (ie: '$user->id==3'). Set to 1 to always show when module is enabled.
|
||||
// $this->export_permission[$r]=array(array("facture","facture","export"));
|
||||
// $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'CompanyName','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','s.fk_pays'=>'Country','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','s.code_compta'=>'CustomerAccountancyCode','s.code_compta_fournisseur'=>'SupplierAccountancyCode','f.rowid'=>"InvoiceId",'f.facnumber'=>"InvoiceRef",'f.datec'=>"InvoiceDateCreation",'f.datef'=>"DateInvoice",'f.total'=>"TotalHT",'f.total_ttc'=>"TotalTTC",'f.tva'=>"TotalVAT",'f.paye'=>"InvoicePaid",'f.fk_statut'=>'InvoiceStatus','f.note'=>"InvoiceNote",'fd.rowid'=>'LineId','fd.description'=>"LineDescription",'fd.price'=>"LineUnitPrice",'fd.tva_tx'=>"LineVATRate",'fd.qty'=>"LineQty",'fd.total_ht'=>"LineTotalHT",'fd.total_tva'=>"LineTotalTVA",'fd.total_ttc'=>"LineTotalTTC",'fd.date_start'=>"DateStart",'fd.date_end'=>"DateEnd",'fd.fk_product'=>'ProductId','p.ref'=>'ProductRef');
|
||||
// $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','s.fk_pays'=>'company','s.phone'=>'company','s.siren'=>'company','s.siret'=>'company','s.ape'=>'company','s.idprof4'=>'company','s.code_compta'=>'company','s.code_compta_fournisseur'=>'company','f.rowid'=>"invoice",'f.facnumber'=>"invoice",'f.datec'=>"invoice",'f.datef'=>"invoice",'f.total'=>"invoice",'f.total_ttc'=>"invoice",'f.tva'=>"invoice",'f.paye'=>"invoice",'f.fk_statut'=>'invoice','f.note'=>"invoice",'fd.rowid'=>'invoice_line','fd.description'=>"invoice_line",'fd.price'=>"invoice_line",'fd.total_ht'=>"invoice_line",'fd.total_tva'=>"invoice_line",'fd.total_ttc'=>"invoice_line",'fd.tva_tx'=>"invoice_line",'fd.qty'=>"invoice_line",'fd.date_start'=>"invoice_line",'fd.date_end'=>"invoice_line",'fd.fk_product'=>'product','p.ref'=>'product');
|
||||
// $this->export_sql_start[$r]='SELECT DISTINCT ';
|
||||
// $this->export_sql_end[$r] =' FROM ('.MAIN_DB_PREFIX.'facture as f, '.MAIN_DB_PREFIX.'facturedet as fd, '.MAIN_DB_PREFIX.'societe as s)';
|
||||
// $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on (fd.fk_product = p.rowid)';
|
||||
// $this->export_sql_end[$r] .=' WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture';
|
||||
// $this->export_sql_order[$r] .=' ORDER BY s.nom';
|
||||
// $r++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when module is enabled.
|
||||
* The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database.
|
||||
* It also creates data directories
|
||||
*
|
||||
* @param string $options Options when enabling module ('', 'noboxes')
|
||||
* @return int 1 if OK, 0 if KO
|
||||
*/
|
||||
function init($options='')
|
||||
{
|
||||
$sql = array();
|
||||
|
||||
$result=$this->_load_tables('/api/sql/');
|
||||
|
||||
return $this->_init($sql, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when module is disabled.
|
||||
* Remove from database constants, boxes and permissions from Dolibarr database.
|
||||
* Data directories are not deleted
|
||||
*
|
||||
* @param string $options Options when enabling module ('', 'noboxes')
|
||||
* @return int 1 if OK, 0 if KO
|
||||
*/
|
||||
function remove($options='')
|
||||
{
|
||||
$sql = array();
|
||||
|
||||
return $this->_remove($sql, $options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,27 +42,27 @@
|
||||
|
||||
if (GETPOST('type') == "separate")
|
||||
{
|
||||
print "jQuery('#size, #unique, #required, #default_value').val('').attr('disabled','disabled');";
|
||||
print "jQuery('#size, #unique, #required, #default_value').val('').prop('disabled', true);";
|
||||
print 'jQuery("#value_choice").hide();';
|
||||
}
|
||||
?>
|
||||
|
||||
if (type == 'date') { size.val('').attr('disabled','disabled'); unique.removeAttr('disabled','disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide(); }
|
||||
else if (type == 'datetime') { size.val('').attr('disabled','disabled'); unique.removeAttr('disabled','disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
|
||||
if (type == 'date') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide(); }
|
||||
else if (type == 'datetime') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
|
||||
else if (type == 'double') { size.val('24,8').removeAttr('disabled'); unique.removeAttr('disabled','disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
|
||||
else if (type == 'int') { size.val('10').removeAttr('disabled'); unique.removeAttr('disabled','disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
|
||||
else if (type == 'text') { size.val('2000').removeAttr('disabled'); unique.attr('disabled','disabled').removeAttr('checked'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide(); }
|
||||
else if (type == 'int') { size.val('10').removeAttr('disabled'); unique.removeAttr('disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
|
||||
else if (type == 'text') { size.val('2000').removeAttr('disabled'); unique.prop('disabled', true).removeAttr('checked'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide(); }
|
||||
else if (type == 'varchar') { size.val('255').removeAttr('disabled'); unique.removeAttr('disabled','disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide(); }
|
||||
else if (type == 'boolean') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide();}
|
||||
else if (type == 'price') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide();}
|
||||
else if (type == 'select') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else if (type == 'link') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").show();}
|
||||
else if (type == 'sellist') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").show();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else if (type == 'radio') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else if (type == 'checkbox') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else if (type == 'chkbxlst') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").show();jQuery("#helplink").hide();}
|
||||
else if (type == 'separate') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); required.val('').attr('disabled','disabled'); default_value.val('').attr('disabled','disabled'); jQuery("#value_choice").hide();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else size.val('').attr('disabled','disabled');
|
||||
else if (type == 'boolean') { size.val('').prop('disabled', true); unique.prop('disabled', true); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide();}
|
||||
else if (type == 'price') { size.val('').prop('disabled', true); unique.prop('disabled', true); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide();}
|
||||
else if (type == 'select') { size.val('').prop('disabled', true); unique.prop('disabled', true); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else if (type == 'link') { size.val('').prop('disabled', true); unique.prop('disabled', true); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").show();}
|
||||
else if (type == 'sellist') { size.val('').prop('disabled', true); unique.prop('disabled', true); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").show();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else if (type == 'radio') { size.val('').prop('disabled', true); unique.prop('disabled', true); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else if (type == 'checkbox') { size.val('').prop('disabled', true); unique.prop('disabled', true); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else if (type == 'chkbxlst') { size.val('').prop('disabled', true); unique.prop('disabled', true); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").show();jQuery("#helplink").hide();}
|
||||
else if (type == 'separate') { size.val('').prop('disabled', true); unique.prop('disabled', true); required.val('').prop('disabled', true); default_value.val('').prop('disabled', true); jQuery("#value_choice").hide();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
|
||||
else size.val('').prop('disabled', true);
|
||||
}
|
||||
init_typeoffields('<?php echo GETPOST('type'); ?>');
|
||||
jQuery("#type").change(function() {
|
||||
|
||||
@@ -25,15 +25,15 @@
|
||||
var size = jQuery("#size");
|
||||
var unique = jQuery("#unique");
|
||||
var required = jQuery("#required");
|
||||
if (type == 'date') { size.attr('disabled','disabled'); }
|
||||
else if (type == 'datetime') { size.attr('disabled','disabled'); }
|
||||
if (type == 'date') { size.prop('disabled', true); }
|
||||
else if (type == 'datetime') { size.prop('disabled', true); }
|
||||
else if (type == 'double') { size.removeAttr('disabled'); }
|
||||
else if (type == 'int') { size.removeAttr('disabled'); }
|
||||
else if (type == 'text') { size.removeAttr('disabled'); unique.attr('disabled','disabled').removeAttr('checked'); }
|
||||
else if (type == 'text') { size.removeAttr('disabled'); unique.prop('disabled', true).removeAttr('checked'); }
|
||||
else if (type == 'varchar') { size.removeAttr('disabled'); }
|
||||
else if (type == 'boolean') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled');}
|
||||
else if (type == 'price') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled');}
|
||||
else size.val('').attr('disabled','disabled');
|
||||
else if (type == 'boolean') { size.val('').prop('disabled', true); unique.prop('disabled', true);}
|
||||
else if (type == 'price') { size.val('').prop('disabled', true); unique.prop('disabled', true);}
|
||||
else size.val('').prop('disabled', true);
|
||||
}
|
||||
init_typeoffields(jQuery("#type").val());
|
||||
});
|
||||
|
||||
@@ -583,8 +583,8 @@ function setforfree() {
|
||||
jQuery("#idprod").val('');
|
||||
jQuery("#idprodfournprice").val('0'); // Set cursor on not selected product
|
||||
jQuery("#search_idprodfournprice").val('');
|
||||
jQuery("#prod_entry_mode_free").attr('checked',true);
|
||||
jQuery("#prod_entry_mode_predef").attr('checked',false);
|
||||
jQuery("#prod_entry_mode_free").prop('checked',true);
|
||||
jQuery("#prod_entry_mode_predef").prop('checked',false);
|
||||
jQuery("#price_ht").show();
|
||||
jQuery("#price_ttc").show(); // May no exists
|
||||
jQuery("#tva_tx").show();
|
||||
@@ -601,8 +601,8 @@ function setforfree() {
|
||||
}
|
||||
function setforpredef() {
|
||||
jQuery("#select_type").val(-1);
|
||||
jQuery("#prod_entry_mode_free").attr('checked',false);
|
||||
jQuery("#prod_entry_mode_predef").attr('checked',true);
|
||||
jQuery("#prod_entry_mode_free").prop('checked',false);
|
||||
jQuery("#prod_entry_mode_predef").prop('checked',true);
|
||||
jQuery("#price_ht").hide();
|
||||
jQuery("#title_up_ht").hide();
|
||||
jQuery("#price_ttc").hide(); // May no exists
|
||||
|
||||
@@ -99,7 +99,7 @@ $coldisplay=-1; // We remove first td
|
||||
$doleditor=new DolEditor('product_desc',$line->description,'',164,$toolbarname,'',false,true,$enable,$nbrows,'98%');
|
||||
$doleditor->Create();
|
||||
} else {
|
||||
print '<textarea id="desc" class="flat" name="desc" readonly="readonly" style="width: 200px; height:80px;">' . $line->description . '</textarea>';
|
||||
print '<textarea id="desc" class="flat" name="desc" readonly style="width: 200px; height:80px;">' . $line->description . '</textarea>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
@@ -113,19 +113,19 @@ $coldisplay=-1; // We remove first td
|
||||
if ($this->situation_counter == 1 || !$this->situation_cycle_ref) {
|
||||
print '<td align="right">' . $form->load_tva('tva_tx',$line->tva_tx,$seller,$buyer,0,$line->info_bits,$line->product_type) . '</td>';
|
||||
} else {
|
||||
print '<td align="right"><input size="1" type="text" class="flat" name="tva_tx" value="' . price($line->tva_tx) . '" readonly="readonly" />%</td>';
|
||||
print '<td align="right"><input size="1" type="text" class="flat" name="tva_tx" value="' . price($line->tva_tx) . '" readonly />%</td>';
|
||||
}
|
||||
|
||||
$coldisplay++;
|
||||
print '<td align="right"><input type="text" class="flat" size="8" id="price_ht" name="price_ht" value="' . (isset($line->pu_ht)?price($line->pu_ht,0,'',0):price($line->subprice,0,'',0)) . '"';
|
||||
if ($this->situation_counter > 1) print ' readonly="readonly"';
|
||||
if ($this->situation_counter > 1) print ' readonly';
|
||||
print '></td>';
|
||||
|
||||
if ($inputalsopricewithtax)
|
||||
{
|
||||
$coldisplay++;
|
||||
print '<td align="right"><input type="text" class="flat" size="8" id="price_ttc" name="price_ttc" value="'.(isset($line->pu_ttc)?price($line->pu_ttc,0,'',0):'').'"';
|
||||
if ($this->situation_counter > 1) print ' readonly="readonly"';
|
||||
if ($this->situation_counter > 1) print ' readonly';
|
||||
print '></td>';
|
||||
}
|
||||
?>
|
||||
@@ -136,7 +136,7 @@ $coldisplay=-1; // We remove first td
|
||||
// must also not be output for most entities (proposal, intervention, ...)
|
||||
//if($line->qty > $line->stock) print img_picto($langs->trans("StockTooLow"),"warning", 'style="vertical-align: bottom;"')." ";
|
||||
print '<input size="3" type="text" class="flat" name="qty" id="qty" value="' . $line->qty . '"';
|
||||
if ($this->situation_counter > 1) print ' readonly="readonly"';
|
||||
if ($this->situation_counter > 1) print ' readonly';
|
||||
print '>';
|
||||
} else { ?>
|
||||
|
||||
@@ -152,10 +152,10 @@ $coldisplay=-1; // We remove first td
|
||||
}
|
||||
?>
|
||||
|
||||
<td align="right" nowrap><?php $coldisplay++; ?>
|
||||
<td align="right" class="nowrap"><?php $coldisplay++; ?>
|
||||
<?php if (($line->info_bits & 2) != 2) {
|
||||
print '<input size="1" type="text" class="flat" name="remise_percent" id="remise_percent" value="' . $line->remise_percent . '"';
|
||||
if ($this->situation_counter > 1) print ' readonly="readonly"';
|
||||
if ($this->situation_counter > 1) print ' readonly';
|
||||
print '>%';
|
||||
} else { ?>
|
||||
|
||||
@@ -164,7 +164,7 @@ $coldisplay=-1; // We remove first td
|
||||
<?php
|
||||
if ($this->situation_cycle_ref) {
|
||||
$coldisplay++;
|
||||
print '<td align="right" nowrap><input type="text" size="1" value="' . $line->situation_percent . '" name="progress">%</td>';
|
||||
print '<td align="right" class="nowrap"><input type="text" size="1" value="' . $line->situation_percent . '" name="progress">%</td>';
|
||||
}
|
||||
if (! empty($usemargins))
|
||||
{
|
||||
|
||||
@@ -148,7 +148,7 @@ if (empty($usemargins)) $usemargins=0;
|
||||
<?php
|
||||
if($conf->global->PRODUCT_USE_UNITS)
|
||||
{
|
||||
print '<td align="left" nowrap="nowrap">';
|
||||
print '<td align="left" class="nowrap">';
|
||||
$label = $line->getLabelOfUnit('short');
|
||||
if ($label !== '') {
|
||||
print $langs->trans($label);
|
||||
@@ -169,7 +169,7 @@ if (empty($usemargins)) $usemargins=0;
|
||||
|
||||
if ($this->situation_cycle_ref) {
|
||||
$coldisplay++;
|
||||
print '<td align="right" nowrap="nowrap">' . $line->situation_percent . '%</td>';
|
||||
print '<td align="right" class="nowrap">' . $line->situation_percent . '%</td>';
|
||||
}
|
||||
|
||||
if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id))
|
||||
|
||||
@@ -93,7 +93,7 @@ if ($resql)
|
||||
{
|
||||
$var=!$var;
|
||||
$obj = $db->fetch_object($resql);
|
||||
print "<tr ".$bc[$var]."><td nowrap=\"nowrap\">";
|
||||
print "<tr ".$bc[$var].'><td class="nowrap">';
|
||||
$shipment->id=$obj->rowid;
|
||||
$shipment->ref=$obj->ref;
|
||||
print $shipment->getNomUrl(1);
|
||||
|
||||
@@ -386,10 +386,10 @@ if (($action != 'create' && $action != 'add') || ! empty($mesgs)) {
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function() {
|
||||
jQuery("#checkall").click(function() {
|
||||
jQuery(".checkformerge").attr('checked', true);
|
||||
jQuery(".checkformerge").prop('checked', true);
|
||||
});
|
||||
jQuery("#checknone").click(function() {
|
||||
jQuery(".checkformerge").attr('checked', false);
|
||||
jQuery(".checkformerge").prop('checked', false);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
|
||||
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
|
||||
* Copyright (C) 2015 juanjo Menent <jmenent@2byte.es>
|
||||
*
|
||||
* Copyright (C) 2015 Abbes Bahfir <bafbes@gmail.com>
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
|
||||
114
htdocs/includes/restler/ApcCache.php
Normal file
114
htdocs/includes/restler/ApcCache.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Luracast\Restler\iCache;
|
||||
|
||||
/**
|
||||
* Class ApcCache provides an APC based cache for Restler
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author Joel R. Simpson <joel.simpson@gmail.com>
|
||||
* @copyright 2013 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class ApcCache implements iCache
|
||||
{
|
||||
/**
|
||||
* The namespace that all of the cached entries will be stored under. This allows multiple APIs to run concurrently.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static public $namespace = 'restler';
|
||||
|
||||
/**
|
||||
* store data in the cache
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return boolean true if successful
|
||||
*/
|
||||
public function set($name, $data)
|
||||
{
|
||||
function_exists('apc_store') || $this->apcNotAvailable();
|
||||
|
||||
try {
|
||||
return apc_store(self::$namespace . "-" . $name, $data);
|
||||
} catch
|
||||
(\Exception $exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function apcNotAvailable()
|
||||
{
|
||||
throw new \Exception('APC is not available for use as Restler Cache. Please make sure the module is installed. http://php.net/manual/en/apc.installation.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve data from the cache
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $ignoreErrors
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $ignoreErrors = false)
|
||||
{
|
||||
function_exists('apc_fetch') || $this->apcNotAvailable();
|
||||
|
||||
try {
|
||||
return apc_fetch(self::$namespace . "-" . $name);
|
||||
} catch (\Exception $exception) {
|
||||
if (!$ignoreErrors) {
|
||||
throw $exception;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete data from the cache
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $ignoreErrors
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return boolean true if successful
|
||||
*/
|
||||
public function clear($name, $ignoreErrors = false)
|
||||
{
|
||||
function_exists('apc_delete') || $this->apcNotAvailable();
|
||||
|
||||
try {
|
||||
apc_delete(self::$namespace . "-" . $name);
|
||||
} catch (\Exception $exception) {
|
||||
if (!$ignoreErrors) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the given name is cached
|
||||
*
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return boolean true if cached
|
||||
*/
|
||||
public function isCached($name)
|
||||
{
|
||||
function_exists('apc_exists') || $this->apcNotAvailable();
|
||||
return apc_exists(self::$namespace . "-" . $name);
|
||||
}
|
||||
|
||||
}
|
||||
438
htdocs/includes/restler/AutoLoader.php
Normal file
438
htdocs/includes/restler/AutoLoader.php
Normal file
@@ -0,0 +1,438 @@
|
||||
<?php
|
||||
namespace Luracast\Restler {
|
||||
|
||||
/**
|
||||
* Class that implements spl_autoload facilities and multiple
|
||||
* conventions support.
|
||||
* Supports composer libraries and 100% PSR-0 compliant.
|
||||
* In addition we enable namespace prefixing and class aliases.
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage helper
|
||||
* @author Nick Lombard <github@jigsoft.co.za>
|
||||
* @copyright 2012 Luracast
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class AutoLoader
|
||||
{
|
||||
protected static $instance, // the singleton instance reference
|
||||
$perfectLoaders, // used to keep the ideal list of loaders
|
||||
$rogueLoaders = array(), // other auto loaders now unregistered
|
||||
$classMap = array(), // the class to include file mapping
|
||||
$aliases = array( // aliases and prefixes instead of null list aliases
|
||||
'Luracast\\Restler' => null,
|
||||
'Luracast\\Restler\\Format' => null,
|
||||
'Luracast\\Restler\\Data' => null,
|
||||
'Luracast\\Restler\\Filter' => null,
|
||||
);
|
||||
|
||||
/**
|
||||
* Singleton instance facility.
|
||||
*
|
||||
* @static
|
||||
* @return AutoLoader the current instance or new instance if none exists.
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static::$instance = static::$instance ?: new static();
|
||||
return static::thereCanBeOnlyOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to add a path to the include path.
|
||||
* AutoLoader uses the include path to discover classes.
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param $path string absolute or relative path.
|
||||
*
|
||||
* @return bool false if the path cannot be resolved
|
||||
* or the resolved absolute path.
|
||||
*/
|
||||
public static function addPath($path) {
|
||||
if (false === $path = stream_resolve_include_path($path))
|
||||
return false;
|
||||
else
|
||||
set_include_path($path.PATH_SEPARATOR.get_include_path());
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Other autoLoaders interfere and cause duplicate class loading.
|
||||
* AutoLoader is capable enough to handle all standards so no need
|
||||
* for others stumbling about.
|
||||
*
|
||||
* @return callable the one true auto loader.
|
||||
*/
|
||||
public static function thereCanBeOnlyOne() {
|
||||
if (static::$perfectLoaders === spl_autoload_functions())
|
||||
return static::$instance;
|
||||
|
||||
if (false !== $loaders = spl_autoload_functions())
|
||||
if (0 < $count = count($loaders))
|
||||
for ($i = 0, static::$rogueLoaders += $loaders;
|
||||
$i < $count && false != ($loader = $loaders[$i]);
|
||||
$i++)
|
||||
if ($loader !== static::$perfectLoaders[0])
|
||||
spl_autoload_unregister($loader);
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seen this before cache handler.
|
||||
* Facilitates both lookup and persist operations as well as convenience,
|
||||
* load complete map functionality. The key can only be given a non falsy
|
||||
* value once, this will be truthy for life.
|
||||
*
|
||||
* @param $key mixed class name considered or a collection of
|
||||
* classMap entries
|
||||
* @param $value mixed optional not required when doing a query on
|
||||
* key. Default is false we haven't seen this
|
||||
* class. Most of the time it will be the filename
|
||||
* for include and is set to true if we are unable
|
||||
* to load this class iow true == it does not exist.
|
||||
* value may also be a callable auto loader function.
|
||||
*
|
||||
* @return mixed The known value for the key or false if key has no value
|
||||
*/
|
||||
public static function seen($key, $value = false)
|
||||
{
|
||||
if (is_array($key)) {
|
||||
static::$classMap = $key + static::$classMap;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty(static::$classMap[$key]))
|
||||
static::$classMap[$key] = $value;
|
||||
|
||||
if (is_string($alias = static::$classMap[$key]))
|
||||
if (isset(static::$classMap[$alias]))
|
||||
return static::$classMap[$alias];
|
||||
|
||||
return static::$classMap[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected constructor to enforce singleton pattern.
|
||||
* Populate a default include path.
|
||||
* All possible includes cant possibly be catered for and if you
|
||||
* require another path then simply add it calling set_include_path.
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
static::$perfectLoaders = array($this);
|
||||
|
||||
if (false === static::seen('__include_path')) {
|
||||
|
||||
$paths = explode(PATH_SEPARATOR, get_include_path());
|
||||
$slash = DIRECTORY_SEPARATOR;
|
||||
$dir = dirname(__DIR__);
|
||||
$source_dir = dirname($dir);
|
||||
$dir = dirname($source_dir);
|
||||
|
||||
foreach (
|
||||
array(
|
||||
array($source_dir),
|
||||
array($dir, '..', '..', 'composer'),
|
||||
array($dir, 'vendor', 'composer'),
|
||||
array($dir, '..', '..', '..', 'php'),
|
||||
array($dir, 'vendor', 'php'))
|
||||
as $includePath)
|
||||
if (false !== $path = stream_resolve_include_path(
|
||||
implode($slash, $includePath)
|
||||
))
|
||||
if ('composer' == end($includePath) &&
|
||||
false !== $classmapPath = stream_resolve_include_path(
|
||||
"$path{$slash}autoload_classmap.php"
|
||||
)
|
||||
) {
|
||||
static::seen(static::loadFile(
|
||||
$classmapPath
|
||||
));
|
||||
$paths = array_merge(
|
||||
$paths,
|
||||
array_values(static::loadFile(
|
||||
"$path{$slash}autoload_namespaces.php"
|
||||
))
|
||||
);
|
||||
} else
|
||||
$paths[] = $path;
|
||||
|
||||
$paths = array_filter(array_map(
|
||||
function ($path) {
|
||||
if (false == $realPath = @realpath($path))
|
||||
return null;
|
||||
return $realPath . DIRECTORY_SEPARATOR;
|
||||
},
|
||||
$paths
|
||||
));
|
||||
natsort($paths);
|
||||
static::seen(
|
||||
'__include_path',
|
||||
implode(PATH_SEPARATOR, array_unique($paths))
|
||||
);
|
||||
}
|
||||
|
||||
set_include_path(static::seen('__include_path'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to include the path location.
|
||||
* Called from a static context which will not expose the AutoLoader
|
||||
* instance itself.
|
||||
*
|
||||
* @param $path string location of php file on the include path
|
||||
*
|
||||
* @return bool|mixed returns reference obtained from the include or false
|
||||
*/
|
||||
private static function loadFile($path)
|
||||
{
|
||||
return \Luracast_Restler_autoloaderInclude($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to load class with namespace prefixes.
|
||||
*
|
||||
* @param $className string class name
|
||||
*
|
||||
* @return bool|mixed reference to discovered include or false
|
||||
*/
|
||||
private function loadPrefixes($className)
|
||||
{
|
||||
$currentClass = $className;
|
||||
if (false !== $pos = strrpos($className, '\\'))
|
||||
$className = substr($className, $pos);
|
||||
else
|
||||
$className = "\\$className";
|
||||
|
||||
for (
|
||||
$i = 0,
|
||||
$file = false,
|
||||
$count = count(static::$aliases),
|
||||
$prefixes = array_keys(static::$aliases);
|
||||
$i < $count
|
||||
&& false === $file
|
||||
&& false === $file = $this->discover(
|
||||
$variant = $prefixes[$i++].$className,
|
||||
$currentClass
|
||||
);
|
||||
$file = $this->loadAliases($variant)
|
||||
);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to load configured aliases based on namespace part of class name.
|
||||
*
|
||||
* @param $className string fully qualified class name.
|
||||
*
|
||||
* @return bool|mixed reference to discovered include or false
|
||||
*/
|
||||
private function loadAliases($className)
|
||||
{
|
||||
$file = false;
|
||||
if (preg_match('/(.+)(\\\\\w+$)/U', $className, $parts))
|
||||
for (
|
||||
$i = 0,
|
||||
$aliases = isset(static::$aliases[$parts[1]])
|
||||
? static::$aliases[$parts[1]] : array(),
|
||||
$count = count($aliases);
|
||||
$i < $count && false === $file;
|
||||
$file = $this->discover(
|
||||
"{$aliases[$i++]}$parts[2]",
|
||||
$className
|
||||
)
|
||||
) ;
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from rogueLoaders as last resort.
|
||||
* It may happen that a custom auto loader may load classes in a unique way,
|
||||
* these classes cannot be seen otherwise nor should we attempt to cover every
|
||||
* possible deviation. If we still can't find a class, as a last resort, we will
|
||||
* run through the list of rogue loaders and verify if we succeeded.
|
||||
*
|
||||
* @param $className string className that can't be found
|
||||
* @param null $loader callable loader optional when the loader is known
|
||||
*
|
||||
* @return bool false unless className now exists
|
||||
*/
|
||||
private function loadLastResort($className, $loader = null) {
|
||||
$loaders = array_unique(static::$rogueLoaders);
|
||||
if (isset($loader)) {
|
||||
if (false === array_search($loader, $loaders))
|
||||
static::$rogueLoaders[] = $loader;
|
||||
return $this->loadThisLoader($className, $loader);
|
||||
}
|
||||
foreach ($loaders as $loader)
|
||||
if (false !== $file = $this->loadThisLoader($className, $loader))
|
||||
return $file;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for loadLastResort.
|
||||
* Use loader with $className and see if className exists.
|
||||
*
|
||||
* @param $className string name of a class to load
|
||||
* @param $loader callable autoLoader method
|
||||
*
|
||||
* @return bool false unless className exists
|
||||
*/
|
||||
private function loadThisLoader($className, $loader) {
|
||||
if (is_callable($loader)
|
||||
&& false !== $file = $loader($className)
|
||||
&& $this->exists($className, $loader))
|
||||
return $file;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alias for class.
|
||||
*
|
||||
* @param $className string the name of the alias class
|
||||
* @param $currentClass string the current class this alias references
|
||||
*/
|
||||
private function alias($className, $currentClass)
|
||||
{
|
||||
if ($className != $currentClass
|
||||
&& false !== strpos($className, $currentClass))
|
||||
if (!class_exists($currentClass, false)
|
||||
&& class_alias($className, $currentClass))
|
||||
static::seen($currentClass, $className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovery process.
|
||||
*
|
||||
* @param $className string class name to discover
|
||||
* @param $currentClass string optional name of current class when
|
||||
* looking up an alias
|
||||
*
|
||||
* @return bool|mixed resolved include reference or false
|
||||
*/
|
||||
private function discover($className, $currentClass = null)
|
||||
{
|
||||
$currentClass = $currentClass ?: $className;
|
||||
|
||||
/** The short version we've done this before and found it in cache */
|
||||
if (false !== $file = static::seen($className)) {
|
||||
if (!$this->exists($className))
|
||||
if (is_callable($file))
|
||||
$file = $this->loadLastResort($className, $file);
|
||||
elseif($file = stream_resolve_include_path($file))
|
||||
$file = static::loadFile($file);
|
||||
|
||||
$this->alias($className, $currentClass);
|
||||
return $file;
|
||||
}
|
||||
|
||||
/** We did not find it in cache, lets look for it shall we */
|
||||
|
||||
/** replace \ with / and _ in CLASS NAME with / = PSR-0 in 3 lines */
|
||||
$file = preg_replace("/\\\|_(?=\w+$)/", DIRECTORY_SEPARATOR, $className);
|
||||
if (false === $file = stream_resolve_include_path("$file.php"))
|
||||
return false;
|
||||
|
||||
/** have we loaded this file before could this be an alias */
|
||||
if (in_array($file, get_included_files())) {
|
||||
if (false !== $sameFile = array_search($file, static::$classMap))
|
||||
if (!$this->exists($className, $file))
|
||||
if (false !== strpos($sameFile, $className))
|
||||
$this->alias($sameFile, $className);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
$state = array_merge(get_declared_classes(), get_declared_interfaces());
|
||||
|
||||
if (false !== $result = static::loadFile($file)) {
|
||||
|
||||
if ($this->exists($className, $file))
|
||||
$this->alias($className, $currentClass);
|
||||
elseif (false != $diff = array_diff(
|
||||
array_merge(get_declared_classes(), get_declared_interfaces()), $state))
|
||||
foreach ($diff as $autoLoaded)
|
||||
if ($this->exists($autoLoaded, $file))
|
||||
if (false !== strpos($autoLoaded, $className))
|
||||
$this->alias($autoLoaded, $className);
|
||||
|
||||
if (!$this->exists($currentClass))
|
||||
$result = false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether supplied string exists in a loaded class or interface.
|
||||
* As a convenience the supplied $mapping can be the value for seen.
|
||||
*
|
||||
* @param $className string The class or interface to verify
|
||||
* @param $mapping string (optional) value for map/seen if found to exist
|
||||
*
|
||||
* @return bool whether the class/interface exists without calling auto loader
|
||||
*/
|
||||
private function exists($className, $mapping = null)
|
||||
{
|
||||
if (class_exists($className, false)
|
||||
|| interface_exists($className, false))
|
||||
if (isset($mapping))
|
||||
return static::seen($className, $mapping);
|
||||
else
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto loader callback through __invoke object as function.
|
||||
*
|
||||
* @param $className string class/interface name to auto load
|
||||
*
|
||||
* @return mixed|null the reference from the include or null
|
||||
*/
|
||||
public function __invoke($className)
|
||||
{
|
||||
if (empty($className))
|
||||
return false;
|
||||
|
||||
if (false !== $includeReference = $this->discover($className))
|
||||
return $includeReference;
|
||||
|
||||
static::thereCanBeOnlyOne();
|
||||
|
||||
if (false !== $includeReference = $this->loadAliases($className))
|
||||
return $includeReference;
|
||||
|
||||
if (false !== $includeReference = $this->loadPrefixes($className))
|
||||
return $includeReference;
|
||||
|
||||
if (false !== $includeReference = $this->loadLastResort($className))
|
||||
return $includeReference;
|
||||
|
||||
static::seen($className, true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Include function in the root namespace to include files optimized
|
||||
* for the global context.
|
||||
*
|
||||
* @param $path string path of php file to include into the global context.
|
||||
*
|
||||
* @return mixed|bool false if the file could not be included.
|
||||
*/
|
||||
function Luracast_Restler_autoloaderInclude($path) {
|
||||
return include $path;
|
||||
}
|
||||
}
|
||||
|
||||
466
htdocs/includes/restler/CommentParser.php
Normal file
466
htdocs/includes/restler/CommentParser.php
Normal file
@@ -0,0 +1,466 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Parses the PHPDoc comments for metadata. Inspired by `Documentor` code base.
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage Helper
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class CommentParser
|
||||
{
|
||||
/**
|
||||
* name for the embedded data
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $embeddedDataName = 'properties';
|
||||
/**
|
||||
* Regular Expression pattern for finding the embedded data and extract
|
||||
* the inner information. It is used with preg_match.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $embeddedDataPattern
|
||||
= '/```(\w*)[\s]*(([^`]*`{0,2}[^`]+)*)```/ms';
|
||||
/**
|
||||
* Pattern will have groups for the inner details of embedded data
|
||||
* this index is used to locate the data portion.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $embeddedDataIndex = 2;
|
||||
/**
|
||||
* Delimiter used to split the array data.
|
||||
*
|
||||
* When the name portion is of the embedded data is blank auto detection
|
||||
* will be used and if URLEncodedFormat is detected as the data format
|
||||
* the character specified will be used as the delimiter to find split
|
||||
* array data.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $arrayDelimiter = ',';
|
||||
|
||||
/**
|
||||
* character sequence used to escape \@
|
||||
*/
|
||||
const escapedAtChar = '\\@';
|
||||
|
||||
/**
|
||||
* character sequence used to escape end of comment
|
||||
*/
|
||||
const escapedCommendEnd = '{@*}';
|
||||
|
||||
/**
|
||||
* Instance of Restler class injected at runtime.
|
||||
*
|
||||
* @var Restler
|
||||
*/
|
||||
public $restler;
|
||||
/**
|
||||
* Comment information is parsed and stored in to this array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_data = array();
|
||||
|
||||
/**
|
||||
* Parse the comment and extract the data.
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param $comment
|
||||
* @param bool $isPhpDoc
|
||||
*
|
||||
* @return array associative array with the extracted values
|
||||
*/
|
||||
public static function parse($comment, $isPhpDoc = true)
|
||||
{
|
||||
$p = new self();
|
||||
if (empty($comment)) {
|
||||
return $p->_data;
|
||||
}
|
||||
|
||||
if ($isPhpDoc) {
|
||||
$comment = self::removeCommentTags($comment);
|
||||
}
|
||||
|
||||
$p->extractData($comment);
|
||||
return $p->_data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the comment tags from each line of the comment.
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param string $comment PhpDoc style comment
|
||||
*
|
||||
* @return string comments with out the tags
|
||||
*/
|
||||
public static function removeCommentTags($comment)
|
||||
{
|
||||
$pattern = '/(^\/\*\*)|(^\s*\**[ \/]?)|\s(?=@)|\s\*\//m';
|
||||
return preg_replace($pattern, '', $comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts description and long description, uses other methods to get
|
||||
* parameters.
|
||||
*
|
||||
* @param $comment
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function extractData($comment)
|
||||
{
|
||||
//to use @ as part of comment we need to
|
||||
$comment = str_replace(
|
||||
array(self::escapedCommendEnd, self::escapedAtChar),
|
||||
array('*/', '@'),
|
||||
$comment);
|
||||
|
||||
$description = array();
|
||||
$longDescription = array();
|
||||
$params = array();
|
||||
|
||||
$mode = 0; // extract short description;
|
||||
$comments = preg_split("/(\r?\n)/", $comment);
|
||||
// remove first blank line;
|
||||
array_shift($comments);
|
||||
$addNewline = false;
|
||||
foreach ($comments as $line) {
|
||||
$line = trim($line);
|
||||
$newParam = false;
|
||||
if (empty ($line)) {
|
||||
if ($mode == 0) {
|
||||
$mode++;
|
||||
} else {
|
||||
$addNewline = true;
|
||||
}
|
||||
continue;
|
||||
} elseif ($line{0} == '@') {
|
||||
$mode = 2;
|
||||
$newParam = true;
|
||||
}
|
||||
switch ($mode) {
|
||||
case 0 :
|
||||
$description[] = $line;
|
||||
if (count($description) > 3) {
|
||||
// if more than 3 lines take only first line
|
||||
$longDescription = $description;
|
||||
$description[] = array_shift($longDescription);
|
||||
$mode = 1;
|
||||
} elseif (substr($line, -1) == '.') {
|
||||
$mode = 1;
|
||||
}
|
||||
break;
|
||||
case 1 :
|
||||
if ($addNewline) {
|
||||
$line = ' ' . $line;
|
||||
}
|
||||
$longDescription[] = $line;
|
||||
break;
|
||||
case 2 :
|
||||
$newParam
|
||||
? $params[] = $line
|
||||
: $params[count($params) - 1] .= ' ' . $line;
|
||||
}
|
||||
$addNewline = false;
|
||||
}
|
||||
$description = implode(' ', $description);
|
||||
$longDescription = implode(' ', $longDescription);
|
||||
$description = preg_replace('/\s+/msu', ' ', $description);
|
||||
$longDescription = preg_replace('/\s+/msu', ' ', $longDescription);
|
||||
list($description, $d1)
|
||||
= $this->parseEmbeddedData($description);
|
||||
list($longDescription, $d2)
|
||||
= $this->parseEmbeddedData($longDescription);
|
||||
$this->_data = compact('description', 'longDescription');
|
||||
$d2 += $d1;
|
||||
if (!empty($d2)) {
|
||||
$this->_data[self::$embeddedDataName] = $d2;
|
||||
}
|
||||
foreach ($params as $key => $line) {
|
||||
list(, $param, $value) = preg_split('/\@|\s/', $line, 3)
|
||||
+ array('', '', '');
|
||||
list($value, $embedded) = $this->parseEmbeddedData($value);
|
||||
$value = array_filter(preg_split('/\s+/msu', $value));
|
||||
$this->parseParam($param, $value, $embedded);
|
||||
}
|
||||
return $this->_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse parameters that begin with (at)
|
||||
*
|
||||
* @param $param
|
||||
* @param array $value
|
||||
* @param array $embedded
|
||||
*/
|
||||
private function parseParam($param, array $value, array $embedded)
|
||||
{
|
||||
$data = & $this->_data;
|
||||
$allowMultiple = false;
|
||||
switch ($param) {
|
||||
case 'param' :
|
||||
$value = $this->formatParam($value);
|
||||
$allowMultiple = true;
|
||||
break;
|
||||
case 'var' :
|
||||
$value = $this->formatVar($value);
|
||||
break;
|
||||
case 'return' :
|
||||
$value = $this->formatReturn($value);
|
||||
break;
|
||||
case 'class' :
|
||||
$data = & $data[$param];
|
||||
list ($param, $value) = $this->formatClass($value);
|
||||
break;
|
||||
case 'access' :
|
||||
$value = reset($value);
|
||||
break;
|
||||
case 'expires' :
|
||||
case 'status' :
|
||||
$value = intval(reset($value));
|
||||
break;
|
||||
case 'throws' :
|
||||
$value = $this->formatThrows($value);
|
||||
$allowMultiple = true;
|
||||
break;
|
||||
case 'author':
|
||||
$value = $this->formatAuthor($value);
|
||||
$allowMultiple = true;
|
||||
break;
|
||||
case 'header' :
|
||||
case 'link':
|
||||
case 'example':
|
||||
case 'todo':
|
||||
$allowMultiple = true;
|
||||
//don't break, continue with code for default:
|
||||
default :
|
||||
$value = implode(' ', $value);
|
||||
}
|
||||
if (!empty($embedded)) {
|
||||
if (is_string($value)) {
|
||||
$value = array('description' => $value);
|
||||
}
|
||||
$value[self::$embeddedDataName] = $embedded;
|
||||
}
|
||||
if (empty ($data[$param])) {
|
||||
if ($allowMultiple) {
|
||||
$data[$param] = array(
|
||||
$value
|
||||
);
|
||||
} else {
|
||||
$data[$param] = $value;
|
||||
}
|
||||
} elseif ($allowMultiple) {
|
||||
$data[$param][] = $value;
|
||||
} elseif ($param == 'param') {
|
||||
$arr = array(
|
||||
$data[$param],
|
||||
$value
|
||||
);
|
||||
$data[$param] = $arr;
|
||||
} else {
|
||||
if (!is_string($value) && isset($value[self::$embeddedDataName])
|
||||
&& isset($data[$param][self::$embeddedDataName])
|
||||
) {
|
||||
$value[self::$embeddedDataName]
|
||||
+= $data[$param][self::$embeddedDataName];
|
||||
}
|
||||
$data[$param] = $value + $data[$param];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the inline php doc comments and embedded data.
|
||||
*
|
||||
* @param $subject
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function parseEmbeddedData($subject)
|
||||
{
|
||||
$data = array();
|
||||
|
||||
//parse {@pattern } tags specially
|
||||
while (preg_match('|(?s-m)({@pattern (/.+/[imsxuADSUXJ]*)})|', $subject, $matches)) {
|
||||
$subject = str_replace($matches[0], '', $subject);
|
||||
$data['pattern'] = $matches[2];
|
||||
}
|
||||
while (preg_match('/{@(\w+)\s?([^}]*)}/ms', $subject, $matches)) {
|
||||
$subject = str_replace($matches[0], '', $subject);
|
||||
if ($matches[2] == 'true' || $matches[2] == 'false') {
|
||||
$matches[2] = $matches[2] == 'true';
|
||||
} elseif ($matches[2] == '') {
|
||||
$matches[2] = true;
|
||||
}
|
||||
if ($matches[1] == 'pattern') {
|
||||
throw new Exception('Inline pattern tag should follow {@pattern /REGEX_PATTERN_HERE/} format and can optionally include PCRE modifiers following the ending `/`');
|
||||
} elseif (false !== strpos($matches[2], static::$arrayDelimiter)) {
|
||||
$matches[2] = explode(static::$arrayDelimiter, $matches[2]);
|
||||
}
|
||||
$data[$matches[1]] = $matches[2];
|
||||
}
|
||||
|
||||
while (preg_match(self::$embeddedDataPattern, $subject, $matches)) {
|
||||
$subject = str_replace($matches[0], '', $subject);
|
||||
$str = $matches[self::$embeddedDataIndex];
|
||||
if (isset ($this->restler)
|
||||
&& self::$embeddedDataIndex > 1
|
||||
&& !empty ($matches[1])
|
||||
) {
|
||||
$extension = $matches[1];
|
||||
$formatMap = $this->restler->getFormatMap();
|
||||
if (isset ($formatMap[$extension])) {
|
||||
/**
|
||||
* @var \Luracast\Restler\Format\iFormat
|
||||
*/
|
||||
$format = $formatMap[$extension];
|
||||
$format = new $format();
|
||||
$data = $format->decode($str);
|
||||
}
|
||||
} else { // auto detect
|
||||
if ($str{0} == '{') {
|
||||
$d = json_decode($str, true);
|
||||
if (json_last_error() != JSON_ERROR_NONE) {
|
||||
throw new Exception('Error parsing embedded JSON data'
|
||||
. " $str");
|
||||
}
|
||||
$data = $d + $data;
|
||||
} else {
|
||||
parse_str($str, $d);
|
||||
//clean up
|
||||
$d = array_filter($d);
|
||||
foreach ($d as $key => $val) {
|
||||
$kt = trim($key);
|
||||
if ($kt != $key) {
|
||||
unset($d[$key]);
|
||||
$key = $kt;
|
||||
$d[$key] = $val;
|
||||
}
|
||||
if (is_string($val)) {
|
||||
if ($val == 'true' || $val == 'false') {
|
||||
$d[$key] = $val == 'true' ? true : false;
|
||||
} else {
|
||||
$val = explode(self::$arrayDelimiter, $val);
|
||||
if (count($val) > 1) {
|
||||
$d[$key] = $val;
|
||||
} else {
|
||||
$d[$key] =
|
||||
preg_replace('/\s+/msu', ' ',
|
||||
$d[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$data = $d + $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array($subject, $data);
|
||||
}
|
||||
|
||||
private function formatThrows(array $value)
|
||||
{
|
||||
$r = array();
|
||||
$r['code'] = count($value) && is_numeric($value[0])
|
||||
? intval(array_shift($value)) : 500;
|
||||
$reason = implode(' ', $value);
|
||||
$r['reason'] = empty($reason) ? '' : $reason;
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function formatClass(array $value)
|
||||
{
|
||||
$param = array_shift($value);
|
||||
|
||||
if (empty($param)) {
|
||||
$param = 'Unknown';
|
||||
}
|
||||
$value = implode(' ', $value);
|
||||
return array(
|
||||
ltrim($param, '\\'),
|
||||
array('description' => $value)
|
||||
);
|
||||
}
|
||||
|
||||
private function formatAuthor(array $value)
|
||||
{
|
||||
$r = array();
|
||||
$email = end($value);
|
||||
if ($email{0} == '<') {
|
||||
$email = substr($email, 1, -1);
|
||||
array_pop($value);
|
||||
$r['email'] = $email;
|
||||
}
|
||||
$r['name'] = implode(' ', $value);
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function formatReturn(array $value)
|
||||
{
|
||||
$data = explode('|', array_shift($value));
|
||||
$r = array(
|
||||
'type' => count($data) == 1 ? $data[0] : $data
|
||||
);
|
||||
$r['description'] = implode(' ', $value);
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function formatParam(array $value)
|
||||
{
|
||||
$r = array();
|
||||
$data = array_shift($value);
|
||||
if (empty($data)) {
|
||||
$r['type'] = 'mixed';
|
||||
} elseif ($data{0} == '$') {
|
||||
$r['name'] = substr($data, 1);
|
||||
$r['type'] = 'mixed';
|
||||
} else {
|
||||
$data = explode('|', $data);
|
||||
$r['type'] = count($data) == 1 ? $data[0] : $data;
|
||||
|
||||
$data = array_shift($value);
|
||||
if (!empty($data) && $data{0} == '$') {
|
||||
$r['name'] = substr($data, 1);
|
||||
}
|
||||
}
|
||||
if ($value) {
|
||||
$r['description'] = implode(' ', $value);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function formatVar(array $value)
|
||||
{
|
||||
$r = array();
|
||||
$data = array_shift($value);
|
||||
if (empty($data)) {
|
||||
$r['type'] = 'mixed';
|
||||
} elseif ($data{0} == '$') {
|
||||
$r['name'] = substr($data, 1);
|
||||
$r['type'] = 'mixed';
|
||||
} else {
|
||||
$data = explode('|', $data);
|
||||
$r['type'] = count($data) == 1 ? $data[0] : $data;
|
||||
}
|
||||
if ($value) {
|
||||
$r['description'] = implode(' ', $value);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
71
htdocs/includes/restler/Compose.php
Normal file
71
htdocs/includes/restler/Compose.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
/**
|
||||
* Default Composer to provide standard structure for all HTTP responses
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage result
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
*/
|
||||
class Compose implements iCompose
|
||||
{
|
||||
/**
|
||||
* @var bool When restler is not running in production mode, this value will
|
||||
* be checked to include the debug information on error response
|
||||
*/
|
||||
public static $includeDebugInfo = true;
|
||||
/**
|
||||
* Current Restler instance
|
||||
* Injected at runtime
|
||||
*
|
||||
* @var Restler
|
||||
*/
|
||||
public $restler;
|
||||
|
||||
/**
|
||||
* Result of an api call is passed to this method
|
||||
* to create a standard structure for the data
|
||||
*
|
||||
* @param mixed $result can be a primitive or array or object
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function response($result)
|
||||
{
|
||||
//TODO: check Defaults::language and change result accordingly
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the api call results in RestException this method
|
||||
* will be called to return the error message
|
||||
*
|
||||
* @param RestException $exception exception that has reasons for failure
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function message(RestException $exception)
|
||||
{
|
||||
//TODO: check Defaults::language and change result accordingly
|
||||
$r = array(
|
||||
'error' => array(
|
||||
'code' => $exception->getCode(),
|
||||
'message' => $exception->getErrorMessage(),
|
||||
) + $exception->getDetails()
|
||||
);
|
||||
if (!Scope::get('Restler')->getProductionMode() && self::$includeDebugInfo) {
|
||||
$r += array(
|
||||
'debug' => array(
|
||||
'source' => $exception->getSource(),
|
||||
'stages' => $exception->getStages(),
|
||||
)
|
||||
);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
55
htdocs/includes/restler/Data/ApiMethodInfo.php
Normal file
55
htdocs/includes/restler/Data/ApiMethodInfo.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
/**
|
||||
* ValueObject for api method info. All needed information about a api method
|
||||
* is stored here
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class ApiMethodInfo extends ValueObject
|
||||
{
|
||||
/**
|
||||
* @var string target url
|
||||
*/
|
||||
public $url;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $className;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $methodName;
|
||||
/**
|
||||
* @var array parameters to be passed to the api method
|
||||
*/
|
||||
public $parameters = array();
|
||||
/**
|
||||
* @var array information on parameters in the form of array(name => index)
|
||||
*/
|
||||
public $arguments = array();
|
||||
/**
|
||||
* @var array default values for parameters if any
|
||||
* in the form of array(index => value)
|
||||
*/
|
||||
public $defaults = array();
|
||||
/**
|
||||
* @var array key => value pair of method meta information
|
||||
*/
|
||||
public $metadata = array();
|
||||
/**
|
||||
* @var int access level
|
||||
* 0 - @public - available for all
|
||||
* 1 - @hybrid - both public and protected (enhanced info for authorized)
|
||||
* 2 - @protected comment - only for authenticated users
|
||||
* 3 - protected method - only for authenticated users
|
||||
*/
|
||||
public $accessLevel = 0;
|
||||
}
|
||||
33
htdocs/includes/restler/Data/Arr.php
Normal file
33
htdocs/includes/restler/Data/Arr.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
/**
|
||||
* Convenience class for Array manipulation
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
*/
|
||||
class Arr
|
||||
{
|
||||
/**
|
||||
* Deep copy given array
|
||||
*
|
||||
* @param array $arr
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function copy(array $arr)
|
||||
{
|
||||
$copy = array();
|
||||
foreach ($arr as $key => $value) {
|
||||
if (is_array($value)) $copy[$key] = static::copy($value);
|
||||
else if (is_object($value)) $copy[$key] = clone $value;
|
||||
else $copy[$key] = $value;
|
||||
}
|
||||
return $copy;
|
||||
}
|
||||
}
|
||||
20
htdocs/includes/restler/Data/Invalid.php
Normal file
20
htdocs/includes/restler/Data/Invalid.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Invalid Exception
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class Invalid extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
157
htdocs/includes/restler/Data/Object.php
Normal file
157
htdocs/includes/restler/Data/Object.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
/**
|
||||
* Convenience class that converts the given object
|
||||
* in to associative array
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class Object
|
||||
{
|
||||
/**
|
||||
* @var bool|string|callable
|
||||
*/
|
||||
public static $stringEncoderFunction = false;
|
||||
/**
|
||||
* @var bool|string|callable
|
||||
*/
|
||||
public static $numberEncoderFunction = false;
|
||||
/**
|
||||
* @var array key value pairs for fixing value types using functions.
|
||||
* For example
|
||||
*
|
||||
* 'id'=>'intval' will make sure all values of the id properties
|
||||
* will be converted to integers intval function
|
||||
* 'password'=> null will remove all the password entries
|
||||
*/
|
||||
public static $fix = array();
|
||||
/**
|
||||
* @var string character that is used to identify sub objects
|
||||
*
|
||||
* For example
|
||||
*
|
||||
* when Object::$separatorChar = '.';
|
||||
*
|
||||
* array('my.object'=>true) will result in
|
||||
*
|
||||
* array(
|
||||
* 'my'=>array('object'=>true)
|
||||
* );
|
||||
*/
|
||||
public static $separatorChar = null;
|
||||
/**
|
||||
* @var bool set it to true when empty arrays, blank strings, null values
|
||||
* to be automatically removed from response
|
||||
*/
|
||||
public static $removeEmpty = false;
|
||||
/**
|
||||
* @var bool set it to true to remove all null values from the result
|
||||
*/
|
||||
public static $removeNull = false;
|
||||
|
||||
/**
|
||||
* Convenience function that converts the given object
|
||||
* in to associative array
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param mixed $object that needs to be converted
|
||||
*
|
||||
* @param bool $forceObjectTypeWhenEmpty when set to true outputs
|
||||
* actual type (array or
|
||||
* object) rather than
|
||||
* always an array when the
|
||||
* array/object is empty
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function toArray($object,
|
||||
$forceObjectTypeWhenEmpty = false)
|
||||
{
|
||||
//if ($object instanceof JsonSerializable) { //wont work on PHP < 5.4
|
||||
if (is_object($object)) {
|
||||
if (method_exists($object, 'jsonSerialize')) {
|
||||
$object = $object->jsonSerialize();
|
||||
} elseif (method_exists($object, '__sleep')) {
|
||||
$properties = $object->__sleep();
|
||||
$array = array();
|
||||
foreach ($properties as $key) {
|
||||
$value = self::toArray($object->{$key},
|
||||
$forceObjectTypeWhenEmpty);
|
||||
if (self::$stringEncoderFunction && is_string($value)) {
|
||||
$value = self::$stringEncoderFunction ($value);
|
||||
} elseif (self::$numberEncoderFunction && is_numeric($value)) {
|
||||
$value = self::$numberEncoderFunction ($value);
|
||||
}
|
||||
$array [$key] = $value;
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
if (is_array($object) || is_object($object)) {
|
||||
$count = 0;
|
||||
$array = array();
|
||||
foreach ($object as $key => $value) {
|
||||
if (
|
||||
is_string(self::$separatorChar) &&
|
||||
false !== strpos($key, self::$separatorChar)
|
||||
) {
|
||||
list($key, $obj) = explode(self::$separatorChar, $key, 2);
|
||||
$object[$key][$obj] = $value;
|
||||
$value = $object[$key];
|
||||
}
|
||||
if (self::$removeEmpty && empty($value) && !is_numeric($value) && !is_bool($value)) {
|
||||
continue;
|
||||
} elseif (self::$removeNull && is_null($value)) {
|
||||
continue;
|
||||
}
|
||||
if (array_key_exists($key, self::$fix)) {
|
||||
if (isset(self::$fix[$key])) {
|
||||
$value = call_user_func(self::$fix[$key], $value);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$value = self::toArray($value, $forceObjectTypeWhenEmpty);
|
||||
if (self::$stringEncoderFunction && is_string($value)) {
|
||||
$value = self::$encoderFunctionName ($value);
|
||||
} elseif (self::$numberEncoderFunction && is_numeric($value)) {
|
||||
$value = self::$numberEncoderFunction ($value);
|
||||
}
|
||||
$array [$key] = $value;
|
||||
$count++;
|
||||
}
|
||||
return $forceObjectTypeWhenEmpty && $count == 0 ? $object : $array;
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
isset(self::$fix[$name]) ? self::$fix[$name] : null;
|
||||
}
|
||||
|
||||
public function __set($name, $function)
|
||||
{
|
||||
self::$fix[$name] = $function;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset(self::$fix[$name]);
|
||||
}
|
||||
|
||||
public function __unset($name)
|
||||
{
|
||||
unset(self::$fix[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
84
htdocs/includes/restler/Data/String.php
Normal file
84
htdocs/includes/restler/Data/String.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
/**
|
||||
* Convenience class for String manipulation
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
*/
|
||||
class String
|
||||
{
|
||||
/**
|
||||
* Given haystack contains the needle or not?
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @param bool $caseSensitive
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function contains($haystack, $needle, $caseSensitive = true)
|
||||
{
|
||||
if (empty($needle))
|
||||
return true;
|
||||
return $caseSensitive
|
||||
? strpos($haystack, $needle) !== false
|
||||
: stripos($haystack, $needle) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given haystack begins with the needle or not?
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function beginsWith($haystack, $needle)
|
||||
{
|
||||
$length = strlen($needle);
|
||||
return (substr($haystack, 0, $length) === $needle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given haystack ends with the needle or not?
|
||||
*
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function endsWith($haystack, $needle)
|
||||
{
|
||||
$length = strlen($needle);
|
||||
if ($length == 0) {
|
||||
return true;
|
||||
}
|
||||
return (substr($haystack, -$length) === $needle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert camelCased or underscored string in to a title
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function title($name)
|
||||
{
|
||||
return
|
||||
ucwords(
|
||||
preg_replace(
|
||||
array('/(?<=[^A-Z])([A-Z])/', '/(?<=[^0-9])([0-9])/', '/(_)/'),
|
||||
array(' $0', ' $0', ' '),
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
273
htdocs/includes/restler/Data/ValidationInfo.php
Normal file
273
htdocs/includes/restler/Data/ValidationInfo.php
Normal file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
use Luracast\Restler\CommentParser;
|
||||
use Luracast\Restler\Util;
|
||||
|
||||
/**
|
||||
* ValueObject for validation information. An instance is created and
|
||||
* populated by Restler to pass it to iValidate implementing classes for
|
||||
* validation
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class ValidationInfo implements iValueObject
|
||||
{
|
||||
/**
|
||||
* @var mixed given value for the parameter
|
||||
*/
|
||||
public $value;
|
||||
/**
|
||||
* @var string proper name for given parameter
|
||||
*/
|
||||
public $label;
|
||||
/**
|
||||
* @var string html element that can be used to represent the parameter for
|
||||
* input
|
||||
*/
|
||||
public $field;
|
||||
/**
|
||||
* @var mixed default value for the parameter
|
||||
*/
|
||||
public $default;
|
||||
/**
|
||||
* Name of the variable being validated
|
||||
*
|
||||
* @var string variable name
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var bool is it required or not
|
||||
*/
|
||||
public $required;
|
||||
|
||||
/**
|
||||
* @var string body or header or query where this parameter is coming from
|
||||
* in the http request
|
||||
*/
|
||||
public $from;
|
||||
|
||||
/**
|
||||
* Data type of the variable being validated.
|
||||
* It will be mostly string
|
||||
*
|
||||
* @var string|array multiple types are specified it will be of
|
||||
* type array otherwise it will be a string
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* When the type is array, this field is used to define the type of the
|
||||
* contents of the array
|
||||
*
|
||||
* @var string|null when all the items in an array are of certain type, we
|
||||
* can set this property. It will be null if the items can be of any type
|
||||
*/
|
||||
public $contentType;
|
||||
|
||||
/**
|
||||
* Should we attempt to fix the value?
|
||||
* When set to false validation class should throw
|
||||
* an exception or return false for the validate call.
|
||||
* When set to true it will attempt to fix the value if possible
|
||||
* or throw an exception or return false when it cant be fixed.
|
||||
*
|
||||
* @var boolean true or false
|
||||
*/
|
||||
public $fix = false;
|
||||
|
||||
/**
|
||||
* @var array of children to be validated
|
||||
*/
|
||||
public $children = null;
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// VALUE RANGE
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
/**
|
||||
* Given value should match one of the values in the array
|
||||
*
|
||||
* @var array of choices to match to
|
||||
*/
|
||||
public $choice;
|
||||
/**
|
||||
* If the type is string it will set the lower limit for length
|
||||
* else will specify the lower limit for the value
|
||||
*
|
||||
* @var number minimum value
|
||||
*/
|
||||
public $min;
|
||||
/**
|
||||
* If the type is string it will set the upper limit limit for length
|
||||
* else will specify the upper limit for the value
|
||||
*
|
||||
* @var number maximum value
|
||||
*/
|
||||
public $max;
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// REGEX VALIDATION
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
/**
|
||||
* RegEx pattern to match the value
|
||||
*
|
||||
* @var string regular expression
|
||||
*/
|
||||
public $pattern;
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// CUSTOM VALIDATION
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
/**
|
||||
* Rules specified for the parameter in the php doc comment.
|
||||
* It is passed to the validation method as the second parameter
|
||||
*
|
||||
* @var array custom rule set
|
||||
*/
|
||||
public $rules;
|
||||
|
||||
/**
|
||||
* Specifying a custom error message will override the standard error
|
||||
* message return by the validator class
|
||||
*
|
||||
* @var string custom error response
|
||||
*/
|
||||
public $message;
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// METHODS
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Name of the method to be used for validation.
|
||||
* It will be receiving two parameters $input, $rules (array)
|
||||
*
|
||||
* @var string validation method name
|
||||
*/
|
||||
public $method;
|
||||
|
||||
/**
|
||||
* Instance of the API class currently being called. It will be null most of
|
||||
* the time. Only when method is defined it will contain an instance.
|
||||
* This behavior is for lazy loading of the API class
|
||||
*
|
||||
* @var null|object will be null or api class instance
|
||||
*/
|
||||
public $apiClassInstance = null;
|
||||
|
||||
public static function numericValue($value)
|
||||
{
|
||||
return ( int )$value == $value
|
||||
? ( int )$value
|
||||
: floatval($value);
|
||||
}
|
||||
|
||||
public static function arrayValue($value)
|
||||
{
|
||||
return is_array($value) ? $value : array(
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
public static function stringValue($value, $glue = ',')
|
||||
{
|
||||
return is_array($value)
|
||||
? implode($glue, $value)
|
||||
: ( string )$value;
|
||||
}
|
||||
|
||||
public static function booleanValue($value)
|
||||
{
|
||||
return is_bool($value)
|
||||
? $value
|
||||
: $value !== 'false';
|
||||
}
|
||||
|
||||
public static function filterArray(array $data, $keepNumericKeys)
|
||||
{
|
||||
$r = array();
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
if ($keepNumericKeys) {
|
||||
$r[$key] = $value;
|
||||
}
|
||||
} elseif (!$keepNumericKeys) {
|
||||
$r[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return ' new ValidationInfo() ';
|
||||
}
|
||||
|
||||
private function getProperty(array &$from, $property)
|
||||
{
|
||||
$p = Util::nestedValue($from, $property);
|
||||
unset($from[$property]);
|
||||
$p2 = Util::nestedValue(
|
||||
$from, CommentParser::$embeddedDataName, $property
|
||||
);
|
||||
unset($from[CommentParser::$embeddedDataName][$property]);
|
||||
|
||||
if ($property == 'type' && $p == 'array' && $p2) {
|
||||
$this->contentType = $p2;
|
||||
return $p;
|
||||
}
|
||||
$r = is_null($p2) ? (is_null($p) ? null : $p) : $p2;
|
||||
if (!is_null($r)) {
|
||||
if ($property == 'min' || $property == 'max') {
|
||||
return static::numericValue($r);
|
||||
} elseif ($property == 'required' || $property == 'fix') {
|
||||
return static::booleanValue($r);
|
||||
} elseif ($property == 'choice') {
|
||||
return static::arrayValue($r);
|
||||
} elseif ($property == 'pattern') {
|
||||
return static::stringValue($r);
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function __construct(array $info)
|
||||
{
|
||||
$properties = get_object_vars($this);
|
||||
unset($properties['contentType']);
|
||||
foreach ($properties as $property => $value) {
|
||||
$this->{$property} = $this->getProperty($info, $property);
|
||||
}
|
||||
$inner = Util::nestedValue($info, 'properties');
|
||||
$this->rules = !empty($inner) ? $inner + $info : $info;
|
||||
unset($this->rules['properties']);
|
||||
if (is_string($this->type) && $this->type == 'integer') {
|
||||
$this->type = 'int';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method used for creating instance at run time
|
||||
*/
|
||||
public static function __set_state(array $info)
|
||||
{
|
||||
$o = new self ($info);
|
||||
return $o;
|
||||
}
|
||||
}
|
||||
|
||||
626
htdocs/includes/restler/Data/Validator.php
Normal file
626
htdocs/includes/restler/Data/Validator.php
Normal file
@@ -0,0 +1,626 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
use Luracast\Restler\CommentParser;
|
||||
use Luracast\Restler\Format\HtmlFormat;
|
||||
use Luracast\Restler\RestException;
|
||||
use Luracast\Restler\Scope;
|
||||
use Luracast\Restler\Util;
|
||||
|
||||
/**
|
||||
* Default Validator class used by Restler. It can be replaced by any
|
||||
* iValidate implementing class by setting Defaults::$validatorClass
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class Validator implements iValidate
|
||||
{
|
||||
public static $holdException = false;
|
||||
public static $exceptions = array();
|
||||
|
||||
/**
|
||||
* Validate alphabetic characters.
|
||||
*
|
||||
* Check that given value contains only alphabetic characters.
|
||||
*
|
||||
* @param $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function alpha($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (ctype_alpha($input)) {
|
||||
return $input;
|
||||
}
|
||||
if ($info && $info->fix) {
|
||||
//remove non alpha characters
|
||||
return preg_replace("/[^a-z]/i", "", $input);
|
||||
}
|
||||
throw new Invalid('Expecting only alphabetic characters.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate alpha numeric characters.
|
||||
*
|
||||
* Check that given value contains only alpha numeric characters.
|
||||
*
|
||||
* @param $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function alphanumeric($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (ctype_alnum($input)) {
|
||||
return $input;
|
||||
}
|
||||
if ($info && $info->fix) {
|
||||
//remove non alpha numeric and space characters
|
||||
return preg_replace("/[^a-z0-9 ]/i", "", $input);
|
||||
}
|
||||
throw new Invalid('Expecting only alpha numeric characters.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate printable characters.
|
||||
*
|
||||
* Check that given value contains only printable characters.
|
||||
*
|
||||
* @param $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function printable($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (ctype_print($input)) {
|
||||
return $input;
|
||||
}
|
||||
if ($info && $info->fix) {
|
||||
//remove non printable characters
|
||||
return preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $input);
|
||||
}
|
||||
throw new Invalid('Expecting only printable characters.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate hexadecimal digits.
|
||||
*
|
||||
* Check that given value contains only hexadecimal digits.
|
||||
*
|
||||
* @param $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function hex($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (ctype_xdigit($input)) {
|
||||
return $input;
|
||||
}
|
||||
throw new Invalid('Expecting only hexadecimal digits.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Telephone number
|
||||
*
|
||||
* Check if the given value is numeric with or without a `+` prefix
|
||||
*
|
||||
* @param $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function tel($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (is_numeric($input) && '-' != substr($input, 0, 1)) {
|
||||
return $input;
|
||||
}
|
||||
throw new Invalid('Expecting phone number, a numeric value ' .
|
||||
'with optional `+` prefix');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Email
|
||||
*
|
||||
* Check if the given string is a valid email
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function email($input, ValidationInfo $info = null)
|
||||
{
|
||||
$r = filter_var($input, FILTER_VALIDATE_EMAIL);
|
||||
if ($r) {
|
||||
return $r;
|
||||
} elseif ($info && $info->fix) {
|
||||
$r = filter_var($input, FILTER_SANITIZE_EMAIL);
|
||||
return static::email($r);
|
||||
}
|
||||
throw new Invalid('Expecting email in `name@example.com` format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate IP Address
|
||||
*
|
||||
* Check if the given string is a valid ip address
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function ip($input, ValidationInfo $info = null)
|
||||
{
|
||||
$r = filter_var($input, FILTER_VALIDATE_IP);
|
||||
if ($r)
|
||||
return $r;
|
||||
|
||||
throw new Invalid('Expecting IP address in IPV6 or IPV4 format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Url
|
||||
*
|
||||
* Check if the given string is a valid url
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function url($input, ValidationInfo $info = null)
|
||||
{
|
||||
$r = filter_var($input, FILTER_VALIDATE_URL);
|
||||
if ($r) {
|
||||
return $r;
|
||||
} elseif ($info && $info->fix) {
|
||||
$r = filter_var($input, FILTER_SANITIZE_URL);
|
||||
return static::url($r);
|
||||
}
|
||||
throw new Invalid('Expecting url in `http://example.com` format');
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL Date
|
||||
*
|
||||
* Check if the given string is a valid date in YYYY-MM-DD format
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function date($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (
|
||||
preg_match(
|
||||
'#^(?P<year>\d{2}|\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})$#',
|
||||
$input,
|
||||
$date
|
||||
)
|
||||
&& checkdate($date['month'], $date['day'], $date['year'])
|
||||
) {
|
||||
return $input;
|
||||
}
|
||||
throw new Invalid(
|
||||
'Expecting date in `YYYY-MM-DD` format, such as `'
|
||||
. date("Y-m-d") . '`'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL DateTime
|
||||
*
|
||||
* Check if the given string is a valid date and time in YYY-MM-DD HH:MM:SS format
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function datetime($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (
|
||||
preg_match('/^(?P<year>19\d\d|20\d\d)\-(?P<month>0[1-9]|1[0-2])\-' .
|
||||
'(?P<day>0\d|[1-2]\d|3[0-1]) (?P<h>0\d|1\d|2[0-3]' .
|
||||
')\:(?P<i>[0-5][0-9])\:(?P<s>[0-5][0-9])$/',
|
||||
$input, $date)
|
||||
&& checkdate($date['month'], $date['day'], $date['year'])
|
||||
) {
|
||||
return $input;
|
||||
}
|
||||
throw new Invalid(
|
||||
'Expecting date and time in `YYYY-MM-DD HH:MM:SS` format, such as `'
|
||||
. date("Y-m-d H:i:s") . '`'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for Time
|
||||
*
|
||||
* Check if the given string is a valid time in HH:MM:SS format
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function time24($input, ValidationInfo $info = null)
|
||||
{
|
||||
return static::time($input, $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Time
|
||||
*
|
||||
* Check if the given string is a valid time in HH:MM:SS format
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function time($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (preg_match('/^([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/', $input)) {
|
||||
return $input;
|
||||
}
|
||||
throw new Invalid(
|
||||
'Expecting time in `HH:MM:SS` format, such as `'
|
||||
. date("H:i:s") . '`'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Time in 12 hour format
|
||||
*
|
||||
* Check if the given string is a valid time 12 hour format
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return string
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function time12($input, ValidationInfo $info = null)
|
||||
{
|
||||
if (preg_match(
|
||||
'/^([1-9]|1[0-2]|0[1-9]){1}(:[0-5][0-9])?\s?([aApP][mM]{1})?$/',
|
||||
$input)
|
||||
) {
|
||||
return $input;
|
||||
}
|
||||
throw new Invalid(
|
||||
'Expecting time in 12 hour format, such as `08:00AM` and `10:05:11`'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unix Timestamp
|
||||
*
|
||||
* Check if the given value is a valid timestamp
|
||||
*
|
||||
* @param String $input
|
||||
* @param ValidationInfo $info
|
||||
*
|
||||
* @return int
|
||||
* @throws Invalid
|
||||
*/
|
||||
public static function timestamp($input, ValidationInfo $info = null)
|
||||
{
|
||||
if ((string)(int)$input == $input
|
||||
&& ($input <= PHP_INT_MAX)
|
||||
&& ($input >= ~PHP_INT_MAX)
|
||||
) {
|
||||
return (int)$input;
|
||||
}
|
||||
throw new Invalid('Expecting unix timestamp, such as ' . time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the given input
|
||||
*
|
||||
* Validates the input and attempts to fix it when fix is requested
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param ValidationInfo $info
|
||||
* @param null $full
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return array|bool|float|int|mixed|null|number|string
|
||||
*/
|
||||
public static function validate($input, ValidationInfo $info, $full = null)
|
||||
{
|
||||
$html = Scope::get('Restler')->responseFormat instanceof HtmlFormat;
|
||||
$name = $html ? "<strong>$info->label</strong>" : "`$info->name`";
|
||||
try {
|
||||
if (is_null($input)) {
|
||||
if ($info->required) {
|
||||
throw new RestException (400,
|
||||
"$name is required.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
$error = isset ($info->message)
|
||||
? $info->message
|
||||
: "Invalid value specified for $name";
|
||||
|
||||
//if a validation method is specified
|
||||
if (!empty($info->method)) {
|
||||
$method = $info->method;
|
||||
$info->method = '';
|
||||
$r = self::validate($input, $info);
|
||||
return $info->apiClassInstance->{$method} ($r);
|
||||
}
|
||||
|
||||
// when type is an array check if it passes for any type
|
||||
if (is_array($info->type)) {
|
||||
//trace("types are ".print_r($info->type, true));
|
||||
$types = $info->type;
|
||||
foreach ($types as $type) {
|
||||
$info->type = $type;
|
||||
try {
|
||||
$r = self::validate($input, $info);
|
||||
if ($r !== false) {
|
||||
return $r;
|
||||
}
|
||||
} catch (RestException $e) {
|
||||
// just continue
|
||||
}
|
||||
}
|
||||
throw new RestException (400, $error);
|
||||
}
|
||||
|
||||
//patterns are supported only for non numeric types
|
||||
if (isset ($info->pattern)
|
||||
&& $info->type != 'int'
|
||||
&& $info->type != 'float'
|
||||
&& $info->type != 'number'
|
||||
) {
|
||||
if (!preg_match($info->pattern, $input)) {
|
||||
throw new RestException (400, $error);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset ($info->choice)) {
|
||||
if (is_array($input)) {
|
||||
foreach ($input as $i) {
|
||||
if (!in_array($i, $info->choice)) {
|
||||
$error .= ". Expected one of (" . implode(',', $info->choice) . ").";
|
||||
throw new RestException (400, $error);
|
||||
}
|
||||
}
|
||||
} elseif (!in_array($input, $info->choice)) {
|
||||
$error .= ". Expected one of (" . implode(',', $info->choice) . ").";
|
||||
throw new RestException (400, $error);
|
||||
}
|
||||
}
|
||||
|
||||
if (method_exists($class = get_called_class(), $info->type) && $info->type != 'validate') {
|
||||
try {
|
||||
return call_user_func("$class::$info->type", $input, $info);
|
||||
} catch (Invalid $e) {
|
||||
throw new RestException(400, $error . '. ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
switch ($info->type) {
|
||||
case 'int' :
|
||||
case 'float' :
|
||||
case 'number' :
|
||||
if (!is_numeric($input)) {
|
||||
$error .= '. Expecting '
|
||||
. ($info->type == 'int' ? 'integer' : 'numeric')
|
||||
. ' value';
|
||||
break;
|
||||
}
|
||||
if ($info->type == 'int' && (int)$input != $input) {
|
||||
if ($info->fix) {
|
||||
$r = (int)$input;
|
||||
} else {
|
||||
$error .= '. Expecting integer value';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$r = $info->numericValue($input);
|
||||
}
|
||||
if (isset ($info->min) && $r < $info->min) {
|
||||
if ($info->fix) {
|
||||
$r = $info->min;
|
||||
} else {
|
||||
$error .= ". Minimum required value is $info->min.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset ($info->max) && $r > $info->max) {
|
||||
if ($info->fix) {
|
||||
$r = $info->max;
|
||||
} else {
|
||||
$error .= ". Maximum allowed value is $info->max.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
|
||||
case 'string' :
|
||||
if (!is_string($input)) {
|
||||
$error .= '. Expecting alpha numeric value';
|
||||
break;
|
||||
}
|
||||
if ($info->required && $input === '') {
|
||||
$error = "$name is required.";
|
||||
break;
|
||||
}
|
||||
$r = strlen($input);
|
||||
if (isset ($info->min) && $r < $info->min) {
|
||||
if ($info->fix) {
|
||||
$input = str_pad($input, $info->min, $input);
|
||||
} else {
|
||||
$char = $info->min > 1 ? 'characters' : 'character';
|
||||
$error .= ". Minimum $info->min $char required.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset ($info->max) && $r > $info->max) {
|
||||
if ($info->fix) {
|
||||
$input = substr($input, 0, $info->max);
|
||||
} else {
|
||||
$char = $info->max > 1 ? 'characters' : 'character';
|
||||
$error .= ". Maximum $info->max $char allowed.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $input;
|
||||
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
if ($input === 'true' || $input === true) return true;
|
||||
if (is_numeric($input)) return $input > 0;
|
||||
return false;
|
||||
|
||||
case 'array':
|
||||
if ($info->fix && is_string($input)) {
|
||||
$input = explode(CommentParser::$arrayDelimiter, $input);
|
||||
}
|
||||
if (is_array($input)) {
|
||||
$contentType =
|
||||
Util::nestedValue($info, 'contentType') ? : null;
|
||||
if ($info->fix) {
|
||||
if ($contentType == 'indexed') {
|
||||
$input = $info->filterArray($input, true);
|
||||
} elseif ($contentType == 'associative') {
|
||||
$input = $info->filterArray($input, true);
|
||||
}
|
||||
} elseif (
|
||||
$contentType == 'indexed' &&
|
||||
array_values($input) != $input
|
||||
) {
|
||||
$error .= '. Expecting a list of items but an item is given';
|
||||
break;
|
||||
} elseif (
|
||||
$contentType == 'associative' &&
|
||||
array_values($input) == $input &&
|
||||
count($input)
|
||||
) {
|
||||
$error .= '. Expecting an item but a list is given';
|
||||
break;
|
||||
}
|
||||
$r = count($input);
|
||||
if (isset ($info->min) && $r < $info->min) {
|
||||
$item = $info->max > 1 ? 'items' : 'item';
|
||||
$error .= ". Minimum $info->min $item required.";
|
||||
break;
|
||||
}
|
||||
if (isset ($info->max) && $r > $info->max) {
|
||||
if ($info->fix) {
|
||||
$input = array_slice($input, 0, $info->max);
|
||||
} else {
|
||||
$item = $info->max > 1 ? 'items' : 'item';
|
||||
$error .= ". Maximum $info->max $item allowed.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (
|
||||
isset($contentType) &&
|
||||
$contentType != 'associative' &&
|
||||
$contentType != 'indexed'
|
||||
) {
|
||||
$name = $info->name;
|
||||
$info->type = $contentType;
|
||||
unset($info->contentType);
|
||||
foreach ($input as $key => $chinput) {
|
||||
$info->name = "{$name}[$key]";
|
||||
$input[$key] = static::validate($chinput, $info);
|
||||
}
|
||||
}
|
||||
return $input;
|
||||
} elseif (isset($contentType)) {
|
||||
$error .= '. Expecting items of type ' .
|
||||
($html ? "<strong>$contentType</strong>" : "`$contentType`");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'mixed':
|
||||
case 'unknown_type':
|
||||
case 'unknown':
|
||||
case null: //treat as unknown
|
||||
return $input;
|
||||
default :
|
||||
if (!is_array($input)) {
|
||||
break;
|
||||
}
|
||||
//do type conversion
|
||||
if (class_exists($info->type)) {
|
||||
$input = $info->filterArray($input, false);
|
||||
$implements = class_implements($info->type);
|
||||
if (
|
||||
is_array($implements) &&
|
||||
in_array('Luracast\\Restler\\Data\\iValueObject', $implements)
|
||||
) {
|
||||
return call_user_func(
|
||||
"{$info->type}::__set_state", $input
|
||||
);
|
||||
}
|
||||
$class = $info->type;
|
||||
$instance = new $class();
|
||||
if (is_array($info->children)) {
|
||||
if (
|
||||
empty($input) ||
|
||||
!is_array($input) ||
|
||||
$input === array_values($input)
|
||||
) {
|
||||
$error .= '. Expecting an item of type ' .
|
||||
($html ? "<strong>$info->type</strong>" : "`$info->type`");
|
||||
break;
|
||||
}
|
||||
foreach ($info->children as $key => $value) {
|
||||
$cv = new ValidationInfo($value);
|
||||
if (array_key_exists($key, $input) || $cv->required) {
|
||||
$instance->{$key} = static::validate(
|
||||
Util::nestedValue($input, $key),
|
||||
$cv
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
throw new RestException (400, $error);
|
||||
} catch (\Exception $e) {
|
||||
static::$exceptions[] = $e;
|
||||
if (static::$holdException) {
|
||||
return null;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
61
htdocs/includes/restler/Data/ValueObject.php
Normal file
61
htdocs/includes/restler/Data/ValueObject.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
/**
|
||||
* ValueObject base class, you may use this class to create your
|
||||
* iValueObjects quickly
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class ValueObject implements iValueObject
|
||||
{
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return ' new ' . get_called_class() . '() ';
|
||||
}
|
||||
|
||||
public static function __set_state(array $properties)
|
||||
{
|
||||
$class = get_called_class();
|
||||
$instance = new $class ();
|
||||
$vars = get_object_vars($instance);
|
||||
foreach ($properties as $property => $value) {
|
||||
if (property_exists($instance, $property)) {
|
||||
// see if the property is accessible
|
||||
if (array_key_exists($property, $vars)) {
|
||||
$instance->{$property} = $value;
|
||||
} else {
|
||||
$method = 'set' . ucfirst($property);
|
||||
if (method_exists($instance, $method)) {
|
||||
call_user_func(array(
|
||||
$instance,
|
||||
$method
|
||||
), $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function __toArray()
|
||||
{
|
||||
$r = get_object_vars($this);
|
||||
$methods = get_class_methods($this);
|
||||
foreach ($methods as $m) {
|
||||
if (substr($m, 0, 3) == 'get') {
|
||||
$r [lcfirst(substr($m, 3))] = @$this->{$m} ();
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
32
htdocs/includes/restler/Data/iValidate.php
Normal file
32
htdocs/includes/restler/Data/iValidate.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
/**
|
||||
* Validation classes should implement this interface
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
interface iValidate {
|
||||
|
||||
/**
|
||||
* method used for validation.
|
||||
*
|
||||
* @param mixed $input
|
||||
* data that needs to be validated
|
||||
* @param ValidationInfo $info
|
||||
* information to be used for validation
|
||||
* @return boolean false in case of failure or fixed value in the expected
|
||||
* type
|
||||
* @throws \Luracast\Restler\RestException 400 with information about the
|
||||
* failed
|
||||
* validation
|
||||
*/
|
||||
public static function validate($input, ValidationInfo $info);
|
||||
}
|
||||
|
||||
39
htdocs/includes/restler/Data/iValueObject.php
Normal file
39
htdocs/includes/restler/Data/iValueObject.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Data;
|
||||
|
||||
/**
|
||||
* Restler is using many ValueObjects across to make it easy for the developers
|
||||
* to use them with the help of code hinting etc.,
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
interface iValueObject
|
||||
{
|
||||
|
||||
/**
|
||||
* This static method is called for creating an instance of the class by
|
||||
* passing the initiation values as an array.
|
||||
*
|
||||
* @static
|
||||
* @abstract
|
||||
*
|
||||
* @param array $properties
|
||||
*
|
||||
* @return iValueObject
|
||||
*/
|
||||
public static function __set_state(array $properties);
|
||||
|
||||
/**
|
||||
* This method provides a string representation for the instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
}
|
||||
|
||||
360
htdocs/includes/restler/Defaults.php
Normal file
360
htdocs/includes/restler/Defaults.php
Normal file
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Luracast\Restler\Data\ValidationInfo;
|
||||
use Luracast\Restler\Data\Validator;
|
||||
|
||||
/**
|
||||
* Static class to hold all restler defaults, change the values to suit your
|
||||
* needs in the gateway file (index.php), you may also allow the api users to
|
||||
* change them per request by adding the properties to Defaults::$overridables
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class Defaults
|
||||
{
|
||||
// ==================================================================
|
||||
//
|
||||
// Class Mappings
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var string of name of the class that implements
|
||||
* \Luracast\Restler\iCache the cache class to be used
|
||||
*/
|
||||
public static $cacheClass = 'Luracast\\Restler\\HumanReadableCache';
|
||||
|
||||
/**
|
||||
* @var string full path of the directory where all the generated files will
|
||||
* be kept. When set to null (default) it will use the cache folder that is
|
||||
* in the same folder as index.php (gateway)
|
||||
*/
|
||||
public static $cacheDirectory;
|
||||
|
||||
/**
|
||||
* @var string of name of the class that implements
|
||||
* \Luracast\Restler\Data\iValidate the validator class to be used
|
||||
*/
|
||||
public static $validatorClass = 'Luracast\\Restler\\Data\\Validator';
|
||||
|
||||
/**
|
||||
* @var string name of the class that implements \Luracast\Restler\iCompose
|
||||
* the class to be used to compose the response
|
||||
*/
|
||||
public static $composeClass = 'Luracast\\Restler\\Compose';
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Routing
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var bool should auto routing for public and protected api methods
|
||||
* should be enabled by default or not. Set this to false to get
|
||||
* Restler 1.0 style behavior
|
||||
*/
|
||||
public static $autoRoutingEnabled = true;
|
||||
|
||||
/**
|
||||
* @var boolean avoids creating multiple routes that can increase the
|
||||
* ambiguity when set to true. when a method parameter is optional it is
|
||||
* not mapped to the url and should only be used in request body or as
|
||||
* query string `/resource?id=value`. When a parameter is required and is
|
||||
* scalar, it will be mapped as part of the url `/resource/{id}`
|
||||
*/
|
||||
public static $smartAutoRouting = true;
|
||||
|
||||
/**
|
||||
* @var boolean enables more ways of finding the parameter data in the request.
|
||||
* If you need backward compatibility with Restler 2 or below turn this off
|
||||
*/
|
||||
public static $smartParameterParsing = true;
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// API Version Management
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var null|string name that is used for vendor specific media type and
|
||||
* api version using the Accept Header for example
|
||||
* application/vnd.{vendor}-v1+json
|
||||
*
|
||||
* Keep this null if you do not want to use vendor MIME for specifying api version
|
||||
*/
|
||||
public static $apiVendor = null;
|
||||
|
||||
/**
|
||||
* @var bool set it to true to force vendor specific MIME for versioning.
|
||||
* It will be automatically set to true when Defaults::$vendor is not
|
||||
* null and client is requesting for the custom MIME type
|
||||
*/
|
||||
public static $useVendorMIMEVersioning = false;
|
||||
|
||||
/**
|
||||
* @var bool set it to true to use enableUrl based versioning
|
||||
*/
|
||||
public static $useUrlBasedVersioning = false;
|
||||
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Request
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var string name to be used for the method parameter to capture the
|
||||
* entire request data
|
||||
*/
|
||||
public static $fullRequestDataName = 'request_data';
|
||||
|
||||
/**
|
||||
* @var string name of the property that can sent through $_GET or $_POST to
|
||||
* override the http method of the request. Set it to null or
|
||||
* blank string to disable http method override through request
|
||||
* parameters.
|
||||
*/
|
||||
public static $httpMethodOverrideProperty = 'http_method';
|
||||
|
||||
/**
|
||||
* @var bool should auto validating api parameters should be enabled by
|
||||
* default or not. Set this to false to avoid validation.
|
||||
*/
|
||||
public static $autoValidationEnabled = true;
|
||||
|
||||
/**
|
||||
* @var string name of the class that implements iUser interface to identify
|
||||
* the user for caching purposes
|
||||
*/
|
||||
public static $userIdentifierClass = 'Luracast\\Restler\\User';
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Response
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var bool HTTP status codes are set on all responses by default.
|
||||
* Some clients (like flash, mobile) have trouble dealing with non-200
|
||||
* status codes on error responses.
|
||||
*
|
||||
* You can set it to true to force a HTTP 200 status code on all responses,
|
||||
* even when errors occur. If you suppress status codes, look for an error
|
||||
* response to determine if an error occurred.
|
||||
*/
|
||||
public static $suppressResponseCode = false;
|
||||
|
||||
public static $supportedCharsets = array('utf-8', 'iso-8859-1');
|
||||
public static $supportedLanguages = array('en', 'en-US');
|
||||
|
||||
public static $charset = 'utf-8';
|
||||
public static $language = 'en';
|
||||
|
||||
/**
|
||||
* @var bool when set to true, it will exclude the response body
|
||||
*/
|
||||
public static $emptyBodyForNullResponse = true;
|
||||
|
||||
/**
|
||||
* @var bool enables CORS support
|
||||
*/
|
||||
public static $crossOriginResourceSharing = false;
|
||||
public static $accessControlAllowOrigin = '*';
|
||||
public static $accessControlAllowMethods =
|
||||
'GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD';
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Header
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var array default Cache-Control template that used to set the
|
||||
* Cache-Control header and has two values, first one is used when
|
||||
* Defaults::$headerExpires is 0 and second one when it has some time
|
||||
* value specified. When only one value is specified it will be used for
|
||||
* both cases
|
||||
*/
|
||||
public static $headerCacheControl = array(
|
||||
'no-cache, must-revalidate',
|
||||
|
||||
/* "public, " or "private, " will be prepended based on api method
|
||||
* called (public or protected)
|
||||
*/
|
||||
'max-age={expires}, must-revalidate',
|
||||
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @var int sets the content to expire immediately when set to zero
|
||||
* alternatively you can specify the number of seconds the content will
|
||||
* expire. This setting can be altered at api level using php doc comment
|
||||
* with @expires numOfSeconds
|
||||
*/
|
||||
public static $headerExpires = 0;
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Access Control
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var null|callable if the api methods are under access control mechanism
|
||||
* you can attach a function here that returns true or false to determine
|
||||
* visibility of a protected api method. this function will receive method
|
||||
* info as the only parameter.
|
||||
*/
|
||||
public static $accessControlFunction = null;
|
||||
|
||||
/**
|
||||
* @var int set the default api access mode
|
||||
* value of 0 = public api
|
||||
* value of 1 = hybrid api using `@access hybrid` comment
|
||||
* value of 2 = protected api using `@access protected` comment
|
||||
* value of 3 = protected api using `protected function` method
|
||||
*/
|
||||
public static $apiAccessLevel = 0;
|
||||
|
||||
/**
|
||||
* @var string authentication method to be called in iAuthenticate
|
||||
* Interface
|
||||
*/
|
||||
public static $authenticationMethod = '__isAllowed';
|
||||
|
||||
/**
|
||||
* @var int time in milliseconds for bandwidth throttling,
|
||||
* which is the minimum response time for each api request. You can
|
||||
* change it per api method by setting `@throttle 3000` in php doc
|
||||
* comment either at the method level or class level
|
||||
*/
|
||||
public static $throttle = 0;
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Overrides for API User
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var array use 'alternativeName'=> 'actualName' to set alternative
|
||||
* names that can be used to represent the api method parameters and/or
|
||||
* static properties of Defaults
|
||||
*/
|
||||
public static $aliases = array(
|
||||
/**
|
||||
* suppress_response_codes=true as an URL parameter to force
|
||||
* a HTTP 200 status code on all responses
|
||||
*/
|
||||
'suppress_response_codes' => 'suppressResponseCode',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array determines the defaults that can be overridden by the api
|
||||
* user by passing them as URL parameters
|
||||
*/
|
||||
public static $overridables = array(
|
||||
'suppressResponseCode',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array contains validation details for defaults to be used when
|
||||
* set through URL parameters
|
||||
*/
|
||||
public static $validation = array(
|
||||
'suppressResponseCode' => array('type' => 'bool'),
|
||||
'headerExpires' => array('type' => 'int', 'min' => 0),
|
||||
);
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Overrides API Developer
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var array determines what are the phpdoc comment tags that will
|
||||
* override the Defaults here with their values
|
||||
*/
|
||||
public static $fromComments = array(
|
||||
|
||||
/**
|
||||
* use PHPDoc comments such as the following
|
||||
* `
|
||||
*
|
||||
* @cache no-cache, must-revalidate` to set the Cache-Control header
|
||||
* for a specific api method
|
||||
*/
|
||||
'cache' => 'headerCacheControl',
|
||||
|
||||
/**
|
||||
* use PHPDoc comments such as the following
|
||||
* `
|
||||
*
|
||||
* @expires 50` to set the Expires header
|
||||
* for a specific api method
|
||||
*/
|
||||
'expires' => 'headerExpires',
|
||||
|
||||
/**
|
||||
* use PHPDoc comments such as the following
|
||||
* `
|
||||
*
|
||||
* @throttle 300`
|
||||
* to set the bandwidth throttling for 300 milliseconds
|
||||
* for a specific api method
|
||||
*/
|
||||
'throttle' => 'throttle',
|
||||
|
||||
/**
|
||||
* enable or disable smart auto routing from method comments
|
||||
* this one is hardwired so cant be turned off
|
||||
* it is placed here just for documentation purpose
|
||||
*/
|
||||
'smart-auto-routing' => 'smartAutoRouting',
|
||||
);
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Util
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Use this method to set value to a static properly of Defaults when
|
||||
* you want to make sure only proper values are taken in with the help of
|
||||
* validation
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param string $name name of the static property
|
||||
* @param mixed $value value to set the property to
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function setProperty($name, $value)
|
||||
{
|
||||
if (!property_exists(__CLASS__, $name)) return false;
|
||||
if (@is_array(Defaults::$validation[$name])) {
|
||||
$info = new ValidationInfo(Defaults::$validation[$name]);
|
||||
$value = Validator::validate($value, $info);
|
||||
}
|
||||
Defaults::$$name = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
98
htdocs/includes/restler/EventDispatcher.php
Normal file
98
htdocs/includes/restler/EventDispatcher.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
/**
|
||||
* Static event broadcasting system for Restler
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
use Closure;
|
||||
|
||||
class EventDispatcher
|
||||
{
|
||||
private $listeners = array();
|
||||
protected static $_waitList = array();
|
||||
|
||||
public static $self;
|
||||
protected $events = array();
|
||||
|
||||
public function __construct() {
|
||||
static::$self = $this;
|
||||
if (!empty(static::$_waitList)) {
|
||||
foreach (static::$_waitList as $param) {
|
||||
call_user_func_array(array($this,$param[0]), $param[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function __callStatic($eventName, $params)
|
||||
{
|
||||
if (0 === strpos($eventName, 'on')) {
|
||||
if(static::$self){
|
||||
return call_user_func_array(array(static::$self, $eventName), $params);
|
||||
}
|
||||
static::$_waitList[] = func_get_args();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function __call($eventName, $params)
|
||||
{
|
||||
if (0 === strpos($eventName, 'on')) {
|
||||
if (!@is_array($this->listeners[$eventName]))
|
||||
$this->listeners[$eventName] = array();
|
||||
$this->listeners[$eventName][] = $params[0];
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function addListener($eventName, Closure $callback)
|
||||
{
|
||||
return static::$eventName($callback);
|
||||
}
|
||||
|
||||
public function on(array $eventHandlers)
|
||||
{
|
||||
for (
|
||||
$count = count($eventHandlers),
|
||||
$events = array_map(
|
||||
'ucfirst',
|
||||
$keys = array_keys(
|
||||
$eventHandlers = array_change_key_case(
|
||||
$eventHandlers,
|
||||
CASE_LOWER
|
||||
)
|
||||
)
|
||||
),
|
||||
$i = 0;
|
||||
$i < $count;
|
||||
call_user_func(
|
||||
array($this, "on{$events[$i]}"),
|
||||
$eventHandlers[$keys[$i++]]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an event to notify all listeners
|
||||
*
|
||||
* @param string $eventName name of the event
|
||||
* @param array $params event related data
|
||||
*/
|
||||
protected function dispatch($eventName, array $params = array())
|
||||
{
|
||||
$this->events[] = $eventName;
|
||||
$params = func_get_args();
|
||||
$eventName = 'on'.ucfirst(array_shift($params));
|
||||
if (isset($this->listeners[$eventName]))
|
||||
foreach ($this->listeners[$eventName] as $callback)
|
||||
call_user_func_array($callback, $params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
178
htdocs/includes/restler/Filter/RateLimit.php
Normal file
178
htdocs/includes/restler/Filter/RateLimit.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Filter;
|
||||
|
||||
use Luracast\Restler\Defaults;
|
||||
use Luracast\Restler\iFilter;
|
||||
use Luracast\Restler\iUseAuthentication;
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
/**
|
||||
* Describe the purpose of this class/interface/trait
|
||||
*
|
||||
* @category Framework
|
||||
* @package restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class RateLimit implements iFilter, iUseAuthentication
|
||||
{
|
||||
/**
|
||||
* @var \Luracast\Restler\Restler;
|
||||
*/
|
||||
public $restler;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public static $usagePerUnit = 1200;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public static $authenticatedUsagePerUnit = 5000;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public static $unit = 'hour';
|
||||
/**
|
||||
* @var string group the current api belongs to
|
||||
*/
|
||||
public static $group = 'common';
|
||||
|
||||
protected static $units = array(
|
||||
'second' => 1,
|
||||
'minute' => 60,
|
||||
'hour' => 3600, // 60*60 seconds
|
||||
'day' => 86400, // 60*60*24 seconds
|
||||
'week' => 604800, // 60*60*24*7 seconds
|
||||
'month' => 2592000, // 60*60*24*30 seconds
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array all paths beginning with any of the following will be excluded
|
||||
* from documentation
|
||||
*/
|
||||
public static $excludedPaths = array('resources');
|
||||
|
||||
|
||||
/**
|
||||
* @param string $unit
|
||||
* @param int $usagePerUnit
|
||||
* @param int $authenticatedUsagePerUnit set it to false to give unlimited access
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return void
|
||||
*/
|
||||
public static function setLimit(
|
||||
$unit, $usagePerUnit, $authenticatedUsagePerUnit = null
|
||||
)
|
||||
{
|
||||
static::$unit = $unit;
|
||||
static::$usagePerUnit = $usagePerUnit;
|
||||
static::$authenticatedUsagePerUnit =
|
||||
is_null($authenticatedUsagePerUnit) ? $usagePerUnit : $authenticatedUsagePerUnit;
|
||||
}
|
||||
|
||||
public function __isAllowed()
|
||||
{
|
||||
if (static::$authenticatedUsagePerUnit
|
||||
== static::$usagePerUnit
|
||||
) return $this->check();
|
||||
return null;
|
||||
}
|
||||
|
||||
public function __setAuthenticationStatus($isAuthenticated = false)
|
||||
{
|
||||
header('X-Auth-Status: ' . ($isAuthenticated ? 'true' : 'false'));
|
||||
$this->check($isAuthenticated);
|
||||
}
|
||||
|
||||
private static function validate($unit)
|
||||
{
|
||||
if (!isset(static::$units[$unit]))
|
||||
throw new \InvalidArgumentException(
|
||||
'Rate Limit time unit should be '
|
||||
. implode('|', array_keys(static::$units)) . '.'
|
||||
);
|
||||
}
|
||||
|
||||
private function check($isAuthenticated = false)
|
||||
{
|
||||
$path = $this->restler->url;
|
||||
foreach (static::$excludedPaths as $exclude) {
|
||||
if (empty($exclude) && empty($path)) {
|
||||
return true;
|
||||
} elseif (0 === strpos($path, $exclude)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
static::validate(static::$unit);
|
||||
$timeUnit = static::$units[static::$unit];
|
||||
$maxPerUnit = $isAuthenticated
|
||||
? static::$authenticatedUsagePerUnit
|
||||
: static::$usagePerUnit;
|
||||
if ($maxPerUnit) {
|
||||
$user = Defaults::$userIdentifierClass;
|
||||
if (!method_exists($user, 'getUniqueIdentifier')) {
|
||||
throw new \UnexpectedValueException('`Defaults::$userIdentifierClass` must implement `iIdentifyUser` interface');
|
||||
}
|
||||
$id = "RateLimit_" . $maxPerUnit . '_per_' . static::$unit
|
||||
. '_for_' . static::$group
|
||||
. '_' . $user::getUniqueIdentifier();
|
||||
$lastRequest = $this->restler->cache->get($id, true)
|
||||
? : array('time' => 0, 'used' => 0);
|
||||
$time = $lastRequest['time'];
|
||||
$diff = time() - $time; # in seconds
|
||||
$used = $lastRequest['used'];
|
||||
|
||||
header("X-RateLimit-Limit: $maxPerUnit per " . static::$unit);
|
||||
if ($diff >= $timeUnit) {
|
||||
$used = 1;
|
||||
$time = time();
|
||||
} elseif ($used >= $maxPerUnit) {
|
||||
header("X-RateLimit-Remaining: 0");
|
||||
$wait = $timeUnit - $diff;
|
||||
sleep(1);
|
||||
throw new RestException(429,
|
||||
'Rate limit of ' . $maxPerUnit . ' request' .
|
||||
($maxPerUnit > 1 ? 's' : '') . ' per '
|
||||
. static::$unit . ' exceeded. Please wait for '
|
||||
. static::duration($wait) . '.'
|
||||
);
|
||||
} else {
|
||||
$used++;
|
||||
}
|
||||
$remainingPerUnit = $maxPerUnit - $used;
|
||||
header("X-RateLimit-Remaining: $remainingPerUnit");
|
||||
$this->restler->cache->set($id,
|
||||
array('time' => $time, 'used' => $used));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function duration($secs)
|
||||
{
|
||||
$units = array(
|
||||
'week' => (int)($secs / 86400 / 7),
|
||||
'day' => $secs / 86400 % 7,
|
||||
'hour' => $secs / 3600 % 24,
|
||||
'minute' => $secs / 60 % 60,
|
||||
'second' => $secs % 60);
|
||||
|
||||
$ret = array();
|
||||
|
||||
//$unit = 'days';
|
||||
foreach ($units as $k => $v) {
|
||||
if ($v > 0) {
|
||||
$ret[] = $v > 1 ? "$v {$k}s" : "$v $k";
|
||||
//$unit = $k;
|
||||
}
|
||||
}
|
||||
$i = count($ret) - 1;
|
||||
if ($i) {
|
||||
$ret[$i] = 'and ' . $ret[$i];
|
||||
}
|
||||
return implode(' ', $ret); //." $unit.";
|
||||
}
|
||||
}
|
||||
146
htdocs/includes/restler/Flash.php
Normal file
146
htdocs/includes/restler/Flash.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Luracast\Restler\Format\HtmlFormat;
|
||||
|
||||
/**
|
||||
* Storing and retrieving a message or array of key value pairs for one time use using $_SESSION
|
||||
*
|
||||
* They are typically used in view templates when using HtmlFormat
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class Flash //implements \JsonSerializable
|
||||
{
|
||||
const SUCCESS = 'success';
|
||||
const INFO = 'info';
|
||||
const WARNING = 'warning';
|
||||
const DANGER = 'danger';
|
||||
|
||||
/**
|
||||
* @var Flash
|
||||
*/
|
||||
private static $instance;
|
||||
private $usedOnce = false;
|
||||
|
||||
/**
|
||||
* Flash a success message to user
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $header
|
||||
*
|
||||
* @return Flash
|
||||
*/
|
||||
public static function success($message, $header = '')
|
||||
{
|
||||
return static::message($message, $header, Flash::SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flash a info message to user
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $header
|
||||
*
|
||||
* @return Flash
|
||||
*/
|
||||
public static function info($message, $header = '')
|
||||
{
|
||||
return static::message($message, $header, Flash::INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flash a warning message to user
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $header
|
||||
*
|
||||
* @return Flash
|
||||
*/
|
||||
public static function warning($message, $header = '')
|
||||
{
|
||||
return static::message($message, $header, Flash::WARNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flash a error message to user
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $header
|
||||
*
|
||||
* @return Flash
|
||||
*/
|
||||
public static function danger($message, $header = '')
|
||||
{
|
||||
return static::message($message, $header, Flash::DANGER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flash a message to user
|
||||
*
|
||||
* @param string $text message text
|
||||
* @param string $header
|
||||
* @param string $type
|
||||
*
|
||||
* @return Flash
|
||||
*/
|
||||
public static function message($text, $header = '', $type = Flash::WARNING)
|
||||
{
|
||||
return static::set(array('message' => $text, 'header' => $header, 'type' => $type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set some data for one time use
|
||||
*
|
||||
* @param array $data array of key value pairs {@type associative}
|
||||
*
|
||||
* @return Flash
|
||||
*/
|
||||
public static function set(array $data)
|
||||
{
|
||||
if (!static::$instance)
|
||||
static::$instance = new Flash();
|
||||
if (!isset($_SESSION['flash']))
|
||||
$_SESSION['flash'] = array();
|
||||
$_SESSION['flash'] += $data;
|
||||
HtmlFormat::$data['flash'] = static::$instance;
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
$this->usedOnce = true;
|
||||
return Util::nestedValue($_SESSION, 'flash', $name);
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return !is_null(Util::nestedValue($_SESSION, 'flash', $name));
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->usedOnce)
|
||||
unset($_SESSION['flash']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify data which should be serialized to JSON
|
||||
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
|
||||
* @return mixed data which can be serialized by <b>json_encode</b>,
|
||||
* which is a value of any type other than a resource.
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$this->usedOnce = true;
|
||||
return isset($_SESSION['flash'])
|
||||
? $_SESSION['flash']
|
||||
: array();
|
||||
}
|
||||
}
|
||||
45
htdocs/includes/restler/Format/AmfFormat.php
Normal file
45
htdocs/includes/restler/Format/AmfFormat.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
use ZendAmf\Parser\Amf3\Deserializer;
|
||||
use ZendAmf\Parser\Amf3\Serializer;
|
||||
use ZendAmf\Parser\InputStream;
|
||||
use ZendAmf\Parser\OutputStream;
|
||||
|
||||
/**
|
||||
* AMF Binary Format for Restler Framework.
|
||||
* Native format supported by Adobe Flash and Adobe AIR
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class AmfFormat extends Format
|
||||
{
|
||||
const MIME = 'application/x-amf';
|
||||
const EXTENSION = 'amf';
|
||||
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
|
||||
$stream = new OutputStream();
|
||||
$serializer = new Serializer($stream);
|
||||
$serializer->writeTypeMarker($data);
|
||||
|
||||
return $stream->getStream();
|
||||
}
|
||||
|
||||
public function decode($data)
|
||||
{
|
||||
$stream = new InputStream(substr($data, 1));
|
||||
$deserializer = new Deserializer($stream);
|
||||
|
||||
return $deserializer->readTypeMarker();
|
||||
}
|
||||
}
|
||||
|
||||
181
htdocs/includes/restler/Format/CsvFormat.php
Normal file
181
htdocs/includes/restler/Format/CsvFormat.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
|
||||
use Luracast\Restler\Data\Object;
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
/**
|
||||
* Comma Separated Value Format
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class CsvFormat extends Format implements iDecodeStream
|
||||
{
|
||||
|
||||
const MIME = 'text/csv';
|
||||
const EXTENSION = 'csv';
|
||||
public static $delimiter = ',';
|
||||
public static $enclosure = '"';
|
||||
public static $escape = '\\';
|
||||
public static $haveHeaders = null;
|
||||
|
||||
/**
|
||||
* Encode the given data in the csv format
|
||||
*
|
||||
* @param array $data
|
||||
* resulting data that needs to
|
||||
* be encoded in the given format
|
||||
* @param boolean $humanReadable
|
||||
* set to TRUE when restler
|
||||
* is not running in production mode. Formatter has to
|
||||
* make the encoded output more human readable
|
||||
*
|
||||
* @return string encoded string
|
||||
*
|
||||
* @throws RestException 500 on unsupported data
|
||||
*/
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
$char = Object::$separatorChar;
|
||||
Object::$separatorChar = false;
|
||||
$data = Object::toArray($data);
|
||||
Object::$separatorChar = $char;
|
||||
if (is_array($data) && array_values($data) == $data) {
|
||||
//if indexed array
|
||||
$lines = array();
|
||||
$row = array_shift($data);
|
||||
if (array_values($row) != $row) {
|
||||
$lines[] = static::putRow(array_keys($row));
|
||||
}
|
||||
$lines[] = static::putRow(array_values($row));
|
||||
foreach ($data as $row) {
|
||||
$lines[] = static::putRow(array_values($row));
|
||||
}
|
||||
return implode(PHP_EOL, $lines) . PHP_EOL;
|
||||
}
|
||||
throw new RestException(
|
||||
500,
|
||||
'Unsupported data for ' . strtoupper(static::EXTENSION) . ' format'
|
||||
);
|
||||
}
|
||||
|
||||
protected static function putRow($data)
|
||||
{
|
||||
$fp = fopen('php://temp', 'r+');
|
||||
fputcsv($fp, $data, static::$delimiter, static::$enclosure);
|
||||
rewind($fp);
|
||||
$data = fread($fp, 1048576);
|
||||
fclose($fp);
|
||||
return rtrim($data, PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the given data from the csv format
|
||||
*
|
||||
* @param string $data
|
||||
* data sent from client to
|
||||
* the api in the given format.
|
||||
*
|
||||
* @return array associative array of the parsed data
|
||||
*/
|
||||
public function decode($data)
|
||||
{
|
||||
$decoded = array();
|
||||
|
||||
if (empty($data)) {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
$lines = array_filter(explode(PHP_EOL, $data));
|
||||
|
||||
$keys = false;
|
||||
$row = static::getRow(array_shift($lines));
|
||||
|
||||
if (is_null(static::$haveHeaders)) {
|
||||
//try to guess with the given data
|
||||
static::$haveHeaders = !count(array_filter($row, 'is_numeric'));
|
||||
}
|
||||
|
||||
static::$haveHeaders ? $keys = $row : $decoded[] = $row;
|
||||
|
||||
while (($row = static::getRow(array_shift($lines), $keys)) !== FALSE)
|
||||
$decoded [] = $row;
|
||||
|
||||
$char = Object::$separatorChar;
|
||||
Object::$separatorChar = false;
|
||||
$decoded = Object::toArray($decoded);
|
||||
Object::$separatorChar = $char;
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
protected static function getRow($data, $keys = false)
|
||||
{
|
||||
if (empty($data)) {
|
||||
return false;
|
||||
}
|
||||
$line = str_getcsv(
|
||||
$data,
|
||||
static::$delimiter,
|
||||
static::$enclosure,
|
||||
static::$escape
|
||||
);
|
||||
|
||||
$row = array();
|
||||
foreach ($line as $key => $value) {
|
||||
if (is_numeric($value))
|
||||
$value = floatval($value);
|
||||
if ($keys) {
|
||||
if (isset($keys [$key]))
|
||||
$row [$keys [$key]] = $value;
|
||||
} else {
|
||||
$row [$key] = $value;
|
||||
}
|
||||
}
|
||||
if ($keys) {
|
||||
for ($i = count($row); $i < count($keys); $i++) {
|
||||
$row[$keys[$i]] = null;
|
||||
}
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the given data stream
|
||||
*
|
||||
* @param string $stream A stream resource with data
|
||||
* sent from client to the api
|
||||
* in the given format.
|
||||
*
|
||||
* @return array associative array of the parsed data
|
||||
*/
|
||||
public function decodeStream($stream)
|
||||
{
|
||||
$decoded = array();
|
||||
|
||||
$keys = false;
|
||||
$row = static::getRow(stream_get_line($stream, 0, PHP_EOL));
|
||||
if (is_null(static::$haveHeaders)) {
|
||||
//try to guess with the given data
|
||||
static::$haveHeaders = !count(array_filter($row, 'is_numeric'));
|
||||
}
|
||||
|
||||
static::$haveHeaders ? $keys = $row : $decoded[] = $row;
|
||||
|
||||
while (($row = static::getRow(stream_get_line($stream, 0, PHP_EOL), $keys)) !== FALSE)
|
||||
$decoded [] = $row;
|
||||
|
||||
$char = Object::$separatorChar;
|
||||
Object::$separatorChar = false;
|
||||
$decoded = Object::toArray($decoded);
|
||||
Object::$separatorChar = $char;
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
140
htdocs/includes/restler/Format/Format.php
Normal file
140
htdocs/includes/restler/Format/Format.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
/**
|
||||
* Abstract class to implement common methods of iFormat
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
abstract class Format implements iFormat
|
||||
{
|
||||
/**
|
||||
* override in the extending class
|
||||
*/
|
||||
const MIME = 'text/plain';
|
||||
/**
|
||||
* override in the extending class
|
||||
*/
|
||||
const EXTENSION = 'txt';
|
||||
|
||||
/**
|
||||
* @var string charset encoding defaults to UTF8
|
||||
*/
|
||||
protected $charset='utf-8';
|
||||
|
||||
/**
|
||||
* Injected at runtime
|
||||
*
|
||||
* @var \Luracast\Restler\Restler
|
||||
*/
|
||||
public $restler;
|
||||
|
||||
/**
|
||||
* Get MIME type => Extension mappings as an associative array
|
||||
*
|
||||
* @return array list of mime strings for the format
|
||||
* @example array('application/json'=>'json');
|
||||
*/
|
||||
public function getMIMEMap()
|
||||
{
|
||||
return array(
|
||||
static::MIME => static::EXTENSION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected MIME type
|
||||
*
|
||||
* @param string $mime
|
||||
* MIME type
|
||||
*/
|
||||
public function setMIME($mime)
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Content-Type field of the HTTP header can send a charset
|
||||
* parameter in the HTTP header to specify the character
|
||||
* encoding of the document.
|
||||
* This information is passed
|
||||
* here so that Format class can encode data accordingly
|
||||
* Format class may choose to ignore this and use its
|
||||
* default character set.
|
||||
*
|
||||
* @param string $charset
|
||||
* Example utf-8
|
||||
*/
|
||||
public function setCharset($charset)
|
||||
{
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Content-Type accepted by the Format class
|
||||
*
|
||||
* @return string $charset Example utf-8
|
||||
*/
|
||||
public function getCharset()
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get selected MIME type
|
||||
*/
|
||||
public function getMIME()
|
||||
{
|
||||
return static::MIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected file extension
|
||||
*
|
||||
* @param string $extension
|
||||
* file extension
|
||||
*/
|
||||
public function setExtension($extension)
|
||||
{
|
||||
//do nothing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the selected file extension
|
||||
*
|
||||
* @return string file extension
|
||||
*/
|
||||
public function getExtension()
|
||||
{
|
||||
return static::EXTENSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean is parsing the request supported?
|
||||
*/
|
||||
public function isReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean is composing response supported?
|
||||
*/
|
||||
public function isWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getExtension();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
485
htdocs/includes/restler/Format/HtmlFormat.php
Normal file
485
htdocs/includes/restler/Format/HtmlFormat.php
Normal file
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\View\Compilers\BladeCompiler;
|
||||
use Illuminate\View\Engines\CompilerEngine;
|
||||
use Illuminate\View\Engines\EngineResolver;
|
||||
use Illuminate\View\Factory;
|
||||
use Illuminate\View\FileViewFinder;
|
||||
use Illuminate\View\View;
|
||||
use Luracast\Restler\Data\ApiMethodInfo;
|
||||
use Luracast\Restler\Data\Object;
|
||||
use Luracast\Restler\Defaults;
|
||||
use Luracast\Restler\RestException;
|
||||
use Luracast\Restler\Restler;
|
||||
use Luracast\Restler\Scope;
|
||||
use Luracast\Restler\UI\Nav;
|
||||
use Luracast\Restler\Util;
|
||||
|
||||
/**
|
||||
* Html template format
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class HtmlFormat extends Format
|
||||
{
|
||||
public static $mime = 'text/html';
|
||||
public static $extension = 'html';
|
||||
public static $view;
|
||||
public static $errorView = 'debug.php';
|
||||
public static $template = 'php';
|
||||
public static $handleSession = true;
|
||||
|
||||
public static $useSmartViews = true;
|
||||
/**
|
||||
* @var null|string defaults to template named folder in Defaults::$cacheDirectory
|
||||
*/
|
||||
public static $cacheDirectory = null;
|
||||
/**
|
||||
* @var array global key value pair to be supplied to the templates. All
|
||||
* keys added here will be available as a variable inside the template
|
||||
*/
|
||||
public static $data = array();
|
||||
/**
|
||||
* @var string set it to the location of your the view files. Defaults to
|
||||
* views folder which is same level as vendor directory.
|
||||
*/
|
||||
public static $viewPath;
|
||||
/**
|
||||
* @var array template and its custom extension key value pair
|
||||
*/
|
||||
public static $customTemplateExtensions = array('blade' => 'blade.php');
|
||||
/**
|
||||
* @var bool used internally for error handling
|
||||
*/
|
||||
protected static $parseViewMetadata = true;
|
||||
/**
|
||||
* @var Restler;
|
||||
*/
|
||||
public $restler;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//============ SESSION MANAGEMENT =============//
|
||||
if (static::$handleSession) {
|
||||
if (session_start() && isset($_SESSION['flash'])) {
|
||||
static::$data['flash'] = $_SESSION['flash'];
|
||||
unset($_SESSION['flash']);
|
||||
}
|
||||
}
|
||||
if (!static::$viewPath) {
|
||||
$array = explode('vendor', __DIR__, 2);
|
||||
static::$viewPath = $array[0] . 'views';
|
||||
}
|
||||
}
|
||||
|
||||
public static function blade(array $data, $debug = true)
|
||||
{
|
||||
if (!class_exists('\Illuminate\View\View', true))
|
||||
throw new RestException(500,
|
||||
'Blade templates require laravel view classes to be installed using `composer install`');
|
||||
$resolver = new EngineResolver();
|
||||
$files = new Filesystem();
|
||||
$compiler = new BladeCompiler($files, static::$cacheDirectory);
|
||||
$engine = new CompilerEngine($compiler);
|
||||
$resolver->register('blade', function () use ($engine) {
|
||||
return $engine;
|
||||
});
|
||||
|
||||
/** @var Restler $restler */
|
||||
$restler = Scope::get('Restler');
|
||||
|
||||
//Lets expose shortcuts for our classes
|
||||
spl_autoload_register(function ($className) use ($restler) {
|
||||
if (isset($restler->apiMethodInfo->metadata['scope'][$className])) {
|
||||
return class_alias($restler->apiMethodInfo->metadata['scope'][$className], $className);
|
||||
}
|
||||
if (isset(Scope::$classAliases[$className])) {
|
||||
return class_alias(Scope::$classAliases[$className], $className);
|
||||
}
|
||||
return false;
|
||||
}, true, true);
|
||||
|
||||
$viewFinder = new FileViewFinder($files, array(static::$viewPath));
|
||||
$factory = new Factory($resolver, $viewFinder, new Dispatcher());
|
||||
$path = $viewFinder->find(self::$view);
|
||||
$view = new View($factory, $engine, self::$view, $path, $data);
|
||||
$factory->callCreator($view);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public static function twig(array $data, $debug = true)
|
||||
{
|
||||
if (!class_exists('\Twig_Environment', true))
|
||||
throw new RestException(500,
|
||||
'Twig templates require twig classes to be installed using `composer install`');
|
||||
$loader = new \Twig_Loader_Filesystem(static::$viewPath);
|
||||
$twig = new \Twig_Environment($loader, array(
|
||||
'cache' => static::$cacheDirectory,
|
||||
'debug' => $debug,
|
||||
'use_strict_variables' => $debug,
|
||||
));
|
||||
if ($debug)
|
||||
$twig->addExtension(new \Twig_Extension_Debug());
|
||||
|
||||
$twig->addFunction(
|
||||
new \Twig_SimpleFunction(
|
||||
'form',
|
||||
'Luracast\Restler\UI\Forms::get',
|
||||
array('is_safe' => array('html'))
|
||||
)
|
||||
);
|
||||
$twig->addFunction(
|
||||
new \Twig_SimpleFunction(
|
||||
'form_key',
|
||||
'Luracast\Restler\UI\Forms::key'
|
||||
)
|
||||
);
|
||||
$twig->addFunction(
|
||||
new \Twig_SimpleFunction(
|
||||
'nav',
|
||||
'Luracast\Restler\UI\Nav::get'
|
||||
)
|
||||
);
|
||||
|
||||
$twig->registerUndefinedFunctionCallback(function ($name) {
|
||||
if (
|
||||
isset(HtmlFormat::$data[$name]) &&
|
||||
is_callable(HtmlFormat::$data[$name])
|
||||
) {
|
||||
return new \Twig_SimpleFunction(
|
||||
$name,
|
||||
HtmlFormat::$data[$name]
|
||||
);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$template = $twig->loadTemplate(static::getViewFile());
|
||||
return $template->render($data);
|
||||
}
|
||||
|
||||
public static function handlebar(array $data, $debug = true)
|
||||
{
|
||||
return static::mustache($data, $debug);
|
||||
}
|
||||
|
||||
public static function mustache(array $data, $debug = true)
|
||||
{
|
||||
if (!class_exists('\Mustache_Engine', true))
|
||||
throw new RestException(
|
||||
500,
|
||||
'Mustache/Handlebar templates require mustache classes ' .
|
||||
'to be installed using `composer install`'
|
||||
);
|
||||
if (!isset($data['nav']))
|
||||
$data['nav'] = array_values(Nav::get());
|
||||
$options = array(
|
||||
'loader' => new \Mustache_Loader_FilesystemLoader(
|
||||
static::$viewPath,
|
||||
array('extension' => static::getViewExtension())
|
||||
),
|
||||
'helpers' => array(
|
||||
'form' => function ($text, \Mustache_LambdaHelper $m) {
|
||||
$params = explode(',', $m->render($text));
|
||||
return call_user_func_array(
|
||||
'Luracast\Restler\UI\Forms::get',
|
||||
$params
|
||||
);
|
||||
},
|
||||
)
|
||||
);
|
||||
if (!$debug)
|
||||
$options['cache'] = static::$cacheDirectory;
|
||||
$m = new \Mustache_Engine($options);
|
||||
return $m->render(static::getViewFile(), $data);
|
||||
}
|
||||
|
||||
public static function php(array $data, $debug = true)
|
||||
{
|
||||
if (static::$view == 'debug')
|
||||
static::$viewPath = dirname(__DIR__) . '/views';
|
||||
$view = static::getViewFile(true);
|
||||
|
||||
if (!is_readable($view)) {
|
||||
throw new RestException(
|
||||
500,
|
||||
"view file `$view` is not readable. " .
|
||||
'Check for file presence and file permissions'
|
||||
);
|
||||
}
|
||||
|
||||
$path = static::$viewPath . DIRECTORY_SEPARATOR;
|
||||
$template = function ($view) use ($data, $path) {
|
||||
$form = function () {
|
||||
return call_user_func_array(
|
||||
'Luracast\Restler\UI\Forms::get',
|
||||
func_get_args()
|
||||
);
|
||||
};
|
||||
if (!isset($data['form']))
|
||||
$data['form'] = $form;
|
||||
$nav = function () {
|
||||
return call_user_func_array(
|
||||
'Luracast\Restler\UI\Nav::get',
|
||||
func_get_args()
|
||||
);
|
||||
};
|
||||
if (!isset($data['nav']))
|
||||
$data['nav'] = $nav;
|
||||
|
||||
$_ = function () use ($data, $path) {
|
||||
extract($data);
|
||||
$args = func_get_args();
|
||||
$task = array_shift($args);
|
||||
switch ($task) {
|
||||
case 'require':
|
||||
case 'include':
|
||||
$file = $path . $args[0];
|
||||
if (is_readable($file)) {
|
||||
if (
|
||||
isset($args[1]) &&
|
||||
($arrays = Util::nestedValue($data, $args[1]))
|
||||
) {
|
||||
$str = '';
|
||||
foreach ($arrays as $arr) {
|
||||
extract($arr);
|
||||
$str .= include $file;
|
||||
}
|
||||
return $str;
|
||||
} else {
|
||||
return include $file;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'if':
|
||||
if (count($args) < 2)
|
||||
$args[1] = '';
|
||||
if (count($args) < 3)
|
||||
$args[2] = '';
|
||||
return $args[0] ? $args[1] : $args[2];
|
||||
break;
|
||||
default:
|
||||
if (isset($data[$task]) && is_callable($data[$task]))
|
||||
return call_user_func_array($data[$task], $args);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
extract($data);
|
||||
return @include $view;
|
||||
};
|
||||
$value = $template($view);
|
||||
if (is_string($value))
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given data in the format
|
||||
*
|
||||
* @param array $data resulting data that needs to
|
||||
* be encoded in the given format
|
||||
* @param boolean $humanReadable set to TRUE when restler
|
||||
* is not running in production mode.
|
||||
* Formatter has to make the encoded
|
||||
* output more human readable
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return string encoded string
|
||||
*/
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
if (!is_readable(static::$viewPath)) {
|
||||
throw new \Exception(
|
||||
'The views directory `'
|
||||
. self::$viewPath . '` should exist with read permission.'
|
||||
);
|
||||
}
|
||||
static::$data['basePath'] = dirname($_SERVER['SCRIPT_NAME']);
|
||||
static::$data['baseUrl'] = $this->restler->getBaseUrl();
|
||||
static::$data['currentPath'] = $this->restler->url;
|
||||
|
||||
try {
|
||||
$exception = $this->restler->exception;
|
||||
$success = is_null($exception);
|
||||
$error = $success ? null : $exception->getMessage();
|
||||
$data = array(
|
||||
'response' => Object::toArray($data),
|
||||
'stages' => $this->restler->getEvents(),
|
||||
'success' => $success,
|
||||
'error' => $error
|
||||
);
|
||||
$info = $data['api'] = $this->restler->apiMethodInfo;
|
||||
$metadata = Util::nestedValue(
|
||||
$this->restler, 'apiMethodInfo', 'metadata'
|
||||
);
|
||||
$view = $success ? 'view' : 'errorView';
|
||||
$value = false;
|
||||
if (static::$parseViewMetadata && isset($metadata[$view])) {
|
||||
if (is_array($metadata[$view])) {
|
||||
self::$view = $metadata[$view]['description'];
|
||||
$value = Util::nestedValue(
|
||||
$metadata[$view], 'properties', 'value'
|
||||
);
|
||||
} else {
|
||||
self::$view = $metadata[$view];
|
||||
}
|
||||
} elseif (!self::$view) {
|
||||
$file = static::$viewPath . '/' . $this->restler->url . '.' . static::getViewExtension();
|
||||
self::$view = static::$useSmartViews && is_readable($file)
|
||||
? $this->restler->url
|
||||
: static::$errorView;
|
||||
}
|
||||
if (
|
||||
isset($metadata['param'])
|
||||
&& (!$value || 0 === strpos($value, 'request'))
|
||||
) {
|
||||
$params = $metadata['param'];
|
||||
foreach ($params as $index => &$param) {
|
||||
$index = intval($index);
|
||||
if (is_numeric($index)) {
|
||||
$param['value'] = $this
|
||||
->restler
|
||||
->apiMethodInfo
|
||||
->parameters[$index];
|
||||
}
|
||||
}
|
||||
$data['request']['parameters'] = $params;
|
||||
}
|
||||
if ($value) {
|
||||
$data = Util::nestedValue($data, explode('.', $value));
|
||||
}
|
||||
$data += static::$data;
|
||||
if (false === ($i = strrpos(self::$view, '.'))) {
|
||||
$template = self::$template;
|
||||
} else {
|
||||
self::$template = $template = substr(self::$view, $i + 1);
|
||||
self::$view = substr(self::$view, 0, $i);
|
||||
}
|
||||
if (!static::$cacheDirectory) {
|
||||
static::$cacheDirectory = Defaults::$cacheDirectory . DIRECTORY_SEPARATOR . $template;
|
||||
if (!file_exists(static::$cacheDirectory)) {
|
||||
if (!mkdir(static::$cacheDirectory)) {
|
||||
throw new RestException(500, 'Unable to create cache directory `' . static::$cacheDirectory . '`');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method_exists($class = get_called_class(), $template)) {
|
||||
return call_user_func("$class::$template", $data, $humanReadable);
|
||||
}
|
||||
throw new RestException(500, "Unsupported template system `$template`");
|
||||
} catch (Exception $e) {
|
||||
static::$parseViewMetadata = false;
|
||||
$this->reset();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getViewExtension()
|
||||
{
|
||||
return isset(static::$customTemplateExtensions[static::$template])
|
||||
? static::$customTemplateExtensions[static::$template]
|
||||
: static::$template;
|
||||
}
|
||||
|
||||
public static function getViewFile($fullPath = false, $includeExtension = true)
|
||||
{
|
||||
$v = $fullPath ? static::$viewPath . '/' : '';
|
||||
$v .= static::$view;
|
||||
if ($includeExtension)
|
||||
$v .= '.' . static::getViewExtension();
|
||||
return $v;
|
||||
}
|
||||
|
||||
private function reset()
|
||||
{
|
||||
static::$mime = 'text/html';
|
||||
static::$extension = 'html';
|
||||
static::$view = 'debug';
|
||||
static::$template = 'php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the given data from the format
|
||||
*
|
||||
* @param string $data
|
||||
* data sent from client to
|
||||
* the api in the given format.
|
||||
*
|
||||
* @return array associative array of the parsed data
|
||||
*
|
||||
* @throws RestException
|
||||
*/
|
||||
public function decode($data)
|
||||
{
|
||||
throw new RestException(500, 'HtmlFormat is write only');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool false as HTML format is write only
|
||||
*/
|
||||
public function isReadable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MIME type => Extension mappings as an associative array
|
||||
*
|
||||
* @return array list of mime strings for the format
|
||||
* @example array('application/json'=>'json');
|
||||
*/
|
||||
public function getMIMEMap()
|
||||
{
|
||||
return array(
|
||||
static::$mime => static::$extension
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected MIME type
|
||||
*
|
||||
* @param string $mime MIME type
|
||||
*/
|
||||
public function setMIME($mime)
|
||||
{
|
||||
static::$mime = $mime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get selected MIME type
|
||||
*/
|
||||
public function getMIME()
|
||||
{
|
||||
return static::$mime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the selected file extension
|
||||
*
|
||||
* @return string file extension
|
||||
*/
|
||||
public function getExtension()
|
||||
{
|
||||
return static::$extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected file extension
|
||||
*
|
||||
* @param string $extension file extension
|
||||
*/
|
||||
public function setExtension($extension)
|
||||
{
|
||||
static::$extension = $extension;
|
||||
}
|
||||
}
|
||||
48
htdocs/includes/restler/Format/JsFormat.php
Normal file
48
htdocs/includes/restler/Format/JsFormat.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
/**
|
||||
* Javascript Object Notation Packaged in a method (JSONP)
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class JsFormat extends JsonFormat
|
||||
{
|
||||
const MIME = 'text/javascript';
|
||||
const EXTENSION = 'js';
|
||||
|
||||
public static $callbackMethodName = 'parseResponse';
|
||||
public static $callbackOverrideQueryString = 'callback';
|
||||
public static $includeHeaders = true;
|
||||
|
||||
public function encode($data, $human_readable = false)
|
||||
{
|
||||
$r = array();
|
||||
if (static::$includeHeaders) {
|
||||
$r['meta'] = array();
|
||||
foreach (headers_list() as $header) {
|
||||
list($h, $v) = explode(': ', $header, 2);
|
||||
$r['meta'][$h] = $v;
|
||||
}
|
||||
}
|
||||
$r['data'] = $data;
|
||||
if (isset($_GET[static::$callbackOverrideQueryString])) {
|
||||
static::$callbackMethodName
|
||||
= (string) $_GET[static::$callbackOverrideQueryString];
|
||||
}
|
||||
return static::$callbackMethodName . '('
|
||||
. parent::encode($r, $human_readable) . ');';
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
210
htdocs/includes/restler/Format/JsonFormat.php
Normal file
210
htdocs/includes/restler/Format/JsonFormat.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
use Luracast\Restler\Data\Object;
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
/**
|
||||
* Javascript Object Notation Format
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class JsonFormat extends Format
|
||||
{
|
||||
/**
|
||||
* @var boolean|null shim for json_encode option JSON_PRETTY_PRINT set
|
||||
* it to null to use smart defaults
|
||||
*/
|
||||
public static $prettyPrint = null;
|
||||
|
||||
/**
|
||||
* @var boolean|null shim for json_encode option JSON_UNESCAPED_SLASHES
|
||||
* set it to null to use smart defaults
|
||||
*/
|
||||
public static $unEscapedSlashes = null;
|
||||
|
||||
/**
|
||||
* @var boolean|null shim for json_encode JSON_UNESCAPED_UNICODE set it
|
||||
* to null to use smart defaults
|
||||
*/
|
||||
public static $unEscapedUnicode = null;
|
||||
|
||||
/**
|
||||
* @var boolean|null shim for json_decode JSON_BIGINT_AS_STRING set it to
|
||||
* null to
|
||||
* use smart defaults
|
||||
*/
|
||||
public static $bigIntAsString = null;
|
||||
|
||||
const MIME = 'application/json';
|
||||
const EXTENSION = 'json';
|
||||
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
if (!is_null(self::$prettyPrint)) {
|
||||
$humanReadable = self::$prettyPrint;
|
||||
}
|
||||
if (is_null(self::$unEscapedSlashes)) {
|
||||
self::$unEscapedSlashes = $humanReadable;
|
||||
}
|
||||
if (is_null(self::$unEscapedUnicode)) {
|
||||
self::$unEscapedUnicode = $this->charset == 'utf-8';
|
||||
}
|
||||
$options = 0;
|
||||
if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) // PHP >= 5.4
|
||||
|| PHP_MAJOR_VERSION > 5 // PHP >= 6.0
|
||||
) {
|
||||
if ($humanReadable) $options |= JSON_PRETTY_PRINT;
|
||||
if (self::$unEscapedSlashes) $options |= JSON_UNESCAPED_SLASHES;
|
||||
if (self::$bigIntAsString) $options |= JSON_BIGINT_AS_STRING;
|
||||
if (self::$unEscapedUnicode) $options |= JSON_UNESCAPED_UNICODE;
|
||||
return json_encode(
|
||||
Object::toArray($data, true), $options
|
||||
);
|
||||
}
|
||||
|
||||
$result = json_encode(Object::toArray($data, true));
|
||||
if ($humanReadable) $result = $this->formatJson($result);
|
||||
if (self::$unEscapedUnicode) {
|
||||
$result = preg_replace_callback('/\\\u(\w\w\w\w)/',
|
||||
function($matches)
|
||||
{
|
||||
if (function_exists('mb_convert_encoding'))
|
||||
{
|
||||
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE');
|
||||
}
|
||||
else
|
||||
{
|
||||
return iconv('UTF-16BE','UTF-8',pack('H*', $matches[1]));
|
||||
}
|
||||
}
|
||||
, $result);
|
||||
}
|
||||
if (self::$unEscapedSlashes) $result = str_replace('\/', '/', $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function decode($data)
|
||||
{
|
||||
$options = 0;
|
||||
if (self::$bigIntAsString) {
|
||||
if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) // PHP >= 5.4
|
||||
|| PHP_MAJOR_VERSION > 5 // PHP >= 6.0
|
||||
) {
|
||||
$options |= JSON_BIGINT_AS_STRING;
|
||||
} else {
|
||||
$data = preg_replace(
|
||||
'/:\s*(\-?\d+(\.\d+)?([e|E][\-|\+]\d+)?)/',
|
||||
': "$1"', $data
|
||||
);
|
||||
}
|
||||
}
|
||||
$decoded = json_decode($data, $options);
|
||||
if (function_exists('json_last_error')) {
|
||||
switch (json_last_error()) {
|
||||
case JSON_ERROR_NONE :
|
||||
return Object::toArray($decoded);
|
||||
break;
|
||||
case JSON_ERROR_DEPTH :
|
||||
$message = 'maximum stack depth exceeded';
|
||||
break;
|
||||
case JSON_ERROR_STATE_MISMATCH :
|
||||
$message = 'underflow or the modes mismatch';
|
||||
break;
|
||||
case JSON_ERROR_CTRL_CHAR :
|
||||
$message = 'unexpected control character found';
|
||||
break;
|
||||
case JSON_ERROR_SYNTAX :
|
||||
$message = 'malformed JSON';
|
||||
break;
|
||||
case JSON_ERROR_UTF8 :
|
||||
$message = 'malformed UTF-8 characters, possibly ' .
|
||||
'incorrectly encoded';
|
||||
break;
|
||||
default :
|
||||
$message = 'unknown error';
|
||||
break;
|
||||
}
|
||||
throw new RestException (400, 'Error parsing JSON, ' . $message);
|
||||
} elseif (strlen($data) && $decoded === null || $decoded === $data) {
|
||||
throw new RestException (400, 'Error parsing JSON');
|
||||
}
|
||||
|
||||
return Object::toArray($decoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty print JSON string
|
||||
*
|
||||
* @param string $json
|
||||
*
|
||||
* @return string formatted json
|
||||
*/
|
||||
private function formatJson($json)
|
||||
{
|
||||
$tab = ' ';
|
||||
$newJson = '';
|
||||
$indentLevel = 0;
|
||||
$inString = false;
|
||||
$len = strlen($json);
|
||||
for ($c = 0; $c < $len; $c++) {
|
||||
$char = $json [$c];
|
||||
switch ($char) {
|
||||
case '{' :
|
||||
case '[' :
|
||||
if (!$inString) {
|
||||
$newJson .= $char . "\n" .
|
||||
str_repeat($tab, $indentLevel + 1);
|
||||
$indentLevel++;
|
||||
} else {
|
||||
$newJson .= $char;
|
||||
}
|
||||
break;
|
||||
case '}' :
|
||||
case ']' :
|
||||
if (!$inString) {
|
||||
$indentLevel--;
|
||||
$newJson .= "\n" .
|
||||
str_repeat($tab, $indentLevel) . $char;
|
||||
} else {
|
||||
$newJson .= $char;
|
||||
}
|
||||
break;
|
||||
case ',' :
|
||||
if (!$inString) {
|
||||
$newJson .= ",\n" .
|
||||
str_repeat($tab, $indentLevel);
|
||||
} else {
|
||||
$newJson .= $char;
|
||||
}
|
||||
break;
|
||||
case ':' :
|
||||
if (!$inString) {
|
||||
$newJson .= ': ';
|
||||
} else {
|
||||
$newJson .= $char;
|
||||
}
|
||||
break;
|
||||
case '"' :
|
||||
if ($c == 0) {
|
||||
$inString = true;
|
||||
} elseif ($c > 0 && $json [$c - 1] != '\\') {
|
||||
$inString = !$inString;
|
||||
}
|
||||
default :
|
||||
$newJson .= $char;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $newJson;
|
||||
}
|
||||
}
|
||||
|
||||
144
htdocs/includes/restler/Format/MultiFormat.php
Normal file
144
htdocs/includes/restler/Format/MultiFormat.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
/**
|
||||
* Describe the purpose of this class/interface/trait
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
abstract class MultiFormat implements iFormat
|
||||
{
|
||||
/**
|
||||
* override in the extending class
|
||||
*/
|
||||
const MIME = 'text/plain,text/html';
|
||||
/**
|
||||
* override in the extending class
|
||||
*/
|
||||
const EXTENSION = 'txt,html';
|
||||
|
||||
/**
|
||||
* @var string charset encoding defaults to UTF8
|
||||
*/
|
||||
protected $charset='utf-8';
|
||||
|
||||
public static $mime;
|
||||
public static $extension;
|
||||
|
||||
/**
|
||||
* Injected at runtime
|
||||
*
|
||||
* @var \Luracast\Restler\Restler
|
||||
*/
|
||||
public $restler;
|
||||
|
||||
/**
|
||||
* Get MIME type => Extension mappings as an associative array
|
||||
*
|
||||
* @return array list of mime strings for the format
|
||||
* @example array('application/json'=>'json');
|
||||
*/
|
||||
public function getMIMEMap()
|
||||
{
|
||||
$extensions = explode(',',static::EXTENSION);
|
||||
$mimes = explode(',',static::MIME);
|
||||
$count = max(count($extensions), count($mimes));
|
||||
$extensions += array_fill(0, $count, end($extensions));
|
||||
$mimes += array_fill(0, $count, end($mimes));
|
||||
return array_combine($mimes,$extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected MIME type
|
||||
*
|
||||
* @param string $mime
|
||||
* MIME type
|
||||
*/
|
||||
public function setMIME($mime)
|
||||
{
|
||||
static::$mime = $mime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Content-Type field of the HTTP header can send a charset
|
||||
* parameter in the HTTP header to specify the character
|
||||
* encoding of the document.
|
||||
* This information is passed
|
||||
* here so that Format class can encode data accordingly
|
||||
* Format class may choose to ignore this and use its
|
||||
* default character set.
|
||||
*
|
||||
* @param string $charset
|
||||
* Example utf-8
|
||||
*/
|
||||
public function setCharset($charset)
|
||||
{
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Content-Type accepted by the Format class
|
||||
*
|
||||
* @return string $charset Example utf-8
|
||||
*/
|
||||
public function getCharset()
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get selected MIME type
|
||||
*/
|
||||
public function getMIME()
|
||||
{
|
||||
return static::$mime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected file extension
|
||||
*
|
||||
* @param string $extension
|
||||
* file extension
|
||||
*/
|
||||
public function setExtension($extension)
|
||||
{
|
||||
static::$extension = $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the selected file extension
|
||||
*
|
||||
* @return string file extension
|
||||
*/
|
||||
public function getExtension()
|
||||
{
|
||||
return static::$extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean is parsing the request supported?
|
||||
*/
|
||||
public function isReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean is composing response supported?
|
||||
*/
|
||||
public function isWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getExtension();
|
||||
}
|
||||
}
|
||||
|
||||
91
htdocs/includes/restler/Format/PlistFormat.php
Normal file
91
htdocs/includes/restler/Format/PlistFormat.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
use Luracast\Restler\Data\Object;
|
||||
use CFPropertyList\CFTypeDetector;
|
||||
use CFPropertyList\CFPropertyList;
|
||||
|
||||
/**
|
||||
* Plist Format for Restler Framework.
|
||||
* Plist is the native data exchange format for Apple iOS and Mac platform.
|
||||
* Use this format to talk to mac applications and iOS devices.
|
||||
* This class is capable of serving both xml plist and binary plist.
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class PlistFormat extends MultiFormat
|
||||
{
|
||||
/**
|
||||
* @var boolean set it to true binary plist is preferred
|
||||
*/
|
||||
public static $compact = null;
|
||||
const MIME = 'application/xml,application/x-plist';
|
||||
const EXTENSION = 'plist';
|
||||
|
||||
public function setMIME($mime)
|
||||
{
|
||||
static::$mime = $mime;
|
||||
static::$compact = $mime == 'application/x-plist';
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given data in plist format
|
||||
*
|
||||
* @param array $data
|
||||
* resulting data that needs to
|
||||
* be encoded in plist format
|
||||
* @param boolean $humanReadable
|
||||
* set to true when restler
|
||||
* is not running in production mode. Formatter has to
|
||||
* make the encoded output more human readable
|
||||
*
|
||||
* @return string encoded string
|
||||
*/
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
//require_once 'CFPropertyList.php';
|
||||
if (!isset(self::$compact)) {
|
||||
self::$compact = !$humanReadable;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @var CFPropertyList
|
||||
*/
|
||||
$plist = new CFPropertyList ();
|
||||
$td = new CFTypeDetector ();
|
||||
$guessedStructure = $td->toCFType(
|
||||
Object::toArray($data)
|
||||
);
|
||||
$plist->add($guessedStructure);
|
||||
|
||||
return self::$compact
|
||||
? $plist->toBinary()
|
||||
: $plist->toXML(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the given data from plist format
|
||||
*
|
||||
* @param string $data
|
||||
* data sent from client to
|
||||
* the api in the given format.
|
||||
*
|
||||
* @return array associative array of the parsed data
|
||||
*/
|
||||
public function decode($data)
|
||||
{
|
||||
//require_once 'CFPropertyList.php';
|
||||
$plist = new CFPropertyList ();
|
||||
$plist->parse($data);
|
||||
|
||||
return $plist->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
24
htdocs/includes/restler/Format/TsvFormat.php
Normal file
24
htdocs/includes/restler/Format/TsvFormat.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
/**
|
||||
* Tab Separated Value Format
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class TsvFormat extends CsvFormat
|
||||
{
|
||||
const MIME = 'text/csv';
|
||||
const EXTENSION = 'csv';
|
||||
public static $delimiter = "\t";
|
||||
public static $enclosure = '"';
|
||||
public static $escape = '\\';
|
||||
public static $haveHeaders = null;
|
||||
}
|
||||
145
htdocs/includes/restler/Format/UploadFormat.php
Normal file
145
htdocs/includes/restler/Format/UploadFormat.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
use Luracast\Restler\RestException;
|
||||
|
||||
/**
|
||||
* Support for Multi Part Form Data and File Uploads
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class UploadFormat extends Format
|
||||
{
|
||||
const MIME = 'multipart/form-data';
|
||||
const EXTENSION = 'post';
|
||||
public static $errors = array(
|
||||
0 => false,
|
||||
1 => "The uploaded file exceeds the maximum allowed size",
|
||||
2 => "The uploaded file exceeds the maximum allowed size",
|
||||
3 => "The uploaded file was only partially uploaded",
|
||||
4 => "No file was uploaded",
|
||||
6 => "Missing a temporary folder"
|
||||
);
|
||||
/**
|
||||
* use it if you need to restrict uploads based on file type
|
||||
* setting it as an empty array allows all file types
|
||||
* default is to allow only png and jpeg images
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $allowedMimeTypes = array('image/jpeg', 'image/png');
|
||||
/**
|
||||
* use it to restrict uploads based on file size
|
||||
* set it to 0 to allow all sizes
|
||||
* please note that it upload restrictions in the server
|
||||
* takes precedence so it has to be lower than or equal to that
|
||||
* default value is 1MB (1024x1024)bytes
|
||||
* usual value for the server is 8388608
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $maximumFileSize = 1048576;
|
||||
/**
|
||||
* Your own validation function for validating each uploaded file
|
||||
* it can return false or throw an exception for invalid file
|
||||
* use anonymous function / closure in PHP 5.3 and above
|
||||
* use function name in other cases
|
||||
*
|
||||
* @var Callable
|
||||
*/
|
||||
public static $customValidationFunction;
|
||||
/**
|
||||
* Since exceptions are triggered way before at the `get` stage
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $suppressExceptionsAsError = false;
|
||||
|
||||
protected static function checkFile(& $file, $doMimeCheck = false, $doSizeCheck = false)
|
||||
{
|
||||
try {
|
||||
if ($file['error']) {
|
||||
//server is throwing an error
|
||||
//assume that the error is due to maximum size limit
|
||||
throw new RestException($file['error'] > 5 ? 500 : 413, static::$errors[$file['error']]);
|
||||
}
|
||||
$typeElements = explode('/', $file['type']);
|
||||
$genericType = $typeElements[0].'/*';
|
||||
if (
|
||||
$doMimeCheck
|
||||
&& !(
|
||||
in_array($file['type'], self::$allowedMimeTypes)
|
||||
|| in_array($genericType, self::$allowedMimeTypes)
|
||||
)
|
||||
) {
|
||||
throw new RestException(403, "File type ({$file['type']}) is not supported.");
|
||||
}
|
||||
if ($doSizeCheck && $file['size'] > self::$maximumFileSize) {
|
||||
throw new RestException(413, "Uploaded file ({$file['name']}) is too big.");
|
||||
}
|
||||
if (self::$customValidationFunction) {
|
||||
if (!call_user_func(self::$customValidationFunction, $file)) {
|
||||
throw new RestException(403, "File ({$file['name']}) is not supported.");
|
||||
}
|
||||
}
|
||||
} catch (RestException $e) {
|
||||
if (static::$suppressExceptionsAsError) {
|
||||
$file['error'] = $e->getCode() == 413 ? 1 : 6;
|
||||
$file['exception'] = $e;
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
throw new RestException(500, 'UploadFormat is read only');
|
||||
}
|
||||
|
||||
public function decode($data)
|
||||
{
|
||||
$doMimeCheck = !empty(self::$allowedMimeTypes);
|
||||
$doSizeCheck = self::$maximumFileSize ? TRUE : FALSE;
|
||||
//validate
|
||||
foreach ($_FILES as & $file) {
|
||||
if (is_array($file['error'])) {
|
||||
foreach ($file['error'] as $i => $error) {
|
||||
$innerFile = array();
|
||||
foreach ($file as $property => $value) {
|
||||
$innerFile[$property] = $value[$i];
|
||||
}
|
||||
if ($innerFile['name'])
|
||||
static::checkFile($innerFile, $doMimeCheck, $doSizeCheck);
|
||||
|
||||
if (isset($innerFile['exception'])) {
|
||||
$file['error'][$i] = $innerFile['error'];
|
||||
$file['exception'] = $innerFile['exception'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($file['name'])
|
||||
static::checkFile($file, $doMimeCheck, $doSizeCheck);
|
||||
if (isset($innerFile['exception'])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//sort file order if needed;
|
||||
return UrlEncodedFormat::decoderTypeFix($_FILES + $_POST);
|
||||
}
|
||||
|
||||
function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
58
htdocs/includes/restler/Format/UrlEncodedFormat.php
Normal file
58
htdocs/includes/restler/Format/UrlEncodedFormat.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
/**
|
||||
* URL Encoded String Format
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class UrlEncodedFormat extends Format
|
||||
{
|
||||
const MIME = 'application/x-www-form-urlencoded';
|
||||
const EXTENSION = 'post';
|
||||
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
return http_build_query(static::encoderTypeFix($data));
|
||||
}
|
||||
|
||||
public function decode($data)
|
||||
{
|
||||
parse_str($data, $r);
|
||||
return self::decoderTypeFix($r);
|
||||
}
|
||||
|
||||
public static function encoderTypeFix(array $data)
|
||||
{
|
||||
foreach ($data as $k => $v) {
|
||||
if (is_bool($v)) {
|
||||
$data[$k] = $v = $v ? 'true' : 'false';
|
||||
} elseif (is_array($v)) {
|
||||
$data[$k] = $v = static::decoderTypeFix($v);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function decoderTypeFix(array $data)
|
||||
{
|
||||
foreach ($data as $k => $v) {
|
||||
if ($v === 'true' || $v === 'false') {
|
||||
$data[$k] = $v = $v === 'true';
|
||||
} elseif (is_array($v)) {
|
||||
$data[$k] = $v = static::decoderTypeFix($v);
|
||||
} elseif (empty($v) && $v != 0) {
|
||||
unset($data[$k]);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
348
htdocs/includes/restler/Format/XmlFormat.php
Normal file
348
htdocs/includes/restler/Format/XmlFormat.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
use Luracast\Restler\Data\Object;
|
||||
use Luracast\Restler\RestException;
|
||||
use SimpleXMLElement;
|
||||
use XMLWriter;
|
||||
|
||||
/**
|
||||
* XML Markup Format for Restler Framework
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class XmlFormat extends Format
|
||||
{
|
||||
const MIME = 'application/xml';
|
||||
const EXTENSION = 'xml';
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Properties related to reading/parsing/decoding xml
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
public static $importSettingsFromXml = false;
|
||||
public static $parseAttributes = true;
|
||||
public static $parseNamespaces = true;
|
||||
public static $parseTextNodeAsProperty = true;
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Properties related to writing/encoding xml
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
public static $useTextNodeProperty = true;
|
||||
public static $useNamespaces = true;
|
||||
public static $cdataNames = array();
|
||||
|
||||
// ==================================================================
|
||||
//
|
||||
// Common Properties
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
public static $attributeNames = array();
|
||||
public static $textNodeName = 'text';
|
||||
public static $namespaces = array();
|
||||
public static $namespacedProperties = array();
|
||||
/**
|
||||
* Default name for the root node.
|
||||
*
|
||||
* @var string $rootNodeName
|
||||
*/
|
||||
public static $rootName = 'response';
|
||||
public static $defaultTagName = 'item';
|
||||
|
||||
/**
|
||||
* When you decode an XML its structure is copied to the static vars
|
||||
* we can use this function to echo them out and then copy paste inside
|
||||
* our service methods
|
||||
*
|
||||
* @return string PHP source code to reproduce the configuration
|
||||
*/
|
||||
public static function exportCurrentSettings()
|
||||
{
|
||||
$s = 'XmlFormat::$rootName = "' . (self::$rootName) . "\";\n";
|
||||
$s .= 'XmlFormat::$attributeNames = ' .
|
||||
(var_export(self::$attributeNames, true)) . ";\n";
|
||||
$s .= 'XmlFormat::$defaultTagName = "' .
|
||||
self::$defaultTagName . "\";\n";
|
||||
$s .= 'XmlFormat::$parseAttributes = ' .
|
||||
(self::$parseAttributes ? 'true' : 'false') . ";\n";
|
||||
$s .= 'XmlFormat::$parseNamespaces = ' .
|
||||
(self::$parseNamespaces ? 'true' : 'false') . ";\n";
|
||||
if (self::$parseNamespaces) {
|
||||
$s .= 'XmlFormat::$namespaces = ' .
|
||||
(var_export(self::$namespaces, true)) . ";\n";
|
||||
$s .= 'XmlFormat::$namespacedProperties = ' .
|
||||
(var_export(self::$namespacedProperties, true)) . ";\n";
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
$data = Object::toArray($data);
|
||||
$xml = new XMLWriter();
|
||||
$xml->openMemory();
|
||||
$xml->startDocument('1.0', $this->charset);
|
||||
if ($humanReadable) {
|
||||
$xml->setIndent(true);
|
||||
$xml->setIndentString(' ');
|
||||
}
|
||||
static::$useNamespaces && isset(static::$namespacedProperties[static::$rootName])
|
||||
?
|
||||
$xml->startElementNs(
|
||||
static::$namespacedProperties[static::$rootName],
|
||||
static::$rootName,
|
||||
static::$namespaces[static::$namespacedProperties[static::$rootName]]
|
||||
)
|
||||
:
|
||||
$xml->startElement(static::$rootName);
|
||||
if (static::$useNamespaces) {
|
||||
foreach (static::$namespaces as $prefix => $ns) {
|
||||
if (isset(static::$namespacedProperties[static::$rootName])
|
||||
&& static::$namespacedProperties[static::$rootName] == $prefix
|
||||
)
|
||||
continue;
|
||||
$prefix = 'xmlns' . (empty($prefix) ? '' : ':' . $prefix);
|
||||
$xml->writeAttribute($prefix, $ns);
|
||||
}
|
||||
}
|
||||
$this->write($xml, $data, static::$rootName);
|
||||
$xml->endElement();
|
||||
return $xml->outputMemory();
|
||||
}
|
||||
|
||||
public function write(XMLWriter $xml, $data, $parent)
|
||||
{
|
||||
$text = array();
|
||||
if (is_array($data)) {
|
||||
if (static::$useTextNodeProperty && isset($data[static::$textNodeName])) {
|
||||
$text [] = $data[static::$textNodeName];
|
||||
unset($data[static::$textNodeName]);
|
||||
}
|
||||
$attributes = array_flip(static::$attributeNames);
|
||||
//make sure we deal with attributes first
|
||||
$temp = array();
|
||||
foreach ($data as $key => $value) {
|
||||
if (isset($attributes[$key])) {
|
||||
$temp[$key] = $data[$key];
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
$data = array_merge($temp, $data);
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
if (!is_array($value)) {
|
||||
$text [] = $value;
|
||||
continue;
|
||||
}
|
||||
$key = static::$defaultTagName;
|
||||
}
|
||||
$useNS = static::$useNamespaces
|
||||
&& !empty(static::$namespacedProperties[$key])
|
||||
&& false === strpos($key, ':');
|
||||
if (is_array($value)) {
|
||||
if ($value == array_values($value)) {
|
||||
//numeric array, create siblings
|
||||
foreach ($value as $v) {
|
||||
$useNS
|
||||
? $xml->startElementNs(
|
||||
static::$namespacedProperties[$key],
|
||||
$key,
|
||||
null
|
||||
)
|
||||
: $xml->startElement($key);
|
||||
$this->write($xml, $v, $key);
|
||||
$xml->endElement();
|
||||
}
|
||||
} else {
|
||||
$useNS
|
||||
? $xml->startElementNs(
|
||||
static::$namespacedProperties[$key],
|
||||
$key,
|
||||
null
|
||||
)
|
||||
: $xml->startElement($key);
|
||||
$this->write($xml, $value, $key);
|
||||
$xml->endElement();
|
||||
}
|
||||
continue;
|
||||
} elseif (is_bool($value)) {
|
||||
$value = $value ? 'true' : 'false';
|
||||
}
|
||||
if (isset($attributes[$key])) {
|
||||
$xml->writeAttribute($useNS ? static::$namespacedProperties[$key] . ':' . $key : $key, $value);
|
||||
} else {
|
||||
$useNS
|
||||
?
|
||||
$xml->startElementNs(
|
||||
static::$namespacedProperties[$key],
|
||||
$key,
|
||||
null
|
||||
)
|
||||
: $xml->startElement($key);
|
||||
$this->write($xml, $value, $key);
|
||||
$xml->endElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$text [] = (string)$data;
|
||||
}
|
||||
if (!empty($text)) {
|
||||
if (count($text) == 1) {
|
||||
in_array($parent, static::$cdataNames)
|
||||
? $xml->writeCdata(implode('', $text))
|
||||
: $xml->text(implode('', $text));
|
||||
} else {
|
||||
foreach ($text as $t) {
|
||||
$xml->writeElement(static::$textNodeName, $t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function decode($data)
|
||||
{
|
||||
try {
|
||||
if ($data == '') {
|
||||
return array();
|
||||
}
|
||||
libxml_use_internal_errors(true);
|
||||
$xml = simplexml_load_string($data,
|
||||
"SimpleXMLElement", LIBXML_NOBLANKS | LIBXML_NOCDATA | LIBXML_COMPACT);
|
||||
if (false === $xml) {
|
||||
$error = libxml_get_last_error();
|
||||
throw new RestException(400, 'Malformed XML. '
|
||||
. trim($error->message, "\r\n") . ' at line ' . $error->line);
|
||||
}
|
||||
libxml_clear_errors();
|
||||
if (static::$importSettingsFromXml) {
|
||||
static::$attributeNames = array();
|
||||
static::$namespacedProperties = array();
|
||||
static::$namespaces = array();
|
||||
static::$rootName = $xml->getName();
|
||||
$namespaces = $xml->getNamespaces();
|
||||
if (count($namespaces)) {
|
||||
$p = strpos($data, $xml->getName());
|
||||
if ($p && $data{$p - 1} == ':') {
|
||||
$s = strpos($data, '<') + 1;
|
||||
$prefix = substr($data, $s, $p - $s - 1);
|
||||
static::$namespacedProperties[static::$rootName] = $prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
$data = $this->read($xml);
|
||||
if (count($data) == 1 && isset($data[static::$textNodeName]))
|
||||
$data = $data[static::$textNodeName];
|
||||
return $data;
|
||||
} catch (\RuntimeException $e) {
|
||||
throw new RestException(400,
|
||||
"Error decoding request. " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function read(SimpleXMLElement $xml, $namespaces = null)
|
||||
{
|
||||
$r = array();
|
||||
$text = (string)$xml;
|
||||
|
||||
if (static::$parseAttributes) {
|
||||
$attributes = $xml->attributes();
|
||||
foreach ($attributes as $key => $value) {
|
||||
if (static::$importSettingsFromXml
|
||||
&& !in_array($key, static::$attributeNames)
|
||||
) {
|
||||
static::$attributeNames[] = $key;
|
||||
}
|
||||
$r[$key] = static::setType((string)$value);
|
||||
}
|
||||
}
|
||||
$children = $xml->children();
|
||||
foreach ($children as $key => $value) {
|
||||
if (isset($r[$key])) {
|
||||
if (is_array($r[$key])) {
|
||||
if ($r[$key] != array_values($r[$key]))
|
||||
$r[$key] = array($r[$key]);
|
||||
} else {
|
||||
$r[$key] = array($r[$key]);
|
||||
}
|
||||
$r[$key][] = $this->read($value, $namespaces);
|
||||
} else {
|
||||
$r[$key] = $this->read($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (static::$parseNamespaces) {
|
||||
if (is_null($namespaces))
|
||||
$namespaces = $xml->getDocNamespaces(true);
|
||||
foreach ($namespaces as $prefix => $ns) {
|
||||
static::$namespaces[$prefix] = $ns;
|
||||
if (static::$parseAttributes) {
|
||||
$attributes = $xml->attributes($ns);
|
||||
foreach ($attributes as $key => $value) {
|
||||
if (isset($r[$key])) {
|
||||
$key = "{$prefix}:$key";
|
||||
}
|
||||
if (static::$importSettingsFromXml
|
||||
&& !in_array($key, static::$attributeNames)
|
||||
) {
|
||||
static::$namespacedProperties[$key] = $prefix;
|
||||
static::$attributeNames[] = $key;
|
||||
}
|
||||
$r[$key] = static::setType((string)$value);
|
||||
}
|
||||
}
|
||||
$children = $xml->children($ns);
|
||||
foreach ($children as $key => $value) {
|
||||
if (static::$importSettingsFromXml)
|
||||
static::$namespacedProperties[$key] = $prefix;
|
||||
if (isset($r[$key])) {
|
||||
if (is_array($r[$key])) {
|
||||
if ($r[$key] != array_values($r[$key]))
|
||||
$r[$key] = array($r[$key]);
|
||||
} else {
|
||||
$r[$key] = array($r[$key]);
|
||||
}
|
||||
$r[$key][] = $this->read($value, $namespaces);
|
||||
} else {
|
||||
$r[$key] = $this->read($value, $namespaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($text) && $text !== '0') {
|
||||
if (empty($r)) return null;
|
||||
} else {
|
||||
empty($r)
|
||||
? $r = static::setType($text)
|
||||
: (
|
||||
static::$parseTextNodeAsProperty
|
||||
? $r[static::$textNodeName] = static::setType($text)
|
||||
: $r[] = static::setType($text)
|
||||
);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
public static function setType($value)
|
||||
{
|
||||
if (empty($value) && $value !== '0')
|
||||
return null;
|
||||
if ($value == 'true')
|
||||
return true;
|
||||
if ($value == 'false')
|
||||
return true;
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
36
htdocs/includes/restler/Format/YamlFormat.php
Normal file
36
htdocs/includes/restler/Format/YamlFormat.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Luracast\Restler\Data\Object;
|
||||
|
||||
/**
|
||||
* YAML Format for Restler Framework
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class YamlFormat extends Format
|
||||
{
|
||||
const MIME = 'text/plain';
|
||||
const EXTENSION = 'yaml';
|
||||
|
||||
public function encode($data, $humanReadable = false)
|
||||
{
|
||||
// require_once 'sfyaml.php';
|
||||
return @Yaml::dump(Object::toArray($data));
|
||||
}
|
||||
|
||||
public function decode($data)
|
||||
{
|
||||
// require_once 'sfyaml.php';
|
||||
return Yaml::parse($data);
|
||||
}
|
||||
}
|
||||
|
||||
30
htdocs/includes/restler/Format/iDecodeStream.php
Normal file
30
htdocs/includes/restler/Format/iDecodeStream.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
/**
|
||||
* Interface for creating formats that accept steams for decoding
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
interface iDecodeStream
|
||||
{
|
||||
|
||||
/**
|
||||
* Decode the given data stream
|
||||
*
|
||||
* @param string $stream A stream resource with data
|
||||
* sent from client to the api
|
||||
* in the given format.
|
||||
*
|
||||
* @return array associative array of the parsed data
|
||||
*/
|
||||
public function decodeStream($stream);
|
||||
|
||||
}
|
||||
109
htdocs/includes/restler/Format/iFormat.php
Normal file
109
htdocs/includes/restler/Format/iFormat.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
namespace Luracast\Restler\Format;
|
||||
|
||||
/**
|
||||
* Interface for creating custom data formats
|
||||
* like xml, json, yaml, amf etc
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage format
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
interface iFormat
|
||||
{
|
||||
/**
|
||||
* Get MIME type => Extension mappings as an associative array
|
||||
*
|
||||
* @return array list of mime strings for the format
|
||||
* @example array('application/json'=>'json');
|
||||
*/
|
||||
public function getMIMEMap();
|
||||
|
||||
/**
|
||||
* Set the selected MIME type
|
||||
*
|
||||
* @param string $mime
|
||||
* MIME type
|
||||
*/
|
||||
public function setMIME($mime);
|
||||
|
||||
/**
|
||||
* Content-Type field of the HTTP header can send a charset
|
||||
* parameter in the HTTP header to specify the character
|
||||
* encoding of the document.
|
||||
* This information is passed
|
||||
* here so that Format class can encode data accordingly
|
||||
* Format class may choose to ignore this and use its
|
||||
* default character set.
|
||||
*
|
||||
* @param string $charset
|
||||
* Example utf-8
|
||||
*/
|
||||
public function setCharset($charset);
|
||||
|
||||
/**
|
||||
* Content-Type accepted by the Format class
|
||||
*
|
||||
* @return string $charset Example utf-8
|
||||
*/
|
||||
public function getCharset();
|
||||
|
||||
/**
|
||||
* Get selected MIME type
|
||||
*/
|
||||
public function getMIME();
|
||||
|
||||
/**
|
||||
* Set the selected file extension
|
||||
*
|
||||
* @param string $extension
|
||||
* file extension
|
||||
*/
|
||||
public function setExtension($extension);
|
||||
|
||||
/**
|
||||
* Get the selected file extension
|
||||
*
|
||||
* @return string file extension
|
||||
*/
|
||||
public function getExtension();
|
||||
|
||||
/**
|
||||
* Encode the given data in the format
|
||||
*
|
||||
* @param array $data
|
||||
* resulting data that needs to
|
||||
* be encoded in the given format
|
||||
* @param boolean $humanReadable
|
||||
* set to TRUE when restler
|
||||
* is not running in production mode. Formatter has to
|
||||
* make the encoded output more human readable
|
||||
* @return string encoded string
|
||||
*/
|
||||
public function encode($data, $humanReadable = false);
|
||||
|
||||
/**
|
||||
* Decode the given data from the format
|
||||
*
|
||||
* @param string $data
|
||||
* data sent from client to
|
||||
* the api in the given format.
|
||||
* @return array associative array of the parsed data
|
||||
*/
|
||||
public function decode($data);
|
||||
|
||||
/**
|
||||
* @return boolean is parsing the request supported?
|
||||
*/
|
||||
public function isReadable();
|
||||
|
||||
/**
|
||||
* @return boolean is composing response supported?
|
||||
*/
|
||||
public function isWritable();
|
||||
}
|
||||
|
||||
129
htdocs/includes/restler/HumanReadableCache.php
Normal file
129
htdocs/includes/restler/HumanReadableCache.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
/**
|
||||
* Default Cache that writes/reads human readable files for caching purpose
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class HumanReadableCache implements iCache
|
||||
{
|
||||
/**
|
||||
* @var string path of the folder to hold cache files
|
||||
*/
|
||||
public static $cacheDir;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (is_null(self::$cacheDir)) {
|
||||
self::$cacheDir = Defaults::$cacheDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* store data in the cache
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $data
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return boolean true if successful
|
||||
*/
|
||||
public function set($name, $data)
|
||||
{
|
||||
if (is_array($data)) {
|
||||
$s = '$o = array();' . PHP_EOL . PHP_EOL;
|
||||
$s .= '// ** THIS IS AN AUTO GENERATED FILE.'
|
||||
. ' DO NOT EDIT MANUALLY ** ';
|
||||
foreach ($data as $key => $value) {
|
||||
$s .= PHP_EOL . PHP_EOL .
|
||||
"//==================== $key ===================="
|
||||
. PHP_EOL . PHP_EOL;
|
||||
if (is_array($value)) {
|
||||
$s .= '$o[\'' . $key . '\'] = array();';
|
||||
foreach ($value as $ke => $va) {
|
||||
$s .= PHP_EOL . PHP_EOL . "//==== $key $ke ===="
|
||||
. PHP_EOL . PHP_EOL;
|
||||
$s .= '$o[\'' . $key . '\'][\'' . $ke . '\'] = ' .
|
||||
str_replace(' ', ' ',
|
||||
var_export($va, true)) . ';';
|
||||
}
|
||||
} else {
|
||||
$s .= '$o[\'' . $key . '\'] = '
|
||||
. var_export($value, true) . ';';
|
||||
}
|
||||
}
|
||||
$s .= PHP_EOL . 'return $o;';
|
||||
} else {
|
||||
$s = 'return ' . var_export($data, true) . ';';
|
||||
}
|
||||
$file = $this->_file($name);
|
||||
$r = @file_put_contents($file, "<?php $s");
|
||||
@chmod($file, 0777);
|
||||
if ($r === false) {
|
||||
$this->throwException();
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve data from the cache
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $ignoreErrors
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $ignoreErrors = false)
|
||||
{
|
||||
$file = $this->_file($name);
|
||||
if (file_exists($file)) {
|
||||
return include($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete data from the cache
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $ignoreErrors
|
||||
*
|
||||
* @return boolean true if successful
|
||||
*/
|
||||
public function clear($name, $ignoreErrors = false)
|
||||
{
|
||||
return @unlink($this->_file($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the given name is cached
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return boolean true if cached
|
||||
*/
|
||||
public function isCached($name)
|
||||
{
|
||||
return file_exists($this->_file($name));
|
||||
}
|
||||
|
||||
private function _file($name)
|
||||
{
|
||||
return self::$cacheDir . '/' . $name . '.php';
|
||||
}
|
||||
|
||||
private function throwException()
|
||||
{
|
||||
throw new \Exception(
|
||||
'The cache directory `'
|
||||
. self::$cacheDir . '` should exist with write permission.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
8
htdocs/includes/restler/README.md
Normal file
8
htdocs/includes/restler/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
Luracast Restler Framework
|
||||
==========================
|
||||
|
||||
Restler is a simple and effective multi-format Web API Server written in PHP.
|
||||
|
||||
This repository contains just the framework files for installing the framework core using composer require statements.
|
||||
|
||||
For more information, usage examples, pull requests, and issues go to the [Main Repository](https://github.com/Luracast/Restler)
|
||||
53
htdocs/includes/restler/Redirect.php
Normal file
53
htdocs/includes/restler/Redirect.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Luracast\Restler\Format\JsonFormat;
|
||||
|
||||
/**
|
||||
* Static class for handling redirection
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class Redirect
|
||||
{
|
||||
/**
|
||||
* Redirect to given url
|
||||
*
|
||||
* @param string $url relative path or full url
|
||||
* @param array $params associative array of query parameters
|
||||
* @param array $flashData associative array of properties to be set in $_SESSION for one time use
|
||||
* @param int $status http status code to send the response with ideally 301 or 302
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function to($url, array $params = array(), array $flashData = array(), $status = 302)
|
||||
{
|
||||
$url = ltrim($url, '/');
|
||||
/** @var $r Restler */
|
||||
$r = Scope::get('Restler');
|
||||
$base = $r->getBaseUrl() . '/';
|
||||
if (0 !== strpos($url, 'http'))
|
||||
$url = $base . $url;
|
||||
if (!empty($flashData) || $base . $r->url !== $url || Util::getRequestMethod() != 'GET') {
|
||||
if ($r->responseFormat instanceof JsonFormat)
|
||||
return array('redirect' => $url);
|
||||
if (!empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
}
|
||||
Flash::set($flashData);
|
||||
header(
|
||||
"{$_SERVER['SERVER_PROTOCOL']} $status " .
|
||||
(isset(RestException::$codes[$status]) ? RestException::$codes[$status] : '')
|
||||
);
|
||||
header("Location: $url");
|
||||
die('');
|
||||
}
|
||||
return array();
|
||||
}
|
||||
}
|
||||
1006
htdocs/includes/restler/Resources.php
Normal file
1006
htdocs/includes/restler/Resources.php
Normal file
File diff suppressed because it is too large
Load Diff
138
htdocs/includes/restler/RestException.php
Normal file
138
htdocs/includes/restler/RestException.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Special Exception for raising API errors
|
||||
* that can be used in API methods
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @subpackage exception
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
*/
|
||||
|
||||
class RestException extends Exception
|
||||
{
|
||||
/**
|
||||
* HTTP status codes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $codes = array(
|
||||
100 => 'Continue',
|
||||
101 => 'Switching Protocols',
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
306 => '(Unused)',
|
||||
307 => 'Temporary Redirect',
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Timeout',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Long',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
429 => 'Too Many Requests', //still in draft but used for rate limiting
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Timeout',
|
||||
505 => 'HTTP Version Not Supported'
|
||||
);
|
||||
private $details;
|
||||
private $stage;
|
||||
|
||||
/**
|
||||
* @param string $httpStatusCode http status code
|
||||
* @param string|null $errorMessage error message
|
||||
* @param array $details any extra detail about the exception
|
||||
* @param Exception $previous previous exception if any
|
||||
*/
|
||||
public function __construct($httpStatusCode, $errorMessage = null, array $details = array(), Exception $previous = null)
|
||||
{
|
||||
$events = Scope::get('Restler')->getEvents();
|
||||
if(count($events)<= 1){
|
||||
$this->stage = 'setup';
|
||||
} else {
|
||||
$this->stage = $previous ? $events[count($events)-2] : end($events);
|
||||
}
|
||||
$this->details = $details;
|
||||
parent::__construct($errorMessage, $httpStatusCode, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extra details about the exception
|
||||
*
|
||||
* @return array details array
|
||||
*/
|
||||
public function getDetails()
|
||||
{
|
||||
return $this->details;
|
||||
}
|
||||
|
||||
public function getStage()
|
||||
{
|
||||
return $this->stage;
|
||||
}
|
||||
|
||||
public function getStages()
|
||||
{
|
||||
$e = Scope::get('Restler')->getEvents();
|
||||
$i = array_search($this->stage, $e);
|
||||
return array(
|
||||
'success' => array_slice($e, 0, $i),
|
||||
'failure' => array_slice($e, $i),
|
||||
);
|
||||
}
|
||||
|
||||
public function getErrorMessage()
|
||||
{
|
||||
$statusCode = $this->getCode();
|
||||
$message = $this->getMessage();
|
||||
if (isset(RestException::$codes[$statusCode])) {
|
||||
$message = RestException::$codes[$statusCode] .
|
||||
(empty($message) ? '' : ': ' . $message);
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function getSource()
|
||||
{
|
||||
$e = $this;
|
||||
while ($e->getPrevious()) {
|
||||
$e = $e->getPrevious();
|
||||
}
|
||||
return basename($e->getFile()) . ':'
|
||||
. $e->getLine() . ' at '
|
||||
. $this->getStage() . ' stage';
|
||||
}
|
||||
}
|
||||
|
||||
1451
htdocs/includes/restler/Restler.php
Normal file
1451
htdocs/includes/restler/Restler.php
Normal file
File diff suppressed because it is too large
Load Diff
696
htdocs/includes/restler/Routes.php
Normal file
696
htdocs/includes/restler/Routes.php
Normal file
@@ -0,0 +1,696 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
use Luracast\Restler\Data\ApiMethodInfo;
|
||||
use Luracast\Restler\Data\String;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Router class that routes the urls to api methods along with parameters
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class Routes
|
||||
{
|
||||
public static $prefixingParameterNames = array(
|
||||
'id'
|
||||
);
|
||||
protected static $routes = array();
|
||||
|
||||
protected static $models = array();
|
||||
|
||||
/**
|
||||
* Route the public and protected methods of an Api class
|
||||
*
|
||||
* @param string $className
|
||||
* @param string $resourcePath
|
||||
* @param int $version
|
||||
*
|
||||
* @throws RestException
|
||||
*/
|
||||
public static function addAPIClass($className, $resourcePath = '', $version = 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* Mapping Rules
|
||||
* =============
|
||||
*
|
||||
* - Optional parameters should not be mapped to URL
|
||||
* - If a required parameter is of primitive type
|
||||
* - If one of the self::$prefixingParameterNames
|
||||
* - Map it to URL
|
||||
* - Else If request method is POST/PUT/PATCH
|
||||
* - Map it to body
|
||||
* - Else If request method is GET/DELETE
|
||||
* - Map it to body
|
||||
* - If a required parameter is not primitive type
|
||||
* - Do not include it in URL
|
||||
*/
|
||||
$class = new ReflectionClass($className);
|
||||
try {
|
||||
$classMetadata = CommentParser::parse($class->getDocComment());
|
||||
} catch (Exception $e) {
|
||||
throw new RestException(500, "Error while parsing comments of `$className` class. " . $e->getMessage());
|
||||
}
|
||||
$classMetadata['scope'] = $scope = static::scope($class);
|
||||
$methods = $class->getMethods(ReflectionMethod::IS_PUBLIC +
|
||||
ReflectionMethod::IS_PROTECTED);
|
||||
foreach ($methods as $method) {
|
||||
$methodUrl = strtolower($method->getName());
|
||||
//method name should not begin with _
|
||||
if ($methodUrl{0} == '_') {
|
||||
continue;
|
||||
}
|
||||
$doc = $method->getDocComment();
|
||||
|
||||
try {
|
||||
$metadata = CommentParser::parse($doc) + $classMetadata;
|
||||
} catch (Exception $e) {
|
||||
throw new RestException(500, "Error while parsing comments of `{$className}::{$method->getName()}` method. " . $e->getMessage());
|
||||
}
|
||||
//@access should not be private
|
||||
if (isset($metadata['access'])
|
||||
&& $metadata['access'] == 'private'
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
$arguments = array();
|
||||
$defaults = array();
|
||||
$params = $method->getParameters();
|
||||
$position = 0;
|
||||
$pathParams = array();
|
||||
$allowAmbiguity
|
||||
= (isset($metadata['smart-auto-routing'])
|
||||
&& $metadata['smart-auto-routing'] != 'true')
|
||||
|| !Defaults::$smartAutoRouting;
|
||||
$metadata['resourcePath'] = $resourcePath;
|
||||
if (isset($classMetadata['description'])) {
|
||||
$metadata['classDescription'] = $classMetadata['description'];
|
||||
}
|
||||
if (isset($classMetadata['classLongDescription'])) {
|
||||
$metadata['classLongDescription']
|
||||
= $classMetadata['longDescription'];
|
||||
}
|
||||
if (!isset($metadata['param'])) {
|
||||
$metadata['param'] = array();
|
||||
}
|
||||
if (isset($metadata['return']['type'])) {
|
||||
if ($qualified = Scope::resolve($metadata['return']['type'], $scope))
|
||||
list($metadata['return']['type'], $metadata['return']['children']) =
|
||||
static::getTypeAndModel(new ReflectionClass($qualified), $scope);
|
||||
} else {
|
||||
//assume return type is array
|
||||
$metadata['return']['type'] = 'array';
|
||||
}
|
||||
foreach ($params as $param) {
|
||||
$children = array();
|
||||
$type =
|
||||
$param->isArray() ? 'array' : $param->getClass();
|
||||
$arguments[$param->getName()] = $position;
|
||||
$defaults[$position] = $param->isDefaultValueAvailable() ?
|
||||
$param->getDefaultValue() : null;
|
||||
if (!isset($metadata['param'][$position])) {
|
||||
$metadata['param'][$position] = array();
|
||||
}
|
||||
$m = & $metadata ['param'] [$position];
|
||||
$m ['name'] = $param->getName();
|
||||
if (empty($m['label']))
|
||||
$m['label'] = static::label($m['name']);
|
||||
if (is_null($type) && isset($m['type'])) {
|
||||
$type = $m['type'];
|
||||
}
|
||||
if ($m['name'] == 'email' && empty($m[CommentParser::$embeddedDataName]['type']) && $type == 'string')
|
||||
$m[CommentParser::$embeddedDataName]['type'] = 'email';
|
||||
$m ['default'] = $defaults [$position];
|
||||
$m ['required'] = !$param->isOptional();
|
||||
$contentType = Util::nestedValue(
|
||||
$m,
|
||||
CommentParser::$embeddedDataName,
|
||||
'type'
|
||||
);
|
||||
if ($contentType && $qualified = Scope::resolve($contentType, $scope)) {
|
||||
list($m[CommentParser::$embeddedDataName]['type'], $children) = static::getTypeAndModel(
|
||||
new ReflectionClass($qualified), $scope
|
||||
);
|
||||
}
|
||||
if ($type instanceof ReflectionClass) {
|
||||
list($type, $children) = static::getTypeAndModel($type, $scope);
|
||||
} elseif ($type && is_string($type) && $qualified = Scope::resolve($type, $scope)) {
|
||||
list($type, $children)
|
||||
= static::getTypeAndModel(new ReflectionClass($qualified), $scope);
|
||||
}
|
||||
if (isset($type)) {
|
||||
$m['type'] = $type;
|
||||
}
|
||||
$m['children'] = $children;
|
||||
|
||||
if ($m['name'] == Defaults::$fullRequestDataName) {
|
||||
$from = 'body';
|
||||
if (!isset($m['type'])) {
|
||||
$type = $m['type'] = 'array';
|
||||
}
|
||||
|
||||
} elseif (isset($m[CommentParser::$embeddedDataName]['from'])) {
|
||||
$from = $m[CommentParser::$embeddedDataName]['from'];
|
||||
} else {
|
||||
if ((isset($type) && Util::isObjectOrArray($type))
|
||||
) {
|
||||
$from = 'body';
|
||||
if (!isset($type)) {
|
||||
$type = $m['type'] = 'array';
|
||||
}
|
||||
} elseif ($m['required'] && in_array($m['name'], static::$prefixingParameterNames)) {
|
||||
$from = 'path';
|
||||
} else {
|
||||
$from = 'body';
|
||||
}
|
||||
}
|
||||
$m[CommentParser::$embeddedDataName]['from'] = $from;
|
||||
if (!isset($m['type'])) {
|
||||
$type = $m['type'] = static::type($defaults[$position]);
|
||||
}
|
||||
|
||||
if ($allowAmbiguity || $from == 'path') {
|
||||
$pathParams [] = $position;
|
||||
}
|
||||
$position++;
|
||||
}
|
||||
$accessLevel = 0;
|
||||
if ($method->isProtected()) {
|
||||
$accessLevel = 3;
|
||||
} elseif (isset($metadata['access'])) {
|
||||
if ($metadata['access'] == 'protected') {
|
||||
$accessLevel = 2;
|
||||
} elseif ($metadata['access'] == 'hybrid') {
|
||||
$accessLevel = 1;
|
||||
}
|
||||
} elseif (isset($metadata['protected'])) {
|
||||
$accessLevel = 2;
|
||||
}
|
||||
/*
|
||||
echo " access level $accessLevel for $className::"
|
||||
.$method->getName().$method->isProtected().PHP_EOL;
|
||||
*/
|
||||
|
||||
// take note of the order
|
||||
$call = array(
|
||||
'url' => null,
|
||||
'className' => $className,
|
||||
'path' => rtrim($resourcePath, '/'),
|
||||
'methodName' => $method->getName(),
|
||||
'arguments' => $arguments,
|
||||
'defaults' => $defaults,
|
||||
'metadata' => $metadata,
|
||||
'accessLevel' => $accessLevel,
|
||||
);
|
||||
// if manual route
|
||||
if (preg_match_all(
|
||||
'/@url\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)'
|
||||
. '[ \t]*\/?(\S*)/s',
|
||||
$doc, $matches, PREG_SET_ORDER
|
||||
)
|
||||
) {
|
||||
foreach ($matches as $match) {
|
||||
$httpMethod = $match[1];
|
||||
$url = rtrim($resourcePath . $match[2], '/');
|
||||
//deep copy the call, as it may change for each @url
|
||||
$copy = unserialize(serialize($call));
|
||||
foreach ($copy['metadata']['param'] as $i => $p) {
|
||||
$inPath =
|
||||
strpos($url, '{' . $p['name'] . '}') ||
|
||||
strpos($url, ':' . $p['name']);
|
||||
if ($inPath) {
|
||||
$copy['metadata']['param'][$i][CommentParser::$embeddedDataName]['from'] = 'path';
|
||||
} elseif ($httpMethod == 'GET' || $httpMethod == 'DELETE') {
|
||||
$copy['metadata']['param'][$i][CommentParser::$embeddedDataName]['from'] = 'query';
|
||||
} elseif ($p[CommentParser::$embeddedDataName]['from'] == 'path') {
|
||||
$copy['metadata']['param'][$i][CommentParser::$embeddedDataName]['from'] = 'body';
|
||||
}
|
||||
}
|
||||
$url = preg_replace_callback('/{[^}]+}|:[^\/]+/',
|
||||
function ($matches) use ($call) {
|
||||
$match = trim($matches[0], '{}:');
|
||||
$index = $call['arguments'][$match];
|
||||
return '{' .
|
||||
Routes::typeChar(isset(
|
||||
$call['metadata']['param'][$index]['type'])
|
||||
? $call['metadata']['param'][$index]['type']
|
||||
: null)
|
||||
. $index . '}';
|
||||
}, $url);
|
||||
static::addPath($url, $copy, $httpMethod, $version);
|
||||
}
|
||||
//if auto route enabled, do so
|
||||
} elseif (Defaults::$autoRoutingEnabled) {
|
||||
// no configuration found so use convention
|
||||
if (preg_match_all(
|
||||
'/^(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/i',
|
||||
$methodUrl, $matches)
|
||||
) {
|
||||
$httpMethod = strtoupper($matches[0][0]);
|
||||
$methodUrl = substr($methodUrl, strlen($httpMethod));
|
||||
} else {
|
||||
$httpMethod = 'GET';
|
||||
}
|
||||
if ($methodUrl == 'index') {
|
||||
$methodUrl = '';
|
||||
}
|
||||
$url = empty($methodUrl) ? rtrim($resourcePath, '/')
|
||||
: $resourcePath . $methodUrl;
|
||||
$lastPathParam = array_keys($pathParams);
|
||||
$lastPathParam = end($lastPathParam);
|
||||
for ($position = 0; $position < count($params); $position++) {
|
||||
$from = $metadata['param'][$position][CommentParser::$embeddedDataName]['from'];
|
||||
if ($from == 'body' && ($httpMethod == 'GET' ||
|
||||
$httpMethod == 'DELETE')
|
||||
) {
|
||||
$call['metadata']['param'][$position][CommentParser::$embeddedDataName]['from']
|
||||
= 'query';
|
||||
}
|
||||
}
|
||||
if (empty($pathParams) || $allowAmbiguity) {
|
||||
static::addPath($url, $call, $httpMethod, $version);
|
||||
}
|
||||
foreach ($pathParams as $position) {
|
||||
if (!empty($url))
|
||||
$url .= '/';
|
||||
$url .= '{' .
|
||||
static::typeChar(isset($call['metadata']['param'][$position]['type'])
|
||||
? $call['metadata']['param'][$position]['type']
|
||||
: null)
|
||||
. $position . '}';
|
||||
if ($allowAmbiguity || $position == $lastPathParam) {
|
||||
static::addPath($url, $call, $httpMethod, $version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
public static function typeChar($type = null)
|
||||
{
|
||||
if (!$type) {
|
||||
return 's';
|
||||
}
|
||||
switch ($type{0}) {
|
||||
case 'i':
|
||||
case 'f':
|
||||
return 'n';
|
||||
}
|
||||
return 's';
|
||||
}
|
||||
|
||||
protected static function addPath($path, array $call,
|
||||
$httpMethod = 'GET', $version = 1)
|
||||
{
|
||||
$call['url'] = preg_replace_callback(
|
||||
"/\{\S(\d+)\}/",
|
||||
function ($matches) use ($call) {
|
||||
return '{' .
|
||||
$call['metadata']['param'][$matches[1]]['name'] . '}';
|
||||
},
|
||||
$path
|
||||
);
|
||||
//check for wildcard routes
|
||||
if (substr($path, -1, 1) == '*') {
|
||||
$path = rtrim($path, '/*');
|
||||
static::$routes["v$version"]['*'][$path][$httpMethod] = $call;
|
||||
} else {
|
||||
static::$routes["v$version"][$path][$httpMethod] = $call;
|
||||
//create an alias with index if the method name is index
|
||||
if ($call['methodName'] == 'index')
|
||||
static::$routes["v$version"][ltrim("$path/index", '/')][$httpMethod] = $call;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the api method for the given url and http method
|
||||
*
|
||||
* @param string $path Requested url path
|
||||
* @param string $httpMethod GET|POST|PUT|PATCH|DELETE etc
|
||||
* @param int $version Api Version number
|
||||
* @param array $data Data collected from the request
|
||||
*
|
||||
* @throws RestException
|
||||
* @return ApiMethodInfo
|
||||
*/
|
||||
public static function find($path, $httpMethod,
|
||||
$version = 1, array $data = array())
|
||||
{
|
||||
$p = Util::nestedValue(static::$routes, "v$version");
|
||||
if (!$p) {
|
||||
throw new RestException(
|
||||
404,
|
||||
$version == 1 ? '' : "Version $version is not supported"
|
||||
);
|
||||
}
|
||||
$status = 404;
|
||||
$message = null;
|
||||
$methods = array();
|
||||
if (isset($p[$path][$httpMethod])) {
|
||||
//================== static routes ==========================
|
||||
return static::populate($p[$path][$httpMethod], $data);
|
||||
} elseif (isset($p['*'])) {
|
||||
//================== wildcard routes ========================
|
||||
uksort($p['*'], function ($a, $b) {
|
||||
return strlen($b) - strlen($a);
|
||||
});
|
||||
foreach ($p['*'] as $key => $value) {
|
||||
if (strpos($path, $key) === 0 && isset($value[$httpMethod])) {
|
||||
//path found, convert rest of the path to parameters
|
||||
$path = substr($path, strlen($key) + 1);
|
||||
$call = ApiMethodInfo::__set_state($value[$httpMethod]);
|
||||
$call->parameters = empty($path)
|
||||
? array()
|
||||
: explode('/', $path);
|
||||
return $call;
|
||||
}
|
||||
}
|
||||
}
|
||||
//================== dynamic routes =============================
|
||||
//add newline char if trailing slash is found
|
||||
if (substr($path, -1) == '/')
|
||||
$path .= PHP_EOL;
|
||||
//if double slash is found fill in newline char;
|
||||
$path = str_replace('//', '/' . PHP_EOL . '/', $path);
|
||||
ksort($p);
|
||||
foreach ($p as $key => $value) {
|
||||
if (!isset($value[$httpMethod])) {
|
||||
continue;
|
||||
}
|
||||
$regex = str_replace(array('{', '}'),
|
||||
array('(?P<', '>[^/]+)'), $key);
|
||||
if (preg_match_all(":^$regex$:i", $path, $matches, PREG_SET_ORDER)) {
|
||||
$matches = $matches[0];
|
||||
$found = true;
|
||||
foreach ($matches as $k => $v) {
|
||||
if (is_numeric($k)) {
|
||||
unset($matches[$k]);
|
||||
continue;
|
||||
}
|
||||
$index = intval(substr($k, 1));
|
||||
$details = $value[$httpMethod]['metadata']['param'][$index];
|
||||
if ($k{0} == 's' || strpos($k, static::pathVarTypeOf($v)) === 0) {
|
||||
//remove the newlines
|
||||
$data[$details['name']] = trim($v, PHP_EOL);
|
||||
} else {
|
||||
$status = 400;
|
||||
$message = 'invalid value specified for `'
|
||||
. $details['name'] . '`';
|
||||
$found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($found) {
|
||||
return static::populate($value[$httpMethod], $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($status == 404) {
|
||||
//check if other methods are allowed
|
||||
if (isset($p[$path])) {
|
||||
$status = 405;
|
||||
$methods = array_keys($p[$path]);
|
||||
}
|
||||
}
|
||||
if ($status == 405) {
|
||||
header('Allow: ' . implode(', ', $methods));
|
||||
}
|
||||
throw new RestException($status, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the parameter values
|
||||
*
|
||||
* @param array $call
|
||||
* @param $data
|
||||
*
|
||||
* @return ApiMethodInfo
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
protected static function populate(array $call, $data)
|
||||
{
|
||||
$call['parameters'] = $call['defaults'];
|
||||
$p = & $call['parameters'];
|
||||
foreach ($data as $key => $value) {
|
||||
if (isset($call['arguments'][$key])) {
|
||||
$p[$call['arguments'][$key]] = $value;
|
||||
}
|
||||
}
|
||||
if (Defaults::$smartParameterParsing && 'post' != (string)Util::$restler->requestFormat) {
|
||||
if (
|
||||
count($p) == 1 &&
|
||||
($m = Util::nestedValue($call, 'metadata', 'param', 0)) &&
|
||||
!array_key_exists($m['name'], $data) &&
|
||||
array_key_exists(Defaults::$fullRequestDataName, $data) &&
|
||||
!is_null($d = $data[Defaults::$fullRequestDataName]) &&
|
||||
isset($m['type']) &&
|
||||
static::typeMatch($m['type'], $d)
|
||||
) {
|
||||
$p[0] = $d;
|
||||
} else {
|
||||
$bodyParamCount = 0;
|
||||
$lastBodyParamIndex = -1;
|
||||
$lastM = null;
|
||||
foreach ($call['metadata']['param'] as $k => $m) {
|
||||
if ($m[CommentParser::$embeddedDataName]['from'] == 'body') {
|
||||
$bodyParamCount++;
|
||||
$lastBodyParamIndex = $k;
|
||||
$lastM = $m;
|
||||
}
|
||||
}
|
||||
if (
|
||||
$bodyParamCount == 1 &&
|
||||
!array_key_exists($lastM['name'], $data) &&
|
||||
array_key_exists(Defaults::$fullRequestDataName, $data) &&
|
||||
!is_null($d = $data[Defaults::$fullRequestDataName])
|
||||
) {
|
||||
$p[$lastBodyParamIndex] = $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
$r = ApiMethodInfo::__set_state($call);
|
||||
$modifier = "_modify_{$r->methodName}_api";
|
||||
if (method_exists($r->className, $modifier)) {
|
||||
$stage = end(Scope::get('Restler')->getEvents());
|
||||
if (empty($stage))
|
||||
$stage = 'setup';
|
||||
$r = Scope::get($r->className)->$modifier($r, $stage) ? : $r;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
protected static function pathVarTypeOf($var)
|
||||
{
|
||||
if (is_numeric($var)) {
|
||||
return 'n';
|
||||
}
|
||||
if ($var === 'true' || $var === 'false') {
|
||||
return 'b';
|
||||
}
|
||||
return 's';
|
||||
}
|
||||
|
||||
protected static function typeMatch($type, $var)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'boolean':
|
||||
case 'bool':
|
||||
return is_bool($var);
|
||||
case 'array':
|
||||
case 'object':
|
||||
return is_array($var);
|
||||
case 'string':
|
||||
case 'int':
|
||||
case 'integer':
|
||||
case 'float':
|
||||
case 'number':
|
||||
return is_scalar($var);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type and associated model
|
||||
*
|
||||
* @param ReflectionClass $class
|
||||
* @param array $scope
|
||||
*
|
||||
* @throws RestException
|
||||
* @throws \Exception
|
||||
* @return array
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected static function getTypeAndModel(ReflectionClass $class, array $scope)
|
||||
{
|
||||
$className = $class->getName();
|
||||
if (isset(static::$models[$className])) {
|
||||
return static::$models[$className];
|
||||
}
|
||||
$children = array();
|
||||
try {
|
||||
$props = $class->getProperties(ReflectionProperty::IS_PUBLIC);
|
||||
foreach ($props as $prop) {
|
||||
$name = $prop->getName();
|
||||
$child = array('name' => $name);
|
||||
if ($c = $prop->getDocComment()) {
|
||||
$child += Util::nestedValue(CommentParser::parse($c), 'var');
|
||||
} else {
|
||||
$o = $class->newInstance();
|
||||
$p = $prop->getValue($o);
|
||||
if (is_object($p)) {
|
||||
$child['type'] = get_class($p);
|
||||
} elseif (is_array($p)) {
|
||||
$child['type'] = 'array';
|
||||
if (count($p)) {
|
||||
$pc = reset($p);
|
||||
if (is_object($pc)) {
|
||||
$child['contentType'] = get_class($pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$child += array(
|
||||
'type' => $child['name'] == 'email' ? 'email' : 'string',
|
||||
'label' => static::label($child['name'])
|
||||
);
|
||||
isset($child[CommentParser::$embeddedDataName])
|
||||
? $child[CommentParser::$embeddedDataName] += array('required' => true)
|
||||
: $child[CommentParser::$embeddedDataName]['required'] = true;
|
||||
if ($qualified = Scope::resolve($child['type'], $scope)) {
|
||||
list($child['type'], $child['children'])
|
||||
= static::getTypeAndModel(new ReflectionClass($qualified), $scope);
|
||||
} elseif (
|
||||
($contentType = Util::nestedValue($child, CommentParser::$embeddedDataName, 'type')) &&
|
||||
($qualified = Scope::resolve($contentType, $scope))
|
||||
) {
|
||||
list($child['contentType'], $child['children'])
|
||||
= static::getTypeAndModel(new ReflectionClass($qualified), $scope);
|
||||
}
|
||||
$children[$name] = $child;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
if (String::endsWith($e->getFile(), 'CommentParser.php')) {
|
||||
throw new RestException(500, "Error while parsing comments of `$className` class. " . $e->getMessage());
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
static::$models[$className] = array($className, $children);
|
||||
return static::$models[$className];
|
||||
}
|
||||
|
||||
/**
|
||||
* Import previously created routes from cache
|
||||
*
|
||||
* @param array $routes
|
||||
*/
|
||||
public static function fromArray(array $routes)
|
||||
{
|
||||
static::$routes = $routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export current routes for cache
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function toArray()
|
||||
{
|
||||
return static::$routes;
|
||||
}
|
||||
|
||||
public static function type($var)
|
||||
{
|
||||
if (is_object($var)) return get_class($var);
|
||||
if (is_array($var)) return 'array';
|
||||
if (is_bool($var)) return 'boolean';
|
||||
if (is_numeric($var)) return is_float($var) ? 'float' : 'int';
|
||||
return 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a label from name of the parameter or property
|
||||
*
|
||||
* Convert `camelCase` style names into proper `Title Case` names
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function label($name)
|
||||
{
|
||||
return ucfirst(preg_replace(array('/(?<=[^A-Z])([A-Z])/', '/(?<=[^0-9])([0-9])/'), ' $0', $name));
|
||||
}
|
||||
|
||||
public static function scope(ReflectionClass $class)
|
||||
{
|
||||
$namespace = $class->getNamespaceName();
|
||||
$imports = array(
|
||||
'*' => empty($namespace) ? '' : $namespace . '\\'
|
||||
);
|
||||
$file = file_get_contents($class->getFileName());
|
||||
$tokens = token_get_all($file);
|
||||
$namespace = '';
|
||||
$alias = '';
|
||||
$reading = false;
|
||||
$last = 0;
|
||||
foreach ($tokens as $token) {
|
||||
if (is_string($token)) {
|
||||
if ($reading && ',' == $token) {
|
||||
//===== STOP =====//
|
||||
$reading = false;
|
||||
if (!empty($namespace))
|
||||
$imports[$alias] = trim($namespace, '\\');
|
||||
//===== START =====//
|
||||
$reading = true;
|
||||
$namespace = '';
|
||||
$alias = '';
|
||||
} else {
|
||||
//===== STOP =====//
|
||||
$reading = false;
|
||||
if (!empty($namespace))
|
||||
$imports[$alias] = trim($namespace, '\\');
|
||||
}
|
||||
} elseif (T_USE == $token[0]) {
|
||||
//===== START =====//
|
||||
$reading = true;
|
||||
$namespace = '';
|
||||
$alias = '';
|
||||
} elseif ($reading) {
|
||||
//echo token_name($token[0]) . ' ' . $token[1] . PHP_EOL;
|
||||
switch ($token[0]) {
|
||||
case T_WHITESPACE:
|
||||
continue 2;
|
||||
case T_STRING:
|
||||
$alias = $token[1];
|
||||
if (T_AS == $last) {
|
||||
break;
|
||||
}
|
||||
//don't break;
|
||||
case T_NS_SEPARATOR:
|
||||
$namespace .= $token[1];
|
||||
break;
|
||||
}
|
||||
$last = $token[0];
|
||||
}
|
||||
}
|
||||
return $imports;
|
||||
}
|
||||
}
|
||||
190
htdocs/includes/restler/Scope.php
Normal file
190
htdocs/includes/restler/Scope.php
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
namespace Luracast\Restler;
|
||||
|
||||
/**
|
||||
* Scope resolution class, manages instantiation and acts as a dependency
|
||||
* injection container
|
||||
*
|
||||
* @category Framework
|
||||
* @package Restler
|
||||
* @author R.Arul Kumaran <arul@luracast.com>
|
||||
* @copyright 2010 Luracast
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://luracast.com/products/restler/
|
||||
* @version 3.0.0rc5
|
||||
*/
|
||||
class Scope
|
||||
{
|
||||
public static $classAliases = array(
|
||||
|
||||
//Core
|
||||
'Restler' => 'Luracast\Restler\Restler',
|
||||
|
||||
//Format classes
|
||||
'AmfFormat' => 'Luracast\Restler\Format\AmfFormat',
|
||||
'JsFormat' => 'Luracast\Restler\Format\JsFormat',
|
||||
'JsonFormat' => 'Luracast\Restler\Format\JsonFormat',
|
||||
'HtmlFormat' => 'Luracast\Restler\Format\HtmlFormat',
|
||||
'PlistFormat' => 'Luracast\Restler\Format\PlistFormat',
|
||||
'UploadFormat' => 'Luracast\Restler\Format\UploadFormat',
|
||||
'UrlEncodedFormat' => 'Luracast\Restler\Format\UrlEncodedFormat',
|
||||
'XmlFormat' => 'Luracast\Restler\Format\XmlFormat',
|
||||
'YamlFormat' => 'Luracast\Restler\Format\YamlFormat',
|
||||
'CsvFormat' => 'Luracast\Restler\Format\CsvFormat',
|
||||
'TsvFormat' => 'Luracast\Restler\Format\TsvFormat',
|
||||
|
||||
//Filter classes
|
||||
'RateLimit' => 'Luracast\Restler\Filter\RateLimit',
|
||||
|
||||
//UI classes
|
||||
'Forms' => 'Luracast\Restler\UI\Forms',
|
||||
'Nav' => 'Luracast\Restler\UI\Nav',
|
||||
'Emmet' => 'Luracast\Restler\UI\Emmet',
|
||||
'T' => 'Luracast\Restler\UI\Tags',
|
||||
|
||||
//API classes
|
||||
'Resources' => 'Luracast\Restler\Resources',
|
||||
|
||||
//Cache classes
|
||||
'HumanReadableCache' => 'Luracast\Restler\HumanReadableCache',
|
||||
'ApcCache' => 'Luracast\Restler\ApcCache',
|
||||
|
||||
//Utility classes
|
||||
'Object' => 'Luracast\Restler\Data\Object',
|
||||
'String' => 'Luracast\Restler\Data\String',
|
||||
'Arr' => 'Luracast\Restler\Data\Arr',
|
||||
|
||||
//Exception
|
||||
'RestException' => 'Luracast\Restler\RestException'
|
||||
);
|
||||
public static $properties = array();
|
||||
protected static $instances = array();
|
||||
protected static $registry = array();
|
||||
|
||||
public static function register($name, Callable $function, $singleton = true)
|
||||
{
|
||||
static::$registry[$name] = (object)compact('function', 'singleton');
|
||||
}
|
||||
|
||||
public static function set($name, $instance)
|
||||
{
|
||||
static::$instances[$name] = (object)array('instance' => $instance);
|
||||
}
|
||||
|
||||
public static function get($name)
|
||||
{
|
||||
$r = null;
|
||||
$initialized = false;
|
||||
$properties = array();
|
||||
if (array_key_exists($name, static::$instances)) {
|
||||
$initialized = true;
|
||||
$r = static::$instances[$name]->instance;
|
||||
} elseif (!empty(static::$registry[$name])) {
|
||||
$function = static::$registry[$name]->function;
|
||||
$r = $function();
|
||||
if (static::$registry[$name]->singleton)
|
||||
static::$instances[$name] = (object)array('instance' => $r);
|
||||
} else {
|
||||
$fullName = $name;
|
||||
if (isset(static::$classAliases[$name])) {
|
||||
$fullName = static::$classAliases[$name];
|
||||
}
|
||||
if (class_exists($fullName)) {
|
||||
$shortName = Util::getShortName($name);
|
||||
$r = new $fullName();
|
||||
static::$instances[$name] = (object)array('instance' => $r);
|
||||
if ($name != 'Restler') {
|
||||
$r->restler = static::get('Restler');
|
||||
$m = Util::nestedValue($r->restler, 'apiMethodInfo', 'metadata');
|
||||
if ($m) {
|
||||
$properties = Util::nestedValue(
|
||||
$m, 'class', $fullName,
|
||||
CommentParser::$embeddedDataName
|
||||
) ? : (Util::nestedValue(
|
||||
$m, 'class', $shortName,
|
||||
CommentParser::$embeddedDataName
|
||||
) ? : array());
|
||||
} else {
|
||||
static::$instances[$name]->initPending = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
$r instanceof iUseAuthentication &&
|
||||
static::get('Restler')->_authVerified &&
|
||||
!isset(static::$instances[$name]->authVerified)
|
||||
) {
|
||||
static::$instances[$name]->authVerified = true;
|
||||
$r->__setAuthenticationStatus
|
||||
(static::get('Restler')->_authenticated);
|
||||
}
|
||||
if (isset(static::$instances[$name]->initPending)) {
|
||||
$m = Util::nestedValue(static::get('Restler'), 'apiMethodInfo', 'metadata');
|
||||
$fullName = $name;
|
||||
if (class_exists($name)) {
|
||||
$shortName = Util::getShortName($name);
|
||||
} else {
|
||||
$shortName = $name;
|
||||
if (isset(static::$classAliases[$name]))
|
||||
$fullName = static::$classAliases[$name];
|
||||
}
|
||||
if ($m) {
|
||||
$properties = Util::nestedValue(
|
||||
$m, 'class', $fullName,
|
||||
CommentParser::$embeddedDataName
|
||||
) ? : (Util::nestedValue(
|
||||
$m, 'class', $shortName,
|
||||
CommentParser::$embeddedDataName
|
||||
) ? : array());
|
||||
unset(static::$instances[$name]->initPending);
|
||||
$initialized = false;
|
||||
}
|
||||
}
|
||||
if (!$initialized && is_object($r)) {
|
||||
$properties += static::$properties;
|
||||
$objectVars = get_object_vars($r);
|
||||
$className = get_class($r);
|
||||
foreach ($properties as $property => $value) {
|
||||
if (property_exists($className, $property)) {
|
||||
//if not a static property
|
||||
array_key_exists($property, $objectVars)
|
||||
? $r->{$property} = $value
|
||||
: $r::$$property = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fully qualified class name for the given scope
|
||||
*
|
||||
* @param string $className
|
||||
* @param array $scope local scope
|
||||
*
|
||||
* @return string|boolean returns the class name or false
|
||||
*/
|
||||
public static function resolve($className, array $scope)
|
||||
{
|
||||
if (empty($className) || !is_string($className))
|
||||
return false;
|
||||
$divider = '\\';
|
||||
$qualified = false;
|
||||
if ($className{0} == $divider) {
|
||||
$qualified = trim($className, $divider);
|
||||
} elseif (array_key_exists($className, $scope)) {
|
||||
$qualified = $scope[$className];
|
||||
} else {
|
||||
$qualified = $scope['*'] . $className;
|
||||
}
|
||||
if (class_exists($qualified))
|
||||
return $qualified;
|
||||
if (isset(static::$classAliases[$className])) {
|
||||
$qualified = static::$classAliases[$className];
|
||||
if (class_exists($qualified))
|
||||
return $qualified;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user