PhpToolCase
Api Documentation Version 0.9.2
PtcHm.php
Go to the documentation of this file.
1 <?php
2 
3  /**
4  * PHP TOOLCASE HANDYMAN CLASS
5  * PHP version 5.3
6  * @category Library
7  * @version 0.9.2
8  * @author Irony <carlo@salapc.com>
9  * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
10  * @link http://phptoolcase.com
11  */
12 
13  class PtcHandyMan
14  {
15  /**
16  * Alias of @ref addDirs()
17  */
18  public static function addDir( $path ) { static::addDirs( $path ); }
19  /**
20  * Alias of @ref addFiles()
21  */
22  public static function addFile( $file ){ static::addFiles( $file ); }
23  /**
24  * Alias of @ref addSeparator()
25  */
26  public static function addSeparator( $sep ) { static::addSeparators( $sep ); }
27  /**
28  * Alias of @ref addConventions()
29  */
30  public static function addConvention( $conventions )
31  {
32  static::addConventions( $conventions );
33  }
34  /**
35  * Alias of @ref addAppPaths()
36  */
37  public static function addAppPath( $path ) { static::addAppPaths( $path ); }
38  /**
39  * Alias of @ref getAppPaths()
40  */
41  public static function getAppPath( $type = null ) { return static::getAppPaths( $type ); }
42  /**
43  * Adds path(s) to the PtcHandyMan::$_dirs property to load classes when needed.
44  * See @ref add_dirs and @ref namespace_dirs
45  * @param string|array $paths full path(s) to directories with classes
46  */
47  public static function addDirs( $paths )
48  {
49  if ( !is_array( $paths ) ) { $paths = array( $paths ); }
50  foreach ( $paths as $k => $v )
51  {
52  $path = realpath( $v ); // get real os path
53  if ( $path ) // if path exists
54  {
55  $result = ( !is_int( $k ) ) ? static::_addNamespaceDirectory(
56  str_replace( '\\' , '' , $k ) , $path ) : static::_addDirectory( $path );
57  if ( !$result ) { unset( $paths[ $k ] ); continue; }
58  }
59  else // need to trigger error if path is not found
60  {
61  trigger_error( 'The path "' . $v .
62  '" does not exists or is not accessible!' , E_USER_ERROR );
63  }
64  }
65  if ( $paths ) // debug
66  {
67  static::_debug( $paths , 'Added path(s) to autoloader' , 'Autoloader' );
68  }
69  }
70  /**
71  * Adds class file(s) to the autoloader. See @ref add_files
72  * @param string $files full path of the class file
73  */
74  public static function addFiles( $files )
75  {
76  if ( !is_array( $files ) ) { $files = array( $files ); }
77  foreach ( $files as $k => $v )
78  {
79  $file = realpath( $v ); // get real OS path
80  if( $file ) // path exists
81  {
82  // remove first '\' if present
83  $key = ( substr( $k , 0 , 1 ) == '\\' ) ? substr( $k , 1 ) : $k;
84  // check if class name exists already
85  if ( @array_key_exists( $key , @static::$_dirs[ 'files' ] ) )
86  {
87  trigger_error( 'Cannot redeclare "' . $k . '" as class name!' , E_USER_ERROR );
88  unset( $files[ $k ] );
89  continue;
90  } // maybe we should check if the file is already present as well?
91  @static::$_dirs[ 'files' ][ $key ] = $file;
92  }
93  else { trigger_error( 'the file "' . $v . '" cannot be found!' , E_USER_ERROR ); } // file not found
94  }
95  if ( $files ) { static::_debug( $files , 'Added file(s) to autoloader' , 'Autoloader' ); } // debug
96  }
97  /**
98  * Registers the autoloader to load classes when needed. See @ref hm_getting_started
99  * @param bool $addThisPath adds the path where the class resides as a directory
100  * @param bool $useHelpers load the ptc-helpers.php file if found, and registers the event class
101  * @param bool $registerAutoLoader registers the load method with the spl utilities
102  */
103  public static function register( $addThisPath = true , $useHelpers = true , $registerAutoLoader = true )
104  {
105  $this_class = get_called_class( );
106  if ( $addThisPath ) { static::addDir( dirname( __FILE__ ) ); } // add this path
107  if ( $registerAutoLoader ) { spl_autoload_register( array( $this_class , 'load' ) ); }
108  if ( $useHelpers && file_exists( dirname( __FILE__ ) . '/ptc-helpers.php' ) ) // add helpers if found
109  {
110  require_once( dirname( __FILE__ ) . '/ptc-helpers.php' );
111  }
112  if ( $useHelpers && file_exists( dirname( __FILE__ ) . '/PtcEvent.php' ) )
113  {
114  __NAMESPACE__ . PtcEvent::register( ); // register PtcEvent with helpers
115  }
116  $namespace = @strtoupper( @str_replace( '\\' , '_' , __NAMESPACE__ ) ) . '_';
117  @define( '_PTCHANDYMAN_' . $namespace , $this_class ); // declare the class namespace
118  static::_debug( 'Autoloader registerd' , '' , 'Autoloader' );
119  }
120  /**
121  * Retrieves the separators used by the autoloader
122  */
123  public static function getSeparators( ){ return static::$_separators; }
124  /**
125  * Retrieves the naming conventions used by the autoloader
126  */
127  public static function getConventions( ){ return static::$_namingConventions; }
128  /**
129  * Adds a separator to the PtcHandyMan::$_separators property for the autoloader.
130  * See @ref using_separators
131  * @param array|string $sep the separator(s) to be added
132  */
133  public static function addSeparators( $sep )
134  {
135  $seps = ( is_array( $sep ) ) ? $sep : array( $sep );
136  foreach ( $seps as $k => $v )
137  {
138  if ( in_array( $v , static::$_separators ) )
139  {
140  static::_debug( 'Separator "' . $v . ' " already present!' , '' , 'Autoloader' );
141  continue;
142  }
143  static::$_separators[ ] = $v;
144  }
145  }
146  /**
147  * Adds naming convention(s) to the PtcHandyMan::$_namingConventions property for the autoloader.
148  * See @ref using_separators
149  * @param array|string $conventions the naming convention(s) to be added
150  */
151  public static function addConventions( $conventions )
152  {
153  $conventions = ( is_array( $conventions ) ) ? $conventions : array( $conventions );
154  foreach ( $conventions as $k => $v)
155  {
156  if ( in_array( $v, static::$_namingConventions ) )
157  {
158  static::_debug( 'Separator "' . $v . ' " already present!' , '' , 'Autoloader' );
159  continue;
160  }
161  static::$_namingConventions[ ] = $v;
162  }
163  }
164  /**
165  * Returns the current included paths for the autoloader. See @ref getDirs
166  * @param string $type directories , ns , files
167  * @return the PtcHandyMan::$_dirs property based on the $type argument
168  */
169  public static function getDirs( $type = null )
170  {
171  if ( $type && !in_array( $type , array( 'directories' , 'ns' , 'files' ) ) ) // wrong parameter
172  {
173  trigger_error( 'No directories are present with the "' .
174  $type . '" parameter!' , E_USER_WARNING );
175  return;
176  }
177  else if ( $type && !@static::$_dirs[ $type ] ) { return false; } // no values in array
178  if ( @static::$_dirs[ $type ] ) { return static::$_dirs[ $type ]; } // return value
179  return @static::$_dirs; // return all values
180  }
181  /**
182  * Helper method to retrieve paths for the application. See @ref usingAddedPath
183  * @param string $name the path to return stored in the PtcHandyMan::$_appPaths property
184  * @return the PtcHandyMan::$_appPaths property based on the $name argument
185  */
186  public static function getAppPaths( $name = null )
187  {
188  if ( empty( static::$_appPaths ) ) { static::_buildAppPaths( ); } // build paths once
189  if ( !$name ) { return static::$_appPaths; } // return all application paths by default
190  if ( !@array_key_exists( $name , static::$_appPaths ) )
191  {
192  trigger_error( 'No paths found with the option "' . $name . '"!' , E_USER_WARNING );
193  return;
194  }
195  return static::$_appPaths[ $name ];
196  }
197  /**
198  * Adds paths to the PtcHandyMan::$_appPaths property for later usage. See @ref addingAppPath
199  * @param array $paths array of paths to add
200  */
201  public static function addAppPaths( $paths )
202  {
203  if ( empty( static::$_appPaths ) ) { static::_buildAppPaths( ); } // build paths once
204  foreach ( $paths as $k => $v )
205  {
206  if ( !$path = @realpath( $v ) )
207  {
208  trigger_error( 'The file or path "' . $v .
209  '" does not exists or is not accessible!' , E_USER_ERROR );
210  return;
211  }
212  @$add_paths[ $k ] = $path;
213  }
214  static::$_appPaths = array_merge( static::$_appPaths , $add_paths );
215  }
216  /**
217  * Retrieves inaccessible properties from a class or object. See @ref read_properties
218  * @param mixed $object the name of the class or the initialized object
219  * @param string $propertyName the name of the property
220  * @return the value of the property if found.
221  */
222  public static function getProperty( $object , $propertyName )
223  {
224  if ( !$object ){ return null; }
225  if ( is_string( $object ) ) // static property
226  {
227  if ( !class_exists( $object ) ){ return null; }
228  $reflection = new \ReflectionProperty( $object , $propertyName );
229  if ( !$reflection ){ return null; }
230  $reflection->setAccessible( true );
231  return $reflection->getValue( );
232  }
233  $class = new \ReflectionClass( $object );
234  if ( !$class ){ return null; }
235  if( !$class->hasProperty( $propertyName ) ) // check if property exists
236  {
237  trigger_error( 'Property "' . $propertyName . '" not found in class "' .
238  get_class( $object ) . '"!' , E_USER_WARNING );
239  return null;
240  }
241  $property = $class->getProperty( $propertyName );
242  $property->setAccessible( true );
243  return $property->getValue( $object );
244  }
245  /**
246  * Load classes automatically with namespaces support based on folder structure.
247  * See @ref adding_dirs
248  * @param string $class the name of the class to autoload
249  * @return true if a file has been loaded, false otherwise.
250  */
251  public static function load( $class )
252  {
253  /* check files array first if class matches any name */
254  if ( @array_key_exists( $class , @static::$_dirs[ 'files' ] ) )
255  {
256  $msg = array( 'file' => static::$_dirs[ 'files' ][ $class ] , 'class' => $class );
257  static::_debug( $msg , 'Included class file' , 'Autoloader' );
258  require_once( static::$_dirs[ 'files' ][ $class ] );
259  return true;
260  }
261  else if ( strpos( $class , '\\' ) ) // try namespace first
262  {
263  $folders = explode( '\\' , $class );
264  if ( @static::$_dirs[ 'ns' ][ $folders[ 0 ] ] )
265  {
266  $path = static::$_dirs[ 'ns' ][ $folders[ 0 ] ];
267  unset( $folders[ 0 ] );
268  $class_name = end( $folders );
269  if ( sizeof( $folders ) > 1 )
270  {
271  array_pop( $folders );
272  foreach ( $folders as $k => $v ) { $path .= DIRECTORY_SEPARATOR . $v; }
273  }
274  if ( !@realpath( $path ) )
275  {
276  trigger_error( 'The path "' . $path .
277  '" does not exists or is not accessible!' , E_USER_ERROR );
278  return false;
279  }
280  if ( $found = static::_loadClass( $class_name , $path , $class ) ) { return true; }
281  }
282  }
283  else if ( @static::$_dirs[ 'directories' ] ) // try all paths in directories array
284  {
285  foreach ( static::$_dirs[ 'directories' ] as $k => $v )
286  {
287  if ( $found = static::_loadClass( $class , $v ) ) { return true; }
288  }
289  }
290  return false;
291  }
292  /**
293  * Paths for directories to autoload classes
294  */
295  protected static $_dirs = array();
296  /**
297  * Separators for naming conventions
298  */
299  protected static $_separators = array( );
300  /**
301  * Naming conventions to attempt to load with the autoloader
302  */
303  protected static $_namingConventions = array( );
304  /**
305  * Application paths property
306  */
307  protected static $_appPaths = array( );
308  /**
309  * Classes autoloader engine, tries various possibilities for file names
310  * @param string $class the class name without namespaces
311  * @param string $path the full path to the file
312  * @param string $namespace the class name with namespace if present
313  * @return true if a file is found, false otherwise
314  */
315  protected static function _loadClass( $class , $path , $namespace = null )
316  {
317  $class_name = ( $namespace ) ? $namespace : $class;
318  $path = $path . DIRECTORY_SEPARATOR;
319  if ( file_exists( $path . $class . '.php' ) ) // try the file
320  {
321  static::_debug( array( 'file' => $path . $class . '.php' , 'class' => $class_name ),
322  'Included class file' , 'Autoloader' ); // debug
323  require_once( $path . $class . '.php');
324  return true;
325  }
326  else if ( file_exists( $path . $new_file = strtolower( $class ) . '.php' ) ) // try the file lowercase
327  {
328  static::_debug( array( 'file' => $path . $new_file , 'class' => $class_name ),
329  'Included class file' , 'Autoloader' ); // debug
330  require_once( $path . $new_file );
331  return true;
332  }
333  else{ return static::_guessFileName( $class , $path , $namespace ); } // use an engine to guess the file
334  return false;
335  }
336  /**
337  * Tries to guess the filename to load based on the naming conventions and the separator properties
338  * @param string $class the class name without namespaces
339  * @param string $path the full path to the file
340  * @param string $namespace the class name with namespace if present
341  * @return true if a file is found, false otherwise
342  */
343  protected static function _guessFileName( $class , $path , $namespace = null )
344  {
345  $class_name = ( $namespace ) ? $namespace : $class;
346  foreach ( static::$_separators as $sep ) // try separators and naming conventions combinations
347  {
348  foreach ( static::$_namingConventions as $convention )
349  {
350  $filename = str_replace( array( '{SEP}' , '{CLASS}' ) ,
351  array( $sep , $class ) , $convention );
352  if ( file_exists( $path . $filename . '.php') ) // try new filename
353  {
354  static::_debug( array( 'file' => $path . $filename . '.php' ,
355  'class' => $class_name ) , 'Included class file' , 'Autoloader' ); // debug
356  require_once( $path . $filename .'.php');
357  return true;
358  }
359  else if ( file_exists( $path . $new_file = strtolower( $filename ) . '.php') ) // try lower case
360  {
361  static::_debug( array( 'file' => $path . $new_file , 'class' => $class_name ) ,
362  'Included class file' , 'Autoloader' ); // debug
363  require_once( $path . $new_file );
364  return true;
365  }
366  else if ( $sep != '_') // try replacing "_" with other separators in class name with lowercase
367  {
368  $replaced = str_replace( '_' , $sep , $filename ); // try new file name
369  if ( file_exists( $path . $replaced . '.php' ) )
370  {
371  static::_debug( array( 'file' =>$path . $replaced . '.php' ,
372  'class' => $class_name ) , 'Included class file','Autoloader'); // debug
373  require_once( $path . $replaced . '.php');
374  return true;
375  }
376  else if ( file_exists( $file = $path . strtolower( $replaced ) . '.php' ) ) // lowercase
377  {
378  static::_debug( array( 'file' => $file ,
379  'class' => $class_name ) , 'Included class file' , 'Autoloader' ); // debug
380  require_once( $file );
381  return true;
382  }
383  }
384  }
385  }
386  return false;
387  }
388  /**
389  * Builds application paths for the first time when PtcHandyMan::getAppPath( ) is called.
390  */
391  protected static function _buildAppPaths( )
392  {
393  static::$_appPaths = array
394  (
395  'docRoot' => @$_SERVER[ 'DOCUMENT_ROOT' ] , // the document root folder
396  'handyMan' => dirname( __FILE__ ) // the directory where this file resides
397  );
398  }
399  /**
400  * Adds a directory to the PtcHandyMan::$_dirs array to autoload classes
401  * @param string $directory the full path to the directory
402  * @return false if directory is already present, true otherwise
403  */
404  protected static function _addDirectory( $directory )
405  {
406  if ( @in_array( $directory , @static::$_dirs[ 'directories' ] ) ) // check if dir is already present
407  {
408  static::_debug( $directory , 'Path already exists!' , 'Autoloader' ); // debug
409  return false;
410  }
411  @static::$_dirs[ 'directories' ][ ] = $directory;
412  return true;
413  }
414  /**
415  * Adds a directory to the PtcHandyMan::$_dirs array to load classes that use namespaces
416  * @param string $namespace the namespace for the path toa utoload classes
417  * @param string $directory the full path to the directory
418  * @return true if directory is not present, triggers an error otherwise
419  */
420  protected static function _addNamespaceDirectory( $namespace , $directory )
421  {
422  if ( @array_key_exists( $namespace , @static::$_dirs[ 'ns' ] ) ) // check if dir is already present
423  {
424  trigger_error( 'Cannot redeclare namespace "' . $namespace . '"!' , E_USER_ERROR );
425  return false;
426  }
427  @static::$_dirs[ 'ns' ][ $namespace ] = $directory;
428  return true;
429  }
430  /**
431  * Send messsages to the PtcDebug class if present
432  * @param mixed $string the string to pass
433  * @param mixed $statement some statement if required
434  * @param string $category a category for the messages panel
435  */
436  protected static function _debug( $string , $statement = null , $category = null )
437  {
438  if ( !defined( '_PTCDEBUG_NAMESPACE_' ) ) { return false; }
439  return @call_user_func_array( array( '\\' . _PTCDEBUG_NAMESPACE_ , 'bufferLog' ) ,
440  array( $string , $statement , $category ) );
441  }
442  }
static _guessFileName($class, $path, $namespace=null)
Tries to guess the filename to load based on the naming conventions and the separator properties...
Definition: PtcHm.php:343
static $_dirs
Paths for directories to autoload classes.
Definition: PtcHm.php:295
static register()
Registers the component with a constant for ptc helpers functions.
Definition: PtcEvent.php:22
static addFiles($files)
Adds class file(s) to the autoloader.
Definition: PtcHm.php:74
static _buildAppPaths()
Builds application paths for the first time when PtcHandyMan::getAppPath( ) is called.
Definition: PtcHm.php:391
static getAppPaths($name=null)
Helper method to retrieve paths for the application.
Definition: PtcHm.php:186
static getSeparators()
Retrieves the separators used by the autoloader.
Definition: PtcHm.php:123
static _loadClass($class, $path, $namespace=null)
Classes autoloader engine, tries various possibilities for file names.
Definition: PtcHm.php:315
static addConventions($conventions)
Adds naming convention(s) to the PtcHandyMan::$_namingConventions property for the autoloader...
Definition: PtcHm.php:151
static _debug($string, $statement=null, $category=null)
Send messsages to the PtcDebug class if present.
Definition: PtcHm.php:436
static addDir($path)
Alias of addDirs()
Definition: PtcHm.php:18
static getAppPath($type=null)
Alias of getAppPaths()
Definition: PtcHm.php:41
static _addNamespaceDirectory($namespace, $directory)
Adds a directory to the PtcHandyMan::$_dirs array to load classes that use namespaces.
Definition: PtcHm.php:420
static addAppPaths($paths)
Adds paths to the PtcHandyMan::$_appPaths property for later usage.
Definition: PtcHm.php:201
static addFile($file)
Alias of addFiles()
Definition: PtcHm.php:22
static $_appPaths
Application paths property.
Definition: PtcHm.php:307
static addDirs($paths)
Adds path(s) to the PtcHandyMan::$_dirs property to load classes when needed.
Definition: PtcHm.php:47
static $_separators
Separators for naming conventions.
Definition: PtcHm.php:299
static addSeparator($sep)
Alias of addSeparator()
Definition: PtcHm.php:26
static addConvention($conventions)
Alias of addConventions()
Definition: PtcHm.php:30
static load($class)
Load classes automatically with namespaces support based on folder structure.
Definition: PtcHm.php:251
static getConventions()
Retrieves the naming conventions used by the autoloader.
Definition: PtcHm.php:127
static _addDirectory($directory)
Adds a directory to the PtcHandyMan::$_dirs array to autoload classes.
Definition: PtcHm.php:404
static $_namingConventions
Naming conventions to attempt to load with the autoloader.
Definition: PtcHm.php:303
static addAppPath($path)
Alias of addAppPaths()
Definition: PtcHm.php:37
static getDirs($type=null)
Returns the current included paths for the autoloader.
Definition: PtcHm.php:169
static addSeparators($sep)
Adds a separator to the PtcHandyMan::$_separators property for the autoloader.
Definition: PtcHm.php:133
static getProperty($object, $propertyName)
Retrieves inaccessible properties from a class or object.
Definition: PtcHm.php:222