Passed
Push — master ( 6454db...278ea8 )
by Romain
03:27
created

PropertyFactory   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 149
rs 10
c 0
b 0
f 0
wmc 11

7 Methods

Rating   Name   Duplication   Size   Complexity  
A buildPropertyDefinition() 0 15 2
A buildPropertyContainer() 0 14 2
A eventHasProperties() 0 3 1
A getPropertyContainer() 0 11 2
A __construct() 0 4 1
A getProperties() 0 3 1
A getPropertyDefinition() 0 11 2
1
<?php
2
3
/*
4
 * Copyright (C) 2018
5
 * Nathan Boiron <[email protected]>
6
 * Romain Canon <[email protected]>
7
 *
8
 * This file is part of the TYPO3 NotiZ project.
9
 * It is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU General Public License, either
11
 * version 3 of the License, or any later version.
12
 *
13
 * For the full copyright and license information, see:
14
 * http://www.gnu.org/licenses/gpl-3.0.html
15
 */
16
17
namespace CuyZ\Notiz\Core\Property\Factory;
18
19
use CuyZ\Notiz\Core\Definition\Tree\EventGroup\Event\EventDefinition;
20
use CuyZ\Notiz\Core\Event\Event;
21
use CuyZ\Notiz\Core\Event\Support\HasProperties;
22
use CuyZ\Notiz\Core\Notification\Notification;
23
use CuyZ\Notiz\Core\Property\PropertyEntry;
24
use CuyZ\Notiz\Service\Traits\ExtendedSelfInstantiateTrait;
25
use TYPO3\CMS\Core\SingletonInterface;
26
use TYPO3\CMS\Core\Utility\GeneralUtility;
27
use TYPO3\CMS\Extbase\Object\Container\Container;
28
use TYPO3\CMS\Extbase\Object\ObjectManager;
29
30
/**
31
 * Factory for getting both properties definitions and values, that are defined
32
 * by events and used by notifications.
33
 */
34
class PropertyFactory implements SingletonInterface
35
{
36
    use ExtendedSelfInstantiateTrait;
37
38
    /**
39
     * @var PropertyDefinition[]
40
     */
41
    protected $propertyDefinition = [];
42
43
    /**
44
     * @var PropertyContainer[]
45
     */
46
    protected $properties = [];
47
48
    /**
49
     * @var ObjectManager
50
     */
51
    protected $objectManager;
52
53
    /**
54
     * @var Container
55
     */
56
    protected $objectContainer;
57
58
    /**
59
     * @param ObjectManager $objectManager
60
     * @param Container $objectContainer
61
     */
62
    public function __construct(ObjectManager $objectManager, Container $objectContainer)
63
    {
64
        $this->objectManager = $objectManager;
65
        $this->objectContainer = $objectContainer;
66
    }
67
68
    /**
69
     * Return property definition from given event definition and notification.
70
     *
71
     * The definition is built only once for the given parameters, memoization
72
     * is used to serve the same definition later in a same run time.
73
     *
74
     * Entries have not been processed by any event instance yet. This means all
75
     * their data can not be accessed yet (mainly their values, but also
76
     * arbitrary data the property can have).
77
     *
78
     * @param string $propertyClassName
79
     * @param EventDefinition $eventDefinition
80
     * @param Notification $notification
81
     * @return PropertyDefinition
82
     */
83
    public function getPropertyDefinition($propertyClassName, EventDefinition $eventDefinition, Notification $notification)
84
    {
85
        $propertyClassName = $this->objectContainer->getImplementationClassName($propertyClassName);
86
87
        $identifier = $eventDefinition->getClassName() . '::' . $propertyClassName;
88
89
        if (false === isset($this->propertyDefinition[$identifier])) {
90
            $this->propertyDefinition[$identifier] = $this->buildPropertyDefinition($propertyClassName, $eventDefinition, $notification);
91
        }
92
93
        return $this->propertyDefinition[$identifier];
94
    }
95
96
    /**
97
     * Returns a container of property entries that have been processed by the
98
     * given event. This means all their data can be accessed properly.
99
     *
100
     * Note that each property type for each event is processed only once,
101
     * memoization is used to serve the same properties later in a same run
102
     * time.
103
     *
104
     * @param string $propertyClassName
105
     * @param Event $event
106
     * @return PropertyContainer
107
     */
108
    public function getPropertyContainer($propertyClassName, Event $event)
109
    {
110
        $propertyClassName = $this->objectContainer->getImplementationClassName($propertyClassName);
111
112
        $hash = spl_object_hash($event) . '::' . $propertyClassName;
113
114
        if (false === isset($this->properties[$hash])) {
115
            $this->properties[$hash] = $this->buildPropertyContainer($propertyClassName, $event);
116
        }
117
118
        return $this->properties[$hash];
119
    }
120
121
122
    /**
123
     * @param string $propertyClassName
124
     * @param Event $event
125
     * @return PropertyEntry[]
126
     */
127
    public function getProperties($propertyClassName, Event $event)
128
    {
129
        return $this->getPropertyContainer($propertyClassName, $event)->getEntries();
130
    }
131
132
    /**
133
     * @param string $propertyClassName
134
     * @param EventDefinition $eventDefinition
135
     * @param Notification $notification
136
     * @return PropertyDefinition
137
     */
138
    protected function buildPropertyDefinition($propertyClassName, EventDefinition $eventDefinition, Notification $notification)
139
    {
140
        /** @var PropertyDefinition $propertyDefinition */
141
        $propertyDefinition = $this->objectManager->get(PropertyDefinition::class, $eventDefinition->getClassName(), $propertyClassName);
142
143
        if ($this->eventHasProperties($eventDefinition)) {
144
            /** @var HasProperties $eventClassName */
145
            $eventClassName = $eventDefinition->getClassName();
146
147
            $propertyBuilder = $eventClassName::getPropertyBuilder();
148
149
            $propertyBuilder->build($propertyDefinition, $notification);
150
        }
151
152
        return $propertyDefinition;
153
    }
154
155
    /**
156
     * @param string $propertyClassName
157
     * @param Event|HasProperties $event
158
     * @return PropertyContainer
159
     */
160
    protected function buildPropertyContainer($propertyClassName, Event $event)
161
    {
162
        $propertyDefinition = $this->getPropertyDefinition($propertyClassName, $event->getDefinition(), $event->getNotification());
163
164
        /** @var PropertyContainer $propertyContainer */
165
        $propertyContainer = GeneralUtility::makeInstance(PropertyContainer::class, $propertyDefinition);
166
167
        if ($this->eventHasProperties($event->getDefinition())) {
168
            $event->fillPropertyEntries($propertyContainer);
0 ignored issues
show
Bug introduced by
The method fillPropertyEntries() does not exist on CuyZ\Notiz\Core\Event\Event. Since it exists in all sub-types, consider adding an abstract or default implementation to CuyZ\Notiz\Core\Event\Event. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

168
            $event->/** @scrutinizer ignore-call */ 
169
                    fillPropertyEntries($propertyContainer);
Loading history...
169
170
            $propertyContainer->freeze();
171
        }
172
173
        return $propertyContainer;
174
    }
175
176
    /**
177
     * @param EventDefinition $eventDefinition
178
     * @return bool
179
     */
180
    protected function eventHasProperties(EventDefinition $eventDefinition)
181
    {
182
        return in_array(HasProperties::class, class_implements($eventDefinition->getClassName()));
183
    }
184
}
185