chevere/chevere

View on GitHub
src/ClassMap/ClassMap.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

/*
 * This file is part of Chevere.
 *
 * (c) Rodolfo Berrios <rodolfo@chevere.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types=1);

namespace Chevere\ClassMap;

use Chevere\ClassMap\Interfaces\ClassMapInterface;
use Chevere\DataStructure\Map;
use Chevere\DataStructure\Traits\MapToArrayTrait;
use Chevere\DataStructure\Traits\MapTrait;
use Chevere\Message\Message;
use Chevere\Throwable\Exceptions\ClassNotExistsException;
use Chevere\Throwable\Exceptions\OutOfBoundsException;
use Chevere\Throwable\Exceptions\OverflowException;

final class ClassMap implements ClassMapInterface
{
    use MapTrait;

    use MapToArrayTrait;

    /**
     * @var Map [className => key]
     */
    private Map $map;

    /**
     * @var Map [key => className]
     */
    private Map $flip;

    public function __construct()
    {
        $this->map = new Map();
        $this->flip = new Map();
    }

    public function __clone()
    {
        $this->map = clone $this->map;
        $this->flip = clone $this->flip;
    }

    public function withPut(string $className, string $key): ClassMapInterface
    {
        if (!class_exists($className) && !interface_exists($className)) {
            throw new ClassNotExistsException(
                (new Message("Class name or interface %className% doesn't exists"))
                    ->strong('%className%', $className)
            );
        }
        $known = $this->flip->has($key)
            ? $this->flip->get($key)
            : null;
        if ($known && $known !== $className) {
            throw new OverflowException(
                (new Message('Attempting to map %className% to the same mapping of %known% -> %string%'))
                    ->code('%className%', $className)
                    ->code('%known%', $known)
                    ->code('%string%', $key)
            );
        }
        $new = clone $this;
        $new->map = $new->map->withPut($className, $key);
        $new->flip = $new->flip->withPut($key, $className);

        return $new;
    }

    public function has(string $className): bool
    {
        return $this->map->has($className);
    }

    public function hasKey(string $key): bool
    {
        return $this->flip->has($key);
    }

    public function key(string $className): string
    {
        try {
            return $this->map->get($className);
        } catch (OutOfBoundsException $e) {
            throw new OutOfBoundsException(
                (new Message("Class %className% doesn't exists in the class map"))
                    ->code('%className%', $className)
            );
        }
    }

    public function keys(): array
    {
        return $this->flip->keys();
    }

    public function className(string $key): string
    {
        try {
            return $this->flip->get($key);
        } catch (OutOfBoundsException $e) {
            throw new OutOfBoundsException(
                (new Message("Key %key% doesn't map any class"))
                    ->code('%key%', $key)
            );
        }
    }
}