Initial Commit

This commit is contained in:
David Stone
2024-11-30 18:24:12 -07:00
commit e8f7955c1c
5432 changed files with 1397750 additions and 0 deletions

View File

@ -0,0 +1,334 @@
<?php
/**
* A PHP autoloader class that follows the WordPress coding standards applying PSR-4 specification.
*
* @see https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/
*
* @author Pablo dos S G Pacheco
* @package pablo-sg-pacheco/wp-namespace-autoloader
*
* phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_error_log
* phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_print_r
*/
namespace WP_Ultimo\Dependencies\Pablo_Pacheco\WP_Namespace_Autoloader;
if (!\class_exists('WP_Ultimo\\Dependencies\\Pablo_Pacheco\\WP_Namespace_Autoloader\\WP_Namespace_Autoloader')) {
/**
* Autoloader - Main class
*
* Class WP_Namespace_Autoloader
*
* @package Pablo_Pacheco\WP_Namespace_Autoloader
*/
class WP_Namespace_Autoloader
{
/**
* The autoloader settings.
*
* @var array Associative array of settings as detailed in the constructor PHPDoc.
*/
private $args = array();
/**
* Autoloader constructor.
*
* Autoloads all your WordPress classes in an easy way
*
* @param array|string $args {
* Array of arguments.
*
* @type string $directory Current directory. Use __DIR__.
* @type string $namespace_prefix Main namespace of your project . Probably use __NAMESPACE__.
* @type array $lowercase If you want to lowercase. It accepts an array with two possible values: 'file' | 'folders'
* @type array $underscore_to_hyphen If you want to convert underscores to hyphens. It accepts an array with two possible values: 'file' | 'folders'
* @type boolean $prepend_class If you want to prepend 'class-' before files
* @type boolean $prepend_interface If you want to prepend 'interface-' before files
* @type boolean $prepend_trait If you want to prepend 'trait-' before files
* @type string|array $classes_dir Name of the directories containing all your classes (optional).
* }
*/
public function __construct($args = array())
{
$defaults = array(
'directory' => $this->get_calling_directory(),
'namespace_prefix' => $this->get_calling_file_namespace(),
'lowercase' => array('file'),
// 'file' | folders
'underscore_to_hyphen' => array('file'),
// 'file' | folders
'prepend_class' => \true,
'prepend_interface' => \true,
'prepend_trait' => \true,
'classes_dir' => array('.', 'vendor'),
'debug' => \false,
);
$parsed_args = \array_merge($defaults, $args);
$this->set_args($parsed_args);
}
/**
* Register autoloader
*/
public function init()
{
\spl_autoload_register(array($this, 'autoload'));
}
/**
* Determine if the class has already been loaded.
*
* @param string $class classFQN.
*
* @return bool
*/
public function need_to_autoload($class)
{
$args = $this->get_args();
$namespace = $args['namespace_prefix'];
if (!\class_exists($class) && !\interface_exists($class) && !\trait_exists($class)) {
if (\false !== \strpos($class, $namespace)) {
if (!\class_exists($class)) {
return \true;
}
}
}
return \false;
}
/**
* Autoloads classes
*
* @param string $class classFQN.
*/
public function autoload($class)
{
if ($this->need_to_autoload($class)) {
$file_paths = $this->convert_class_to_file($class);
foreach ($file_paths as $file) {
if (\file_exists($file)) {
require_once $file;
return;
}
}
$args = $this->get_args();
if ($args['debug']) {
\error_log('WP Namespace Autoloader could not load file: ' . \print_r($file_paths, \true));
}
}
}
/**
* Gets full path of directories containing classes, using the $args['classes_dir'] input argument.
*
* @return string|array
*/
private function get_dir()
{
$args = $this->get_args();
if (\is_array($args['classes_dir'])) {
$dirs = array();
foreach ($args['classes_dir'] as $classes_dir) {
$dir = $this->sanitize_file_path($classes_dir);
$classes_dir = empty($dir) ? '' : \rtrim($dir, \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR;
$dirs[] = \rtrim($args['directory'], '/\\') . \DIRECTORY_SEPARATOR . $classes_dir;
}
return $dirs;
} else {
$dir = $this->sanitize_file_path($args['classes_dir']);
// Directory containing all classes.
$classes_dir = empty($dir) ? '' : \rtrim($dir, \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR;
return \rtrim($args['directory'], '/\\') . \DIRECTORY_SEPARATOR . $classes_dir;
}
}
/**
* Gets only the path leading to final file based on namespace
*
* @param string $class classFQN.
*
* @return string
*/
private function get_namespace_file_path($class)
{
$args = $this->get_args();
$namespace_prefix = $args['namespace_prefix'];
// Sanitized class and namespace prefix.
$sanitized_class = $this->sanitize_namespace($class, \false);
$sanitized_namespace_prefix = $this->sanitize_namespace($namespace_prefix, \true);
// Removes prefix from class namespace.
$namespace_without_prefix = \preg_replace('/' . $sanitized_namespace_prefix . '\\/', '', $sanitized_class, 1);
// Gets namespace file path.
$namespaces_without_prefix_arr = \explode('\\', $namespace_without_prefix);
\array_pop($namespaces_without_prefix_arr);
$namespace_file_path = \implode(\DIRECTORY_SEPARATOR, $namespaces_without_prefix_arr) . \DIRECTORY_SEPARATOR;
if (\in_array('folders', $args['lowercase'], \true)) {
$namespace_file_path = \strtolower($namespace_file_path);
}
if (\in_array('folders', $args['underscore_to_hyphen'], \true)) {
$namespace_file_path = \str_replace(array('_', "\x00"), array('-', ''), $namespace_file_path);
}
if ('\\' === $namespace_file_path || '\\/' === $namespace_file_path) {
$namespace_file_path = '';
}
return $namespace_file_path;
}
/**
* Gets filename to be loaded considering WordPress coding standards
*
* Takes className or end of classFQN and converts it to WPCS "class-" prefixed filename.
*
* @param string $class className or classFNQ.
* @param string $object_type the type of object interface, trait or class (default).
*
* @return string
*/
private function get_file_applying_wp_standards($class, $object_type = 'class')
{
$args = $this->get_args();
$object_type = \in_array($object_type, array('class', 'interface', 'trait'), \true) ? $object_type : 'class';
// Sanitized class and namespace prefix.
$sanitized_class = $this->sanitize_namespace($class, \false);
// Gets namespace file path.
$namespaces_arr = \explode('\\', $sanitized_class);
$final_file = \array_pop($namespaces_arr);
// Final file name.
if (\in_array('file', $args['lowercase'], \true)) {
$final_file = \strtolower($final_file);
}
// Final file with underscores replaced.
if (\in_array('file', $args['underscore_to_hyphen'], \true)) {
$final_file = \str_replace(array('_', "\x00"), array('-', ''), $final_file);
}
// Prepend class.
if ($args['prepend_class'] || $args['prepend_interface'] || $args['prepend_trait']) {
$prepended = \preg_replace('/(.*)-abstract$/', 'abstract-$1', $final_file);
// If no changes were made when looking for interfaces and abstract classes, prepend "class-".
if ($prepended === $final_file) {
$final_file = $object_type . '-' . $final_file;
} else {
$final_file = $prepended;
}
}
$final_file .= '.php';
return $final_file;
}
/**
* Sanitizes file path.
* Removes leading and trailing / (DIRECTORY_SEPARATOR).
*
* @param string $file_path File path.
*
* @return string
*/
private function sanitize_file_path($file_path)
{
return \trim($file_path, \DIRECTORY_SEPARATOR);
}
/**
* Sanitizes namespace or classFQN
*
* @param string $namespace Namespace or classFQN to sanitize.
* @param bool $add_backslash Add a trailing backslash.
*
* @return string
*/
private function sanitize_namespace($namespace, $add_backslash = \false)
{
if ($add_backslash) {
return \trim($namespace, '\\') . '\\';
} else {
return \trim($namespace, '\\');
}
}
/**
* Converts a namespaced class in a file to be loaded
*
* @param string $class classFQN.
* @param bool $check_loading_need Should short circuit if already loaded.
*
* @return array();
*/
public function convert_class_to_file($class, $check_loading_need = \false)
{
if ($check_loading_need) {
if (!$this->need_to_autoload($class)) {
return array();
}
}
$args = $this->get_args();
$namespace_file_path = $this->get_namespace_file_path($class);
$final_files = array($this->get_file_applying_wp_standards($class));
if ($args['prepend_interface']) {
$final_files[] = $this->get_file_applying_wp_standards($class, 'interface');
}
if ($args['prepend_trait']) {
$final_files[] = $this->get_file_applying_wp_standards($class, 'trait');
}
$class_files = array();
$dir = $this->get_dir();
foreach ($final_files as $final_file) {
if (\is_array($dir)) {
foreach ($dir as $class_dir) {
$class_files[] = $class_dir . $namespace_file_path . $final_file;
}
} else {
$class_files[] = $dir . $namespace_file_path . $final_file;
}
}
return $class_files;
}
/**
* Get the directory of the file that instantiated this class.
*
* phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
*/
public function get_calling_directory()
{
$debug_backtrace = \debug_backtrace();
// [0] is the __construct function, [1] is who called it.
$calling_file = $debug_backtrace[1]['file'];
$calling_directory = \dirname($calling_file);
return $calling_directory;
}
/**
* Get the namespace of the file that instantiated this class, presumably the root namespace.
*
* phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fopen
* phpcs:disable WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
* phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fclose
*/
protected function get_calling_file_namespace()
{
$debug_backtrace = \debug_backtrace();
// [0] is the __construct function, [1] is who called it.
$calling_file = $debug_backtrace[1]['file'];
$calling_namespace = null;
$handle = \fopen($calling_file, 'r');
if ($handle) {
while (\false !== ($line = \fgets($handle))) {
if (0 === \strpos($line, 'namespace')) {
$parts = \explode(' ', $line);
$calling_namespace = \rtrim(\trim($parts[1]), ';');
break;
}
}
\fclose($handle);
}
return $calling_namespace;
}
/**
* Getter for autoloader settings.
*
* @return array Associative array of settings as detailed in the constructor PHPDoc.
*/
public function get_args()
{
return $this->args;
}
/**
* Setter for autoloader settings.
*
* @param array $args Associative array of settings as detailed in the constructor PHPDoc.
*/
public function set_args($args)
{
$this->args = $args;
}
}
}