api-8.x-1.x-dev/src/Plugin/QueueWorker/ParseQueueWorker.php
src/Plugin/QueueWorker/ParseQueueWorker.php
<?php
namespace Drupal\api\Plugin\QueueWorker;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Queue\QueueWorkerBase;
use Drupal\api\Entity\DocBlock;
use Drupal\api\Entity\DocBlock\DocReference;
use Drupal\api\Entity\DocBlock\DocReferenceCount;
use Drupal\api\Entity\ExternalDocumentation;
use Drupal\api\Entity\PhpDocumentation;
use Drupal\api\Parser;
/**
* Defines 'api_parse_queue_worker' queue worker.
*
* Run via `drush` like this `drush queue:run api_parse_queue`.
*
* @QueueWorker(
* id = "api_parse_queue",
* title = @Translation("Parser Queue Worker")
* )
*/
class ParseQueueWorker extends QueueWorkerBase {
/**
* {@inheritdoc}
*/
public function processItem($data) {
if (!$this->validateItem($data)) {
return FALSE;
}
$temp_store = \Drupal::service('tempstore.private')->get(Parser::QUEUE_PARSE);
$queue = \Drupal::service('queue')->get(Parser::QUEUE_PARSE);
$branch = $this->loadBranch($data['branch_type'], $data['branch_id']);
$action = $data['action'];
if ($action == 'parse' && !empty($data['data'])) {
switch ($branch->getEntityTypeId()) {
case 'branch':
DocBlock::createOrUpdate($data['data'], $branch);
break;
case 'php_branch':
PhpDocumentation::createOrUpdate($data['data'], $branch);
break;
case 'external_branch':
ExternalDocumentation::createOrUpdate($data['data'], $branch);
break;
}
}
elseif ($action == 'calculate_counts') {
DocReferenceCount::calculateReferenceCounts($branch);
// These are no longer needed.
$temp_store->delete('api:class_members:' . $branch->id());
$temp_store->delete('api:class_parents:' . $branch->id());
}
elseif ($action == 'class_references_information' && !empty($data['data'])) {
$class_members = $temp_store->get('api:class_members:' . $branch->id());
$class_parents = $temp_store->get('api:class_parents:' . $branch->id());
$arguments = Json::decode($data['data']);
if ($class_members && $class_parents && !empty($arguments['cid'])) {
DocReference::updateClassReferenceInfo($arguments['cid'], $class_parents, $class_members);
}
}
elseif ($action == 'direct_method_references' && !empty($data['data'])) {
$class_members = $temp_store->get('api:class_members:' . $branch->id());
$arguments = Json::decode($data['data']);
if ($class_members && !empty($arguments['classes_changed'])) {
DocReference::directMethodReferences($arguments['classes_changed'], $class_members);
}
}
elseif ($action == 'class_relations') {
DocReference::classRelations($branch);
// To make sure that they are run in this order.
$counts_info = [
'branch_id' => $branch->id(),
'branch_type' => $branch->getEntityTypeId(),
'action' => 'calculate_counts',
];
$queue->createItem($counts_info);
}
elseif ($action === 'hook_pattern') {
$hook_patterns = [];
foreach (DocBlock::getHookFunctions($branch) as $docblock) {
// Sanity check. This should not happen because methods are written in
// camel case and not snake case.
$hook_function = $docblock->getObjectName();
if (str_contains($hook_function, '::')) {
continue;
}
$hook_pattern = preg_replace_callback(
'/^(?<prefix>[a-z0-9_]+_)?[A-Z][A-Z0-9_]+(?<suffix>_[a-z0-9]+)?$/',
fn ($m) => $m['prefix'] . '[a-z0-9_]+' . $m['suffix'],
$hook_function
);
// (*:) is shorthand for (*MARK:).
$hook_patterns[] = '(?:' . $hook_pattern . ")(*:$hook_function)";
}
\Drupal::keyValue('api_hook_pattern')->set($branch->id(), '/' . implode('|', $hook_patterns) . '/');
}
}
/**
* Validate item array to make sure all key elements are there.
*
* @param array $data
* Item to validate.
*
* @return bool
* Whether the item was valid or not.
*/
protected function validateItem(array $data) {
if (empty($data['branch_id']) || empty($data['branch_type'])) {
return FALSE;
}
if (empty($data['action'])) {
return FALSE;
}
$branch = $this->loadBranch($data['branch_type'], $data['branch_id']);
if (!$branch) {
return FALSE;
}
return TRUE;
}
/**
* Loads a given branch object based on the type and id.
*
* @param string $type
* Type of branch.
* @param int $id
* ID of the branch.
*
* @return \Drupal\Core\Entity\EntityInterface|null
* Branch object or null if nothing was found.
*/
protected function loadBranch($type, $id) {
return \Drupal::entityTypeManager()->getStorage($type)->load($id);
}
}
