Skip to content
Snippets Groups Projects

OperationType custom discovery and plugin base class

Merged Prashant Chauhan requested to merge issue/ai-3521877:3521877-not-getting-all into 1.1.x
Files
3
+ 156
0
<?php
namespace Drupal\ai\Plugin\Discovery;
use Drupal\ai\Attribute\OperationType;
use Drupal\ai\OperationType\OperationTypeInterface;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Core\Plugin\Discovery\AttributeClassDiscovery;
/**
* Discovers operation types from interfaces and their plugin classes.
*/
class OperationTypeDiscovery implements DiscoveryInterface {
/**
* The attribute discovery.
*
* @var \Drupal\Core\Plugin\Discovery\AttributeClassDiscovery
*/
protected AttributeClassDiscovery $attributeDiscovery;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a new OperationTypeDiscovery.
*
* @param \Drupal\Core\Plugin\Discovery\AttributeClassDiscovery $attribute_discovery
* The attribute discovery.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
public function __construct(
AttributeClassDiscovery $attribute_discovery,
$module_handler,
) {
$this->attributeDiscovery = $attribute_discovery;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public function getDefinitions() {
$definitions = [];
$base_path = $this->moduleHandler->getModule('ai')->getPath() . '/src/OperationType';
$directories = new \RecursiveDirectoryIterator($base_path);
$iterator = new \RecursiveIteratorIterator($directories);
$regex = new \RegexIterator($iterator, '/^.+\.php$/i', \RecursiveRegexIterator::GET_MATCH);
foreach ($regex as $file) {
$interface = $this->getInterfaceFromFile($file[0]);
if ($interface && $this->doesInterfaceExtend($interface, OperationTypeInterface::class)) {
$reflection = new \ReflectionClass($interface);
$attributes = $reflection->getAttributes(OperationType::class);
foreach ($attributes as $attribute) {
$instance = $attribute->newInstance();
$plugin_id = $instance->id;
// Create a plugin class name based on the interface name.
$interface_parts = explode('\\', $interface);
$interface_name = end($interface_parts);
$plugin_class = 'Drupal\\ai\\Plugin\\OperationType\\' . $interface_name . 'Plugin';
$definitions[$plugin_id] = [
'id' => $plugin_id,
'label' => $instance->label,
'class' => $plugin_class,
'interface_class' => $interface,
'actual_type' => $instance->actual_type ?? $plugin_id,
'filter' => $instance->filter ?? [],
];
}
}
}
// Allow modules to alter the operation type definitions.
$this->moduleHandler->alter('ai_operationtype', $definitions);
return $definitions;
}
/**
* Extracts the fully qualified interface name from a file.
*
* @param string $file
* The file path.
*
* @return string|null
* The fully qualified interface name, or NULL if not found.
*/
protected function getInterfaceFromFile($file) {
$contents = file_get_contents($file);
// Match namespace and interface declarations.
if (preg_match('/namespace\s+([^;]+);/i', $contents, $matches)) {
$namespace = $matches[1];
}
// Match on starts with interface and has extends in it.
if (preg_match('/interface\s+([^ ]+)\s+extends\s+([^ ]+)/i', $contents, $matches) && isset($namespace)) {
$interface = $matches[1];
return $namespace . '\\' . $interface;
}
return NULL;
}
/**
* Checks if an interface extends another interface.
*
* @param string $interface
* The interface to check.
* @param string $parent
* The parent interface.
*
* @return bool
* TRUE if the interface extends the parent, FALSE otherwise.
*/
protected function doesInterfaceExtend($interface, $parent) {
try {
$reflection = new \ReflectionClass($interface);
return $reflection->isInterface() && $reflection->implementsInterface($parent);
}
catch (\ReflectionException) {
return FALSE;
}
}
/**
* {@inheritdoc}
*/
public function hasDefinition($plugin_id) {
$definitions = $this->getDefinitions();
return isset($definitions[$plugin_id]);
}
/**
* {@inheritdoc}
*/
public function getDefinition($plugin_id, $exception_on_invalid = TRUE) {
$definitions = $this->getDefinitions();
if (isset($definitions[$plugin_id])) {
return $definitions[$plugin_id];
}
if ($exception_on_invalid) {
throw new \InvalidArgumentException(sprintf('The "%s" operation type does not exist.', $plugin_id));
}
return NULL;
}
}
Loading