Completed
Push — master ( 28dda4...aabe55 )
by Craig
06:13
created

DoctrineStorage::unbindSubscriber()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Zikula package.
5
 *
6
 * Copyright Zikula Foundation - http://zikula.org/
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Zikula\Bundle\HookBundle\Dispatcher\Storage\Doctrine;
13
14
use Doctrine\Common\Persistence\ObjectManager;
15
use Doctrine\ORM\Query\Expr\OrderBy;
16
use Symfony\Bridge\Doctrine\RegistryInterface;
17
use Zikula\Bundle\HookBundle\Collector\HookCollectorInterface;
18
use Zikula\Bundle\HookBundle\Dispatcher\Storage\Doctrine\Entity\RepositoryInterface\HookBindingRepositoryInterface;
19
use Zikula\Bundle\HookBundle\Dispatcher\Storage\Doctrine\Entity\RepositoryInterface\HookRuntimeRepositoryInterface;
20
use Zikula\Bundle\HookBundle\Dispatcher\StorageInterface;
21
22
/**
23
 * Doctrine class.
24
 */
25
class DoctrineStorage implements StorageInterface
26
{
27
    /**
28
     * @var Entity\HookRuntimeEntity[]
29
     */
30
    private $runtimeHandlers = [];
31
32
    /**
33
     * @var ObjectManager
34
     */
35
    private $objectManager;
36
37
    /**
38
     * @var HookBindingRepositoryInterface
39
     */
40
    private $hookBindingRepository;
41
42
    /**
43
     * @var HookRuntimeRepositoryInterface
44
     */
45
    private $hookRuntimeRepository;
46
47
    /**
48
     * @var HookCollectorInterface
49
     */
50
    private $hookCollector;
51
52
    public function __construct(
53
        RegistryInterface $doctrine,
54
        HookBindingRepositoryInterface $hookBindingRepository,
55
        HookRuntimeRepositoryInterface $hookRuntimeRepository,
56
        HookCollectorInterface $hookCollector
57
    ) {
58
        $this->objectManager = $doctrine->getManager();
59
        $this->hookBindingRepository = $hookBindingRepository;
60
        $this->hookRuntimeRepository = $hookRuntimeRepository;
61
        $this->hookCollector = $hookCollector;
62
    }
63
64
65
    private function generateRuntimeHandlers()
66
    {
67
        // truncate runtime
68
        $this->hookRuntimeRepository->truncate();
69
70
        $bindings = $this->hookBindingRepository->findBy([], ['sareaid' => 'ASC', 'sortorder' => 'ASC']);
71
        foreach ($bindings as $binding) {
72
            $this->addRuntimeHandlers($binding['sareaid'], $binding['pareaid']);
73
        }
74
    }
75
76
    private function addRuntimeHandlers($subscriberArea, $providerArea)
77
    {
78
        $subscriberAreaObject = $this->hookCollector->getSubscriber($subscriberArea);
79
        $providerAreaObject = $this->hookCollector->getProvider($providerArea);
80
        $subscribers = $subscriberAreaObject->getEvents();
81
82
        if (!$subscribers) {
83
            return false;
84
        }
85
86
        foreach ($subscribers as $hookType => $eventName) {
87
            $types = $providerAreaObject->getProviderTypes();
88
            if (isset($types[$hookType])) {
89
                $methods = is_array($types[$hookType]) ? $types[$hookType] : [$types[$hookType]];
90
                foreach ($methods as $method) {
91
                    $hookRuntimeEntity = new Entity\HookRuntimeEntity();
92
                    $hookRuntimeEntity->setSowner($subscriberAreaObject->getOwner());
93
                    $hookRuntimeEntity->setPowner($providerAreaObject->getOwner());
94
                    $hookRuntimeEntity->setSareaid($subscriberArea);
95
                    $hookRuntimeEntity->setPareaid($providerArea);
96
                    $hookRuntimeEntity->setEventname($eventName);
97
                    $hookRuntimeEntity->setClassname(get_class($providerAreaObject));
98
                    $hookRuntimeEntity->setMethod($method);
99
                    $hookRuntimeEntity->setServiceid($providerAreaObject->getServiceId());
100
                    $hookRuntimeEntity->setPriority(10);
101
                    $this->objectManager->persist($hookRuntimeEntity);
102
                }
103
            }
104
        }
105
        $this->objectManager->flush();
106
107
        return true;
108
    }
109
110
    public function bindSubscriber($subscriberArea, $providerArea)
111
    {
112
        $sa = $this->hookCollector->getSubscriber($subscriberArea);
113
        $pa = $this->hookCollector->getProvider($providerArea);
114
115
        $binding = new Entity\HookBindingEntity();
116
        $binding->setSowner($sa->getOwner());
117
        $binding->setPowner($pa->getOwner());
118
        $binding->setSareaid($subscriberArea);
119
        $binding->setPareaid($providerArea);
120
        $binding->setCategory($sa->getCategory());
121
        $binding->setSortorder(999);
122
        $this->objectManager->persist($binding);
123
        $this->objectManager->flush();
124
125
        $this->generateRuntimeHandlers();
126
    }
127
128
    public function unbindSubscriber($subscriberArea, $providerArea)
129
    {
130
        $this->hookBindingRepository->deleteByBothAreas($subscriberArea, $providerArea);
131
        $this->generateRuntimeHandlers();
132
    }
133
134
    /**
135
     * @param $areaName
136
     * @param string $type
137
     * @return array
138
     */
139
    public function getBindingsFor($areaName, $type = 'subscriber')
140
    {
141
        $type = in_array($type, ['subscriber', 'provider']) ? $type : 'subscriber'; // validate field
142
        $area = $this->hookCollector->getSubscriber($areaName);
143
144
        if (!isset($area)) {
145
            return [];
146
        }
147
148
        $order = new OrderBy();
149
        $order->add('t.sortorder', 'ASC');
150
        $order->add('t.sareaid', 'ASC');
151
        $fieldMap = ['subscriber' => 'sareaid', 'provider' => 'pareaid'];
152
        $results = $this->hookBindingRepository->selectByAreaName($areaName, $fieldMap[$type]);
153
154
        $areas = [];
155
        foreach ($results as $result) {
156
            $area = $this->hookCollector->getProvider($result['pareaid']);
157
            $areas[] = [
158
                'areaname' => $result['pareaid'],
159
                'category' => $area->getCategory()
160
            ];
161
        }
162
163
        return $areas;
164
    }
165
166
    /**
167
     * sort bindings in order of appearance from $providerAreaIds
168
     * @param string $subscriberAreaName
169
     * @param array $providerAreaNames
170
     */
171
    public function setBindOrder($subscriberAreaName, array $providerAreaNames)
172
    {
173
        $counter = 1;
174
        foreach ($providerAreaNames as $providerAreaName) {
175
            $this->hookBindingRepository->setSortOrder($counter, $subscriberAreaName, $providerAreaName);
176
            $counter++;
177
        }
178
179
        $this->generateRuntimeHandlers();
180
    }
181
182
    public function getRuntimeMetaByEventName($eventName)
183
    {
184
        if (!isset($this->runtimeHandlers[$eventName])) {
185
            $this->runtimeHandlers[$eventName] = $this->hookRuntimeRepository->getOneOrNullByEventName($eventName);
186
        }
187
        if ($this->runtimeHandlers[$eventName]) {
188
            return [
189
                'areaid' => $this->runtimeHandlers[$eventName]->getSareaid(),
190
                'owner' => $this->runtimeHandlers[$eventName]->getSowner()
191
            ];
192
        }
193
194
        return false;
195
    }
196
197
    public function getBindingBetweenAreas($subscriberArea, $providerArea)
198
    {
199
        return $this->hookBindingRepository->findOneOrNullByAreas($subscriberArea, $providerArea);
200
    }
201
202
    /**
203
     * binding between hook areas should be allowed if:
204
     *   1. *Category* is the same for both
205
     *   2. the provider and subscriber have implemented at least one of same *hookType*
206
     * @param $subscriberArea
207
     * @param $providerArea
208
     * @return bool
209
     */
210
    public function isAllowedBindingBetweenAreas($subscriberArea, $providerArea)
211
    {
212
        if ($this->hookCollector->hasSubscriber($subscriberArea)) {
213
            $subscriberTypes = $this->hookCollector->getSubscriber($subscriberArea)->getEvents(); // array('hookType' => 'eventName')
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
214
            $subscriberTypes = array_keys($subscriberTypes);
215
            $subscriberCategory = $this->hookCollector->getSubscriber($subscriberArea)->getCategory();
216
        }
217
218
        if (empty($subscriberTypes)) {
219
            return false;
220
        }
221
222
        foreach ($subscriberTypes as $subscriberType) {
223
            if ($this->hookCollector->hasProvider($providerArea)) {
224
                $providerTypes = $this->hookCollector->getProvider($providerArea)->getProviderTypes();
225
                $providerCategory = $this->hookCollector->getProvider($providerArea)->getCategory();
226
                foreach (array_keys($providerTypes) as $providerType) {
227
                    if ($subscriberCategory == $providerCategory && $subscriberType == $providerType) {
0 ignored issues
show
Bug introduced by
The variable $subscriberCategory does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
228
                        return true;
229
                    }
230
                }
231
            }
232
        }
233
234
        return false;
235
    }
236
237
    public function getBindingsBetweenOwners($subscriberOwner, $providerOwner)
238
    {
239
        return $this->hookBindingRepository->findByOwners($subscriberOwner, $providerOwner);
240
    }
241
}
242