khaihihi
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* Yoast SEO Plugin File.
|
||||
*
|
||||
* @package Yoast\YoastSEO\Dependency_Injection
|
||||
*/
|
||||
|
||||
namespace Yoast\WP\SEO\Dependency_Injection;
|
||||
|
||||
use Symfony\Component\Config\ConfigCache;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
|
||||
|
||||
/**
|
||||
* This class is responsible for compiling the dependency injection container.
|
||||
*/
|
||||
class Container_Compiler {
|
||||
|
||||
/**
|
||||
* Compiles the dependency injection container.
|
||||
*
|
||||
* @param boolean $debug If false the container will only be re-compiled if it does not yet already exist.
|
||||
*
|
||||
* @throws \Exception If compiling the container fails.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function compile( $debug ) {
|
||||
$file = __DIR__ . '/../../src/generated/container.php';
|
||||
$cache = new ConfigCache( $file, $debug );
|
||||
|
||||
if ( ! $cache->isFresh() ) {
|
||||
$container_builder = new ContainerBuilder();
|
||||
$container_builder->addCompilerPass( new Loader_Pass() );
|
||||
$loader = new Custom_Loader( $container_builder );
|
||||
$loader->load( 'config/dependency-injection/services.php' );
|
||||
$container_builder->compile();
|
||||
|
||||
$dumper = new PhpDumper( $container_builder );
|
||||
$code = $dumper->dump(
|
||||
[
|
||||
'class' => 'Cached_Container',
|
||||
'namespace' => 'Yoast\WP\SEO\Generated',
|
||||
]
|
||||
);
|
||||
$code = \str_replace( 'Symfony\\Component\\DependencyInjection', 'YoastSEO_Vendor\\Symfony\\Component\\DependencyInjection', $code );
|
||||
$code = \str_replace( 'Symfony\\\\Component\\\\DependencyInjection', 'YoastSEO_Vendor\\\\Symfony\\\\Component\\\\DependencyInjection', $code );
|
||||
|
||||
$cache->write( $code, $container_builder->getResources() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
/**
|
||||
* Yoast SEO Plugin File.
|
||||
*
|
||||
* @package Yoast\YoastSEO\Dependency_Injection
|
||||
*/
|
||||
|
||||
namespace Yoast\WP\SEO\Dependency_Injection;
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
|
||||
use Symfony\Component\Config\Resource\GlobResource;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
/**
|
||||
* This class is mostly a direct copy-paste of the symfony PhpFileLoader class.
|
||||
* It's been adapted to allow automatic discovery based on not just PSR-4 but also the Yoast standards.
|
||||
*/
|
||||
class Custom_Loader extends PhpFileLoader {
|
||||
|
||||
/**
|
||||
* Custom_Loader constructor.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container The ContainerBuilder to load classes for.
|
||||
*/
|
||||
public function __construct( ContainerBuilder $container ) {
|
||||
parent::__construct( $container, new FileLocator( __DIR__ . '/../..' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a path to a class name using the class map.
|
||||
*
|
||||
* @param string $path The path of the class.
|
||||
*
|
||||
* @return bool|string The classname.
|
||||
*/
|
||||
private function getClassFromClassMap( $path ) {
|
||||
static $class_map;
|
||||
|
||||
if ( ! $class_map ) {
|
||||
$class_map = require __DIR__ . '/../../vendor/composer/autoload_classmap.php';
|
||||
}
|
||||
|
||||
foreach ( $class_map as $class => $class_path ) {
|
||||
if ( $path === $class_path ) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of classes as services using PSR-4 for discovery.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\Definition $prototype A definition to use as template.
|
||||
* @param string $namespace The namespace prefix of classes
|
||||
* in the scanned directory.
|
||||
* @param string $resource The directory to look for classes,
|
||||
* glob-patterns allowed.
|
||||
* @param string $exclude A globed path of files to exclude.
|
||||
*
|
||||
* @throws InvalidArgumentException If invalid arguments are supplied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerClasses( Definition $prototype, $namespace, $resource, $exclude = null ) {
|
||||
if ( \substr( $namespace, -1 ) !== '\\' ) {
|
||||
throw new InvalidArgumentException( \sprintf( 'Namespace prefix must end with a "\\": %s.', $namespace ) );
|
||||
}
|
||||
if ( ! \preg_match( '/^(?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+\\\\)++$/', $namespace ) ) {
|
||||
throw new InvalidArgumentException( \sprintf( 'Namespace is not a valid PSR-4 prefix: %s.', $namespace ) );
|
||||
}
|
||||
|
||||
$classes = $this->findClasses( $namespace, $resource, $exclude );
|
||||
// Prepare for deep cloning.
|
||||
$serialized_prototype = \serialize( $prototype );
|
||||
$interfaces = [];
|
||||
$singly_implemented = [];
|
||||
|
||||
foreach ( $classes as $class => $error_message ) {
|
||||
if ( \interface_exists( $class, false ) ) {
|
||||
$interfaces[] = $class;
|
||||
}
|
||||
else {
|
||||
$this->setDefinition( $class, $definition = \unserialize( $serialized_prototype ) );
|
||||
if ( $error_message !== null ) {
|
||||
$definition->addError( $error_message );
|
||||
|
||||
continue;
|
||||
}
|
||||
foreach ( \class_implements( $class, false ) as $interface ) {
|
||||
$singly_implemented[ $interface ] = isset( $singly_implemented[ $interface ] ) ? false : $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ( $interfaces as $interface ) {
|
||||
if ( ! empty( $singly_implemented[ $interface ] ) ) {
|
||||
$this->container->setAlias( $interface, $singly_implemented[ $interface ] )
|
||||
->setPublic( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a definition in the container with its instanceof-conditionals.
|
||||
*
|
||||
* @param string $id The ID of the definition.
|
||||
* @param \Symfony\Component\DependencyInjection\Definition $definition The definition.
|
||||
*
|
||||
* @throws InvalidArgumentException If invalid arguments were supplied.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setDefinition( $id, Definition $definition ) {
|
||||
$this->container->removeBindings( $id );
|
||||
|
||||
// @codingStandardsIgnoreLine WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar This is from an inherited class not abiding by that standard.
|
||||
if ( $this->isLoadingInstanceof ) {
|
||||
if ( ! $definition instanceof ChildDefinition ) {
|
||||
throw new InvalidArgumentException( \sprintf( 'Invalid type definition "%s": ChildDefinition expected, "%s" given.', $id, \get_class( $definition ) ) );
|
||||
}
|
||||
$this->instanceof[ $id ] = $definition;
|
||||
}
|
||||
else {
|
||||
$this->container->setDefinition( $id, ( $definition instanceof ChildDefinition ) ? $definition : $definition->setInstanceofConditionals( $this->instanceof ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds classes based on a given pattern and exclude pattern.
|
||||
*
|
||||
* @param string $namespace The namespace prefix of classes in the scanned directory.
|
||||
* @param string $pattern The directory to look for classes, glob-patterns allowed.
|
||||
* @param string $exclude A globed path of files to exclude.
|
||||
*
|
||||
* @throws InvalidArgumentException If invalid arguments were supplied.
|
||||
*
|
||||
* @return array The found classes.
|
||||
*/
|
||||
private function findClasses( $namespace, $pattern, $exclude ) {
|
||||
$parameter_bag = $this->container->getParameterBag();
|
||||
|
||||
$exclude_paths = [];
|
||||
$exclude_prefix = null;
|
||||
if ( $exclude ) {
|
||||
$exclude = $parameter_bag->unescapeValue( $parameter_bag->resolveValue( $exclude ) );
|
||||
foreach ( $this->glob( $exclude, true, $resource ) as $path => $info ) {
|
||||
if ( $exclude_prefix === null ) {
|
||||
$exclude_prefix = $resource->getPrefix();
|
||||
}
|
||||
|
||||
// Normalize Windows slashes.
|
||||
$exclude_paths[ \str_replace( '\\', '/', $path ) ] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$pattern = $parameter_bag->unescapeValue( $parameter_bag->resolveValue( $pattern ) );
|
||||
$classes = [];
|
||||
$ext_regexp = \defined( 'HHVM_VERSION' ) ? '/\\.(?:php|hh)$/' : '/\\.php$/';
|
||||
$prefix_len = null;
|
||||
foreach ( $this->glob( $pattern, true, $resource ) as $path => $info ) {
|
||||
if ( $prefix_len === null ) {
|
||||
$prefix_len = \strlen( $resource->getPrefix() );
|
||||
|
||||
if ( $exclude_prefix && \strpos( $exclude_prefix, $resource->getPrefix() ) !== 0 ) {
|
||||
throw new InvalidArgumentException( \sprintf( 'Invalid "exclude" pattern when importing classes for "%s": make sure your "exclude" pattern (%s) is a subset of the "resource" pattern (%s)', $namespace, $exclude, $pattern ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $exclude_paths[ \str_replace( '\\', '/', $path ) ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! \preg_match( $ext_regexp, $path, $m ) || ! $info->isReadable() ) {
|
||||
continue;
|
||||
}
|
||||
$class = $this->getClassFromClassMap( $path );
|
||||
|
||||
if ( ! $class || ! \preg_match( '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+$/', $class ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$r = $this->container->getReflectionClass( $class );
|
||||
} catch ( \ReflectionException $e ) {
|
||||
$classes[ $class ] = \sprintf(
|
||||
'While discovering services from namespace "%s", an error was thrown when processing the class "%s": "%s".',
|
||||
$namespace,
|
||||
$class,
|
||||
$e->getMessage()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// Check to make sure the expected class exists.
|
||||
if ( ! $r ) {
|
||||
throw new InvalidArgumentException( \sprintf( 'Expected to find class "%s" in file "%s" while importing services from resource "%s", but it was not found! Check the namespace prefix used with the resource.', $class, $path, $pattern ) );
|
||||
}
|
||||
|
||||
if ( $r->isInstantiable() || $r->isInterface() ) {
|
||||
$classes[ $class ] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Track only for new & removed files.
|
||||
if ( $resource instanceof GlobResource ) {
|
||||
$this->container->addResource( $resource );
|
||||
}
|
||||
else {
|
||||
foreach ( $resource as $path ) {
|
||||
$this->container->fileExists( $path, false );
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* Yoast SEO Plugin File.
|
||||
*
|
||||
* @package Yoast\YoastSEO\Dependency_Injection
|
||||
*/
|
||||
|
||||
namespace Yoast\WP\SEO\Dependency_Injection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Yoast\WP\SEO\Conditionals\Conditional;
|
||||
use Yoast\WP\SEO\Loader;
|
||||
use Yoast\WP\SEO\WordPress\Initializer;
|
||||
use Yoast\WP\SEO\WordPress\Integration;
|
||||
|
||||
/**
|
||||
* A pass is a step in the compilation process of the container.
|
||||
*
|
||||
* This step will automatically ensure all classes implementing the Integration interface
|
||||
* are registered with the Loader class.
|
||||
*/
|
||||
class Loader_Pass implements CompilerPassInterface {
|
||||
|
||||
/**
|
||||
* Checks all definitions to ensure all classes implementing the Integration interface
|
||||
* are registered with the Loader class.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container The container.
|
||||
*/
|
||||
public function process( ContainerBuilder $container ) {
|
||||
if ( ! $container->hasDefinition( Loader::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loader_definition = $container->getDefinition( Loader::class );
|
||||
$loader_definition->setArgument( 0, new Reference( 'service_container' ) );
|
||||
$loader_definition->setPublic( true );
|
||||
|
||||
$definitions = $container->getDefinitions();
|
||||
|
||||
foreach ( $definitions as $definition ) {
|
||||
$this->process_definition( $definition, $loader_definition );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a definition in the container.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\Definition $definition The definition to process.
|
||||
* @param \Symfony\Component\DependencyInjection\Definition $loader_definition The loader definition.
|
||||
*/
|
||||
private function process_definition( Definition $definition, Definition $loader_definition ) {
|
||||
$class = $definition->getClass();
|
||||
|
||||
if ( \is_subclass_of( $class, Initializer::class ) ) {
|
||||
$loader_definition->addMethodCall( 'register_initializer', [ $class ] );
|
||||
$definition->setPublic( true );
|
||||
}
|
||||
|
||||
if ( \is_subclass_of( $class, Integration::class ) ) {
|
||||
$loader_definition->addMethodCall( 'register_integration', [ $class ] );
|
||||
$definition->setPublic( true );
|
||||
}
|
||||
|
||||
if ( \is_subclass_of( $class, Conditional::class ) ) {
|
||||
$definition->setPublic( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* Yoast SEO Plugin File.
|
||||
*
|
||||
* @package Yoast\YoastSEO\Dependency_Injection
|
||||
*/
|
||||
|
||||
namespace Yoast\WP\SEO\Dependency_Injection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Yoast\WP\SEO\Repositories\Indexable_Repository;
|
||||
use Yoast\WP\SEO\Repositories\Primary_Term_Repository;
|
||||
use Yoast\WP\SEO\Repositories\SEO_Links_Repository;
|
||||
use Yoast\WP\SEO\Repositories\SEO_Meta_Repository;
|
||||
use Yoast\WP\SEO\WordPress\Wrapper;
|
||||
|
||||
/* @var $container \Symfony\Component\DependencyInjection\ContainerBuilder */
|
||||
|
||||
// WordPress factory functions.
|
||||
$container->register( 'wpdb', 'wpdb' )->setFactory( [ Wrapper::class, 'get_wpdb' ] );
|
||||
$container->register( 'wp_query', 'WP_Query' )->setFactory( [ Wrapper::class, 'get_wp_query' ] );
|
||||
|
||||
// Model repository factory functions.
|
||||
$container->register( Indexable_Repository::class, Indexable_Repository::class )->setFactory( [ Indexable_Repository::class, 'get_instance' ] )->setAutowired( true );
|
||||
$container->register( Primary_Term_Repository::class, Primary_Term_Repository::class )->setFactory( [ Primary_Term_Repository::class, 'get_instance' ] )->setAutowired( true );
|
||||
$container->register( SEO_Meta_Repository::class, SEO_Meta_Repository::class )->setFactory( [ SEO_Meta_Repository::class, 'get_instance' ] )->setAutowired( true );
|
||||
$container->register( SEO_Links_Repository::class, SEO_Links_Repository::class )->setFactory( [ SEO_Links_Repository::class, 'get_instance' ] )->setAutowired( true );
|
||||
|
||||
$excluded_files = [
|
||||
'main.php',
|
||||
];
|
||||
|
||||
$excluded_directories = [
|
||||
'models',
|
||||
'loaders',
|
||||
'wordpress',
|
||||
'generated',
|
||||
'orm',
|
||||
];
|
||||
|
||||
$excluded = \implode( ',', \array_merge( $excluded_directories, $excluded_files ) );
|
||||
|
||||
$base_definition = new Definition();
|
||||
|
||||
$base_definition
|
||||
->setAutowired( true )
|
||||
->setAutoconfigured( true )
|
||||
->setPublic( false );
|
||||
|
||||
/* @var $loader \Yoast\WP\SEO\Dependency_Injection\Custom_Loader */
|
||||
$loader->registerClasses( $base_definition, 'Yoast\\WP\\SEO\\', 'src/*', 'src/{' . $excluded . '}' );
|
||||
|
||||
if ( \file_exists( __DIR__ . '/../../premium/config/dependency-injection/services.php' ) ) {
|
||||
include __DIR__ . '/../../premium/config/dependency-injection/services.php';
|
||||
}
|
||||
Reference in New Issue
Block a user