196 lines
7.1 KiB
PHP
196 lines
7.1 KiB
PHP
<?php
|
|
/**
|
|
* @brief API Reference
|
|
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
|
* @copyright (c) Invision Power Services, Inc.
|
|
* @license https://www.invisioncommunity.com/legal/standards/
|
|
* @package Invision Community
|
|
* @since 03 Dec 2015
|
|
*/
|
|
|
|
namespace IPS\core\modules\admin\applications;
|
|
|
|
/* To prevent PHP errors (extending class does not exist) revealing path */
|
|
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
|
{
|
|
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* apiReference
|
|
*/
|
|
class _apiReference extends \IPS\Dispatcher\Controller
|
|
{
|
|
/**
|
|
* Execute
|
|
*
|
|
* @return void
|
|
*/
|
|
public function execute()
|
|
{
|
|
\IPS\Dispatcher::i()->checkAcpPermission( 'api_reference' );
|
|
parent::execute();
|
|
}
|
|
|
|
/**
|
|
* View Reference
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function manage()
|
|
{
|
|
/* If Opcache is enabled but opcache.save_comments is disabled, the API reference won't work */
|
|
if( extension_loaded( 'opcache' ) AND !ini_get( 'opcache.save_comments' ) )
|
|
{
|
|
\IPS\Output::i()->error( 'api_opcache_disable', '4C331/1', 403, '' );
|
|
}
|
|
|
|
/* Get endpoint details */
|
|
$endpoints = \IPS\Api\Controller::getAllEndpoints();
|
|
$selected = NULL;
|
|
$content = '';
|
|
|
|
/* If we're viewing a specific one, get information about it */
|
|
if ( isset( \IPS\Request::i()->endpoint ) and array_key_exists( \IPS\Request::i()->endpoint, $endpoints ) )
|
|
{
|
|
$selected = \IPS\Request::i()->endpoint;
|
|
|
|
$additionalClassesToReference = array();
|
|
|
|
$params = array();
|
|
if ( isset( $endpoints[ $selected ]['details']['reqapiparam'] ) )
|
|
{
|
|
$params = array_map( function( $v ) {
|
|
$v[4] = 'required';
|
|
return $v;
|
|
}, $endpoints[ $selected ]['details']['reqapiparam'] );
|
|
}
|
|
if ( isset( $endpoints[ $selected ]['details']['apiparam'] ) )
|
|
{
|
|
$params = array_merge( $params, $endpoints[ $selected ]['details']['apiparam'] );
|
|
}
|
|
$exceptions = isset( $endpoints[ $selected ]['details']['throws'] ) ? $endpoints[ $selected ]['details']['throws'] : NULL;
|
|
if ( isset( $endpoints[ $selected ]['details']['apimemberonly'] ) )
|
|
{
|
|
$exceptions[] = array(
|
|
'3S290/C',
|
|
'MEMBER_ONLY',
|
|
\IPS\Member::loggedIn()->language()->addToStack('api_endpoint_member_only_err')
|
|
);
|
|
}
|
|
if ( isset( $endpoints[ $selected ]['details']['apiclientonly'] ) )
|
|
{
|
|
$exceptions[] = array(
|
|
'3S290/D',
|
|
'CLIENT_ONLY',
|
|
\IPS\Member::loggedIn()->language()->addToStack('api_endpoint_client_only_err')
|
|
);
|
|
}
|
|
|
|
$response = NULL;
|
|
$return = array_filter( $endpoints[ $selected ]['details']['return'][0] );
|
|
$return = array_pop( $return );
|
|
if ( $return == 'array' )
|
|
{
|
|
if ( isset( $endpoints[ $selected ]['details']['apiresponse'] ) )
|
|
{
|
|
foreach ( $endpoints[ $selected ]['details']['apiresponse'] as $data )
|
|
{
|
|
if ( mb_strpos( $data[0], '|' ) === FALSE AND !in_array( $data[0], array( 'int', 'string', 'float', 'datetime', 'bool', 'object', 'array' ) ) )
|
|
{
|
|
if ( mb_substr( $data[0], 0, 1 ) == '[' )
|
|
{
|
|
if ( !in_array( mb_substr( $data[0], 1, -1 ), array( 'int', 'string', 'float', 'datetime', 'bool', 'object', 'array' ) ) )
|
|
{
|
|
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( mb_substr( $data[0], 1, -1 ) ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( $data[0] ) );
|
|
}
|
|
}
|
|
}
|
|
$response = \IPS\Theme::i()->getTemplate('api')->referenceTable( $endpoints[ $selected ]['details']['apiresponse'] );
|
|
}
|
|
}
|
|
elseif ( mb_substr( $return, 0, mb_strlen( '\IPS\Api\PaginatedResponse' ) ) == '\IPS\Api\PaginatedResponse' )
|
|
{
|
|
$class = mb_substr( trim( $return ), mb_strlen( '\IPS\Api\PaginatedResponse' ) + 1, -1 );
|
|
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( $class ) );
|
|
$response = \IPS\Theme::i()->getTemplate('api')->referenceTable( array(
|
|
array( 'int', 'page', 'api_int_page' ),
|
|
array( 'int', 'perPage', 'api_int_perpage' ),
|
|
array( 'int', 'totalResults', 'api_int_totalresults' ),
|
|
array( 'int', 'totalPages', 'api_int_totalpages' ),
|
|
array( "[{$class}]", 'results', 'api_results_thispage' ),
|
|
) );
|
|
}
|
|
elseif ( $return = trim( $return ) and class_exists( $return ) and method_exists( $return, 'apiOutput' ) )
|
|
{
|
|
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( $return, TRUE ) );
|
|
$reflection = new \ReflectionMethod( $return, 'apiOutput' );
|
|
$decoded = \IPS\Api\Controller::decodeDocblock( $reflection->getDocComment() );
|
|
$response = \IPS\Theme::i()->getTemplate('api')->referenceTable( $decoded['details']['apiresponse'] );
|
|
}
|
|
|
|
$additionalClasses = array();
|
|
foreach ( $additionalClassesToReference as $class )
|
|
{
|
|
$reflection = new \ReflectionMethod( $class, 'apiOutput' );
|
|
$decoded = \IPS\Api\Controller::decodeDocblock( $reflection->getDocComment() );
|
|
$additionalClasses[ mb_strtolower( mb_substr( $class, mb_strrpos( $class, '\\' ) + 1 ) ) ] = \IPS\Theme::i()->getTemplate('api')->referenceTable( $decoded['details']['apiresponse'] );
|
|
}
|
|
|
|
$content = \IPS\Theme::i()->getTemplate('api')->referenceEndpoint( $endpoints[ $selected ], $params, $exceptions, $response, $additionalClasses );
|
|
}
|
|
|
|
$endpointTree = array();
|
|
foreach ( $endpoints as $key => $endpoint )
|
|
{
|
|
$pieces = explode('/', $key);
|
|
$endpointTree[ $pieces[0] ][ $pieces[1] ][ $key ] = $endpoint;
|
|
}
|
|
|
|
if ( \IPS\Request::i()->endpoint and \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->sendOutput( $content, 200, 'text/html' );
|
|
}
|
|
|
|
/* Output */
|
|
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('api')->referenceTemplate( $endpoints, $endpointTree, $selected, $content );
|
|
}
|
|
|
|
/**
|
|
* Get any additional classes referenced in the return types of this class
|
|
*
|
|
* @param string $class The classname
|
|
* @param bool $exclude If FALSE, will include this class itself in the return array
|
|
* @return array
|
|
*/
|
|
protected function _getAdditionalClasses( $class, $exclude=FALSE )
|
|
{
|
|
$return = $exclude ? array() : array( $class => $class );
|
|
$reflection = new \ReflectionMethod( $class, 'apiOutput' );
|
|
$decoded = \IPS\Api\Controller::decodeDocblock( $reflection->getDocComment() );
|
|
foreach ( $decoded['details']['apiresponse'] as $response )
|
|
{
|
|
if ( mb_strpos( $response[0], '|' ) === FALSE AND !in_array( $response[0], array( 'int', 'string', 'float', 'datetime', 'bool', 'object', 'array' ) ) )
|
|
{
|
|
if ( mb_substr( $response[0], 0, 1 ) == '[' )
|
|
{
|
|
if ( !in_array( mb_substr( $response[0], 1, -1 ), $return ) and !in_array( mb_substr( $response[0], 1, -1 ), array( 'int', 'string', 'float', 'datetime', 'bool', 'object', 'array' ) ) )
|
|
{
|
|
$return = array_merge( $return, $this->_getAdditionalClasses( mb_substr( $response[0], 1, -1 ) ) );
|
|
}
|
|
}
|
|
elseif ( !in_array( $response[0], $return ) )
|
|
{
|
|
$return = array_merge( $return, $this->_getAdditionalClasses( $response[0] ) );
|
|
}
|
|
}
|
|
}
|
|
return $return;
|
|
}
|
|
} |