khaihihi
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( '-1' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class VcShortcodeAutoloader
|
||||
*/
|
||||
class VcShortcodeAutoloader {
|
||||
|
||||
private static $instance = null;
|
||||
private static $config = null;
|
||||
private static $cached = null;
|
||||
|
||||
/**
|
||||
* @param bool $load_config
|
||||
* @return \VcShortcodeAutoloader|null
|
||||
*/
|
||||
public static function getInstance( $load_config = true ) {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new VcShortcodeAutoloader( $load_config );
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* VcShortcodeAutoloader constructor.
|
||||
* @param bool $load_config
|
||||
*/
|
||||
private function __construct( $load_config = true ) {
|
||||
if ( ! $load_config ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config = array(
|
||||
'classmap_file' => vc_path_dir( 'APP_ROOT', 'vc_classmap.json.php' ),
|
||||
'shortcodes_dir' => vc_path_dir( 'SHORTCODES_DIR' ),
|
||||
'root_dir' => vc_path_dir( 'APP_ROOT' ),
|
||||
);
|
||||
|
||||
if ( is_file( $config['classmap_file'] ) ) {
|
||||
$config['classmap'] = require $config['classmap_file'];
|
||||
self::$cached = true;
|
||||
} else {
|
||||
$config['classmap'] = self::generateClassMap( $config['shortcodes_dir'] );
|
||||
self::$cached = false;
|
||||
}
|
||||
|
||||
self::$config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include class dependencies
|
||||
*
|
||||
* @param string $class Class name
|
||||
*
|
||||
* @return string[] Included (if any) files
|
||||
*/
|
||||
public static function includeClass( $class ) {
|
||||
// call the constructor (php 7.4 compat)
|
||||
self::getInstance();
|
||||
$class = strtolower( $class );
|
||||
$files = array();
|
||||
|
||||
if ( self::$config['classmap'] ) {
|
||||
$files = isset( self::$config['classmap'][ $class ] ) ? self::$config['classmap'][ $class ] : array();
|
||||
}
|
||||
|
||||
if ( $files ) {
|
||||
foreach ( $files as $k => $file ) {
|
||||
if ( self::$cached ) {
|
||||
$files[ $k ] = $file = self::$config['root_dir'] . DIRECTORY_SEPARATOR . $file;
|
||||
}
|
||||
|
||||
if ( is_file( $file ) ) {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all classes defined in file
|
||||
*
|
||||
* @param string $file Full path to file
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function extractClassNames( $file ) {
|
||||
$classes = array();
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
$contents = file_get_contents( $file );
|
||||
if ( ! $contents ) {
|
||||
return $classes;
|
||||
}
|
||||
|
||||
$tokens = token_get_all( $contents );
|
||||
$class_token = false;
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( is_array( $token ) ) {
|
||||
if ( T_CLASS === $token[0] ) {
|
||||
$class_token = true;
|
||||
} elseif ( $class_token && T_STRING === $token[0] ) {
|
||||
$classes[] = $token[1];
|
||||
$class_token = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all classes from file with their extends
|
||||
*
|
||||
* @param $file
|
||||
*
|
||||
* @return array Associative array where key is class name and value is parent class name (if any))
|
||||
*/
|
||||
public static function extractClassesAndExtends( $file ) {
|
||||
$classes = array();
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
$contents = file_get_contents( $file );
|
||||
if ( ! $contents ) {
|
||||
return $classes;
|
||||
}
|
||||
|
||||
// class Foo extends Bar {
|
||||
preg_match_all( '/class\s+(\w+)\s+extends\s(\w+)\s+\{/i', $contents, $matches, PREG_SET_ORDER );
|
||||
foreach ( $matches as $v ) {
|
||||
$classes[ $v[1] ] = $v[2];
|
||||
}
|
||||
|
||||
// class Foo {
|
||||
preg_match_all( '/class\s+(\w+)\s+\{/i', $contents, $matches, PREG_SET_ORDER );
|
||||
foreach ( $matches as $v ) {
|
||||
$classes[ $v[1] ] = null;
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find file by class name
|
||||
*
|
||||
* Search is case-insensitive
|
||||
*
|
||||
* @param string $class
|
||||
* @param string[]|string $dirs One or more directories where to look (recursive)
|
||||
*
|
||||
* @return string|false Full path to class file
|
||||
*/
|
||||
public static function findClassFile( $class, $dirs ) {
|
||||
foreach ( (array) $dirs as $dir ) {
|
||||
$Directory = new RecursiveDirectoryIterator( $dir );
|
||||
$Iterator = new RecursiveIteratorIterator( $Directory );
|
||||
$Regex = new RegexIterator( $Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH );
|
||||
$class = strtolower( $class );
|
||||
|
||||
foreach ( $Regex as $file => $object ) {
|
||||
$classes = self::extractClassNames( $file );
|
||||
|
||||
if ( $classes && in_array( $class, array_map( 'strtolower', $classes ), true ) ) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct full dependency list of classes for each class in right order (including class itself)
|
||||
*
|
||||
* @param string[]|string $dirs Directories where to look (recursive)
|
||||
*
|
||||
* @return array Associative array where key is lowercase class name and value is array of files to include for
|
||||
* that class to work
|
||||
*/
|
||||
public static function generateClassMap( $dirs ) {
|
||||
$flat_map = array();
|
||||
foreach ( (array) $dirs as $dir ) {
|
||||
$Directory = new RecursiveDirectoryIterator( $dir );
|
||||
$Iterator = new RecursiveIteratorIterator( $Directory );
|
||||
$Regex = new RegexIterator( $Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH );
|
||||
|
||||
foreach ( $Regex as $file => $object ) {
|
||||
$classes = self::extractClassesAndExtends( $file );
|
||||
|
||||
foreach ( $classes as $class => $extends ) {
|
||||
$class = strtolower( $class );
|
||||
$extends = strtolower( $extends );
|
||||
if ( in_array( $extends, array(
|
||||
'wpbakeryshortcodescontainer',
|
||||
'wpbakeryvisualcomposer',
|
||||
'wpbakeryshortcode',
|
||||
'wpbmap',
|
||||
), true ) ) {
|
||||
$extends = null;
|
||||
}
|
||||
$flat_map[ $class ] = array(
|
||||
'class' => $class,
|
||||
'file' => $file,
|
||||
'extends' => $extends,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$map = array();
|
||||
foreach ( $flat_map as $params ) {
|
||||
$dependencies = array(
|
||||
array(
|
||||
'class' => $params['class'],
|
||||
'file' => $params['file'],
|
||||
),
|
||||
);
|
||||
|
||||
if ( $params['extends'] ) {
|
||||
$queue = array( $params['extends'] );
|
||||
|
||||
while ( $queue ) {
|
||||
$current_class = array_pop( $queue );
|
||||
$current_class = $flat_map[ $current_class ];
|
||||
|
||||
$dependencies[] = array(
|
||||
'class' => $current_class['class'],
|
||||
'file' => $current_class['file'],
|
||||
);
|
||||
|
||||
if ( ! empty( $current_class['extends'] ) ) {
|
||||
$queue[] = $current_class['extends'];
|
||||
}
|
||||
}
|
||||
|
||||
$map[ $params['class'] ] = array_reverse( $dependencies );
|
||||
} else {
|
||||
$map[ $params['class'] ] = $dependencies;
|
||||
}
|
||||
}
|
||||
|
||||
// simplify array
|
||||
$classmap = array();
|
||||
foreach ( $map as $class => $dependencies ) {
|
||||
$classmap[ $class ] = array();
|
||||
foreach ( $dependencies as $v ) {
|
||||
$classmap[ $class ][] = str_replace( '\\', '/', $v['file'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $classmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate and save class map file
|
||||
*
|
||||
* @param string[]|string $dirs Directories where to look (recursive)
|
||||
* @param string $target Output file
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function saveClassMap( $dirs, $target ) {
|
||||
if ( ! $target ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$classmap = self::generateClassMap( $dirs );
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
$code = '<?php return (array) json_decode(\'' . json_encode( $classmap ) . '\') ?>';
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
return (bool) file_put_contents( $target, $code );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user