GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 42287f...fba610 )
by Andy
03:33
created

isDependencyCircular()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 56
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 8.0093

Importance

Changes 0
Metric Value
dl 0
loc 56
ccs 18
cts 19
cp 0.9474
rs 7.3333
c 0
b 0
f 0
cc 8
eloc 19
nc 8
nop 3
crap 8.0093

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 *
4
 * @package: chapi
5
 *
6
 * @author: bthapaliya
7
 * @since: 2017-01-03
8
 *
9
 */
10
11
namespace Chapi\BusinessCase\JobManagement;
12
13
use Chapi\BusinessCase\Comparison\JobComparisonInterface;
14
use Chapi\Entity\Marathon\MarathonAppEntity;
15
use Chapi\Service\JobIndex\JobIndexServiceInterface;
16
use Chapi\Service\JobRepository\JobRepositoryInterface;
17
use Psr\Log\LoggerInterface;
18
19
class MarathonStoreJobBusinessCase extends AbstractStoreJobBusinessCase implements StoreJobBusinessCaseInterface
20
{
21
    /**
22
     * MarathonStoreJobBusinessCase constructor.
23
     * @param JobIndexServiceInterface $jobIndexService
24
     * @param JobRepositoryInterface $jobRepositoryRemote
25
     * @param JobRepositoryInterface $jobRepositoryLocal
26
     * @param JobComparisonInterface $jobComparisonBusinessCase
27
     * @param LoggerInterface $logger
28
     */
29 12 View Code Duplication
    public function __construct(
30
        JobIndexServiceInterface $jobIndexService,
31
        JobRepositoryInterface $jobRepositoryRemote,
32
        JobRepositoryInterface $jobRepositoryLocal,
33
        JobComparisonInterface $jobComparisonBusinessCase,
34
        LoggerInterface $logger
35
    ) {
36 12
        $this->jobIndexService = $jobIndexService;
37 12
        $this->logger = $logger;
38 12
        $this->jobComparisonBusinessCase = $jobComparisonBusinessCase;
39 12
        $this->jobRepositoryRemote = $jobRepositoryRemote;
40 12
        $this->jobRepositoryLocal = $jobRepositoryLocal;
41 12
    }
42
43
    /**
44
     * @return void
45
     */
46 7 View Code Duplication
    public function storeIndexedJobs()
47
    {
48 7
        $remoteMissingApps = $this->jobComparisonBusinessCase->getRemoteMissingJobs();
49 7
        foreach ($remoteMissingApps as $appId) {
50 5
            $this->addRemoteMissingApp($appId);
51
        }
52
53 7
        $localMissingApps = $this->jobComparisonBusinessCase->getLocalMissingJobs();
54 7
        foreach ($localMissingApps as $appId) {
55 1
            $this->removeLocalMissingAppInRemote($appId);
56
        }
57 7
        $localUpdates = $this->jobComparisonBusinessCase->getLocalJobUpdates();
58 7
        foreach ($localUpdates as $appId) {
59 1
            $this->updateAppInRemote($appId);
60
        }
61 7
    }
62
63
    /**
64
     * @param string $appId
65
     * @return bool
66
     */
67 5
    private function addRemoteMissingApp($appId)
68
    {
69 5
        if ($this->jobIndexService->isJobInIndex($appId)) {
70
            /** @var MarathonAppEntity $jobEntityLocal */
71 5
            $jobEntityLocal = $this->jobRepositoryLocal->getJob($appId);
72
73 5
            if (!$jobEntityLocal instanceof MarathonAppEntity) {
74
                throw new \RuntimeException('Encountered entity that is not MarathonAppEntity');
75
            }
76
77
            // check if dependency is satisfied
78 5
            if ($jobEntityLocal->isDependencyJob()) {
79
                try {
80 4
                    $circular = $this->isDependencyCircular($jobEntityLocal, count($jobEntityLocal->dependencies));
81 3
                    if ($circular) {
82 1
                        $this->logger->error(sprintf(
83 1
                            'The dependency for %s is circular. Please fix them.',
84
                            $appId
85
                        ));
86 3
                        return false;
87
                    }
88 1
                } catch (\Exception $exception) {
89 1
                    $this->logger->error(sprintf(
90 1
                        'Job %s cannot be added to remote : %s',
91
                        $appId,
92 1
                        $exception->getMessage()
93
                    ));
94 1
                    return false;
95
                }
96
97
98 2
                foreach ($jobEntityLocal->dependencies as $dependencyKey) {
99 2
                    $wasAdded = $this->addRemoteMissingApp($dependencyKey);
100
101 2
                    if (!$wasAdded) {
102 1
                        $this->logger->error(sprintf(
103 1
                            'Job "%s" is dependent on "%s" which is missing. Please add them and try again.',
104
                            $appId,
105
                            $dependencyKey
106
                        ));
107 1
                        $this->jobIndexService->removeJob($dependencyKey);
108 2
                        return false;
109
                    }
110
                }
111
            }
112
113 2
            if ($this->jobRepositoryRemote->addJob($jobEntityLocal)) {
114 2
                $this->jobIndexService->removeJob($jobEntityLocal->getKey());
115 2
                $this->logger->notice(sprintf(
116 2
                    'Job "%s" successfully added to marathon',
117 2
                    $jobEntityLocal->getKey()
118
                ));
119
120 2
                return true;
121
            }
122
            $this->logger->error(sprintf(
123
                'Failed to add job "%s" to marathon',
124
                $jobEntityLocal->getKey()
125
            ));
126
        }
127 2
        return false;
128
    }
129
130
    /**
131
     * @param array $array
132
     * @return bool
133
     */
134 4
    private function hasDuplicates($array)
135
    {
136 4
        return !(count($array) == count(array_unique($array)));
137
    }
138
139
    /**
140
     * @param MarathonAppEntity $entity
141
     * @param int $immediateChildren
142
     * @param array $path
143
     * @return bool
144
     * @throws \Exception
145
     */
146 4
    private function isDependencyCircular(MarathonAppEntity $entity, $immediateChildren, &$path = [])
147
    {
148
        // Invariant: path will not have duplicates for acyclic dependency tree
149 4
        if ($this->hasDuplicates($path)) {
150 1
            return true;
151
        }
152
153
        // if we hit leaf (emptyarray), and have no
154
        // cycle yet, then remove the leaf and return false
155
        // removing leaf will help maintain a proper path from root to leaf
156
        // For tree : A ---> B ---> D
157
        //                      |-> C
158
        // When we reach node D, path will be [A, B, D]
159
        // so we pop off D so that the next append will properly show [A, B, C] (legit path)
160 4
        if (empty($entity->dependencies)) {
161 2
            array_pop($path);
162 2
            return false;
163
        }
164
165 4
        foreach ($entity->dependencies as $dependency) {
166
            // add this key in path as we will explore its child now
167 4
            $path[] = $entity->getKey();
168
169
            /** @var MarathonAppEntity $dependEntity */
170 4
            $dependEntity = $this->jobRepositoryLocal->getJob($dependency);
171
172 4
            if (!$dependEntity) {
173 1
                throw new \Exception(sprintf('Dependency chain on non-existing app "%s"', $dependency));
174
            }
175
176 3
            if (!$dependEntity instanceof MarathonAppEntity) {
177
                throw new \RuntimeException('Expected MarathonAppEntity. Found something else');
178
            }
179
180
181
            // check if dependency has cycle
182 3
            if ($this->isDependencyCircular($dependEntity, count($dependEntity->dependencies), $path)) {
183 1
                return true;
184
            }
185
186
            // tracking immediateChildren, this helps us with
187
            // removing knowing when to pop off key for intermediary dependency
188
            // For tree: A ---> B ---> D
189
            //              |      |-> C
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% 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...
190
            //              |->E
191
            // for B intermediate Child will be 2.
192
            // when we process D, it will be reduced to 1 and with C to 0
193
            // then we will pop B to generate path [A, E] when we reach E.
194 2
            $immediateChildren--;
195 2
            if ($immediateChildren == 0) {
196 2
                array_pop($path);
197
            }
198
        }
199
200 2
        return false;
201
    }
202
203
    /**
204
     * @param string $appId
205
     * @return bool
206
     */
207 1 View Code Duplication
    private function removeLocalMissingAppInRemote($appId)
208
    {
209 1
        if ($this->jobIndexService->isJobInIndex($appId)) {
210 1
            if ($this->jobRepositoryRemote->removeJob($appId)) {
211 1
                $this->jobIndexService->removeJob($appId);
212 1
                $this->logger->notice(sprintf(
213 1
                    'Job "%s" successfully removed from marathon',
214
                    $appId
215
                ));
216
217 1
                return true;
218
            }
219
            $this->logger->error(sprintf(
220
                'Failed to remove"%s" from marathon',
221
                $appId
222
            ));
223
        }
224
        return false;
225
    }
226
227
    /**
228
     * @param string $appId
229
     * @return bool
230
     */
231 1
    private function updateAppInRemote($appId)
232
    {
233 1
        if ($this->jobIndexService->isJobInIndex($appId)) {
234 1
            $updatedConfig = $this->jobRepositoryLocal->getJob($appId);
235 1
            $wasAddedBack = $this->jobRepositoryRemote->updateJob($updatedConfig);
236
237
            // updated
238 1
            if ($wasAddedBack) {
239 1
                $this->jobIndexService->removeJob($appId);
240 1
                $this->logger->notice(sprintf(
241 1
                    'Job "%s" successfully updated in marathon',
242
                    $appId
243
                ));
244
245 1
                return true;
246
            }
247
248
            $this->logger->error(sprintf(
249
                'Failed to update job "%s" in marathon',
250
                $appId
251
            ));
252
        }
253
254
        return false;
255
    }
256
}
257