Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/Tools/Console/Command/Debug/AbstractCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Tools\Console\Command\Debug;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Console\Command\Command;

use function assert;

abstract class AbstractCommand extends Command
{
public function __construct(private readonly ManagerRegistry $managerRegistry)
{
parent::__construct();
}

protected function getEntityManager(string $name): EntityManagerInterface
{
$manager = $this->getManagerRegistry()->getManager($name);

assert($manager instanceof EntityManagerInterface);

return $manager;
}

protected function getManagerRegistry(): ManagerRegistry
{
return $this->managerRegistry;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Tools\Console\Command\Debug;

use Doctrine\ORM\Mapping\ClassMetadata;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

use function array_keys;
use function array_merge;
use function array_unique;
use function array_values;
use function assert;
use function class_exists;
use function ksort;
use function ltrim;
use function sort;
use function sprintf;

final class DebugEntityListenersDoctrineCommand extends AbstractCommand
{
protected function configure(): void
{
$this
->setName('orm:debug:entity-listeners')
->setDescription('Lists entity listeners for a given entity')
->addArgument('entity', InputArgument::OPTIONAL, 'The fully-qualified entity class name')
->addArgument('event', InputArgument::OPTIONAL, 'The event name to filter by (e.g. postPersist)')
->setHelp(<<<'EOT'
The <info>%command.name%</info> command lists all entity listeners for a given entity:

<info>php %command.full_name% 'App\Entity\User'</info>

To show only listeners for a specific event, pass the event name:

<info>php %command.full_name% 'App\Entity\User' postPersist</info>
EOT);
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

/** @var class-string|null $entityName */
$entityName = $input->getArgument('entity');

if ($entityName === null) {
/** @var class-string $entityName */
$entityName = $io->choice('Which entity do you want to list listeners for?', $this->listAllEntities());
}

$entityName = ltrim($entityName, '\\');
$entityManager = $this->getManagerRegistry()->getManagerForClass($entityName);

if ($entityManager === null) {
$io->error(sprintf('No entity manager found for class "%s".', $entityName));

return self::FAILURE;
}

$classMetadata = $entityManager->getClassMetadata($entityName);
assert($classMetadata instanceof ClassMetadata);

$eventName = $input->getArgument('event');

$allListeners = $eventName === null
? $classMetadata->entityListeners
: [$eventName => $classMetadata->entityListeners[$eventName] ?? []];

ksort($allListeners);

$io->title(sprintf('Entity listeners for <info>%s</info>', $entityName));

if (! $allListeners) {
$io->text('No listeners are configured for this entity.');

return self::SUCCESS;
}

foreach ($allListeners as $event => $listeners) {
$io->section(sprintf('"%s" event', $event));

if (! $listeners) {
$io->text('No listeners are configured for this event.');
continue;
}

$rows = [];
foreach ($listeners as $order => $listener) {
$rows[] = [sprintf('#%d', ++$order), sprintf('%s::%s()', $listener['class'], $listener['method'])];
}

$io->table(['Order', 'Listener'], $rows);
}

return self::SUCCESS;
}

public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('entity')) {
$suggestions->suggestValues($this->listAllEntities());

return;
}

if ($input->mustSuggestArgumentValuesFor('event')) {
$entityName = ltrim($input->getArgument('entity'), '\\');

if (! class_exists($entityName)) {
return;
}

$entityManager = $this->getManagerRegistry()->getManagerForClass($entityName);

if ($entityManager === null) {
return;
}

$classMetadata = $entityManager->getClassMetadata($entityName);
assert($classMetadata instanceof ClassMetadata);

$suggestions->suggestValues(array_keys($classMetadata->entityListeners));

return;
}
}

/** @return list<class-string> */
private function listAllEntities(): array
{
$entities = [];
foreach (array_keys($this->getManagerRegistry()->getManagerNames()) as $managerName) {
$entities[] = $this->getEntityManager($managerName)->getConfiguration()->getMetadataDriverImpl()->getAllClassNames();
}

$entities = array_values(array_unique(array_merge(...$entities)));

sort($entities);

return $entities;
}
}
105 changes: 105 additions & 0 deletions src/Tools/Console/Command/Debug/DebugEventManagerDoctrineCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Tools\Console\Command\Debug;

use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

use function array_keys;
use function array_values;
use function ksort;
use function method_exists;
use function sprintf;

final class DebugEventManagerDoctrineCommand extends AbstractCommand
{
protected function configure(): void
{
$this
->setName('orm:debug:event-manager')
->setDescription('Lists event listeners for an entity manager')
->addArgument('event', InputArgument::OPTIONAL, 'The event name to filter by (e.g. postPersist)')
->addOption('em', null, InputOption::VALUE_REQUIRED, 'The entity manager to use for this command')
->setHelp(<<<'EOT'
The <info>%command.name%</info> command lists all event listeners for the default entity manager:

<info>php %command.full_name%</info>

You can also specify an entity manager:

<info>php %command.full_name% --em=default</info>

To show only listeners for a specific event, pass the event name as an argument:

<info>php %command.full_name% postPersist</info>
EOT);
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

$entityManagerName = $input->getOption('em') ?: $this->getManagerRegistry()->getDefaultManagerName();
$eventManager = $this->getEntityManager($entityManagerName)->getEventManager();

$eventName = $input->getArgument('event');

$allListeners = $eventName === null
? $eventManager->getAllListeners()
: [$eventName => $eventManager->hasListeners($eventName) ? $eventManager->getListeners($eventName) : []];

ksort($allListeners);

$io->title(sprintf('Event listeners for <info>%s</info> entity manager', $entityManagerName));

if (! $allListeners) {
$io->text('No listeners are configured for this entity manager.');

return self::SUCCESS;
}

foreach ($allListeners as $event => $listeners) {
$io->section(sprintf('"%s" event', $event));

if (! $listeners) {
$io->text('No listeners are configured for this event.');
continue;
}

$rows = [];
foreach (array_values($listeners) as $order => $listener) {
$method = method_exists($listener, '__invoke') ? '__invoke' : $event;
$rows[] = [sprintf('#%d', ++$order), sprintf('%s::%s()', $listener::class, $method)];
}

$io->table(['Order', 'Listener'], $rows);
}

return self::SUCCESS;
}

public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('event')) {
$entityManagerName = $input->getOption('em') ?: $this->getManagerRegistry()->getDefaultManagerName();
$eventManager = $this->getEntityManager($entityManagerName)->getEventManager();

$suggestions->suggestValues(array_keys($eventManager->getAllListeners()));

return;
}

if ($input->mustSuggestOptionValuesFor('em')) {
$suggestions->suggestValues(array_keys($this->getManagerRegistry()->getManagerNames()));

return;
}
}
}
Loading