Completed
Pull Request — master (#32377)
by Piotr
08:55
created

Scanner::scan()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 4
dl 9
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
use OC\Files\Cache\Scanner as CacheScanner;
30
31
/**
32
 * Scanner for SharedStorage
33
 */
34
class Scanner extends CacheScanner {
35
36
	/**
37
	 * @var null|CacheScanner
38
	 */
39
	private $sourceScanner;
40
41
	/**
42
	 * Scan a single file and use source scanner if needed
43
	 *
44
	 * @inheritdoc
45
	 */
46
	public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) {
47
		$sourceScanner = $this->getSourceScanner();
48
		if ($sourceScanner instanceof NoopScanner) {
49
			// No Operation Scanner will not update share permission (scanFile won't call getData)
50
			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...
51
			return $sourceScanner->scanFile($internalPath, $reuseExisting, $parentId, $cacheData, $lock);
52
		} else {
53
			return parent::scanFile($file, $reuseExisting, $parentId, $cacheData, $lock);
54
		}
55
	}
56
57
	/**
58
	 * Returns metadata from the shared storage, but
59
	 * with permissions from the source storage.
60
	 *
61
	 * NOTE: This function gets called from within scanFile parent function
62
	 *
63
	 * @inheritdoc
64
	 */
65
	protected function getData($path) {
66
		$data = parent::getData($path);
67
		if ($data === null) {
68
			return null;
69
		}
70
		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...
71
		$data['permissions'] = $sourceStorage->getPermissions($internalPath);
72
		return $data;
73
	}
74
75
	private function getSourceScanner() {
76
		if ($this->sourceScanner) {
77
			return $this->sourceScanner;
78
		}
79
		if ($this->storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
80
			/** @var \OC\Files\Storage\Storage $storage */
81
			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...
82
			$this->sourceScanner = $storage->getScanner();
83
			return $this->sourceScanner;
84
		} else {
85
			return null;
86
		}
87
	}
88
}
89