Passed
Push — master ( 5b6246...3f1c48 )
by Morris
11:26 queued 10s
created

File::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 8
dl 0
loc 18
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * @copyright Copyright (c) 2019 Arthur Schiwon <[email protected]>
6
 *
7
 * @author Arthur Schiwon <[email protected]>
8
 *
9
 * @license GNU AGPL version 3 or any later version
10
 *
11
 * This program is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License as
13
 * published by the Free Software Foundation, either version 3 of the
14
 * License, or (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 */
25
26
namespace OCA\WorkflowEngine\Entity;
27
28
use OCP\EventDispatcher\Event;
29
use OCP\EventDispatcher\GenericEvent;
30
use OCP\Files\InvalidPathException;
31
use OCP\Files\IRootFolder;
32
use OCP\Files\Node;
33
use OCP\Files\NotFoundException;
34
use OCP\IL10N;
35
use OCP\ILogger;
36
use OCP\IURLGenerator;
37
use OCP\IUser;
38
use OCP\IUserManager;
39
use OCP\IUserSession;
40
use OCP\Share\IManager as ShareManager;
41
use OCP\SystemTag\ISystemTag;
42
use OCP\SystemTag\ISystemTagManager;
43
use OCP\SystemTag\MapperEvent;
44
use OCP\WorkflowEngine\EntityContext\IContextPortation;
45
use OCP\WorkflowEngine\EntityContext\IDisplayText;
46
use OCP\WorkflowEngine\EntityContext\IUrl;
47
use OCP\WorkflowEngine\GenericEntityEvent;
48
use OCP\WorkflowEngine\IEntity;
49
use OCP\WorkflowEngine\IRuleMatcher;
50
51
class File implements IEntity, IDisplayText, IUrl, IContextPortation {
52
	private const EVENT_NAMESPACE = '\OCP\Files::';
53
54
	/** @var IL10N */
55
	protected $l10n;
56
	/** @var IURLGenerator */
57
	protected $urlGenerator;
58
	/** @var IRootFolder */
59
	protected $root;
60
	/** @var ILogger */
61
	protected $logger;
62
	/** @var string */
63
	protected $eventName;
64
	/** @var Event */
65
	protected $event;
66
	/** @var ShareManager */
67
	private $shareManager;
68
	/** @var IUserSession */
69
	private $userSession;
70
	/** @var ISystemTagManager */
71
	private $tagManager;
72
	/** @var ?Node */
73
	private $node;
74
	/** @var ?IUser */
75
	private $actingUser = null;
76
	/** @var IUserManager */
77
	private $userManager;
78
79
	public function __construct(
80
		IL10N $l10n,
81
		IURLGenerator $urlGenerator,
82
		IRootFolder $root,
83
		ILogger $logger,
84
		ShareManager $shareManager,
85
		IUserSession $userSession,
86
		ISystemTagManager $tagManager,
87
		IUserManager $userManager
88
	) {
89
		$this->l10n = $l10n;
90
		$this->urlGenerator = $urlGenerator;
91
		$this->root = $root;
92
		$this->logger = $logger;
93
		$this->shareManager = $shareManager;
94
		$this->userSession = $userSession;
95
		$this->tagManager = $tagManager;
96
		$this->userManager = $userManager;
97
	}
98
99
	public function getName(): string {
100
		return $this->l10n->t('File');
101
	}
102
103
	public function getIcon(): string {
104
		return $this->urlGenerator->imagePath('core', 'categories/files.svg');
105
	}
106
107
	public function getEvents(): array {
108
		return [
109
			new GenericEntityEvent($this->l10n->t('File created'), self::EVENT_NAMESPACE . 'postCreate'),
110
			new GenericEntityEvent($this->l10n->t('File updated'), self::EVENT_NAMESPACE . 'postWrite'),
111
			new GenericEntityEvent($this->l10n->t('File renamed'), self::EVENT_NAMESPACE . 'postRename'),
112
			new GenericEntityEvent($this->l10n->t('File deleted'), self::EVENT_NAMESPACE . 'postDelete'),
113
			new GenericEntityEvent($this->l10n->t('File accessed'), self::EVENT_NAMESPACE . 'postTouch'),
114
			new GenericEntityEvent($this->l10n->t('File copied'), self::EVENT_NAMESPACE . 'postCopy'),
115
			new GenericEntityEvent($this->l10n->t('Tag assigned'), MapperEvent::EVENT_ASSIGN),
116
		];
117
	}
118
119
	public function prepareRuleMatcher(IRuleMatcher $ruleMatcher, string $eventName, Event $event): void {
120
		if (!$event instanceof GenericEvent && !$event instanceof MapperEvent) {
121
			return;
122
		}
123
		$this->eventName = $eventName;
124
		$this->event = $event;
125
		$this->actingUser = $this->actingUser ?? $this->userSession->getUser();
126
		try {
127
			$node = $this->getNode();
128
			$ruleMatcher->setEntitySubject($this, $node);
129
			$ruleMatcher->setFileInfo($node->getStorage(), $node->getInternalPath());
130
		} catch (NotFoundException $e) {
131
			// pass
132
		}
133
	}
134
135
	public function isLegitimatedForUserId(string $uid): bool {
136
		try {
137
			$node = $this->getNode();
138
			if ($node->getOwner()->getUID() === $uid) {
139
				return true;
140
			}
141
			$acl = $this->shareManager->getAccessList($node, true, true);
142
			return array_key_exists($uid, $acl['users']);
143
		} catch (NotFoundException $e) {
144
			return false;
145
		}
146
	}
147
148
	/**
149
	 * @throws NotFoundException
150
	 */
151
	protected function getNode(): Node {
152
		if ($this->node) {
153
			return $this->node;
154
		}
155
		if (!$this->event instanceof GenericEvent && !$this->event instanceof MapperEvent) {
156
			throw new NotFoundException();
157
		}
158
		switch ($this->eventName) {
159
			case self::EVENT_NAMESPACE . 'postCreate':
160
			case self::EVENT_NAMESPACE . 'postWrite':
161
			case self::EVENT_NAMESPACE . 'postDelete':
162
			case self::EVENT_NAMESPACE . 'postTouch':
163
				return $this->event->getSubject();
0 ignored issues
show
Bug introduced by
The method getSubject() does not exist on OCP\SystemTag\MapperEvent. ( Ignorable by Annotation )

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

163
				return $this->event->/** @scrutinizer ignore-call */ getSubject();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
164
			case self::EVENT_NAMESPACE . 'postRename':
165
			case self::EVENT_NAMESPACE . 'postCopy':
166
				return $this->event->getSubject()[1];
167
			case MapperEvent::EVENT_ASSIGN:
168
				if (!$this->event instanceof MapperEvent || $this->event->getObjectType() !== 'files') {
169
					throw new NotFoundException();
170
				}
171
				$nodes = $this->root->getById((int)$this->event->getObjectId());
172
				if (is_array($nodes) && isset($nodes[0])) {
173
					$this->node = $nodes[0];
174
					return $this->node;
175
				}
176
				break;
177
		}
178
		throw new NotFoundException();
179
	}
180
181
	public function getDisplayText(int $verbosity = 0): string {
182
		try {
183
			$node = $this->getNode();
184
		} catch (NotFoundException $e) {
185
			return '';
186
		}
187
188
		$options = [
189
			$this->actingUser ? $this->actingUser->getDisplayName() : $this->l10n->t('Someone'),
190
			$node->getName()
191
		];
192
193
		switch ($this->eventName) {
194
			case self::EVENT_NAMESPACE . 'postCreate':
195
				return $this->l10n->t('%s created %s', $options);
196
			case self::EVENT_NAMESPACE . 'postWrite':
197
				return $this->l10n->t('%s modified %s', $options);
198
			case self::EVENT_NAMESPACE . 'postDelete':
199
				return $this->l10n->t('%s deleted %s', $options);
200
			case self::EVENT_NAMESPACE . 'postTouch':
201
				return $this->l10n->t('%s accessed %s', $options);
202
			case self::EVENT_NAMESPACE . 'postRename':
203
				return $this->l10n->t('%s renamed %s', $options);
204
			case self::EVENT_NAMESPACE . 'postCopy':
205
				return $this->l10n->t('%s copied %s', $options);
206
			case MapperEvent::EVENT_ASSIGN:
207
				$tagNames = [];
208
				if ($this->event instanceof MapperEvent) {
209
					$tagIDs = $this->event->getTags();
210
					$tagObjects = $this->tagManager->getTagsByIds($tagIDs);
211
					foreach ($tagObjects as $systemTag) {
212
						/** @var ISystemTag $systemTag */
213
						if ($systemTag->isUserVisible()) {
214
							$tagNames[] = $systemTag->getName();
215
						}
216
					}
217
				}
218
				$filename = array_pop($options);
219
				$tagString = implode(', ', $tagNames);
220
				if ($tagString === '') {
221
					return '';
222
				}
223
				array_push($options, $tagString, $filename);
224
				return $this->l10n->t('%s assigned %s to %s', $options);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
225
		}
226
	}
227
228
	public function getUrl(): string {
229
		try {
230
			return $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $this->getNode()->getId()]);
231
		} catch (InvalidPathException $e) {
232
			return '';
233
		} catch (NotFoundException $e) {
234
			return '';
235
		}
236
	}
