Completed
Pull Request — master (#32337)
by Piotr
09:51
created

Scanner::getData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Joas Schilling <[email protected]>
4
 * @author Morris Jobke <[email protected]>
5
 * @author Robin Appelman <[email protected]>
6
 * @author Roeland Jago Douma <[email protected]>
7
 * @author Vincent Petry <[email protected]>
8
 *
9
 * @copyright Copyright (c) 2018, ownCloud GmbH
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
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, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OCA\Files_Sharing;
27
28
use OC\Files\ObjectStore\NoopScanner;
29
30
/**
31
 * Scanner for SharedStorage
32
 */
33
class Scanner extends \OC\Files\Cache\Scanner {
34
	private $sourceScanner;
35
36
	/**
37
	 * Returns metadata from the shared storage, but
38
	 * with permissions from the source storage.
39
	 *
40
	 * @param string $path path of the file for which to retrieve metadata
41
	 *
42
	 * @return array an array of metadata of the file
43
	 */
44
	public function getData($path) {
45
		$data = parent::getData($path);
46
		if ($data === null) {
47
			return null;
48
		}
49
		list($sourceStorage, $internalPath) = $this->storage->resolvePath($path);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Files\Storage\Storage as the method resolvePath() does only exist in the following implementations of said interface: OCA\Files_Sharing\SharedStorage, OC\Files\Storage\Wrapper\Jail.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
50
		$data['permissions'] = $sourceStorage->getPermissions($internalPath);
51
		return $data;
52
	}
53
54
	private function getSourceScanner() {
55
		if ($this->sourceScanner) {
56
			return $this->sourceScanner;
57
		}
58
		if ($this->storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
59
			/** @var \OC\Files\Storage\Storage $storage */
60
			list($storage) = $this->storage->resolvePath('');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Files\Storage\Storage as the method resolvePath() does only exist in the following implementations of said interface: OCA\Files_Sharing\SharedStorage, OC\Files\Storage\Wrapper\Jail.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
61
			$this->sourceScanner = $storage->getScanner();
62
			return $this->sourceScanner;
63
		} else {
64
			return null;
65
		}
66
	}
67
68
	/**
69
	 * scan a folder and all it's children,  use source scanner if needed
70
	 *
71
	 * @inheritdoc
72
	 */
73 View Code Duplication
	public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true) {
74
		$sourceScanner = $this->getSourceScanner();
75
		if ($sourceScanner instanceof NoopScanner) {
76
			list(, $internalPath) = $this->storage->resolvePath($path);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Files\Storage\Storage as the method resolvePath() does only exist in the following implementations of said interface: OCA\Files_Sharing\SharedStorage, OC\Files\Storage\Wrapper\Jail.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
77
			return $sourceScanner->scan($internalPath, $recursive, $reuse, $lock);
78
		} else {
79
			return parent::scan($path, $recursive, $reuse, $lock);
80
		}
81
	}
82
83
	/**
84
	 * scan a single file and use source scanner if needed
85
	 *
86
	 * @inheritdoc
87
	 */
88 View Code Duplication
	public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) {
89
		$sourceScanner = $this->getSourceScanner();
90
		if ($sourceScanner instanceof NoopScanner) {
91
			list(, $internalPath) = $this->storage->resolvePath($file);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Files\Storage\Storage as the method resolvePath() does only exist in the following implementations of said interface: OCA\Files_Sharing\SharedStorage, OC\Files\Storage\Wrapper\Jail.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
92
			return parent::scan($internalPath, $reuseExisting, $parentId, $cacheData, $lock);
0 ignored issues
show
Documentation introduced by
$reuseExisting is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Unused Code introduced by
The call to Scanner::scan() has too many arguments starting with $lock.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (scan() instead of scanFile()). Are you sure this is correct? If so, you might want to change this to $this->scan().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
93
		} else {
94
			return parent::scanFile($file, $reuseExisting, $parentId, $cacheData, $lock);
95
		}
96
	}
97
}
98