Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. ChangeLogger.php

class ChangeLogger

Event subscriber to log changes that happen during the stage life cycle.

@internal This is an internal part of Package Manager and may be changed or removed at any time without warning. External code should not interact with this class.

Hierarchy

  • class \Drupal\package_manager\EventSubscriber\ChangeLogger implements \Symfony\Component\EventDispatcher\EventSubscriberInterface, \Psr\Log\LoggerAwareInterface uses \Psr\Log\LoggerAwareTrait, \Drupal\Core\StringTranslation\StringTranslationTrait

Expanded class hierarchy of ChangeLogger

File

core/modules/package_manager/src/EventSubscriber/ChangeLogger.php, line 25

Namespace

Drupal\package_manager\EventSubscriber
View source
final class ChangeLogger implements EventSubscriberInterface, LoggerAwareInterface {
    use LoggerAwareTrait;
    use StringTranslationTrait;
    
    /**
     * The key to store the list of packages installed when the stage is created.
     *
     * @var string
     *
     * @see ::recordInstalledPackages()
     */
    private const INSTALLED_PACKAGES_KEY = 'package_manager_installed_packages';
    
    /**
     * The metadata key under which to store the requested package versions.
     *
     * @var string
     *
     * @see ::recordRequestedPackageVersions()
     */
    private const REQUESTED_PACKAGES_KEY = 'package_manager_requested_packages';
    public function __construct(ComposerInspector $composerInspector, PathLocator $pathLocator) {
    }
    
    /**
     * Records packages installed in the project root.
     *
     * We need to do this before the staging environment has been created, so that
     * we have a complete picture of which requested packages are merely being
     * updated, and which are being newly added. Once the staging environment has
     * been created, the installed packages won't change -- if they do, a
     * validation error will be raised.
     *
     * @param \Drupal\package_manager\Event\PreCreateEvent $event
     *   The event being handled.
     *
     * @see \Drupal\package_manager\Validator\LockFileValidator
     */
    public function recordInstalledPackages(PreCreateEvent $event) : void {
        $packages = $this->composerInspector
            ->getInstalledPackagesList($this->pathLocator
            ->getProjectRoot());
        $event->stage
            ->setMetadata(static::INSTALLED_PACKAGES_KEY, $packages);
    }
    
    /**
     * Records requested packages.
     *
     * @param \Drupal\package_manager\Event\PostRequireEvent $event
     *   The event object.
     */
    public function recordRequestedPackageVersions(PostRequireEvent $event) : void {
        // There could be multiple 'require' operations, so overlay the requested
        // packages from the current operation onto the requested packages from any
        // previous 'require' operation.
        $requested_packages = array_merge($event->stage
            ->getMetadata(static::REQUESTED_PACKAGES_KEY) ?? [], $event->getRuntimePackages(), $event->getDevPackages());
        $event->stage
            ->setMetadata(static::REQUESTED_PACKAGES_KEY, $requested_packages);
    }
    
    /**
     * Logs changes made by Package Manager.
     *
     * @param \Drupal\package_manager\Event\PostApplyEvent $event
     *   The event being handled.
     */
    public function logChanges(PostApplyEvent $event) : void {
        $installed_at_start = $event->stage
            ->getMetadata(static::INSTALLED_PACKAGES_KEY);
        $installed_post_apply = $this->composerInspector
            ->getInstalledPackagesList($this->pathLocator
            ->getProjectRoot());
        // Compare the packages which were installed when the stage was created
        // against the package versions that were requested over all the stage's
        // require operations, and create a log entry listing all of it.
        $requested_log = [];
        $requested_packages = $event->stage
            ->getMetadata(static::REQUESTED_PACKAGES_KEY) ?? [];
        // Sort the requested packages by name, to make it easier to review a large
        // change list.
        ksort($requested_packages, SORT_NATURAL);
        foreach ($requested_packages as $name => $constraint) {
            $installed_version = $installed_at_start[$name]?->version;
            if ($installed_version === NULL) {
                // For clarity, make the "any version" constraint human-readable.
                if ($constraint === '*') {
                    $constraint = $this->t('* (any version)');
                }
                $requested_log[] = $this->t('- Install @name @constraint', [
                    '@name' => $name,
                    '@constraint' => $constraint,
                ]);
            }
            else {
                $requested_log[] = $this->t('- Update @name from @installed_version to @constraint', [
                    '@name' => $name,
                    '@installed_version' => $installed_version,
                    '@constraint' => $constraint,
                ]);
            }
        }
        // It's possible that $requested_log will be empty: for example, a custom
        // stage that only does removals, or some other operation, and never
        // dispatches PostRequireEvent.
        if ($requested_log) {
            $message = $this->t("Requested changes:\n@change_list", [
                '@change_list' => implode("\n", array_map('strval', $requested_log)),
            ]);
            $this->logger?->info($message);
        }
        // Create a separate log entry listing everything that actually changed.
        $applied_log = [];
        $updated_packages = $installed_post_apply->getPackagesWithDifferentVersionsIn($installed_at_start);
        // Sort the packages by name to make it easier to review large change sets.
        $updated_packages->ksort(SORT_NATURAL);
        foreach ($updated_packages as $name => $package) {
            $applied_log[] = $this->t('- Updated @name from @installed_version to @updated_version', [
                '@name' => $name,
                '@installed_version' => $installed_at_start[$name]->version,
                '@updated_version' => $package->version,
            ]);
        }
        $added_packages = $installed_post_apply->getPackagesNotIn($installed_at_start);
        $added_packages->ksort(SORT_NATURAL);
        foreach ($added_packages as $name => $package) {
            $applied_log[] = $this->t('- Installed @name @version', [
                '@name' => $name,
                '@version' => $package->version,
            ]);
        }
        $removed_packages = $installed_at_start->getPackagesNotIn($installed_post_apply);
        $removed_packages->ksort(SORT_NATURAL);
        foreach ($installed_at_start->getPackagesNotIn($installed_post_apply) as $name => $package) {
            $applied_log[] = $this->t('- Uninstalled @name', [
                '@name' => $name,
            ]);
        }
        $message = $this->t("Applied changes:\n@change_list", [
            '@change_list' => implode("\n", array_map('strval', $applied_log)),
        ]);
        $this->logger?->info($message);
    }
    
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents() : array {
        return [
            PreCreateEvent::class => [
                'recordInstalledPackages',
            ],
            PostRequireEvent::class => [
                'recordRequestedPackageVersions',
            ],
            PostApplyEvent::class => [
                'logChanges',
            ],
        ];
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
ChangeLogger::getSubscribedEvents public static function Returns an array of event names this subscriber wants to listen to. Overrides EventSubscriberInterface::getSubscribedEvents
ChangeLogger::INSTALLED_PACKAGES_KEY private constant The key to store the list of packages installed when the stage is created.
ChangeLogger::logChanges public function Logs changes made by Package Manager.
ChangeLogger::recordInstalledPackages public function Records packages installed in the project root.
ChangeLogger::recordRequestedPackageVersions public function Records requested packages.
ChangeLogger::REQUESTED_PACKAGES_KEY private constant The metadata key under which to store the requested package versions.
ChangeLogger::__construct public function
LoggerAwareTrait::$logger protected property The logger instance.
LoggerAwareTrait::setLogger public function Sets a logger.
StringTranslationTrait::$stringTranslation protected property The string translation service.
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use.
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal