<NME> StorageEventListener.php
<BEF> <?php

namespace Bolt\EventListener;

use Bolt\AccessControl\Permissions;
use Bolt\Events\HydrationEvent;
use Bolt\Events\StorageEvent;
use Bolt\Events\StorageEvents;
use Bolt\Exception\AccessControlException;
use Bolt\Logger\FlashLoggerInterface;
use Bolt\Request\ProfilerAwareTrait;
use Bolt\Storage\Collection;
use Bolt\Storage\Database\Schema;
use Bolt\Storage\Entity;
use Bolt\Storage\EntityManagerInterface;
use Bolt\Storage\EventProcessor;
use Bolt\Translation\Translator as Trans;
use PasswordLib\Password\Factory as PasswordFactory;
use PasswordLib\Password\Implementation as Password;
use Silex\Application;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class StorageEventListener implements EventSubscriberInterface
{
    use ProfilerAwareTrait;

    /** @var EntityManagerInterface */
    protected $em;
    /** @var EventProcessor\TimedRecord */
    protected $timedRecord;
    /** @var Schema\SchemaManagerInterface */
    protected $schemaManager;
    /** @var UrlGeneratorInterface */
    protected $urlGenerator;
    /** @var \Bolt\Logger\FlashLoggerInterface */
    protected $loggerFlash;
    /** @var PasswordFactory */
    protected $passwordFactory;
    /** @var int */
    protected $hashStrength;
    /** @var bool */
    protected $timedRecordsEnabled;

    /**
     * Constructor.
     *
     * @param EntityManagerInterface        $em
     * @param EventProcessor\TimedRecord    $timedRecord
     * @param Schema\SchemaManagerInterface $schemaManager
     * @param UrlGeneratorInterface         $urlGenerator
     * @param FlashLoggerInterface          $loggerFlash
     * @param PasswordFactory               $passwordFactory
     * @param int                           $hashStrength
     * @param bool                          $timedRecordsEnabled
     */
    public function __construct(
        EntityManagerInterface $em,
        EventProcessor\TimedRecord $timedRecord,
        Schema\SchemaManagerInterface $schemaManager,
        UrlGeneratorInterface $urlGenerator,
        FlashLoggerInterface $loggerFlash,
        PasswordFactory $passwordFactory,
        $hashStrength,
        $timedRecordsEnabled
    ) {
        $this->em = $em;
        $this->timedRecord = $timedRecord;
        $this->schemaManager = $schemaManager;
        $this->urlGenerator = $urlGenerator;
        $this->loggerFlash = $loggerFlash;
        $this->passwordFactory = $passwordFactory;
        $this->hashStrength = $hashStrength;
        $this->timedRecordsEnabled = $timedRecordsEnabled;
    }

    /**
     * Pre-save storage event for user entities.
     *
     * @param StorageEvent $event
     */
    public function onUserEntityPreSave(StorageEvent $event)
    {
        /** @var Entity\Users $entityRecord */
        $entityRecord = $event->getContent();

        if ($entityRecord instanceof Entity\Users) {
            $this->passwordHash($entityRecord);
        }
    }

    /**
     * Post hydration storage event.
     *
     * @param HydrationEvent $event
     */
    public function onPostHydrate(HydrationEvent $event)
    {
        $entity = $event->getSubject();
        if (!$entity instanceof Entity\Users) {
            return;
        }

        // Ensure Permissions::ROLE_EVERYONE always exists
        $roles = $entity->getRoles();
        if (!in_array(Permissions::ROLE_EVERYONE, $roles)) {
            $roles[] = Permissions::ROLE_EVERYONE;
            $entity->setRoles($roles);
        }
    }

    /**
     * Pre-delete event to delete an entities taxonomy & relation entities.
     *
     * @param StorageEvent $event
     */
    public function onPreDelete(StorageEvent $event)
    {
        $entity = $event->getContent();
        if (!$entity instanceof Entity\Content) {
            return;
        }
        $taxonomies = $entity->getTaxonomy();
        if ($taxonomies instanceof Collection\Taxonomy) {
            $repo = $this->em->getRepository(Entity\Taxonomy::class);
            foreach ($taxonomies as $taxonomy) {
                $repo->delete($taxonomy);
            }
        }
        $relations = $entity->getRelation();
        if ($relations instanceof Collection\Relations) {
            $repo = $this->em->getRepository(Entity\Relations::class);
            foreach ($relations as $relation) {
                $repo->delete($relation);
            }
        }
    }

    /**
     * Kernel request listener callback.
     *
     * @param GetResponseEvent $event
     */
    public function onKernelRequest(GetResponseEvent $event)
    {
        if (!$event->isMasterRequest()) {
            return;
        }
        if ($this->isProfilerRequest($event->getRequest())) {
            return;
        }

        $this->schemaCheck($event);

        // Check if we need to 'publish' any 'timed' records, or 'hold' any expired records.
        if ($this->timedRecordsEnabled && $this->timedRecord->isDuePublish()) {
            $this->timedRecord->publishTimedRecords();
        }
        if ($this->timedRecordsEnabled && $this->timedRecord->isDueHold()) {
            $this->timedRecord->holdExpiredRecords();
        }
    }

    /**
     * Trigger database schema checks if required.
     *
     * @param GetResponseEvent $event
     */
    protected function schemaCheck(GetResponseEvent $event)
    {
        $session = $event->getRequest()->getSession();
        $validSession = $session->isStarted() && $session->get('authentication');
        $expired = $this->schemaManager->isCheckRequired();

        // Don't show the check if we're in the dbcheck already.
        $notInCheck = !in_array(
            $event->getRequest()->get('_route'),
            ['dbupdate', '_wdt']
        );

        if ($validSession && $expired && $this->schemaManager->isUpdateRequired() && $notInCheck) {
            $msg = Trans::__(
                'general.phrase.database-update-required',
                ['%LINK%' => $this->urlGenerator->generate('dbcheck')]
            );
            $this->loggerFlash->error($msg);
        }
    }

    /**
     * Hash user passwords on save.
     *
     * @param Entity\Users $usersEntity
     */
    protected function passwordHash(Entity\Users $usersEntity)
    {
        if ($usersEntity->getPassword() !== null) {
            $usersEntity->setPassword($this->getValidHash($usersEntity->getPassword()));
        }
    }

    /**
     * Return a valid hash for a password, of if the password is already hashed
     * just return as is.
     *
     * @param string $password
     *
     * @throws AccessControlException
     *
     * @return string
     */
    private function getValidHash($password)
    {
        if (Password\Blowfish::detect($password)) {
            return $password;
        }
        if (Password\PHPASS::detect($password)) {
            return $password;
        }
        if (strlen($password) < 6) {
            throw new AccessControlException('Can not save a password with a length shorter than 6 characters!');
        }

        return $this->passwordFactory->createHash($password, '$2y$');
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::REQUEST       => ['onKernelRequest', 31],
            StorageEvents::PRE_SAVE     => ['onUserEntityPreSave', Application::EARLY_EVENT],
            StorageEvents::POST_HYDRATE => 'onPostHydrate',
            StorageEvents::PRE_DELETE   => 'onPreDelete',
        ];
    }
}

