PHP Classes

File: Xyndravandria/Averazain/Averazain.php

Recommend this page to a friend!
  Classes of Mauro Di Girolamo   Xyndravandria Averazain   Xyndravandria/Averazain/Averazain.php   Download  
File: Xyndravandria/Averazain/Averazain.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Xyndravandria Averazain
Handle AJAX requests with PHP classes
Author: By
Last change: Alpha 0.0.0
Date: 10 years ago
Size: 17,645 bytes
 

Contents

Class file image Download
<?php /* ============================================================================================================================================= | This file is part of a project released under the terms of the Xyndravandria PHP License (XyndravandriaPHPLicense.txt). | | | | You should be given a copy of the Xyndravandria PHP License (XyndravandriaPHPLicense.txt) within the same directory as the README.md; | | if not, you can get a copy at http://Xyndravandria.ohost.de/XyndravandriaPHPLicense.txt . | | | | The copyright (c) of this project is owned by Mauro Di Girolamo <maurodigirolamo@.web.de>. | ============================================================================================================================================| Xyndravandria Averazain ----------------------- Alpha 0.0.0 Xyndravandria is the name of a collection of projects designed and developed by Mauro Di Girolamo (maurodigirolamo@web.de); he is therefore the copyright (c) owner of Xyndravandria itself and all of its projects. Xyndravandria Averazain is released under the terms of the Xyndravandria PHP License (XyndravandriaPHPLicense.txt). You should be given a copy of the Xyndravandria PHP License (XyndravandriaPHPLicense.txt) within the same directory as the README.md; if not, you can get a copy at http://Xyndravandria.ohost.de/XyndravandriaPHPLicense.txt . There might be a release under a freer license for a later, more stable version. The documentation is either included in ./admin_media/Documentation/ or can be read at http://Xyndravandria.ohost.de/Averazain/Documentation/. All projects: Xyndravandria Averazain http://github.com/MauroDiGirolamo/Xyndravandria_Averazain PHP Averazain is an Ajax framework supporting also JavaScript disabled clients perfectly - including search engines like Google. Xyndravandria Dyverath http://github.com/MauroDiGirolamo/Xyndravandria_Dyverath PHP Dyverath is a database access wrapper. Xyndravandria Erozaver http://github.com/MauroDiGirolamo/Xyndravandria_Erozaver PHP Erozaver is a class extending the type hinting given by the PHP engine (additional support for basic type hinting and size constraints). Xyndravandria Mondraviel http://github.com/MauroDiGirolamo/Xyndravandria_Mondraviel PHP Mondraviel is a class used to separate HTML from PHP code by firstly register models - files containing place holders embedded in HTML code - and then later fill them dynamically with content by passing values for the place holders. */ namespace Xyndravandria\Averazain; // TODO: Thing about enabling settype( ) again. // TODO: Display errors in requests. /// @ref Averazain "Averazain's" main class. /// @abstract abstract class Averazain { /// Holds all the class names which have been /// registered to Averazain using RegisterClass( ). /// <dl class = "type"><dt><b>%Type:</b></dt> /// <dd>array of string</dd></dl> /// @private /// @static private static $ClassRegister = array( ); /// Registers a class to Averazain. /// @public /// @static /// @param string $ClassName: The class name to be /// registered. public static function RegisterClass( $ClassName ) { //\settype( $ClassName, 'string' ); if( ! \class_exists( $ClassName ) ) throw new XyndravandriaAverazainException( 'The to be registered class \'' . $ClassName . '\' is not defined.' ); else { $ReflectionClass = new \ReflectionClass( $ClassName ); if( ! $ReflectionClass->implementsInterface( 'Xyndravandria\Averazain\PageCollection' ) ) throw new XyndravandriaAverazainException( 'The given class \'' . $ReflectionClass->name . '\' does not implement the Xyndravandria\Averazain\PageCollection interface.' ); else \array_push( self::$ClassRegister, $ReflectionClass->name ); return; } } /// Holds the JavaScript generated by Averazain. /// <dl class = "type"><dt><b>%Type:</b></dt> /// <dd>string</dd></dl> /// @private /// @static private static $JavaScript = ''; /// Returns Averazain::$JavaScript. /// @public /// @static /// @returns string public static function JavaScript( ) { return self::$JavaScript; } /// Holds the form data which has been transferred /// through an Averazain request. @n /// <dl class = "type"><dt><b>%Type:</b></dt> /// <dd>array of mixed</dd></dl> /// @private /// @static private static $FormData = array( ); /// Returns either one element of Data::$FormData or /// the whole attribute. /// @public /// @param integer $Index: Index of an /// element inside the Data::$FormData array. /// @returns array of mixed or mixed or null /// @note $Index is an optional parameter. @n /// If not passed, Data::$FormData will be returned. public static function FormData( $Index = null ) { //\settype( $Index, 'integer' ); if( \is_null( $Index ) ) return self::$FormData; else return isset( self::$FormData[ $Index ] ) ? self::$FormData[ $Index ] : null; } /// Used to influence the behaviour of /// Averazain::Execute( ). const AutomaticallyRegisterClasses = 1; /// <ul> /// <li> /// The behaviour can be influenced using the /// $Operation parameter. /// </li> /// <li> /// Calls ExtractFormData( ). /// </li> /// <li> /// Calls RetrieveAnchor( ) to check whether /// there is an anchor and if yes, handles it. /// <li> /// Calls ProceedRequest( ) to check whether /// Averazain was called by an Ajax request and /// if yes, handles it. /// </li> /// <li> /// Calls GenerateJavaScript( ). /// </li> /// </ul> /// @public /// @static /// @param integer $Operation: Used to influence the /// behaviour of Averazain::Execute( ). @ /// Averazain::AutomaticallyRegisterClasses - defines /// whether Averazain should automatically register /// all classes implementing PageCollection or not. If /// not defined, this has to be done manually using /// Averazain::RegisterClass( ). /// @note This method has to be called before any /// output is sent to the client! public static function Execute( $Operation = 0 ) { //\settype( $Operation, 'integer' ); if( $Operation & Averazain::AutomaticallyRegisterClasses ) foreach( \get_declared_classes( ) as $ClassName ) { $ReflectionClass = new \ReflectionClass( $ClassName ); $ReflectionClass->implementsInterface( 'Xyndravandria\Averazain\PageCollection' ) && \array_push( self::$ClassRegister, $ReflectionClass->name ); } # self::GenerateJavaScript( ); self::ValidateRegisteredClasses( ); self::ExtractFormData( ); self::RetrieveAnchor( ); self::ProceedRequest( ); self::GenerateJavaScript( ); // TODO: Order important (put JavaScript at the end)? return; } /// Validates all registered classes and fills /// Averazain::$Anchor. /// @private /// @static private static function ValidateRegisteredClasses( ) { foreach( self::$ClassRegister as $ClassName ) foreach( \get_class_methods( $ClassName ) as $Method ) if( \in_array( $Method, array( 'Authorise', 'Target', 'Anchor' ) ) ) // TODO: array_diff( ) refuses to work. continue; else { // TODO: Validate $Target and $Anchor. $Target = $ClassName::Target( $Method ); // TODO: Check BEFORE calling whether the methods exist? $Anchor = $ClassName::Anchor( $Method ); if( ! \is_null( $Anchor ) && isset( self::$Anchor[ $Anchor ] ) ) throw new XyndravandriaAverazainException( 'The anchor \'' . $Anchor . '\' for method \'' . $Method . '\' of the class \'' . $ClassName . '\' has already been defined earlier for method \'' . self::$Anchor[ $Anchor ]->Method . '\' of class \'' . self::$Anchor[ $Anchor ]->Class . '\'.' ); else \is_null( $Anchor ) || self::$Anchor[ $Anchor ] = ( object )array( 'Class' => $ClassName, 'Method' => $Method ); } return; } /// Extracts the form data if sent and saves it into /// Averazain::$FormData. /// @private /// @static private static function ExtractFormData( ) { foreach( $_POST as $Index => $Value ) if( \preg_match( '#^Xyndravandria->Averazain->Request->FormData->(.+)#', $Index, $Match ) ) self::$FormData[ $Match[ 1 ] ] = self::Demask( $Value ); // TODO: Demask here correct? return; } /// The associations between anchors and method are /// saved within this array. /// <dl class = "return"><dt><b>%Type:</b></dt> /// <dd>array of array of string</dd></dl> /// @private /// @static private static $Anchor = array( ); /// The anchor retrieved by Averazain. /// <dl class = "return"><dt><b>%Type:</b></dt> /// <dd>null or array of mixed</dd></dl> /// @private /// @static private static $RetrievedAnchor = null; /// Returns Averazain::$RetrievedAnchor. /// @public /// @static /// @returns null or array of mixed public static function RetrievedAnchor( ) { return self::$RetrievedAnchor; } /// Checks whether there is an anchor retrieved. /// @public /// @static /// @returns boolean public static function AnchorRetrieved( ) { return ! \is_null( self::$RetrievedAnchor ); } /// Calls the method of the retrieved anchor and /// returns its output. /// @public /// @static /// @returns mixed public static function CallAnchoredMethod( ) { if( \is_null( self::$RetrievedAnchor ) ) throw new XyndravandriaAverazainException( 'There is no anchored method!' ); else return \forward_static_call_array( array( self::$RetrievedAnchor->Class, self::$RetrievedAnchor->Method ), self::$RetrievedAnchor->Argument ); return; } /// Retrieves the anchor if it exists and then either /// returns the associated method's output directly to /// the client or saves the anchor into /// Averazain::$RetrievedAnchor. /// @private /// @static private static function RetrieveAnchor( ) { foreach( $_GET as $Hash => $Value ) if( preg_match( '#^(?<Anchor>[A-Za-z.]+)(:(?<Argument>.+))?$#', $Hash, $Match ) && isset( self::$Anchor[ $Match[ 'Anchor' ] ] ) ) if( isset( $_GET[ 'Request' ] ) ) { $_POST[ 'Xyndravandria->Averazain->Request->Class' ] = self::$Anchor[ $Match[ 'Anchor' ] ]->Class; $_POST[ 'Xyndravandria->Averazain->Request->Method' ] = self::$Anchor[ $Match[ 'Anchor' ] ]->Method; $_POST[ 'Xyndravandria->Averazain->Request->Argument' ] = ( isset( $Match[ 'Argument' ] ) && ! empty( $Match[ 'Argument' ] ) ) ? $Match[ 'Argument' ] : ''; try { self::ProceedRequest( ); } catch( Exception $Exception ) { } } else { self::$RetrievedAnchor = ( object )array_merge( ( array )self::$Anchor[ $Match[ 'Anchor' ] ], array( 'Argument' => isset( $Match[ 'Argument' ] ) && ! empty( $Match[ 'Argument' ] ) ? \explode( ',', $Match[ 'Argument' ] ) : array( ), 'Anchor' => $Match[ 'Anchor' ] ) ); return; } if( isset( $_GET[ 'Request' ] ) ) exit; return; } /// Checks whether Averazain was called by an Ajax /// request and if yes, sends the demanded method's /// return value back to the client as an Ajax /// response which is, again, handled by Averazain. /// @private /// @static /// @note Calls Averazain::ExtractUniqueMethods( ). private static function ProceedRequest( ) { if( \headers_sent( $File, $Line ) ) throw new XyndravandriaAverazainException( 'Output has already been sent to the client in the file ' . $File . ' on line ' . $Line . '. Please ensure Averazain::Execute( ) is called before any output is sent to the client.' ); else { if( isset( $_POST[ 'Xyndravandria->Averazain->Request->Class' ] ) && isset( $_POST[ 'Xyndravandria->Averazain->Request->Method' ] ) ) { $Class = $_POST[ 'Xyndravandria->Averazain->Request->Class' ]; $Method = $_POST[ 'Xyndravandria->Averazain->Request->Method' ]; if( ! \class_exists( $Class ) ) throw new XyndravandriaAverazainException( 'Unknown class \'' . $Class . '\'.' ); elseif( ! $Class::Authorise( $Method ) ) throw new XyndravandriaAverazainException( 'Access denied for method \'' . $Method . '\' of class \'' . $Class . '\'.' ); elseif( ! \method_exists( $Class, $Method ) ) throw new XyndravandriaAverazainException( 'The \'' . $Class . '\' class does not have a method called \'' . $Method . '\'.' ); else { $Argument = array( ); isset( $_POST[ 'Xyndravandria->Averazain->Request->Argument' ] ) && $Argument = empty( $_POST[ 'Xyndravandria->Averazain->Request->Argument' ] ) ? array( ) : \explode( ',', $_POST[ 'Xyndravandria->Averazain->Request->Argument' ] ); foreach( $Argument as &$Value ) // TODO: Remove reference? self::Demask( $Value ); echo $ResponseText = \forward_static_call_array( array( $Class, $Method ), $Argument ); // TODO: Possible conflict when addslashes( ) escapes also double quotes? $Target = $Class::Target( $Method ); self::TargetAttached( $ResponseText ) || print \is_null( $Target ) ? '$null' : '$' . \addslashes( $Target ); exit( ); } } return; } } /// Turns the registered PHP classes in the @ref /// $ClassRegister and its methods into correspondent /// JavaScript classes and methods which send an /// Ajax request to Averazain demanding to call the /// original PHP method and send its return value back /// to the client as an Ajax response which is, again, /// handled by Averazain. /// @private /// @static private static function GenerateJavaScript( ) { self::$JavaScript = '<script type = "text/javascript">' . \file_get_contents( __DIR__ . '/XyndravandriaAverazain.js' ) . ' '; foreach( self::$ClassRegister as $ClassName ) { self::$JavaScript .= 'function ' . $ClassName . '( ) { } '; foreach( \get_class_methods( $ClassName ) as $Method ) if( \in_array( $Method, array( 'Authorise', 'Target', 'Anchor' ) ) ) // TODO: array_diff( ) refuses to work. continue; else { // TODO: Validate $Target and $Anchor. $Target = $ClassName::Target( $Method ); // TODO: Check BEFORE calling whether the methods exist? $Anchor = $ClassName::Anchor( $Method ); self::$JavaScript .= $ClassName . '.' . $Method . ' = function( ) { ' . "\n"; \is_null( $Anchor ) || self::$JavaScript .= ' XyndravandriaAverazain.SetHash( \'' . \addslashes( $Anchor ) . '\', arguments );' . "\n"; self::$JavaScript .= ' XyndravandriaAverazain.Request( \'POST\', \'' . $ClassName . '\', \'' . $Method . '\', arguments );' . "\n" . ' return;' . "\n" . '};' . "\n"; } self::$JavaScript .= ' '; } self::$JavaScript .= 'XyndravandriaAverazain.OnInit( );' . "\n"; if( ! \is_null( self::$RetrievedAnchor ) && ! isset( $_GET[ 'Request' ] ) ) { list( $HashListing, ) = HTMLBuilder::ArgumentListing( self::$RetrievedAnchor->Argument ); self::$JavaScript .= 'var URL = location.href.split( \'?\' )' . "\n" . 'location.href = URL[ 0 ] + \'#' . self::$RetrievedAnchor->Anchor . ( empty( $HashListing ) ? '' : $HashListing ) . '\';' . "\n"; } self::$JavaScript .= '</script>'; return; } /// Demasks a given value sent within an Averazain request /// @private /// @static /// @param string & $Value: The value to be demasked. /// @returns string private static function Demask( & $Value ) { foreach( array( '[a]' => "\n", '[b]' => '&', '[c]' => ',', '[d]' => ':', '[e]' => '#', '[f]' => '=' ) as $Escape => $Digit ) $Value = \str_replace( $Escape, $Digit, $Value ); return $Value; } /// Checks whether a target is already attached to a /// response text. /// @private /// @static /// @param string $ResponseText: The response text to be /// checked. /// @returns boolean private static function TargetAttached( $ResponseText ) { if( ! empty( $ResponseText ) ) { $a = \strlen( $ResponseText ); while( --$a > 0 && $ResponseText[ $a ] != '$' ); return $ResponseText[ $a ] == '$'; } else return false; } } ?>