Passed
Push — master ( ecccb9...b91912 )
by Robbie
08:46
created

ElementTypeRegistry::registerElement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
nc 2
nop 1
dl 0
loc 23
rs 9.8333
c 0
b 0
f 0
1
<?php
2
namespace DNADesign\Elemental\Services;
3
4
use DNADesign\Elemental\Models\BaseElement;
5
use InvalidArgumentException;
6
use LogicException;
7
use Psr\SimpleCache\CacheInterface;
8
use SilverStripe\Core\ClassInfo;
9
use SilverStripe\Core\Injector\Injectable;
10
use SilverStripe\Core\Injector\Injector;
11
use SilverStripe\GraphQL\Scaffolding\StaticSchema;
12
13
class ElementTypeRegistry
14
{
15
    use Injectable;
16
17
    const CACHE_KEY = 'element-types';
18
19
    /**
20
     * @var array
21
     */
22
    protected $elementTypes;
23
24
    /**
25
     * @var CacheInterface
26
     */
27
    protected static $cache;
28
29
    /**
30
     * Register an element type with this registry
31
     *
32
     * @param string $elementClass
33
     * @return $this
34
     */
35
    public function registerElement($elementClass)
36
    {
37
        $singleton = singleton($elementClass);
38
39
        if (!$singleton instanceof BaseElement) {
40
            throw new LogicException('Only elements that extend ' . BaseElement::class . ' can be registered');
41
        }
42
43
        // Get the GraphQL type name
44
        $typeName = StaticSchema::inst()->typeNameForDataObject($elementClass);
45
46
        $this->elementTypes[] = [
47
            'icon' => $singleton::config()->get('icon'),
48
            'name' => $typeName,
49
            'class' => $elementClass,
50
            'title' => $singleton->getType(),
51
            'inlineEditable' => $singleton->inlineEditable(),
52
            'editTabs' => $this->getTabProvider()->getTabsForElement($elementClass),
53
            // Cast to object as React prop-types expects it.
54
            'config' => (object) $singleton::getBlockConfig(),
55
        ];
56
57
        return $this;
58
    }
59
60
    /**
61
     * Get the schema of the element types that are registered
62
     *
63
     * @return array
64
     */
65
    public function getDefinitions()
66
    {
67
        return $this->elementTypes;
68
    }
69
70
    /**
71
     * Get the element type data for the given instance or class name of an element.
72
     *
73
     * @param $instanceOrClass
74
     * @return mixed
75
     */
76
    public function getDefinition($instanceOrClass)
77
    {
78
        if ($instanceOrClass instanceof BaseElement) {
79
            $instanceOrClass = get_class($instanceOrClass);
80
        }
81
82
        if (!is_string($instanceOrClass)) {
83
            throw new InvalidArgumentException(sprintf(
84
                'Given argument to %s is not an instance of a class extending %s and is not a string',
85
                __METHOD__,
86
                BaseElement::class
87
            ));
88
        }
89
90
        $definitions = $this->getDefinitions();
91
92
        if (!isset($definitions[$instanceOrClass])) {
93
            throw new InvalidArgumentException(sprintf('Unknown element "%s"', $instanceOrClass));
94
        }
95
96
        return $definitions[$instanceOrClass];
97
    }
98
99
    /**
100
     * @internal This API is only intended for use while SilverStripe does not have a caching layer for form schema.
101
     *           See: https://github.com/silverstripe/silverstripe-admin/issues/627
102
     * @return ElementTabProvider
103
     */
104
    protected function getTabProvider()
105
    {
106
        // This is a temporary solution until something client side is implemented to reveal tab names.
107
        return Injector::inst()->get(ElementTabProvider::class);
108
    }
109
110
    /**
111
     * Create a registry and attempt to fill it by resolving element types by introspecting class hierarchy
112
     *
113
     * @return static
114
     */
115
    public static function generate()
116
    {
117
        $registry = static::create();
118
119
        // Look in a cache (if provided) for type details
120
        if (static::$cache && ($types = static::$cache->get(self::CACHE_KEY))) {
121
            $registry->elementTypes = $types;
122
            return $registry;
123
        }
124
125
        // Find all element types
126
        $classNames = ClassInfo::getValidSubClasses(BaseElement::class);
127
        foreach ($classNames as $class) {
128
            // Skip the "abstract" element
129
            if ($class === BaseElement::class) {
130
                continue;
131
            }
132
            $registry->registerElement($class);
133
        }
134
135
        return $registry;
136
    }
137
}
138