Complex classes like SftpAdapter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SftpAdapter, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class SftpAdapter extends AbstractFtpAdapter |
||
18 | { |
||
19 | use StreamedCopyTrait; |
||
20 | |||
21 | /** |
||
22 | * @var SFTP |
||
23 | */ |
||
24 | protected $connection; |
||
25 | |||
26 | /** |
||
27 | * @var int |
||
28 | */ |
||
29 | protected $port = 22; |
||
30 | |||
31 | /** |
||
32 | * @var string |
||
33 | */ |
||
34 | protected $hostFingerprint; |
||
35 | |||
36 | /** |
||
37 | * @var string |
||
38 | */ |
||
39 | protected $privatekey; |
||
40 | |||
41 | /** |
||
42 | * @var bool |
||
43 | */ |
||
44 | protected $useAgent = false; |
||
45 | |||
46 | /** |
||
47 | * @var Agent |
||
48 | */ |
||
49 | private $agent; |
||
50 | |||
51 | /** |
||
52 | * @var array |
||
53 | */ |
||
54 | protected $configurable = ['host', 'hostFingerprint', 'port', 'username', 'password', 'useAgent', 'agent', 'timeout', 'root', 'privateKey', 'permPrivate', 'permPublic', 'directoryPerm', 'NetSftpConnection']; |
||
55 | |||
56 | /** |
||
57 | * @var array |
||
58 | */ |
||
59 | protected $statMap = ['mtime' => 'timestamp', 'size' => 'size']; |
||
60 | |||
61 | /** |
||
62 | * @var int |
||
63 | */ |
||
64 | protected $directoryPerm = 0744; |
||
65 | |||
66 | /** |
||
67 | * Prefix a path. |
||
68 | * |
||
69 | * @param string $path |
||
70 | * |
||
71 | * @return string |
||
72 | */ |
||
73 | 6 | protected function prefix($path) |
|
77 | |||
78 | /** |
||
79 | * Set the finger print of the public key of the host you are connecting to. |
||
80 | * |
||
81 | * If the key does not match the server identification, the connection will |
||
82 | * be aborted. |
||
83 | * |
||
84 | * @param string $fingerprint Example: '88:76:75:96:c1:26:7c:dd:9f:87:50:db:ac:c4:a8:7c'. |
||
85 | * |
||
86 | * @return $this |
||
87 | */ |
||
88 | 6 | public function setHostFingerprint($fingerprint) |
|
94 | |||
95 | /** |
||
96 | * Set the private key (string or path to local file). |
||
97 | * |
||
98 | * @param string $key |
||
99 | * |
||
100 | * @return $this |
||
101 | */ |
||
102 | 9 | public function setPrivateKey($key) |
|
108 | |||
109 | /** |
||
110 | * @param boolean $useAgent |
||
111 | * |
||
112 | * @return $this |
||
113 | */ |
||
114 | public function setUseAgent($useAgent) |
||
120 | |||
121 | /** |
||
122 | * @param Agent $agent |
||
123 | * |
||
124 | * @return $this |
||
125 | */ |
||
126 | public function setAgent(Agent $agent) |
||
132 | |||
133 | /** |
||
134 | * Set permissions for new directory |
||
135 | * |
||
136 | * @param int $directoryPerm |
||
137 | * |
||
138 | * @return $this |
||
139 | */ |
||
140 | 6 | public function setDirectoryPerm($directoryPerm) |
|
146 | |||
147 | /** |
||
148 | * Get permissions for new directory |
||
149 | * |
||
150 | * @return int |
||
151 | */ |
||
152 | 3 | public function getDirectoryPerm() |
|
156 | |||
157 | /** |
||
158 | * Inject the SFTP instance. |
||
159 | * |
||
160 | * @param SFTP $connection |
||
161 | * |
||
162 | * @return $this |
||
163 | */ |
||
164 | 30 | public function setNetSftpConnection(SFTP $connection) |
|
170 | |||
171 | /** |
||
172 | * Connect. |
||
173 | */ |
||
174 | 21 | public function connect() |
|
180 | |||
181 | /** |
||
182 | * Login. |
||
183 | * |
||
184 | * @throws LogicException |
||
185 | */ |
||
186 | 21 | protected function login() |
|
206 | |||
207 | /** |
||
208 | * Convert the SSH RSA public key into a hex formatted fingerprint. |
||
209 | * |
||
210 | * @param string $publickey |
||
211 | * @return string Hex formatted fingerprint, e.g. '88:76:75:96:c1:26:7c:dd:9f:87:50:db:ac:c4:a8:7c'. |
||
212 | */ |
||
213 | 6 | private function getHexFingerprintFromSshPublicKey ($publickey) |
|
218 | |||
219 | /** |
||
220 | * Set the connection root. |
||
221 | */ |
||
222 | 15 | protected function setConnectionRoot() |
|
235 | |||
236 | /** |
||
237 | * Get the password, either the private key or a plain text password. |
||
238 | * |
||
239 | * @return Agent|RSA|string |
||
240 | */ |
||
241 | 21 | public function getAuthentication() |
|
253 | |||
254 | /** |
||
255 | * Get the private key with the password or private key contents. |
||
256 | * |
||
257 | * @return RSA |
||
258 | */ |
||
259 | 9 | public function getPrivateKey() |
|
275 | |||
276 | /** |
||
277 | * @return Agent|bool |
||
278 | */ |
||
279 | public function getAgent() |
||
287 | |||
288 | /** |
||
289 | * List the contents of a directory. |
||
290 | * |
||
291 | * @param string $directory |
||
292 | * @param bool $recursive |
||
293 | * |
||
294 | * @return array |
||
295 | */ |
||
296 | 6 | protected function listDirectoryContents($directory, $recursive = true) |
|
322 | |||
323 | /** |
||
324 | * Normalize a listing response. |
||
325 | * |
||
326 | * @param string $path |
||
327 | * @param array $object |
||
328 | * |
||
329 | * @return array |
||
330 | */ |
||
331 | 6 | protected function normalizeListingObject($path, array $object) |
|
347 | |||
348 | /** |
||
349 | * Disconnect. |
||
350 | */ |
||
351 | 15 | public function disconnect() |
|
355 | |||
356 | /** |
||
357 | * @inheritdoc |
||
358 | */ |
||
359 | 6 | public function write($path, $contents, Config $config) |
|
367 | |||
368 | /** |
||
369 | * @inheritdoc |
||
370 | */ |
||
371 | 6 | public function writeStream($path, $resource, Config $config) |
|
379 | |||
380 | /** |
||
381 | * Upload a file. |
||
382 | * |
||
383 | * @param string $path |
||
384 | * @param string|resource $contents |
||
385 | * @param Config $config |
||
386 | * @return bool |
||
387 | */ |
||
388 | 12 | public function upload($path, $contents, Config $config) |
|
404 | |||
405 | /** |
||
406 | * @inheritdoc |
||
407 | */ |
||
408 | 6 | public function read($path) |
|
418 | |||
419 | /** |
||
420 | * @inheritdoc |
||
421 | */ |
||
422 | 3 | public function readStream($path) |
|
436 | |||
437 | /** |
||
438 | * @inheritdoc |
||
439 | */ |
||
440 | 3 | public function update($path, $contents, Config $config) |
|
444 | |||
445 | /** |
||
446 | * @inheritdoc |
||
447 | */ |
||
448 | 3 | public function updateStream($path, $contents, Config $config) |
|
452 | |||
453 | /** |
||
454 | * @inheritdoc |
||
455 | */ |
||
456 | 3 | public function delete($path) |
|
462 | |||
463 | /** |
||
464 | * @inheritdoc |
||
465 | */ |
||
466 | 3 | public function rename($path, $newpath) |
|
472 | |||
473 | /** |
||
474 | * @inheritdoc |
||
475 | */ |
||
476 | 3 | public function deleteDir($dirname) |
|
482 | |||
483 | /** |
||
484 | * @inheritdoc |
||
485 | */ |
||
486 | 39 | public function has($path) |
|
490 | |||
491 | /** |
||
492 | * @inheritdoc |
||
493 | */ |
||
494 | 48 | public function getMetadata($path) |
|
509 | |||
510 | /** |
||
511 | * @inheritdoc |
||
512 | */ |
||
513 | 6 | public function getTimestamp($path) |
|
517 | |||
518 | /** |
||
519 | * @inheritdoc |
||
520 | */ |
||
521 | 3 | public function getMimetype($path) |
|
531 | |||
532 | /** |
||
533 | * @inheritdoc |
||
534 | */ |
||
535 | 3 | public function createDir($dirname, Config $config) |
|
545 | |||
546 | /** |
||
547 | * @inheritdoc |
||
548 | */ |
||
549 | 6 | public function getVisibility($path) |
|
553 | |||
554 | /** |
||
555 | * @inheritdoc |
||
556 | */ |
||
557 | 12 | public function setVisibility($path, $visibility) |
|
569 | |||
570 | /** |
||
571 | * @inheritdoc |
||
572 | */ |
||
573 | 75 | public function isConnected() |
|
581 | } |
||
582 |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.