2017-08-04 16:28:16 +02:00
< ? php
/**
* Classe per la gestione delle API del progetto .
*
* @ since 2.3
*/
class API extends \Util\Singleton
{
2017-08-29 12:42:42 +02:00
/** @var array Elenco delle risorse disponibili suddivise per categoria */
2017-08-04 16:28:16 +02:00
protected static $resources ;
2017-08-29 12:42:42 +02:00
/** @var array Stati previsti dall'API */
2017-08-04 16:28:16 +02:00
protected static $status = [
'ok' => [
'code' => 200 ,
'message' => 'OK' ,
],
'internalError' => [
'code' => 400 ,
'message' => " Errore interno dell'API " ,
],
'unauthorized' => [
'code' => 401 ,
'message' => 'Non autorizzato' ,
],
'notFound' => [
'code' => 404 ,
'message' => 'Non trovato' ,
],
'serverError' => [
'code' => 500 ,
'message' => 'Errore del server' ,
],
2017-08-31 10:09:06 +02:00
'incompatible' => [
'code' => 503 ,
'message' => 'Servizio non disponibile' ,
],
2017-08-04 16:28:16 +02:00
];
2017-08-29 12:42:42 +02:00
/**
* @ throws InvalidArgumentException
*/
public function __construct ()
2017-08-04 16:28:16 +02:00
{
2017-08-07 13:07:18 +02:00
$user = Auth :: user ();
2017-08-04 16:28:16 +02:00
if ( ! self :: isAPIRequest () || empty ( $user )) {
throw new InvalidArgumentException ();
}
}
2017-08-29 12:42:42 +02:00
/**
* Gestisce le richieste di informazioni riguardanti gli elementi esistenti .
*
* @ param array $request
*
* @ return string
*/
public function retrieve ( $request )
2017-08-04 16:28:16 +02:00
{
$table = '' ;
$select = '*' ;
// Selezione personalizzata
2017-08-29 12:42:42 +02:00
$display = $request [ 'display' ];
2017-08-04 16:28:16 +02:00
$select = ! empty ( $display ) ? explode ( ',' , substr ( $display , 1 , - 1 )) : $select ;
$where = [];
// Ricerca personalizzata
2017-08-29 12:42:42 +02:00
$filter = ( array ) $request [ 'filter' ];
2017-08-04 16:28:16 +02:00
foreach ( $filter as $key => $value ) {
$value = substr ( $value , 1 , - 1 );
$result = [];
if ( str_contains ( $value , ',' )) {
$or = [];
$temp = explode ( ',' , $value );
foreach ( $temp as $value ) {
$or [] = [ $key => $value ];
}
$result [] = [ 'OR' => $or ];
} else {
$result [ $key ] = $value ;
}
$where [] = $result ;
}
$order = [];
// Ordinamento personalizzato
2017-08-29 12:42:42 +02:00
$order_request = ( array ) $request [ 'order' ];
2017-08-04 16:28:16 +02:00
foreach ( $order_request as $value ) {
$pieces = explode ( '|' , $value );
$order [] = empty ( $pieces [ 1 ]) ? $pieces [ 0 ] : [ $pieces [ 0 ] => $pieces [ 1 ]];
}
// Date di interesse
2017-08-29 12:42:42 +02:00
$updated = $request [ 'upd' ];
$created = $request [ 'crd' ];
2017-08-04 16:28:16 +02:00
$dbo = Database :: getConnection ();
$kind = 'retrieve' ;
$resources = self :: getResources ()[ $kind ];
2017-08-29 12:42:42 +02:00
$resource = $request [ 'resource' ];
2017-08-04 16:28:16 +02:00
if ( ! in_array ( $resource , $resources )) {
$excluded = explode ( ',' , Settings :: get ( 'Tabelle escluse per la sincronizzazione API automatica' ));
if ( ! in_array ( $resource , $excluded )) {
$table = $resource ;
if ( empty ( $order )) {
$order [] = $dbo -> fetchArray ( 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ' . prepare ( $table ) . " AND EXTRA LIKE '%AUTO_INCREMENT%' AND TABLE_SCHEMA = " . prepare ( $dbo -> getDatabaseName ()))[ 0 ][ 'COLUMN_NAME' ];
}
}
} else {
$filename = DOCROOT . '/modules/' . $resources [ $resource ] . '/api/' . $kind . '.php' ;
include $filename ;
}
// Paginazione dell'API
2017-08-29 12:42:42 +02:00
$page = ( int ) $request [ 'page' ] ? : 0 ;
2017-08-04 16:28:16 +02:00
$length = Settings :: get ( 'Lunghezza pagine per API' );
// Generazione automatica delle query
if ( empty ( $results ) && ! empty ( $table )) {
try {
// Query per ottenere le informazioni
$results = $dbo -> select ( $table , $select , $where , $order , [ $page * $length , $length ]);
// Informazioni aggiuntive
$query = $dbo -> select ( $table , $select , $where , $order , [], true );
$cont = $dbo -> fetchArray ( 'SELECT COUNT(*) as `records`, CEIL(COUNT(*) / ' . $length . ') as `pages` FROM (' . $query . ') AS `count`' );
if ( ! empty ( $cont )) {
$results [ 'records' ] = $cont [ 0 ][ 'records' ];
$results [ 'pages' ] = $cont [ 0 ][ 'pages' ];
}
} catch ( PDOException $e ) {
return self :: error ( 'internalError' );
}
}
return self :: response ( $results );
}
2017-08-29 12:42:42 +02:00
/**
* Gestisce le richieste di creazione nuovi elementi .
*
* @ param array $request
*
* @ return string
*/
public function create ( $request )
2017-08-04 16:28:16 +02:00
{
2017-08-29 12:42:42 +02:00
return $this -> fileRequest ( $request , 'create' );
2017-08-04 16:28:16 +02:00
}
2017-08-29 12:42:42 +02:00
/**
* Gestisce le richieste di aggiornamento di elementi esistenti .
*
* @ param array $request
*
* @ return string
*/
public function update ( $request )
2017-08-04 16:28:16 +02:00
{
2017-08-29 12:42:42 +02:00
return $this -> fileRequest ( $request , 'update' );
2017-08-04 16:28:16 +02:00
}
2017-08-29 12:42:42 +02:00
/**
* Gestisce le richieste di eliminazione di elementi esistenti .
*
* @ param array $request
*
* @ return string
*/
public function delete ( $request )
2017-08-04 16:28:16 +02:00
{
2017-08-29 12:42:42 +02:00
return $this -> fileRequest ( $request , 'delete' );
2017-08-04 16:28:16 +02:00
}
2017-08-29 12:42:42 +02:00
/**
* Gestisce le richieste in modo generalizzato , con il relativo richiamo ai file specifici responsabili dell ' operazione .
*
* @ param array $request
*
* @ return string
*/
protected function fileRequest ( $request , $kind )
2017-08-04 16:28:16 +02:00
{
$resources = self :: getResources ()[ $kind ];
2017-08-29 12:42:42 +02:00
$resource = $request [ 'resource' ];
2017-08-04 16:28:16 +02:00
2017-08-28 18:15:52 +02:00
if ( ! in_array ( $resource , array_keys ( $resources ))) {
2017-08-04 16:28:16 +02:00
return self :: error ( 'notFound' );
}
2017-08-28 18:15:52 +02:00
// Database
2017-08-04 16:28:16 +02:00
$dbo = Database :: getConnection ();
2017-08-28 18:15:52 +02:00
$dbo -> query ( 'START TRANSACTION' );
2017-08-04 16:28:16 +02:00
$filename = DOCROOT . '/modules/' . $resources [ $resource ] . '/api/' . $kind . '.php' ;
include $filename ;
2017-08-28 18:15:52 +02:00
$dbo -> query ( 'COMMIT' );
2017-08-04 16:28:16 +02:00
return self :: response ( $results );
}
2017-08-29 12:42:42 +02:00
/**
* Genera i contenuti di risposta nel caso si verifichi un errore .
*
* @ param string | int $error
*
* @ return string
*/
2017-08-04 16:28:16 +02:00
public static function error ( $error )
{
$keys = array_keys ( self :: $status );
2017-08-31 10:09:06 +02:00
$error = ( in_array ( $error , $keys )) ? $error : 'serverError' ;
$code = self :: $status [ $error ][ 'code' ];
2017-08-04 16:28:16 +02:00
2017-08-31 10:09:06 +02:00
http_response_code ( $code );
2017-08-29 12:42:42 +02:00
2017-08-04 16:28:16 +02:00
return self :: response ([
2017-08-31 10:09:06 +02:00
'status' => $code ,
2017-08-04 16:28:16 +02:00
]);
}
2017-08-29 12:42:42 +02:00
/**
* Restituisce l 'elenco delle risorse disponibili per l' API , suddivise per categoria .
*
* @ return array
*/
2017-08-04 16:28:16 +02:00
public static function getResources ()
{
if ( ! is_array ( self :: $resources )) {
$resources = [];
$operations = glob ( DOCROOT . '/modules/*/api/{retrieve,create,update,delete}.php' , GLOB_BRACE );
if ( ! empty ( $operations )) {
foreach ( $operations as $operation ) {
$module = basename ( dirname ( dirname ( $operation )));
$kind = basename ( $operation , '.php' );
2017-08-28 18:15:52 +02:00
$resources [ $kind ] = ( array ) $resources [ $kind ];
2017-08-04 16:28:16 +02:00
$temp = str_replace ( '/api/' , '/custom/api/' , $operation );
$operation = file_exists ( $temp ) ? $temp : $operation ;
$api = include $operation ;
2017-08-28 18:15:52 +02:00
$api = is_array ( $api ) ? array_unique ( $api ) : [];
2017-08-04 16:28:16 +02:00
$keys = array_keys ( $resources [ $kind ]);
$results = [];
foreach ( $api as $value ) {
$value .= in_array ( $value , $keys ) ? $module : '' ;
$results [ $value ] = $module ;
}
2017-08-28 18:15:52 +02:00
$resources [ $kind ] = array_merge ( $resources [ $kind ], $results );
2017-08-04 16:28:16 +02:00
}
}
self :: $resources = $resources ;
}
return self :: $resources ;
}
2017-08-29 12:42:42 +02:00
/**
* Formatta i contentuti della risposta secondo il formato JSON .
*
* @ param array $array
*
* @ return string
*/
2017-08-04 16:28:16 +02:00
public static function response ( $array )
{
2017-08-31 10:09:06 +02:00
if ( ! self :: isCompatible ()) {
$array = [
'status' => self :: $status [ 'incompatible' ][ 'code' ],
];
}
2017-08-04 16:28:16 +02:00
if ( empty ( $array [ 'status' ])) {
$array [ 'status' ] = self :: $status [ 'ok' ][ 'code' ];
2017-08-31 10:09:06 +02:00
}
if ( empty ( $array [ 'message' ])) {
$codes = array_column ( self :: $status , 'code' );
$messages = array_column ( self :: $status , 'message' );
$array [ 'message' ] = $messages [ array_search ( $array [ 'status' ], $codes )];
2017-08-04 16:28:16 +02:00
}
$flags = JSON_FORCE_OBJECT ;
2017-08-29 12:42:42 +02:00
if ( get ( 'beautify' ) !== null ) {
2017-08-04 16:28:16 +02:00
$flags |= JSON_PRETTY_PRINT ;
}
return json_encode ( $array , $flags );
}
2017-08-29 12:42:42 +02:00
/**
* Restituisce l 'elenco degli stati dell' API .
*
* @ return array
*/
public static function getStatus ()
{
return self :: $status ;
}
/**
* Controlla se la richiesta effettuata è rivolta all ' API .
*
* @ return bool
*/
2017-08-04 16:28:16 +02:00
public static function isAPIRequest ()
{
return slashes ( $_SERVER [ 'SCRIPT_FILENAME' ]) == slashes ( DOCROOT . '/api/index.php' );
}
2017-08-29 12:42:42 +02:00
/**
* Restituisce i parametri specificati dalla richiesta .
*/
public static function getRequest ()
{
return ( array ) json_decode ( file_get_contents ( 'php://input' ), true );
}
2017-08-31 10:09:06 +02:00
/**
* Controlla se il database è compatibile con l ' API .
*
* @ return bool
*/
public static function isCompatible ()
{
$database = Database :: getConnection ();
return version_compare ( $database -> getMySQLVersion (), '5.6.5' ) >= 0 ;
}
2017-08-04 16:28:16 +02:00
}