237
238
	/**
239
	 * @inheritDoc
240
	 */
241
	public function exportContextIDs(): array {
242
		$nodeOwner = $this->getNode()->getOwner();
243
		$actingUserId = null;
244
		if ($this->actingUser instanceof IUser) {
245
			$actingUserId = $this->actingUser->getUID();
246
		} elseif ($this->userSession->getUser() instanceof IUser) {
247
			$actingUserId = $this->userSession->getUser()->getUID();
248
		}
249
		return [
250
			'eventName' => $this->eventName,
251
			'nodeId' => $this->getNode()->getId(),
252
			'nodeOwnerId' => $nodeOwner ? $nodeOwner->getUID() : null,
0 ignored issues
show
introduced by
$nodeOwner is of type OCP\IUser, thus it always evaluated to true.
Loading history...
253
			'actingUserId' => $actingUserId,
254
		];
255
	}
256
257
	/**
258
	 * @inheritDoc
259
	 */
260
	public function importContextIDs(array $contextIDs): void {
261
		$this->eventName = $contextIDs['eventName'];
262
		if ($contextIDs['nodeOwnerId'] !== null) {
263
			$userFolder = $this->root->getUserFolder($contextIDs['nodeOwnerId']);
264
			$nodes = $userFolder->getById($contextIDs['nodeId']);
265
		} else {
266
			$nodes = $this->root->getById($contextIDs['nodeId']);
267
		}
268
		$this->node = $nodes[0] ?? null;
269
		if ($contextIDs['actingUserId']) {
270
			$this->actingUser = $this->userManager->get($contextIDs['actingUserId']);
271
		}
272
	}
273
}
274