<MSG> Adjust keyword

<DFF> @@ -181,9 +181,12 @@ class StorageEventListener implements EventSubscriberInterface
         );
 
         if ($validSession && $expired && $this->schemaManager->isUpdateRequired() && $notInCheck) {
-            $msg = Trans::__(
-                'general.phrase.database-update-required',
-                ['%LINK%' => $this->urlGenerator->generate('dbcheck')]
+            $msg = sprintf(
+                '%s > \'<a href="%s">%s</a>\' %s',
+                Trans::__('general.phrase.database-update-required-pre'),
+                $this->urlGenerator->generate('dbcheck'),
+                Trans::__('general.phrase.database-check'),
+                Trans::__('general.phrase.database-update-required-post')
             );
             $this->loggerFlash->error($msg);
         }

{'commit': 'diff --git a/src/EventListener/StorageEventListener.php b/src/EventListener/StorageEventListener.php\nindex 9a0ff547a..36a7106c7 100644\n--- a/src/EventListener/StorageEventListener.php\n+++ b/src/EventListener/StorageEventListener.php\n@@ -181,9 +181,12 @@ class StorageEventListener implements EventSubscriberInterface\n         );\n \n         if ($validSession && $expired && $this->schemaManager->isUpdateRequired() && $notInCheck) {\n-            $msg = Trans::__(\n-                \'general.phrase.database-update-required\',\n-                [\'%LINK%\' => $this->urlGenerator->generate(\'dbcheck\')]\n+            $msg = sprintf(\n+                \'%s > \\\'<a href="%s">%s</a>\\\' %s\',\n+                Trans::__(\'general.phrase.database-update-required-pre\'),\n+                $this->urlGenerator->generate(\'dbcheck\'),\n+                Trans::__(\'general.phrase.database-check\'),\n+                Trans::__(\'general.phrase.database-update-required-post\')\n             );\n             $this->loggerFlash->error($msg);\n         }\n', 'commit_subject': 'Adjust keyword', 'repo_name': 'bolt/bolt', 'committer': {'name': 'Gawain Lynch', 'email': 'f745ec5336bcd096400627fc09f6ec7139408726@gmail.com', 'time_sec': '1499512893', 'tz_offset': '120', 'date': {'seconds': '1499512893'}}, 'commit_tree': 'c3c65c0ff3f2eaea6bd7231c7250603a05a81add', 'commit_message': 'Adjust keyword\n', 'language_name': 'HTML', 'license': 'mit', 'hunks': '@@ -181,9 +181,12 @@ class StorageEventListener implements EventSubscriberInterface\n         );\n \n         if ($validSession && $expired && $this->schemaManager->isUpdateRequired() && $notInCheck) {\n-            $msg = Trans::__(\n-                \'general.phrase.database-update-required\',\n-                [\'%LINK%\' => $this->urlGenerator->generate(\'dbcheck\')]\n+            $msg = sprintf(\n+                \'%s > \\\'<a href="%s">%s</a>\\\' %s\',\n+                Trans::__(\'general.phrase.database-update-required-pre\'),\n+                $this->urlGenerator->generate(\'dbcheck\'),\n+                Trans::__(\'general.phrase.database-check\'),\n+                Trans::__(\'general.phrase.database-update-required-post\')\n             );\n             $this->loggerFlash->error($msg);\n         }\n', 'addition_count': 6, 'deletion_count': 3, 'src_file': 'a/src/EventListener/StorageEventListener.php', 'tgt_file': 'b/src/EventListener/StorageEventListener.php', 'file_extension': '.php', 'before_file': "<?php\n\nnamespace Bolt\\EventListener;\n\nuse Bolt\\AccessControl\\Permissions;\nuse Bolt\\Events\\HydrationEvent;\nuse Bolt\\Events\\StorageEvent;\nuse Bolt\\Events\\StorageEvents;\nuse Bolt\\Exception\\AccessControlException;\nuse Bolt\\Logger\\FlashLoggerInterface;\nuse Bolt\\Request\\ProfilerAwareTrait;\nuse Bolt\\Storage\\Collection;\nuse Bolt\\Storage\\Database\\Schema;\nuse Bolt\\Storage\\Entity;\nuse Bolt\\Storage\\EntityManagerInterface;\nuse Bolt\\Storage\\EventProcessor;\nuse Bolt\\Translation\\Translator as Trans;\nuse PasswordLib\\Password\\Factory as PasswordFactory;\nuse PasswordLib\\Password\\Implementation as Password;\nuse Silex\\Application;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\nuse Symfony\\Component\\HttpKernel\\Event\\GetResponseEvent;\nuse Symfony\\Component\\HttpKernel\\KernelEvents;\nuse Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface;\n\nclass StorageEventListener implements EventSubscriberInterface\n{\n    use ProfilerAwareTrait;\n\n    /** @var EntityManagerInterface */\n    protected $em;\n    /** @var EventProcessor\\TimedRecord */\n    protected $timedRecord;\n    /** @var Schema\\SchemaManagerInterface */\n    protected $schemaManager;\n    /** @var UrlGeneratorInterface */\n    protected $urlGenerator;\n    /** @var \\Bolt\\Logger\\FlashLoggerInterface */\n    protected $loggerFlash;\n    /** @var PasswordFactory */\n    protected $passwordFactory;\n    /** @var int */\n    protected $hashStrength;\n    /** @var bool */\n    protected $timedRecordsEnabled;\n\n    /**\n     * Constructor.\n     *\n     * @param EntityManagerInterface        $em\n     * @param EventProcessor\\TimedRecord    $timedRecord\n     * @param Schema\\SchemaManagerInterface $schemaManager\n     * @param UrlGeneratorInterface         $urlGenerator\n     * @param FlashLoggerInterface          $loggerFlash\n     * @param PasswordFactory               $passwordFactory\n     * @param int                           $hashStrength\n     * @param bool                          $timedRecordsEnabled\n     */\n    public function __construct(\n        EntityManagerInterface $em,\n        EventProcessor\\TimedRecord $timedRecord,\n        Schema\\SchemaManagerInterface $schemaManager,\n        UrlGeneratorInterface $urlGenerator,\n        FlashLoggerInterface $loggerFlash,\n        PasswordFactory $passwordFactory,\n        $hashStrength,\n        $timedRecordsEnabled\n    ) {\n        $this->em = $em;\n        $this->timedRecord = $timedRecord;\n        $this->schemaManager = $schemaManager;\n        $this->urlGenerator = $urlGenerator;\n        $this->loggerFlash = $loggerFlash;\n        $this->passwordFactory = $passwordFactory;\n        $this->hashStrength = $hashStrength;\n        $this->timedRecordsEnabled = $timedRecordsEnabled;\n    }\n\n    /**\n     * Pre-save storage event for user entities.\n     *\n     * @param StorageEvent $event\n     */\n    public function onUserEntityPreSave(StorageEvent $event)\n    {\n        /** @var Entity\\Users $entityRecord */\n        $entityRecord = $event->getContent();\n\n        if ($entityRecord instanceof Entity\\Users) {\n            $this->passwordHash($entityRecord);\n        }\n    }\n\n    /**\n     * Post hydration storage event.\n     *\n     * @param HydrationEvent $event\n     */\n    public function onPostHydrate(HydrationEvent $event)\n    {\n        $entity = $event->getSubject();\n        if (!$entity instanceof Entity\\Users) {\n            return;\n        }\n\n        // Ensure Permissions::ROLE_EVERYONE always exists\n        $roles = $entity->getRoles();\n        if (!in_array(Permissions::ROLE_EVERYONE, $roles)) {\n            $roles[] = Permissions::ROLE_EVERYONE;\n            $entity->setRoles($roles);\n        }\n    }\n\n    /**\n     * Pre-delete event to delete an entities taxonomy & relation entities.\n     *\n     * @param StorageEvent $event\n     */\n    public function onPreDelete(StorageEvent $event)\n    {\n        $entity = $event->getContent();\n        if (!$entity instanceof Entity\\Content) {\n            return;\n        }\n        $taxonomies = $entity->getTaxonomy();\n        if ($taxonomies instanceof Collection\\Taxonomy) {\n            $repo = $this->em->getRepository(Entity\\Taxonomy::class);\n            foreach ($taxonomies as $taxonomy) {\n                $repo->delete($taxonomy);\n            }\n        }\n        $relations = $entity->getRelation();\n        if ($relations instanceof Collection\\Relations) {\n            $repo = $this->em->getRepository(Entity\\Relations::class);\n            foreach ($relations as $relation) {\n                $repo->delete($relation);\n            }\n        }\n    }\n\n    /**\n     * Kernel request listener callback.\n     *\n     * @param GetResponseEvent $event\n     */\n    public function onKernelRequest(GetResponseEvent $event)\n    {\n        if (!$event->isMasterRequest()) {\n            return;\n        }\n        if ($this->isProfilerRequest($event->getRequest())) {\n            return;\n        }\n\n        $this->schemaCheck($event);\n\n        // Check if we need to 'publish' any 'timed' records, or 'hold' any expired records.\n        if ($this->timedRecordsEnabled && $this->timedRecord->isDuePublish()) {\n            $this->timedRecord->publishTimedRecords();\n        }\n        if ($this->timedRecordsEnabled && $this->timedRecord->isDueHold()) {\n            $this->timedRecord->holdExpiredRecords();\n        }\n    }\n\n    /**\n     * Trigger database schema checks if required.\n     *\n     * @param GetResponseEvent $event\n     */\n    protected function schemaCheck(GetResponseEvent $event)\n    {\n        $session = $event->getRequest()->getSession();\n        $validSession = $session->isStarted() && $session->get('authentication');\n        $expired = $this->schemaManager->isCheckRequired();\n\n        // Don't show the check if we're in the dbcheck already.\n        $notInCheck = !in_array(\n            $event->getRequest()->get('_route'),\n            ['dbupdate', '_wdt']\n        );\n\n        if ($validSession && $expired && $this->schemaManager->isUpdateRequired() && $notInCheck) {\n            $msg = Trans::__(\n                'general.phrase.database-update-required',\n                ['%LINK%' => $this->urlGenerator->generate('dbcheck')]\n            );\n            $this->loggerFlash->error($msg);\n        }\n    }\n\n    /**\n     * Hash user passwords on save.\n     *\n     * @param Entity\\Users $usersEntity\n     */\n    protected function passwordHash(Entity\\Users $usersEntity)\n    {\n        if ($usersEntity->getPassword() !== null) {\n            $usersEntity->setPassword($this->getValidHash($usersEntity->getPassword()));\n        }\n    }\n\n    /**\n     * Return a valid hash for a password, of if the password is already hashed\n     * just return as is.\n     *\n     * @param string $password\n     *\n     * @throws AccessControlException\n     *\n     * @return string\n     */\n    private function getValidHash($password)\n    {\n        if (Password\\Blowfish::detect($password)) {\n            return $password;\n        }\n        if (Password\\PHPASS::detect($password)) {\n            return $password;\n        }\n        if (strlen($password) < 6) {\n            throw new AccessControlException('Can not save a password with a length shorter than 6 characters!');\n        }\n\n        return $this->passwordFactory->createHash($password, '$2y$');\n    }\n\n    public static function getSubscribedEvents()\n    {\n        return [\n            KernelEvents::REQUEST       => ['onKernelRequest', 31],\n            StorageEvents::PRE_SAVE     => ['onUserEntityPreSave', Application::EARLY_EVENT],\n            StorageEvents::POST_HYDRATE => 'onPostHydrate',\n            StorageEvents::PRE_DELETE   => 'onPreDelete',\n        ];\n    }\n}\n", 'message': 'Adjust keyword\n', 'author_name': 'Gawain Lynch', 'lang': 'php'}