-
Notifications
You must be signed in to change notification settings - Fork 798
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Autoloader: refactor functions.php (#15111)
* Autoloader: refactor functions.php into classes * Autoloader: update unit tests Update the unit tests to use the new Classes_Handler and Files_Handler classes. * Autoloader: update is_current_plugin_active() Update is_current_plugin_active() to check both active and activating plugins when determining whether the current plugin is active. The active and activating plugins can be obtained using the Plugins_Handler::get_active_plugins() method. * Added newly generated files to gitignore. * Autoloader: improve Plugins_Handler Improve the Plugins_Handler class by: - Giving some methods more descriptive names. - Adding a $jetpack_autoloader_activating_plugins global variable that contains the plugins that are activating via a non-request method. - Refactoring a few methods to improve clarity. * Autoloader: update the autoloader chain after autoloader reset Add a new function, Autoloader_Handler::update_autoloader_chain(), which handles updates of the autoloader chain as follows: - Registers the latest autoloader function. - Moves the v1 autoloader function to the end of the chain. - Removes any other v2 autoloader functions. This is needed for situations where a plugin activates using a non-request method, so the activating plugin was not known when the autoloader first ran. If the activating plugin has an autoloader with a later version, that autoloader will be registered and the previously registered autoloader function should be removed. Finally, use the Autoloader_Handler::update_autoloader_chain() method in set_up_autoloader(). * Autoloader: update update_autoloader_chain() In Autoloader_Handler::update_autoloader_chain(), check whether the autoloader object is a string. If not, just continue. We're only looking for Jetpack autoloader functions, and they're registered as strings. Co-authored-by: Igor Zinovyev <zinigor@gmail.com>
- Loading branch information
Showing
10 changed files
with
532 additions
and
300 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
<?php | ||
/* HEADER */ // phpcs:ignore | ||
|
||
/** | ||
* This class selects the package version for the autoloader. | ||
*/ | ||
class Autoloader_Handler { | ||
|
||
// The name of the autoloader function registered by v1.* autoloaders. | ||
const V1_AUTOLOADER_NAME = 'Automattic\Jetpack\Autoloader\autoloader'; | ||
|
||
/* | ||
* The autoloader function for v2.* autoloaders is named __NAMESPACE__ . \autoloader. | ||
* The namespace is defined in AutoloadGenerator as | ||
* 'Automattic\Jetpack\Autoloader\jp' plus a unique suffix. | ||
*/ | ||
const V2_AUTOLOADER_BASE = 'Automattic\Jetpack\Autoloader\jp'; | ||
|
||
/** | ||
* The Plugins_Handler object. | ||
* | ||
* @var Plugins_Handler | ||
*/ | ||
private $plugins_handler = null; | ||
|
||
/** | ||
* The constructor. | ||
* | ||
* @param Plugins_Handler $plugins_handler The plugins_handler object. | ||
*/ | ||
public function __construct( $plugins_handler ) { | ||
$this->plugins_handler = $plugins_handler; | ||
} | ||
|
||
/** | ||
* Finds the latest installed autoloader. | ||
*/ | ||
public function find_latest_autoloader() { | ||
global $jetpack_autoloader_latest_version; | ||
|
||
$current_autoloader_path = trailingslashit( dirname( __FILE__ ) ) . 'autoload_packages.php'; | ||
|
||
$selected_autoloader_version = null; | ||
$selected_autoloader_path = null; | ||
|
||
$active_plugins = $this->plugins_handler->get_all_active_plugins(); | ||
|
||
foreach ( $active_plugins as $plugin ) { | ||
$plugin_path = plugin_dir_path( trailingslashit( WP_PLUGIN_DIR ) . $plugin ); | ||
$classmap_path = trailingslashit( $plugin_path ) . 'vendor/composer/jetpack_autoload_classmap.php'; | ||
|
||
if ( file_exists( $classmap_path ) ) { | ||
$packages = require $classmap_path; | ||
|
||
$compare_version = $packages['Automattic\\Jetpack\\Autoloader\\AutoloadGenerator']['version']; | ||
$compare_path = trailingslashit( $plugin_path ) . 'vendor/autoload_packages.php'; | ||
|
||
// TODO: This comparison needs to properly handle dev versions. | ||
if ( version_compare( $selected_autoloader_version, $compare_version, '<' ) ) { | ||
$selected_autoloader_version = $compare_version; | ||
$selected_autoloader_path = $compare_path; | ||
} | ||
} | ||
} | ||
|
||
$jetpack_autoloader_latest_version = $selected_autoloader_version; | ||
if ( $current_autoloader_path !== $selected_autoloader_path ) { | ||
require $selected_autoloader_path; | ||
} | ||
} | ||
|
||
/** | ||
* Get this autoloader's package version. | ||
* | ||
* @return String The autoloader's package version. | ||
*/ | ||
public function get_current_autoloader_version() { | ||
$classmap_file = trailingslashit( dirname( __FILE__ ) ) . 'composer/jetpack_autoload_classmap.php'; | ||
$autoloader_packages = require $classmap_file; | ||
|
||
return $autoloader_packages['Automattic\\Jetpack\\Autoloader\\AutoloadGenerator']['version']; | ||
} | ||
|
||
|
||
/** | ||
* Updates the spl autoloader chain: | ||
* - Registers this namespace's autoloader function. | ||
* - If a v1 autoloader function is registered, moves it to the end of the chain. | ||
* - Removes any other v2 autoloader functions that have already been registered. This | ||
* can occur when the autoloader is being reset by an activating plugin. | ||
*/ | ||
public function update_autoloader_chain() { | ||
spl_autoload_register( __NAMESPACE__ . '\autoloader' ); | ||
|
||
$autoload_chain = spl_autoload_functions(); | ||
|
||
foreach ( $autoload_chain as $autoloader ) { | ||
if ( ! is_string( $autoloader ) ) { | ||
/* | ||
* The Jetpack Autoloader functions are registered as strings, so | ||
* just continue if $autoloader isn't a string. | ||
*/ | ||
continue; | ||
} | ||
|
||
if ( self::V1_AUTOLOADER_NAME === $autoloader ) { | ||
// Move the v1.* autoloader function to the end of the spl autoloader chain. | ||
spl_autoload_unregister( $autoloader ); | ||
spl_autoload_register( $autoloader ); | ||
|
||
} elseif ( | ||
self::V2_AUTOLOADER_BASE === substr( $autoloader, 0, strlen( self::V2_AUTOLOADER_BASE ) ) | ||
&& __NAMESPACE__ !== substr( $autoloader, 0, strlen( __NAMESPACE__ ) ) | ||
) { | ||
// Unregister any other v2.* autoloader functions if they're in the chain. | ||
spl_autoload_unregister( $autoloader ); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
/* HEADER */ // phpcs:ignore | ||
|
||
/** | ||
* This class selects the package versions for the package classes. | ||
*/ | ||
class Classes_Handler { | ||
|
||
/** | ||
* The Plugins_Handler object. | ||
* | ||
* @var Plugins_Handler | ||
*/ | ||
private $plugins_handler = null; | ||
|
||
/** | ||
* The constructor. | ||
* | ||
* @param Plugins_Handler $plugins_handler The plugins_handler object. | ||
*/ | ||
public function __construct( $plugins_handler ) { | ||
$this->plugins_handler = $plugins_handler; | ||
} | ||
|
||
/** | ||
* Adds the version of a package to the $jetpack_packages_classmap global | ||
* array so that the autoloader is able to find it. | ||
* | ||
* @param string $class_name Name of the class that you want to autoload. | ||
* @param string $version Version of the class. | ||
* @param string $path Absolute path to the class so that we can load it. | ||
*/ | ||
public function enqueue_package_class( $class_name, $version, $path ) { | ||
global $jetpack_packages_classmap; | ||
|
||
if ( ! isset( $jetpack_packages_classmap[ $class_name ] ) ) { | ||
$jetpack_packages_classmap[ $class_name ] = array( | ||
'version' => $version, | ||
'path' => $path, | ||
); | ||
|
||
return; | ||
} | ||
// If we have a @dev version set always use that one! | ||
if ( 'dev-' === substr( $jetpack_packages_classmap[ $class_name ]['version'], 0, 4 ) ) { | ||
return; | ||
} | ||
|
||
// Always favour the @dev version. Since that version is the same as bleeding edge. | ||
// We need to make sure that we don't do this in production! | ||
if ( 'dev-' === substr( $version, 0, 4 ) ) { | ||
$jetpack_packages_classmap[ $class_name ] = array( | ||
'version' => $version, | ||
'path' => $path, | ||
); | ||
|
||
return; | ||
} | ||
// Set the latest version! | ||
if ( version_compare( $jetpack_packages_classmap[ $class_name ]['version'], $version, '<' ) ) { | ||
$jetpack_packages_classmap[ $class_name ] = array( | ||
'version' => $version, | ||
'path' => $path, | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Initializes the classmap. | ||
*/ | ||
public function set_class_paths() { | ||
$paths = $this->plugins_handler->get_active_plugins_paths(); | ||
|
||
foreach ( $paths as $path ) { | ||
if ( is_readable( $path['class'] ) ) { | ||
$class_map = require $path['class']; | ||
|
||
if ( is_array( $class_map ) ) { | ||
foreach ( $class_map as $class_name => $class_info ) { | ||
$this->enqueue_package_class( $class_name, $class_info['version'], $class_info['path'] ); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
/* HEADER */ // phpcs:ignore | ||
|
||
/** | ||
* This class selects the package versions for the package files. | ||
*/ | ||
class Files_Handler { | ||
|
||
/** | ||
* The Plugins_Handler object. | ||
* | ||
* @var Plugins_Handler | ||
*/ | ||
private $plugins_handler = null; | ||
|
||
/** | ||
* The constructor. | ||
* | ||
* @param Plugins_Handler $plugins_handler The plugins_handler object. | ||
*/ | ||
public function __construct( $plugins_handler ) { | ||
$this->plugins_handler = $plugins_handler; | ||
} | ||
|
||
/** | ||
* Adds the version of a package file to the $jetpack_packages_filemap global | ||
* array so that we can load the most recent version. | ||
* | ||
* @param string $file_identifier Unique id to file assigned by composer based on package name and filename. | ||
* @param string $version Version of the file. | ||
* @param string $path Absolute path to the file so that we can load it. | ||
*/ | ||
public function enqueue_package_file( $file_identifier, $version, $path ) { | ||
global $jetpack_packages_filemap; | ||
|
||
if ( ! isset( $jetpack_packages_filemap[ $file_identifier ] ) ) { | ||
$jetpack_packages_filemap[ $file_identifier ] = array( | ||
'version' => $version, | ||
'path' => $path, | ||
); | ||
|
||
return; | ||
} | ||
// If we have a @dev version set always use that one! | ||
if ( 'dev-' === substr( $jetpack_packages_filemap[ $file_identifier ]['version'], 0, 4 ) ) { | ||
return; | ||
} | ||
|
||
// Always favour the @dev version. Since that version is the same as bleeding edge. | ||
// We need to make sure that we don't do this in production! | ||
if ( 'dev-' === substr( $version, 0, 4 ) ) { | ||
$jetpack_packages_filemap[ $file_identifier ] = array( | ||
'version' => $version, | ||
'path' => $path, | ||
); | ||
|
||
return; | ||
} | ||
// Set the latest version! | ||
if ( version_compare( $jetpack_packages_filemap[ $file_identifier ]['version'], $version, '<' ) ) { | ||
$jetpack_packages_filemap[ $file_identifier ] = array( | ||
'version' => $version, | ||
'path' => $path, | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Initializes the filemap. | ||
*/ | ||
public function set_file_paths() { | ||
$paths = $this->plugins_handler->get_active_plugins_paths(); | ||
|
||
foreach ( $paths as $path ) { | ||
if ( is_readable( $path['file'] ) ) { | ||
$file_map = require $path['file']; | ||
|
||
if ( is_array( $file_map ) ) { | ||
foreach ( $file_map as $file_identifier => $file_data ) { | ||
$this->enqueue_package_file( $file_identifier, $file_data['version'], $file_data['path'] ); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Include latest version of all enqueued files. | ||
*/ | ||
public function file_loader() { | ||
global $jetpack_packages_filemap; | ||
foreach ( $jetpack_packages_filemap as $file_identifier => $file_data ) { | ||
if ( empty( $GLOBALS['__composer_autoload_files'][ $file_identifier ] ) ) { | ||
require_once $file_data['path']; | ||
|
||
$GLOBALS['__composer_autoload_files'][ $file_identifier ] = true; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.