Completed
Push — master ( a8fb97...ba7e2b )
by Mathieu
05:06
created

MapFactory::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Charcoal\Factory;
4
5
// Dependencies from `PHP`
6
use \InvalidArgumentException;
7
8
// Local namespace dependencies
9
use \Charcoal\Factory\AbstractFactory;
10
11
/**
12
 * The map Factory resolves the **class name** from an associative array with the **type** key.
13
 *
14
 */
15
class MapFactory extends AbstractFactory
16
{
17
    /**
18
     * The class map array holds available types, in `[$type => $className]` format.
19
     * @var array $map
20
     */
21
    private $map = [];
22
23
    public function __construct($data=null)
24
    {
25
        parent::__construct($data);
26
27
        if ($data['map']) {
28
            $this->setMap($data['map']);
29
        }
30
    }
31
32
    /**
33
     * Add a class name to the available types _map_.
34
     *
35
     * @param string $type      The type (class ident).
36
     * @param string $className The FQN of the class.
37
     * @throws InvalidArgumentException If the $type parameter is not a striing or the $className class does not exist.
38
     * @return FactoryInterface Chainable
39
     */
40
    public function addClass($type, $className)
41
    {
42
        if (!is_string($type)) {
43
            throw new InvalidArgumentException(
44
                'Type (class key) must be a string'
45
            );
46
        }
47
        if (!class_exists($className)) {
48
            throw new InvalidArgumentException(
49
                sprintf('Class "%s" is not a valid class name.', $className)
50
            );
51
        }
52
53
        $this->map[$type] = $className;
54
        return $this;
55
    }
56
57
    /**
58
     * Add multiple types, in a an array of `type` => `className`.
59
     *
60
     * @param array $map The map (key=>classname) to use.
61
     * @return FactoryInterface Chainable
62
     */
63
    public function setMap(array $map)
64
    {
65
        // Resets (overwrites) map.
66
        $this->map = [];
67
        foreach ($map as $type => $className) {
68
            $this->addClass($type, $className);
69
        }
70
        return $this;
71
    }
72
73
    /**
74
     * Get the map of all types in `[$type => $class]` format.
75
     *
76
     * @return array
77
     */
78
    public function map()
79
    {
80
        return $this->map;
81
    }
82
83
    /**
84
     * The "Map Factory" implements `AbstractFactory`'s `resolve()` abstract method
85
     * by fetching the class ident from the `map` member array.
86
     *
87
     * If the object's `type` is not defined in the class map, an exception will be thrown.
88
     *
89
     * @param string $type The "type" of object to resolve (the object ident).
90
     * @throws InvalidArgumentException If the type parameter is not a string.
91
     * @return string The resolved class name (FQN).
92
     */
93
    public function resolve($type)
94
    {
95
        if (!is_string($type)) {
96
            throw new InvalidArgumentException(
97
                'Can not resolve class ident: type must be a string'
98
            );
99
        }
100
101
        $map = $this->map();
102
        if (!isset($map[$type])) {
103
            throw new InvalidArgumentException(
104
                'Invalid type (not defined in class map)'
105
            );
106
        }
107
        return $map[$type];
108
    }
109
110
    /**
111
     * The "Map Factory" implements `AbstractFactory`'s `is_resolvable()` abstract method
112
     * by ensuring the class ident is defined in the class map and is a validd class.
113
     *
114
     * @param string $type The "type" of object to resolve (the object ident).
115
     * @throws InvalidArgumentException If the type parameter is not a string.
116
     * @return boolean
117
     */
118
    public function isResolvable($type)
119
    {
120
        if (!is_string($type)) {
121
            throw new InvalidArgumentException(
122
                'Can not check resolvable: type must be a string'
123
            );
124
        }
125
126
        $map = $this->map();
127
        if (!isset($map[$type])) {
128
            return false;
129
        }
130
131
        $className = $map[$type];
132
        return !!class_exists($className);
133
    }
134
}
135