Fixed \XF::repository does not understand class aliases, breaking the invariant that a repository is created once

Xon

Well-known member
Affected version
2.3.6
If you call

PHP:
\XF::repository('XF:EmailBounce')
and then
PHP:
\XF::repository('XF\Repository\EmailBounceRepository')

This will result in two different repository objects, each with a different slot in the property $repositories in XF\Mvc\Entity\Manager.

The repository itself will have 'XF:EmailBounce' for both stored in the $identifier property on the repository.

PHP:
public function getRepository($identifier)
{
    $identifier = \XF::classToString($identifier, '%s\Repository\%s');
    if (isset($this->repositories[$identifier]))
    {
        return $this->repositories[$identifier];
    }

    $repositoryClass = \XF::stringToClass($identifier, '%s\Repository\%s');
    $repositoryClass = $this->extension->extendClass($repositoryClass, Repository::class);
    if (!$repositoryClass || !class_exists($repositoryClass))
    {
        throw new \LogicException("Could not find repository '$repositoryClass' for '$identifier'");
    }

    $repository = new $repositoryClass($this, $identifier);
    $this->repositories[$identifier] = $repository;

    return $repository;
}
...
public function __construct(Manager $em, $identifier)
{
    $this->em = $em;

    if (substr($identifier, -10) === 'Repository')
    {
        $identifier = substr($identifier, 0, -10);
    }
    $this->identifier = $identifier;
}

getRepository should either remove or add the trailing Repository when computing the cache key to ensure things are consistent.

Either would work as the class-loader appends/removes that so it'll resolve to a class properly.
 
Last edited:
Back
Top Bottom