Completed
Push — master ( fef7a6...aff413 )
by Arne
02:38
created

AbstractFactory::requiresInstanceOf()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Archivr;
4
5
use Archivr\Exception\Exception;
6
7
/**
8
 * todo: Consider replacement by reference implementation
9
 */
10
abstract class AbstractFactory
11
{
12
    /**
13
     * Class is a singleton
14
     */
15
    private function __construct() {}
16
17
    protected static $factoryMaps = [];
18
19
    /**
20
     * Returns true if this factory provides the service of the given name.
21
     *
22
     * @param string $name
23
     * @return bool
24
     */
25
    public static function provides(string $name): bool
26
    {
27
        static::loadFactoryMap();
28
29
        return isset(static::$factoryMaps[static::class][$name]);
30
    }
31
32
    /**
33
     * Creates and returns the service under the given name.
34
     *
35
     * @param string $name
36
     * @param array ...$params Parameters passed to the actual factory.
37
     * @return mixed
38
     * @throws Exception
39
     */
40
    public static function create(string $name, ...$params)
41
    {
42
        static::loadFactoryMap();
43
44
        $factoryMap = static::$factoryMaps[static::class];
45
46
        if (!isset($factoryMap[$name]))
47
        {
48
            throw new \InvalidArgumentException(sprintf('Factory "%s" does not provide "%s".', static::class, $name));
49
        }
50
51
        $factory = $factoryMap[$name];
52
53
        if (is_string($factory))
54
        {
55
            $instance = new $factory(...$params);
56
        }
57
        elseif ($factory instanceof \Closure)
58
        {
59
            $instance = $factory(...$params);
60
        }
61
        elseif (is_object($factory))
62
        {
63
            $instance = $factory;
64
        }
65
        else
66
        {
67
            throw new \LogicException();
68
        }
69
70
        // check for correct interface/class if requirement is set
71
        if ($type = static::requiresInstanceOf())
72
        {
73
            if (!($instance instanceof $type))
74
            {
75
                throw new Exception(sprintf('Factory closure for "%s" does not return instance of %s. %s given.', $name, $type, is_object($instance) ? get_class($instance) : gettype($instance)));
76
            }
77
        }
78
79
        return $instance;
80
    }
81
82
    /**
83
     * Registers a n
84
     *
85
     * @param string $name
86
     * @param string|\Closure|object $factory
87
     * @param bool $allowOverride
88
     */
89
    public static function registerFactory(string $name, $factory, bool $allowOverride = false): void
90
    {
91
        static::loadFactoryMap();
92
93
        if (!$allowOverride && isset(static::$factoryMaps[static::class][$name]))
94
        {
95
            throw new \RuntimeException(sprintf('Trying to register a factory named "%s" to "%s" which already exists.', $name, static::class));
96
        }
97
98
        if (is_string($factory))
99
        {
100
            if (!class_exists($factory))
101
            {
102
                throw new \RuntimeException(sprintf('Trying to register factory named "%s" to "%s" as class name "%s" which does not exist.', $name, static::class, $factory));
103
            }
104
        }
105
        elseif ($factory instanceof \Closure)
0 ignored issues
show
Unused Code introduced by
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
106
        {
107
            // cannot really validate
108
        }
109
        elseif (is_object($factory))
110
        {
111
            if ($type = static::requiresInstanceOf())
112
            {
113
                if (!($factory instanceof $type))
114
                {
115
                    throw new \RuntimeException(sprintf('Trying to register service instance named "%s" to "%s" as which is not an instance of "%s".', $name, static::class, $type));
116
                }
117
            }
118
        }
119
        else
120
        {
121
            throw new \InvalidArgumentException(sprintf('Invalid factory of type "%s" named "%s" given to "%s".', gettype($factory), $name, static::class));
122
        }
123
124
        static::$factoryMaps[static::class][$name] = $factory;
125
    }
126
127
    /**
128
     * Can return an instance/class name that the factories have to return an instance of.
129
     *
130
     * @return string
131
     */
132
    protected static function requiresInstanceOf(): string
133
    {
134
        return null;
135
    }
136
137
    protected static function loadFactoryMap(): void
138
    {
139
        if (!isset(static::$factoryMaps[static::class]))
140
        {
141
            static::$factoryMaps[static::class] = static::getFactoryMap();
142
        }
143
    }
144
145
    /**
146
     * Has to return map of names to factory closures.
147
     *
148
     * @return array
149
     */
150
    abstract protected static function getFactoryMap(): array;
151
}
152