| 1 |
<?php |
| 2 |
|
| 3 |
namespace FilterEverything\Filter; |
| 4 |
|
| 5 |
if ( ! defined('ABSPATH') ) { |
| 6 |
exit; |
| 7 |
} |
| 8 |
|
| 9 |
/** |
| 10 |
* Class autoloader for the plugin. |
| 11 |
* |
| 12 |
* Two lookup strategies, in this order: |
| 13 |
* |
| 14 |
* 1. Class maps (generated by bin/build-classmap.php into src/classmap.php |
| 15 |
* and pro/classmap.php). Needed because the historical classes all live in |
| 16 |
* the flat namespace FilterEverything\Filter regardless of their folder, |
| 17 |
* and src/FormFields/Input.php declares 14 classes in one file. |
| 18 |
* 2. PSR-4 prefixes, for new code whose namespace mirrors its folder |
| 19 |
* (e.g. FilterEverything\Filter\Frontend\Foo -> src/Frontend/Foo.php). |
| 20 |
* |
| 21 |
* The free build ships without the pro/ folder and pro/filters-pro.php is the |
| 22 |
* only place that registers the PRO class map, so commenting out that single |
| 23 |
* include in filter-everything.php (or deleting pro/) is enough to run the |
| 24 |
* plugin as the free version: PRO classes are then simply unknown and every |
| 25 |
* class_exists('FilterEverything\Filter\Pro\…') check stays false. |
| 26 |
* |
| 27 |
* Files that do work at include time (instantiate a class, add hooks, define |
| 28 |
* functions) are NOT autoloaded; filter-everything.php still includes them |
| 29 |
* explicitly and in order. |
| 30 |
* |
| 31 |
* @since 1.9.7 |
| 32 |
*/ |
| 33 |
class Autoloader |
| 34 |
{ |
| 35 |
/** @var array<string,string> FQCN => absolute file path */ |
| 36 |
private static $classMap = []; |
| 37 |
|
| 38 |
/** @var array<string,string[]> namespace prefix (with trailing \) => base dirs */ |
| 39 |
private static $prefixes = []; |
| 40 |
|
| 41 |
/** @var bool */ |
| 42 |
private static $registered = false; |
| 43 |
|
| 44 |
public static function register() |
| 45 |
{ |
| 46 |
if ( ! self::$registered ) { |
| 47 |
spl_autoload_register( [ __CLASS__, 'load' ] ); |
| 48 |
self::$registered = true; |
| 49 |
} |
| 50 |
} |
| 51 |
|
| 52 |
/** |
| 53 |
* @param array<string,string> $map FQCN => path relative to $baseDir |
| 54 |
* @param string $baseDir directory the paths are relative to |
| 55 |
*/ |
| 56 |
public static function addClassMap( array $map, $baseDir ) |
| 57 |
{ |
| 58 |
$baseDir = rtrim( $baseDir, '/\\' ) . '/'; |
| 59 |
foreach ( $map as $class => $relative ) { |
| 60 |
self::$classMap[ ltrim( $class, '\\' ) ] = $baseDir . ltrim( $relative, '/' ); |
| 61 |
} |
| 62 |
} |
| 63 |
|
| 64 |
/** |
| 65 |
* @param string $prefix namespace prefix, e.g. 'FilterEverything\Filter\' |
| 66 |
* @param string $baseDir directory that corresponds to the prefix |
| 67 |
*/ |
| 68 |
public static function addNamespace( $prefix, $baseDir ) |
| 69 |
{ |
| 70 |
$prefix = trim( $prefix, '\\' ) . '\\'; |
| 71 |
self::$prefixes[ $prefix ][] = rtrim( $baseDir, '/\\' ) . '/'; |
| 72 |
} |
| 73 |
|
| 74 |
/** |
| 75 |
* spl_autoload_register callback. |
| 76 |
*/ |
| 77 |
public static function load( $class ) |
| 78 |
{ |
| 79 |
$class = ltrim( $class, '\\' ); |
| 80 |
|
| 81 |
if ( isset( self::$classMap[ $class ] ) ) { |
| 82 |
return self::requireFile( self::$classMap[ $class ] ); |
| 83 |
} |
| 84 |
|
| 85 |
foreach ( self::$prefixes as $prefix => $dirs ) { |
| 86 |
if ( strpos( $class, $prefix ) !== 0 ) { |
| 87 |
continue; |
| 88 |
} |
| 89 |
$relative = str_replace( '\\', '/', substr( $class, strlen( $prefix ) ) ) . '.php'; |
| 90 |
foreach ( $dirs as $dir ) { |
| 91 |
if ( self::requireFile( $dir . $relative ) ) { |
| 92 |
return true; |
| 93 |
} |
| 94 |
} |
| 95 |
} |
| 96 |
|
| 97 |
return false; |
| 98 |
} |
| 99 |
|
| 100 |
private static function requireFile( $file ) |
| 101 |
{ |
| 102 |
if ( is_file( $file ) ) { |
| 103 |
require_once $file; |
| 104 |
return true; |
| 105 |
} |
| 106 |
return false; |
| 107 |
} |
| 108 |
} |
| 109 |
|