Completed
Pull Request — master (#4106)
by Blizzz
18:12 queued 02:03
created
apps/files_external/lib/AppInfo/Application.php 1 patch
Indentation   +103 added lines, -103 removed lines patch added patch discarded remove patch
@@ -52,108 +52,108 @@
 block discarded – undo
52 52
  */
53 53
 class Application extends App implements IBackendProvider, IAuthMechanismProvider {
54 54
 
55
-	public function __construct(array $urlParams = array()) {
56
-		parent::__construct('files_external', $urlParams);
57
-
58
-		$container = $this->getContainer();
59
-
60
-		$container->registerService('OCP\Files\Config\IUserMountCache', function (IAppContainer $c) {
61
-			return $c->getServer()->query('UserMountCache');
62
-		});
63
-
64
-		$backendService = $container->query('OCA\\Files_External\\Service\\BackendService');
65
-		$backendService->registerBackendProvider($this);
66
-		$backendService->registerAuthMechanismProvider($this);
67
-
68
-		// force-load auth mechanisms since some will register hooks
69
-		// TODO: obsolete these and use the TokenProvider to get the user's password from the session
70
-		$this->getAuthMechanisms();
71
-
72
-		// app developers: do NOT depend on this! it will disappear with oC 9.0!
73
-		\OC::$server->getEventDispatcher()->dispatch(
74
-			'OCA\\Files_External::loadAdditionalBackends'
75
-		);
76
-	}
77
-
78
-	/**
79
-	 * Register settings templates
80
-	 */
81
-	public function registerSettings() {
82
-		$container = $this->getContainer();
83
-		$userSession = $container->getServer()->getUserSession();
84
-		if (!$userSession->isLoggedIn()) {
85
-			return;
86
-		}
87
-		$backendService = $container->query('OCA\\Files_External\\Service\\BackendService');
88
-
89
-		/** @var \OCA\Files_External\Service\UserGlobalStoragesService $userGlobalStoragesService */
90
-		$userGlobalStoragesService = $container->query('OCA\Files_External\Service\UserGlobalStoragesService');
91
-		if (count($userGlobalStoragesService->getStorages()) > 0 || $backendService->isUserMountingAllowed()) {
92
-			\OCP\App::registerPersonal('files_external', 'personal');
93
-		}
94
-	}
95
-
96
-	/**
97
-	 * @{inheritdoc}
98
-	 */
99
-	public function getBackends() {
100
-		$container = $this->getContainer();
101
-
102
-		$backends = [
103
-			$container->query(Local::class),
104
-			$container->query(FTP::class),
105
-			$container->query(DAV::class),
106
-			$container->query(OwnCloud::class),
107
-			$container->query(SFTP::class),
108
-			$container->query(AmazonS3::class),
109
-			$container->query(Dropbox::class),
110
-			$container->query(Google::class),
111
-			$container->query(Swift::class),
112
-			$container->query(SFTP_Key::class),
113
-			$container->query(SMB::class),
114
-			$container->query(SMB_OC::class),
115
-			$container->query(SharePoint::class),
116
-		];
117
-
118
-		return $backends;
119
-	}
120
-
121
-	/**
122
-	 * @{inheritdoc}
123
-	 */
124
-	public function getAuthMechanisms() {
125
-		$container = $this->getContainer();
126
-
127
-		return [
128
-			// AuthMechanism::SCHEME_NULL mechanism
129
-			$container->query('OCA\Files_External\Lib\Auth\NullMechanism'),
130
-
131
-			// AuthMechanism::SCHEME_BUILTIN mechanism
132
-			$container->query('OCA\Files_External\Lib\Auth\Builtin'),
133
-
134
-			// AuthMechanism::SCHEME_PASSWORD mechanisms
135
-			$container->query('OCA\Files_External\Lib\Auth\Password\Password'),
136
-			$container->query('OCA\Files_External\Lib\Auth\Password\SessionCredentials'),
137
-			$container->query('OCA\Files_External\Lib\Auth\Password\LoginCredentials'),
138
-			$container->query('OCA\Files_External\Lib\Auth\Password\UserProvided'),
139
-			$container->query('OCA\Files_External\Lib\Auth\Password\GlobalAuth'),
140
-
141
-			// AuthMechanism::SCHEME_OAUTH1 mechanisms
142
-			$container->query('OCA\Files_External\Lib\Auth\OAuth1\OAuth1'),
143
-
144
-			// AuthMechanism::SCHEME_OAUTH2 mechanisms
145
-			$container->query('OCA\Files_External\Lib\Auth\OAuth2\OAuth2'),
146
-
147
-			// AuthMechanism::SCHEME_PUBLICKEY mechanisms
148
-			$container->query('OCA\Files_External\Lib\Auth\PublicKey\RSA'),
149
-
150
-			// AuthMechanism::SCHEME_OPENSTACK mechanisms
151
-			$container->query('OCA\Files_External\Lib\Auth\OpenStack\OpenStack'),
152
-			$container->query('OCA\Files_External\Lib\Auth\OpenStack\Rackspace'),
153
-
154
-			// Specialized mechanisms
155
-			$container->query('OCA\Files_External\Lib\Auth\AmazonS3\AccessKey'),
156
-		];
157
-	}
55
+    public function __construct(array $urlParams = array()) {
56
+        parent::__construct('files_external', $urlParams);
57
+
58
+        $container = $this->getContainer();
59
+
60
+        $container->registerService('OCP\Files\Config\IUserMountCache', function (IAppContainer $c) {
61
+            return $c->getServer()->query('UserMountCache');
62
+        });
63
+
64
+        $backendService = $container->query('OCA\\Files_External\\Service\\BackendService');
65
+        $backendService->registerBackendProvider($this);
66
+        $backendService->registerAuthMechanismProvider($this);
67
+
68
+        // force-load auth mechanisms since some will register hooks
69
+        // TODO: obsolete these and use the TokenProvider to get the user's password from the session
70
+        $this->getAuthMechanisms();
71
+
72
+        // app developers: do NOT depend on this! it will disappear with oC 9.0!
73
+        \OC::$server->getEventDispatcher()->dispatch(
74
+            'OCA\\Files_External::loadAdditionalBackends'
75
+        );
76
+    }
77
+
78
+    /**
79
+     * Register settings templates
80
+     */
81
+    public function registerSettings() {
82
+        $container = $this->getContainer();
83
+        $userSession = $container->getServer()->getUserSession();
84
+        if (!$userSession->isLoggedIn()) {
85
+            return;
86
+        }
87
+        $backendService = $container->query('OCA\\Files_External\\Service\\BackendService');
88
+
89
+        /** @var \OCA\Files_External\Service\UserGlobalStoragesService $userGlobalStoragesService */
90
+        $userGlobalStoragesService = $container->query('OCA\Files_External\Service\UserGlobalStoragesService');
91
+        if (count($userGlobalStoragesService->getStorages()) > 0 || $backendService->isUserMountingAllowed()) {
92
+            \OCP\App::registerPersonal('files_external', 'personal');
93
+        }
94
+    }
95
+
96
+    /**
97
+     * @{inheritdoc}
98
+     */
99
+    public function getBackends() {
100
+        $container = $this->getContainer();
101
+
102
+        $backends = [
103
+            $container->query(Local::class),
104
+            $container->query(FTP::class),
105
+            $container->query(DAV::class),
106
+            $container->query(OwnCloud::class),
107
+            $container->query(SFTP::class),
108
+            $container->query(AmazonS3::class),
109
+            $container->query(Dropbox::class),
110
+            $container->query(Google::class),
111
+            $container->query(Swift::class),
112
+            $container->query(SFTP_Key::class),
113
+            $container->query(SMB::class),
114
+            $container->query(SMB_OC::class),
115
+            $container->query(SharePoint::class),
116
+        ];
117
+
118
+        return $backends;
119
+    }
120
+
121
+    /**
122
+     * @{inheritdoc}
123
+     */
124
+    public function getAuthMechanisms() {
125
+        $container = $this->getContainer();
126
+
127
+        return [
128
+            // AuthMechanism::SCHEME_NULL mechanism
129
+            $container->query('OCA\Files_External\Lib\Auth\NullMechanism'),
130
+
131
+            // AuthMechanism::SCHEME_BUILTIN mechanism
132
+            $container->query('OCA\Files_External\Lib\Auth\Builtin'),
133
+
134
+            // AuthMechanism::SCHEME_PASSWORD mechanisms
135
+            $container->query('OCA\Files_External\Lib\Auth\Password\Password'),
136
+            $container->query('OCA\Files_External\Lib\Auth\Password\SessionCredentials'),
137
+            $container->query('OCA\Files_External\Lib\Auth\Password\LoginCredentials'),
138
+            $container->query('OCA\Files_External\Lib\Auth\Password\UserProvided'),
139
+            $container->query('OCA\Files_External\Lib\Auth\Password\GlobalAuth'),
140
+
141
+            // AuthMechanism::SCHEME_OAUTH1 mechanisms
142
+            $container->query('OCA\Files_External\Lib\Auth\OAuth1\OAuth1'),
143
+
144
+            // AuthMechanism::SCHEME_OAUTH2 mechanisms
145
+            $container->query('OCA\Files_External\Lib\Auth\OAuth2\OAuth2'),
146
+
147
+            // AuthMechanism::SCHEME_PUBLICKEY mechanisms
148
+            $container->query('OCA\Files_External\Lib\Auth\PublicKey\RSA'),
149
+
150
+            // AuthMechanism::SCHEME_OPENSTACK mechanisms
151
+            $container->query('OCA\Files_External\Lib\Auth\OpenStack\OpenStack'),
152
+            $container->query('OCA\Files_External\Lib\Auth\OpenStack\Rackspace'),
153
+
154
+            // Specialized mechanisms
155
+            $container->query('OCA\Files_External\Lib\Auth\AmazonS3\AccessKey'),
156
+        ];
157
+    }
158 158
 
159 159
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Backend/SharePoint.php 1 patch
Indentation   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -32,18 +32,18 @@
 block discarded – undo
32 32
 
33 33
 class SharePoint extends Backend {
34 34
 
35
-	public function __construct(IL10N $l, Password $legacyAuth) {
36
-		$this
37
-			->setIdentifier('sharepoint')
38
-			->setStorageClass(SharePointStorage::class)
39
-			->setText($l->t('SharePoint'))
40
-			->addParameters([
41
-				(new DefinitionParameter('host', $l->t('Host'))),
42
-				(new DefinitionParameter('documentLibrary', $l->t('Document Library'))),
43
-			])
44
-			->addAuthScheme(AuthMechanism::SCHEME_PASSWORD)
45
-			->setLegacyAuthMechanism($legacyAuth)
46
-		;
47
-	}
35
+    public function __construct(IL10N $l, Password $legacyAuth) {
36
+        $this
37
+            ->setIdentifier('sharepoint')
38
+            ->setStorageClass(SharePointStorage::class)
39
+            ->setText($l->t('SharePoint'))
40
+            ->addParameters([
41
+                (new DefinitionParameter('host', $l->t('Host'))),
42
+                (new DefinitionParameter('documentLibrary', $l->t('Document Library'))),
43
+            ])
44
+            ->addAuthScheme(AuthMechanism::SCHEME_PASSWORD)
45
+            ->setLegacyAuthMechanism($legacyAuth)
46
+        ;
47
+    }
48 48
 
49 49
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/SharePoint/ContextsFactory.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -30,12 +30,12 @@
 block discarded – undo
30 30
 
31 31
 class ContextsFactory {
32 32
 
33
-	public function getAuthContext($user, $password) {
34
-		return new NetworkCredentialContext($user, $password);
35
-	}
33
+    public function getAuthContext($user, $password) {
34
+        return new NetworkCredentialContext($user, $password);
35
+    }
36 36
 
37
-	public function getClientContext($server, IAuthenticationContext $authContext) {
38
-		return new ClientContext($server, $authContext);
39
-	}
37
+    public function getClientContext($server, IAuthenticationContext $authContext) {
38
+        return new ClientContext($server, $authContext);
39
+    }
40 40
 
41 41
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/SharePoint/SharePointClientFactory.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -24,19 +24,19 @@
 block discarded – undo
24 24
 namespace OCA\Files_External\Lib\SharePoint;
25 25
 
26 26
 class SharePointClientFactory {
27
-	/**
28
-	 * @param ContextsFactory $contextsFactory
29
-	 * @param string $sharePointUrl
30
-	 * @param array $credentials
31
-	 * @param string $documentLibraryTitle
32
-	 * @return SharePointClient
33
-	 */
34
-	public function getClient(
35
-		ContextsFactory $contextsFactory,
36
-		$sharePointUrl,
37
-		array $credentials,
38
-		$documentLibraryTitle)
39
-	{
40
-		return new SharePointClient($contextsFactory, $sharePointUrl, $credentials, $documentLibraryTitle);
41
-	}
27
+    /**
28
+     * @param ContextsFactory $contextsFactory
29
+     * @param string $sharePointUrl
30
+     * @param array $credentials
31
+     * @param string $documentLibraryTitle
32
+     * @return SharePointClient
33
+     */
34
+    public function getClient(
35
+        ContextsFactory $contextsFactory,
36
+        $sharePointUrl,
37
+        array $credentials,
38
+        $documentLibraryTitle)
39
+    {
40
+        return new SharePointClient($contextsFactory, $sharePointUrl, $credentials, $documentLibraryTitle);
41
+    }
42 42
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/SharePoint/SharePointClient.php 3 patches
Doc Comments   +9 added lines, -5 removed lines patch added patch discarded remove patch
@@ -56,6 +56,10 @@  discard block
 block discarded – undo
56 56
 	/** @var  string */
57 57
 	private $documentLibraryTitle;
58 58
 
59
+	/**
60
+	 * @param string $sharePointUrl
61
+	 * @param string $documentLibraryTitle
62
+	 */
59 63
 	public function __construct(ContextsFactory $contextsFactory, $sharePointUrl, array $credentials, $documentLibraryTitle) {
60 64
 		$this->contextsFactory = $contextsFactory;
61 65
 		$this->sharePointUrl = $sharePointUrl;
@@ -116,7 +120,7 @@  discard block
 block discarded – undo
116 120
 	 * adds a folder on the given server path
117 121
 	 *
118 122
 	 * @param string $relativeServerPath
119
-	 * @return Folder
123
+	 * @return string
120 124
 	 * @throws \Exception
121 125
 	 */
122 126
 	public function createFolder($relativeServerPath) {
@@ -137,7 +141,7 @@  discard block
 block discarded – undo
137 141
 	/**
138 142
 	 * downloads a file by passing it directly into a file resource
139 143
 	 *
140
-	 * @param $relativeServerPath
144
+	 * @param string $relativeServerPath
141 145
 	 * @param resource $fp a file resource open for writing
142 146
 	 * @return \Office365\PHP\Client\Runtime\OData\ODataPayload
143 147
 	 * @throws \Exception
@@ -203,9 +207,9 @@  discard block
 block discarded – undo
203 207
 	 * needs to reimplement adding-file-tp-sp-logic quite some… perhaps upload an
204 208
 	 * empty file and continue with overwriteFileViaStream?
205 209
 	 *
206
-	 * @param $relativeServerPath
207
-	 * @param $content
208
-	 * @return File
210
+	 * @param string $relativeServerPath
211
+	 * @param string $content
212
+	 * @return string
209 213
 	 * @throws \Exception
210 214
 	 */
211 215
 	public function uploadNewFile($relativeServerPath, $content) {
Please login to merge, or discard this patch.
Indentation   +382 added lines, -382 removed lines patch added patch discarded remove patch
@@ -35,386 +35,386 @@
 block discarded – undo
35 35
 use Office365\PHP\Client\SharePoint\SPList;
36 36
 
37 37
 class SharePointClient {
38
-	/** @var  ClientContext */
39
-	protected $context;
40
-
41
-	/** @var  AuthenticationContext */
42
-	protected $authContext;
43
-
44
-	/** @var  SPList */
45
-	protected $documentLibrary;
46
-
47
-	/** @var ContextsFactory */
48
-	private $contextsFactory;
49
-
50
-	/** @var  string */
51
-	private $sharePointUrl;
52
-
53
-	/** @var string[] */
54
-	private $credentials;
55
-
56
-	/** @var  string */
57
-	private $documentLibraryTitle;
58
-
59
-	public function __construct(ContextsFactory $contextsFactory, $sharePointUrl, array $credentials, $documentLibraryTitle) {
60
-		$this->contextsFactory = $contextsFactory;
61
-		$this->sharePointUrl = $sharePointUrl;
62
-		$this->credentials = $credentials;
63
-		$this->documentLibraryTitle = $documentLibraryTitle;
64
-	}
65
-
66
-	/**
67
-	 * @param string $path
68
-	 * @param array $properties
69
-	 * @return File|Folder
70
-	 * @throws \Exception
71
-	 */
72
-	public function fetchFileOrFolder($path, array $properties = null) {
73
-		$fetchFileFunc = function ($path, $props) { return $this->fetchFile($path, $props);};
74
-		$fetchFolderFunc = function ($path, $props) { return $this->fetchFolder($path, $props);};
75
-		$fetchers = [ $fetchFileFunc, $fetchFolderFunc ];
76
-		if(strpos($path, '.') === false) {
77
-			$fetchers = array_reverse($fetchers);
78
-		}
79
-
80
-		foreach ($fetchers as $fetchFunction) {
81
-			try {
82
-				$instance = call_user_func_array($fetchFunction, [$path, $properties]);
83
-				return $instance;
84
-			} catch (\Exception $e) {
85
-				if(preg_match('/^The file \/.* does not exist\.$/', $e->getMessage()) !== 1
86
-					&& $e->getMessage() !== 'Unknown Error'
87
-					&& $e->getMessage() !== 'File Not Found.'
88
-				) {
89
-					$this->resetClientContext();
90
-					# Unexpected Exception, pass it on
91
-					throw $e;
92
-				}
93
-			}
94
-			$this->resetClientContext();
95
-		}
96
-
97
-		# Nothing succeeded, quit with not found
98
-		throw new NotFoundException('File or Folder not found');
99
-	}
100
-
101
-	public function fetchFile($relativeServerPath, array $properties = null) {
102
-		$this->ensureConnection();
103
-		$file = $this->context->getWeb()->getFileByServerRelativeUrl($relativeServerPath);
104
-		$this->loadAndExecute($file, $properties);
105
-		return $file;
106
-	}
107
-
108
-	public function fetchFolder($relativeServerPath, array $properties = null) {
109
-		$this->ensureConnection();
110
-		$folder = $this->context->getWeb()->getFolderByServerRelativeUrl($relativeServerPath);
111
-		$this->loadAndExecute($folder, $properties);
112
-		return $folder;
113
-	}
114
-
115
-	/**
116
-	 * adds a folder on the given server path
117
-	 *
118
-	 * @param string $relativeServerPath
119
-	 * @return Folder
120
-	 * @throws \Exception
121
-	 */
122
-	public function createFolder($relativeServerPath) {
123
-		$this->ensureConnection();
124
-
125
-		$parentFolder = $this->context->getWeb()->getFolderByServerRelativeUrl(dirname($relativeServerPath));
126
-		$folder = $parentFolder->getFolders()->add(basename($relativeServerPath));
127
-
128
-		try {
129
-			$this->context->executeQuery();
130
-			return $folder;
131
-		} catch (\Exception $e) {
132
-			$this->resetClientContext();
133
-			throw $e;
134
-		}
135
-	}
136
-
137
-	/**
138
-	 * downloads a file by passing it directly into a file resource
139
-	 *
140
-	 * @param $relativeServerPath
141
-	 * @param resource $fp a file resource open for writing
142
-	 * @return \Office365\PHP\Client\Runtime\OData\ODataPayload
143
-	 * @throws \Exception
144
-	 */
145
-	public function getFileViaStream($relativeServerPath, $fp) {
146
-		if(!is_resource($fp)) {
147
-			throw new \InvalidArgumentException('file resource expected');
148
-		}
149
-		$relativeServerPath = rawurlencode($relativeServerPath);
150
-		$url = $this->context->getServiceRootUrl() .
151
-			"web/getfilebyserverrelativeurl('$relativeServerPath')/\$value";
152
-		$options = new RequestOptions($url);
153
-		$options->StreamHandle = $fp;
154
-
155
-		try {
156
-			$ok = $this->context->executeQueryDirect($options);
157
-		} catch(\Exception $e) {
158
-			$this->resetClientContext();
159
-			throw $e;
160
-		}
161
-		return $ok;
162
-	}
163
-
164
-	/**
165
-	 * fetches the file content (aka download)
166
-	 *
167
-	 * @param $relativeServerPath
168
-	 * @return string the file content
169
-	 */
170
-	public function getFile($relativeServerPath) {
171
-		return File::openBinary($this->context, $relativeServerPath);
172
-	}
173
-
174
-	/**
175
-	 * @param string $relativeServerPath
176
-	 * @param resource $fp
177
-	 * @param string $localPath - we need to pass the file size for the content length header
178
-	 * @return bool
179
-	 * @throws \Exception
180
-	 */
181
-	public function overwriteFileViaStream($relativeServerPath, $fp, $localPath) {
182
-		$serverRelativeUrl = rawurlencode($relativeServerPath);
183
-		$url = $this->context->getServiceRootUrl() . "web/getfilebyserverrelativeurl('$serverRelativeUrl')/\$value";
184
-		$request = new RequestOptions($url);
185
-		$request->Method = 'POST'; // yes, POST
186
-		$request->addCustomHeader('X-HTTP-Method','PUT'); // yes, PUT
187
-		$this->context->ensureFormDigest($request);
188
-		//FIXME: Proper StreamHandle handling is not upstream, yet
189
-		$request->StreamHandle = $fp;
190
-		$request->addCustomHeader("content-length", filesize($localPath));
191
-
192
-		try {
193
-			$ok = $this->context->executeQueryDirect($request);
194
-		} catch(\Exception $e) {
195
-			$this->resetClientContext();
196
-			throw $e;
197
-		}
198
-		return $ok !== false;
199
-	}
200
-
201
-	/**
202
-	 * FIXME: use StreamHandle as in  overwriteFileViaStream for uploading a file
203
-	 * needs to reimplement adding-file-tp-sp-logic quite some… perhaps upload an
204
-	 * empty file and continue with overwriteFileViaStream?
205
-	 *
206
-	 * @param $relativeServerPath
207
-	 * @param $content
208
-	 * @return File
209
-	 * @throws \Exception
210
-	 */
211
-	public function uploadNewFile($relativeServerPath, $content) {
212
-		$parentFolder = $this->context->getWeb()->getFolderByServerRelativeUrl(dirname($relativeServerPath));
213
-		$fileCollection = $parentFolder->getFiles();
214
-
215
-		$info = new FileCreationInformation();
216
-		$info->Content = $content;
217
-		$info->Url = basename($relativeServerPath);
218
-		$file = $fileCollection->add($info);
219
-		try {
220
-			$this->context->executeQuery();
221
-			return $file;
222
-		} catch(\Exception $e) {
223
-			$this->resetClientContext();
224
-			throw $e;
225
-		}
226
-	}
227
-
228
-	/**
229
-	 * moves a file or a folder to the given destination
230
-	 *
231
-	 * @param string $oldPath
232
-	 * @param string $newPath
233
-	 * @return bool
234
-	 * @throws \Exception
235
-	 */
236
-	public function rename($oldPath, $newPath) {
237
-		$this->ensureConnection();
238
-
239
-		try {
240
-			$item = $this->fetchFileOrFolder($oldPath);
241
-			if($item instanceof File) {
242
-				$this->renameFile($item, $newPath);
243
-			} else if($item instanceof Folder) {
244
-				$this->renameFolder($item, $newPath);
245
-			} else {
246
-				return false;
247
-			}
248
-			return true;
249
-		} catch (\Exception $e) {
250
-			$this->resetClientContext();
251
-			throw $e;
252
-		}
253
-	}
254
-
255
-	/**
256
-	 * renames a folder
257
-	 *
258
-	 * @param Folder $folder
259
-	 * @param string $newPath
260
-	 */
261
-	private function renameFolder(Folder $folder, $newPath) {
262
-		$folder->rename(basename($newPath));
263
-		$this->context->executeQuery();
264
-	}
265
-
266
-	/**
267
-	 * moves a file
268
-	 *
269
-	 * @param File $file
270
-	 * @param string $newPath
271
-	 */
272
-	private function renameFile(File $file, $newPath) {
273
-		$newPath = rawurlencode($newPath);
274
-		$file->moveTo($newPath, 0);
275
-		$this->context->executeQuery();
276
-		#$req = $this->debugGetLastRequest();
277
-	}
278
-
279
-	private function debugGetLastRequest() {
280
-		$requestHistory = Requests::getHistory();
281
-		$request = array_pop($requestHistory);
282
-		return $request;
283
-	}
284
-
285
-	public function delete(ClientObject $item) {
286
-		$this->ensureConnection();
287
-		try {
288
-			if ($item instanceof File) {
289
-				$this->deleteFile($item);
290
-			} else if ($item instanceof Folder) {
291
-				$this->deleteFolder($item);
292
-			}
293
-		} catch(\Exception $e) {
294
-			$this->resetClientContext();
295
-			throw $e;
296
-		}
297
-	}
298
-
299
-	/**
300
-	 * deletes the given file on SP
301
-	 *
302
-	 * @param File $file
303
-	 * @throws \Exception
304
-	 */
305
-	public function deleteFile(File $file) {
306
-		$file->recycle();
307
-		$this->context->executeQuery();
308
-	}
309
-
310
-	public function deleteFolder(Folder $folder) {
311
-		$folder->deleteObject();
312
-		$this->context->executeQuery();
313
-	}
314
-
315
-	/**
316
-	 * @param $relativeServerPath
317
-	 * @param null $properties
318
-	 * @param Folder $folder
319
-	 * @return ClientObjectCollection[]
320
-	 */
321
-	public function fetchFolderContents($relativeServerPath, $properties = null, Folder $folder = null) {
322
-		$this->ensureConnection();
323
-		if($folder === null) {
324
-			$folder = $this->context->getWeb()->getFolderByServerRelativeUrl($relativeServerPath);
325
-		}
326
-
327
-		$folderCollection = $folder->getFolders();
328
-		$fileCollection = $folder->getFiles();
329
-		$this->context->load($folderCollection, $properties);
330
-		$this->context->load($fileCollection, $properties);
331
-		$this->context->executeQuery();
332
-
333
-		$collections = ['folders' => $folderCollection, 'files' => $fileCollection];
334
-
335
-		return $collections;
336
-	}
337
-
338
-	public function isHidden(ClientObject $file) {
339
-		// ClientObject itself does not have getListItemAllFields but is
340
-		// the common denominator of File and Folder
341
-		if(!$file instanceof File && !$file instanceof Folder) {
342
-			throw new \InvalidArgumentException('File or Folder expected');
343
-		}
344
-		if($file instanceof File) {
345
-			// it's expensive, we only check folders
346
-			return false;
347
-		}
348
-		$fields = $file->getListItemAllFields();
349
-		if($fields->getProperties() === []) {
350
-			$this->loadAndExecute($fields, ['Id', 'Hidden']);
351
-		}
352
-		$id = $fields->getProperty('Id');
353
-		$hidden = $fields->getProperty('Hidden'); // TODO: get someone to test this in SP 2013
354
-		if($hidden === false || $id !== null) {
355
-			// avoids listing hidden "Forms" folder (and its contents).
356
-			// Have not found a different mechanism to detect whether
357
-			// a file or folder is hidden. There used to be a Hidden
358
-			// field, but seems to have gone (since SP 2016?).
359
-			return false;
360
-		}
361
-		return true;
362
-	}
363
-
364
-	public function loadAndExecute(ClientObject $object, array $properties = null) {
365
-		$this->context->load($object, $properties);
366
-		$this->context->executeQuery();
367
-	}
368
-
369
-	/**
370
-	 * @return SPList
371
-	 * @throws NotFoundException
372
-	 */
373
-	private function getDocumentLibrary() {
374
-		if(!is_null($this->documentLibrary)) {
375
-			return $this->documentLibrary;
376
-		}
377
-
378
-		$lists = $this->context->getWeb()->getLists()->filter('Title eq \'' . $this->documentLibraryTitle . '\'')->top(1);
379
-		$this->context->load($lists)->executeQuery();
380
-		if ($lists->getCount() === 1 && $lists->getData()[0] instanceof SPList) {
381
-			$this->documentLibrary = $lists->getData()[0];
382
-			return $this->documentLibrary;
383
-		}
384
-
385
-		throw new NotFoundException('List not found');
386
-	}
387
-
388
-	/**
389
-	 * Set up necessary contexts for authentication and access to SharePoint
390
-	 *
391
-	 * @throws \InvalidArgumentException
392
-	 */
393
-	private function ensureConnection() {
394
-		if($this->context instanceof ClientContext) {
395
-			return;
396
-		}
397
-
398
-		if(!is_string($this->credentials['user']) || empty($this->credentials['user'])) {
399
-			throw new \InvalidArgumentException('No user given');
400
-		}
401
-		if(!is_string($this->credentials['password']) || empty($this->credentials['password'])) {
402
-			throw new \InvalidArgumentException('No password given');
403
-		}
404
-		$this->authContext = $this->contextsFactory->getAuthContext($this->credentials['user'], $this->credentials['password']);
405
-		$this->authContext->AuthType = CURLAUTH_NTLM;		# Basic auth does not work somehow…
406
-		$this->context = $this->contextsFactory->getClientContext($this->sharePointUrl, $this->authContext);
407
-		# Auth is not triggered yet. This will happen when something is requested from SharePoint (on demand), e.g.:
408
-	}
409
-
410
-	/**
411
-	 * resets the sharepoint client context
412
-	 *
413
-	 * Usually executed, when a query resulted into an exception. The faulty
414
-	 * query is not removed by default.
415
-	 */
416
-	private function resetClientContext() {
417
-		//FIXME: resetQueries method did not go upstream yet
418
-		$this->context->getPendingRequest()->resetQueries();
419
-	}
38
+    /** @var  ClientContext */
39
+    protected $context;
40
+
41
+    /** @var  AuthenticationContext */
42
+    protected $authContext;
43
+
44
+    /** @var  SPList */
45
+    protected $documentLibrary;
46
+
47
+    /** @var ContextsFactory */
48
+    private $contextsFactory;
49
+
50
+    /** @var  string */
51
+    private $sharePointUrl;
52
+
53
+    /** @var string[] */
54
+    private $credentials;
55
+
56
+    /** @var  string */
57
+    private $documentLibraryTitle;
58
+
59
+    public function __construct(ContextsFactory $contextsFactory, $sharePointUrl, array $credentials, $documentLibraryTitle) {
60
+        $this->contextsFactory = $contextsFactory;
61
+        $this->sharePointUrl = $sharePointUrl;
62
+        $this->credentials = $credentials;
63
+        $this->documentLibraryTitle = $documentLibraryTitle;
64
+    }
65
+
66
+    /**
67
+     * @param string $path
68
+     * @param array $properties
69
+     * @return File|Folder
70
+     * @throws \Exception
71
+     */
72
+    public function fetchFileOrFolder($path, array $properties = null) {
73
+        $fetchFileFunc = function ($path, $props) { return $this->fetchFile($path, $props);};
74
+        $fetchFolderFunc = function ($path, $props) { return $this->fetchFolder($path, $props);};
75
+        $fetchers = [ $fetchFileFunc, $fetchFolderFunc ];
76
+        if(strpos($path, '.') === false) {
77
+            $fetchers = array_reverse($fetchers);
78
+        }
79
+
80
+        foreach ($fetchers as $fetchFunction) {
81
+            try {
82
+                $instance = call_user_func_array($fetchFunction, [$path, $properties]);
83
+                return $instance;
84
+            } catch (\Exception $e) {
85
+                if(preg_match('/^The file \/.* does not exist\.$/', $e->getMessage()) !== 1
86
+                    && $e->getMessage() !== 'Unknown Error'
87
+                    && $e->getMessage() !== 'File Not Found.'
88
+                ) {
89
+                    $this->resetClientContext();
90
+                    # Unexpected Exception, pass it on
91
+                    throw $e;
92
+                }
93
+            }
94
+            $this->resetClientContext();
95
+        }
96
+
97
+        # Nothing succeeded, quit with not found
98
+        throw new NotFoundException('File or Folder not found');
99
+    }
100
+
101
+    public function fetchFile($relativeServerPath, array $properties = null) {
102
+        $this->ensureConnection();
103
+        $file = $this->context->getWeb()->getFileByServerRelativeUrl($relativeServerPath);
104
+        $this->loadAndExecute($file, $properties);
105
+        return $file;
106
+    }
107
+
108
+    public function fetchFolder($relativeServerPath, array $properties = null) {
109
+        $this->ensureConnection();
110
+        $folder = $this->context->getWeb()->getFolderByServerRelativeUrl($relativeServerPath);
111
+        $this->loadAndExecute($folder, $properties);
112
+        return $folder;
113
+    }
114
+
115
+    /**
116
+     * adds a folder on the given server path
117
+     *
118
+     * @param string $relativeServerPath
119
+     * @return Folder
120
+     * @throws \Exception
121
+     */
122
+    public function createFolder($relativeServerPath) {
123
+        $this->ensureConnection();
124
+
125
+        $parentFolder = $this->context->getWeb()->getFolderByServerRelativeUrl(dirname($relativeServerPath));
126
+        $folder = $parentFolder->getFolders()->add(basename($relativeServerPath));
127
+
128
+        try {
129
+            $this->context->executeQuery();
130
+            return $folder;
131
+        } catch (\Exception $e) {
132
+            $this->resetClientContext();
133
+            throw $e;
134
+        }
135
+    }
136
+
137
+    /**
138
+     * downloads a file by passing it directly into a file resource
139
+     *
140
+     * @param $relativeServerPath
141
+     * @param resource $fp a file resource open for writing
142
+     * @return \Office365\PHP\Client\Runtime\OData\ODataPayload
143
+     * @throws \Exception
144
+     */
145
+    public function getFileViaStream($relativeServerPath, $fp) {
146
+        if(!is_resource($fp)) {
147
+            throw new \InvalidArgumentException('file resource expected');
148
+        }
149
+        $relativeServerPath = rawurlencode($relativeServerPath);
150
+        $url = $this->context->getServiceRootUrl() .
151
+            "web/getfilebyserverrelativeurl('$relativeServerPath')/\$value";
152
+        $options = new RequestOptions($url);
153
+        $options->StreamHandle = $fp;
154
+
155
+        try {
156
+            $ok = $this->context->executeQueryDirect($options);
157
+        } catch(\Exception $e) {
158
+            $this->resetClientContext();
159
+            throw $e;
160
+        }
161
+        return $ok;
162
+    }
163
+
164
+    /**
165
+     * fetches the file content (aka download)
166
+     *
167
+     * @param $relativeServerPath
168
+     * @return string the file content
169
+     */
170
+    public function getFile($relativeServerPath) {
171
+        return File::openBinary($this->context, $relativeServerPath);
172
+    }
173
+
174
+    /**
175
+     * @param string $relativeServerPath
176
+     * @param resource $fp
177
+     * @param string $localPath - we need to pass the file size for the content length header
178
+     * @return bool
179
+     * @throws \Exception
180
+     */
181
+    public function overwriteFileViaStream($relativeServerPath, $fp, $localPath) {
182
+        $serverRelativeUrl = rawurlencode($relativeServerPath);
183
+        $url = $this->context->getServiceRootUrl() . "web/getfilebyserverrelativeurl('$serverRelativeUrl')/\$value";
184
+        $request = new RequestOptions($url);
185
+        $request->Method = 'POST'; // yes, POST
186
+        $request->addCustomHeader('X-HTTP-Method','PUT'); // yes, PUT
187
+        $this->context->ensureFormDigest($request);
188
+        //FIXME: Proper StreamHandle handling is not upstream, yet
189
+        $request->StreamHandle = $fp;
190
+        $request->addCustomHeader("content-length", filesize($localPath));
191
+
192
+        try {
193
+            $ok = $this->context->executeQueryDirect($request);
194
+        } catch(\Exception $e) {
195
+            $this->resetClientContext();
196
+            throw $e;
197
+        }
198
+        return $ok !== false;
199
+    }
200
+
201
+    /**
202
+     * FIXME: use StreamHandle as in  overwriteFileViaStream for uploading a file
203
+     * needs to reimplement adding-file-tp-sp-logic quite some… perhaps upload an
204
+     * empty file and continue with overwriteFileViaStream?
205
+     *
206
+     * @param $relativeServerPath
207
+     * @param $content
208
+     * @return File
209
+     * @throws \Exception
210
+     */
211
+    public function uploadNewFile($relativeServerPath, $content) {
212
+        $parentFolder = $this->context->getWeb()->getFolderByServerRelativeUrl(dirname($relativeServerPath));
213
+        $fileCollection = $parentFolder->getFiles();
214
+
215
+        $info = new FileCreationInformation();
216
+        $info->Content = $content;
217
+        $info->Url = basename($relativeServerPath);
218
+        $file = $fileCollection->add($info);
219
+        try {
220
+            $this->context->executeQuery();
221
+            return $file;
222
+        } catch(\Exception $e) {
223
+            $this->resetClientContext();
224
+            throw $e;
225
+        }
226
+    }
227
+
228
+    /**
229
+     * moves a file or a folder to the given destination
230
+     *
231
+     * @param string $oldPath
232
+     * @param string $newPath
233
+     * @return bool
234
+     * @throws \Exception
235
+     */
236
+    public function rename($oldPath, $newPath) {
237
+        $this->ensureConnection();
238
+
239
+        try {
240
+            $item = $this->fetchFileOrFolder($oldPath);
241
+            if($item instanceof File) {
242
+                $this->renameFile($item, $newPath);
243
+            } else if($item instanceof Folder) {
244
+                $this->renameFolder($item, $newPath);
245
+            } else {
246
+                return false;
247
+            }
248
+            return true;
249
+        } catch (\Exception $e) {
250
+            $this->resetClientContext();
251
+            throw $e;
252
+        }
253
+    }
254
+
255
+    /**
256
+     * renames a folder
257
+     *
258
+     * @param Folder $folder
259
+     * @param string $newPath
260
+     */
261
+    private function renameFolder(Folder $folder, $newPath) {
262
+        $folder->rename(basename($newPath));
263
+        $this->context->executeQuery();
264
+    }
265
+
266
+    /**
267
+     * moves a file
268
+     *
269
+     * @param File $file
270
+     * @param string $newPath
271
+     */
272
+    private function renameFile(File $file, $newPath) {
273
+        $newPath = rawurlencode($newPath);
274
+        $file->moveTo($newPath, 0);
275
+        $this->context->executeQuery();
276
+        #$req = $this->debugGetLastRequest();
277
+    }
278
+
279
+    private function debugGetLastRequest() {
280
+        $requestHistory = Requests::getHistory();
281
+        $request = array_pop($requestHistory);
282
+        return $request;
283
+    }
284
+
285
+    public function delete(ClientObject $item) {
286
+        $this->ensureConnection();
287
+        try {
288
+            if ($item instanceof File) {
289
+                $this->deleteFile($item);
290
+            } else if ($item instanceof Folder) {
291
+                $this->deleteFolder($item);
292
+            }
293
+        } catch(\Exception $e) {
294
+            $this->resetClientContext();
295
+            throw $e;
296
+        }
297
+    }
298
+
299
+    /**
300
+     * deletes the given file on SP
301
+     *
302
+     * @param File $file
303
+     * @throws \Exception
304
+     */
305
+    public function deleteFile(File $file) {
306
+        $file->recycle();
307
+        $this->context->executeQuery();
308
+    }
309
+
310
+    public function deleteFolder(Folder $folder) {
311
+        $folder->deleteObject();
312
+        $this->context->executeQuery();
313
+    }
314
+
315
+    /**
316
+     * @param $relativeServerPath
317
+     * @param null $properties
318
+     * @param Folder $folder
319
+     * @return ClientObjectCollection[]
320
+     */
321
+    public function fetchFolderContents($relativeServerPath, $properties = null, Folder $folder = null) {
322
+        $this->ensureConnection();
323
+        if($folder === null) {
324
+            $folder = $this->context->getWeb()->getFolderByServerRelativeUrl($relativeServerPath);
325
+        }
326
+
327
+        $folderCollection = $folder->getFolders();
328
+        $fileCollection = $folder->getFiles();
329
+        $this->context->load($folderCollection, $properties);
330
+        $this->context->load($fileCollection, $properties);
331
+        $this->context->executeQuery();
332
+
333
+        $collections = ['folders' => $folderCollection, 'files' => $fileCollection];
334
+
335
+        return $collections;
336
+    }
337
+
338
+    public function isHidden(ClientObject $file) {
339
+        // ClientObject itself does not have getListItemAllFields but is
340
+        // the common denominator of File and Folder
341
+        if(!$file instanceof File && !$file instanceof Folder) {
342
+            throw new \InvalidArgumentException('File or Folder expected');
343
+        }
344
+        if($file instanceof File) {
345
+            // it's expensive, we only check folders
346
+            return false;
347
+        }
348
+        $fields = $file->getListItemAllFields();
349
+        if($fields->getProperties() === []) {
350
+            $this->loadAndExecute($fields, ['Id', 'Hidden']);
351
+        }
352
+        $id = $fields->getProperty('Id');
353
+        $hidden = $fields->getProperty('Hidden'); // TODO: get someone to test this in SP 2013
354
+        if($hidden === false || $id !== null) {
355
+            // avoids listing hidden "Forms" folder (and its contents).
356
+            // Have not found a different mechanism to detect whether
357
+            // a file or folder is hidden. There used to be a Hidden
358
+            // field, but seems to have gone (since SP 2016?).
359
+            return false;
360
+        }
361
+        return true;
362
+    }
363
+
364
+    public function loadAndExecute(ClientObject $object, array $properties = null) {
365
+        $this->context->load($object, $properties);
366
+        $this->context->executeQuery();
367
+    }
368
+
369
+    /**
370
+     * @return SPList
371
+     * @throws NotFoundException
372
+     */
373
+    private function getDocumentLibrary() {
374
+        if(!is_null($this->documentLibrary)) {
375
+            return $this->documentLibrary;
376
+        }
377
+
378
+        $lists = $this->context->getWeb()->getLists()->filter('Title eq \'' . $this->documentLibraryTitle . '\'')->top(1);
379
+        $this->context->load($lists)->executeQuery();
380
+        if ($lists->getCount() === 1 && $lists->getData()[0] instanceof SPList) {
381
+            $this->documentLibrary = $lists->getData()[0];
382
+            return $this->documentLibrary;
383
+        }
384
+
385
+        throw new NotFoundException('List not found');
386
+    }
387
+
388
+    /**
389
+     * Set up necessary contexts for authentication and access to SharePoint
390
+     *
391
+     * @throws \InvalidArgumentException
392
+     */
393
+    private function ensureConnection() {
394
+        if($this->context instanceof ClientContext) {
395
+            return;
396
+        }
397
+
398
+        if(!is_string($this->credentials['user']) || empty($this->credentials['user'])) {
399
+            throw new \InvalidArgumentException('No user given');
400
+        }
401
+        if(!is_string($this->credentials['password']) || empty($this->credentials['password'])) {
402
+            throw new \InvalidArgumentException('No password given');
403
+        }
404
+        $this->authContext = $this->contextsFactory->getAuthContext($this->credentials['user'], $this->credentials['password']);
405
+        $this->authContext->AuthType = CURLAUTH_NTLM;		# Basic auth does not work somehow…
406
+        $this->context = $this->contextsFactory->getClientContext($this->sharePointUrl, $this->authContext);
407
+        # Auth is not triggered yet. This will happen when something is requested from SharePoint (on demand), e.g.:
408
+    }
409
+
410
+    /**
411
+     * resets the sharepoint client context
412
+     *
413
+     * Usually executed, when a query resulted into an exception. The faulty
414
+     * query is not removed by default.
415
+     */
416
+    private function resetClientContext() {
417
+        //FIXME: resetQueries method did not go upstream yet
418
+        $this->context->getPendingRequest()->resetQueries();
419
+    }
420 420
 }
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -70,10 +70,10 @@  discard block
 block discarded – undo
70 70
 	 * @throws \Exception
71 71
 	 */
72 72
 	public function fetchFileOrFolder($path, array $properties = null) {
73
-		$fetchFileFunc = function ($path, $props) { return $this->fetchFile($path, $props);};
74
-		$fetchFolderFunc = function ($path, $props) { return $this->fetchFolder($path, $props);};
75
-		$fetchers = [ $fetchFileFunc, $fetchFolderFunc ];
76
-		if(strpos($path, '.') === false) {
73
+		$fetchFileFunc = function($path, $props) { return $this->fetchFile($path, $props); };
74
+		$fetchFolderFunc = function($path, $props) { return $this->fetchFolder($path, $props); };
75
+		$fetchers = [$fetchFileFunc, $fetchFolderFunc];
76
+		if (strpos($path, '.') === false) {
77 77
 			$fetchers = array_reverse($fetchers);
78 78
 		}
79 79
 
@@ -82,7 +82,7 @@  discard block
 block discarded – undo
82 82
 				$instance = call_user_func_array($fetchFunction, [$path, $properties]);
83 83
 				return $instance;
84 84
 			} catch (\Exception $e) {
85
-				if(preg_match('/^The file \/.* does not exist\.$/', $e->getMessage()) !== 1
85
+				if (preg_match('/^The file \/.* does not exist\.$/', $e->getMessage()) !== 1
86 86
 					&& $e->getMessage() !== 'Unknown Error'
87 87
 					&& $e->getMessage() !== 'File Not Found.'
88 88
 				) {
@@ -143,18 +143,18 @@  discard block
 block discarded – undo
143 143
 	 * @throws \Exception
144 144
 	 */
145 145
 	public function getFileViaStream($relativeServerPath, $fp) {
146
-		if(!is_resource($fp)) {
146
+		if (!is_resource($fp)) {
147 147
 			throw new \InvalidArgumentException('file resource expected');
148 148
 		}
149 149
 		$relativeServerPath = rawurlencode($relativeServerPath);
150
-		$url = $this->context->getServiceRootUrl() .
150
+		$url = $this->context->getServiceRootUrl().
151 151
 			"web/getfilebyserverrelativeurl('$relativeServerPath')/\$value";
152 152
 		$options = new RequestOptions($url);
153 153
 		$options->StreamHandle = $fp;
154 154
 
155 155
 		try {
156 156
 			$ok = $this->context->executeQueryDirect($options);
157
-		} catch(\Exception $e) {
157
+		} catch (\Exception $e) {
158 158
 			$this->resetClientContext();
159 159
 			throw $e;
160 160
 		}
@@ -180,10 +180,10 @@  discard block
 block discarded – undo
180 180
 	 */
181 181
 	public function overwriteFileViaStream($relativeServerPath, $fp, $localPath) {
182 182
 		$serverRelativeUrl = rawurlencode($relativeServerPath);
183
-		$url = $this->context->getServiceRootUrl() . "web/getfilebyserverrelativeurl('$serverRelativeUrl')/\$value";
183
+		$url = $this->context->getServiceRootUrl()."web/getfilebyserverrelativeurl('$serverRelativeUrl')/\$value";
184 184
 		$request = new RequestOptions($url);
185 185
 		$request->Method = 'POST'; // yes, POST
186
-		$request->addCustomHeader('X-HTTP-Method','PUT'); // yes, PUT
186
+		$request->addCustomHeader('X-HTTP-Method', 'PUT'); // yes, PUT
187 187
 		$this->context->ensureFormDigest($request);
188 188
 		//FIXME: Proper StreamHandle handling is not upstream, yet
189 189
 		$request->StreamHandle = $fp;
@@ -191,7 +191,7 @@  discard block
 block discarded – undo
191 191
 
192 192
 		try {
193 193
 			$ok = $this->context->executeQueryDirect($request);
194
-		} catch(\Exception $e) {
194
+		} catch (\Exception $e) {
195 195
 			$this->resetClientContext();
196 196
 			throw $e;
197 197
 		}
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
 		try {
220 220
 			$this->context->executeQuery();
221 221
 			return $file;
222
-		} catch(\Exception $e) {
222
+		} catch (\Exception $e) {
223 223
 			$this->resetClientContext();
224 224
 			throw $e;
225 225
 		}
@@ -238,9 +238,9 @@  discard block
 block discarded – undo
238 238
 
239 239
 		try {
240 240
 			$item = $this->fetchFileOrFolder($oldPath);
241
-			if($item instanceof File) {
241
+			if ($item instanceof File) {
242 242
 				$this->renameFile($item, $newPath);
243
-			} else if($item instanceof Folder) {
243
+			} else if ($item instanceof Folder) {
244 244
 				$this->renameFolder($item, $newPath);
245 245
 			} else {
246 246
 				return false;
@@ -290,7 +290,7 @@  discard block
 block discarded – undo
290 290
 			} else if ($item instanceof Folder) {
291 291
 				$this->deleteFolder($item);
292 292
 			}
293
-		} catch(\Exception $e) {
293
+		} catch (\Exception $e) {
294 294
 			$this->resetClientContext();
295 295
 			throw $e;
296 296
 		}
@@ -320,7 +320,7 @@  discard block
 block discarded – undo
320 320
 	 */
321 321
 	public function fetchFolderContents($relativeServerPath, $properties = null, Folder $folder = null) {
322 322
 		$this->ensureConnection();
323
-		if($folder === null) {
323
+		if ($folder === null) {
324 324
 			$folder = $this->context->getWeb()->getFolderByServerRelativeUrl($relativeServerPath);
325 325
 		}
326 326
 
@@ -338,20 +338,20 @@  discard block
 block discarded – undo
338 338
 	public function isHidden(ClientObject $file) {
339 339
 		// ClientObject itself does not have getListItemAllFields but is
340 340
 		// the common denominator of File and Folder
341
-		if(!$file instanceof File && !$file instanceof Folder) {
341
+		if (!$file instanceof File && !$file instanceof Folder) {
342 342
 			throw new \InvalidArgumentException('File or Folder expected');
343 343
 		}
344
-		if($file instanceof File) {
344
+		if ($file instanceof File) {
345 345
 			// it's expensive, we only check folders
346 346
 			return false;
347 347
 		}
348 348
 		$fields = $file->getListItemAllFields();
349
-		if($fields->getProperties() === []) {
349
+		if ($fields->getProperties() === []) {
350 350
 			$this->loadAndExecute($fields, ['Id', 'Hidden']);
351 351
 		}
352 352
 		$id = $fields->getProperty('Id');
353 353
 		$hidden = $fields->getProperty('Hidden'); // TODO: get someone to test this in SP 2013
354
-		if($hidden === false || $id !== null) {
354
+		if ($hidden === false || $id !== null) {
355 355
 			// avoids listing hidden "Forms" folder (and its contents).
356 356
 			// Have not found a different mechanism to detect whether
357 357
 			// a file or folder is hidden. There used to be a Hidden
@@ -371,11 +371,11 @@  discard block
 block discarded – undo
371 371
 	 * @throws NotFoundException
372 372
 	 */
373 373
 	private function getDocumentLibrary() {
374
-		if(!is_null($this->documentLibrary)) {
374
+		if (!is_null($this->documentLibrary)) {
375 375
 			return $this->documentLibrary;
376 376
 		}
377 377
 
378
-		$lists = $this->context->getWeb()->getLists()->filter('Title eq \'' . $this->documentLibraryTitle . '\'')->top(1);
378
+		$lists = $this->context->getWeb()->getLists()->filter('Title eq \''.$this->documentLibraryTitle.'\'')->top(1);
379 379
 		$this->context->load($lists)->executeQuery();
380 380
 		if ($lists->getCount() === 1 && $lists->getData()[0] instanceof SPList) {
381 381
 			$this->documentLibrary = $lists->getData()[0];
@@ -391,18 +391,18 @@  discard block
 block discarded – undo
391 391
 	 * @throws \InvalidArgumentException
392 392
 	 */
393 393
 	private function ensureConnection() {
394
-		if($this->context instanceof ClientContext) {
394
+		if ($this->context instanceof ClientContext) {
395 395
 			return;
396 396
 		}
397 397
 
398
-		if(!is_string($this->credentials['user']) || empty($this->credentials['user'])) {
398
+		if (!is_string($this->credentials['user']) || empty($this->credentials['user'])) {
399 399
 			throw new \InvalidArgumentException('No user given');
400 400
 		}
401
-		if(!is_string($this->credentials['password']) || empty($this->credentials['password'])) {
401
+		if (!is_string($this->credentials['password']) || empty($this->credentials['password'])) {
402 402
 			throw new \InvalidArgumentException('No password given');
403 403
 		}
404 404
 		$this->authContext = $this->contextsFactory->getAuthContext($this->credentials['user'], $this->credentials['password']);
405
-		$this->authContext->AuthType = CURLAUTH_NTLM;		# Basic auth does not work somehow…
405
+		$this->authContext->AuthType = CURLAUTH_NTLM; # Basic auth does not work somehow…
406 406
 		$this->context = $this->contextsFactory->getClientContext($this->sharePointUrl, $this->authContext);
407 407
 		# Auth is not triggered yet. This will happen when something is requested from SharePoint (on demand), e.g.:
408 408
 	}
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/SharePoint.php 3 patches
Doc Comments   +5 added lines, -2 removed lines patch added patch discarded remove patch
@@ -381,6 +381,9 @@  discard block
 block discarded – undo
381 381
 		return false;
382 382
 	}
383 383
 
384
+	/**
385
+	 * @param string $path
386
+	 */
384 387
 	public function writeBack($tmpFile, $path) {
385 388
 		$serverUrl = $this->formatPath($path);
386 389
 		$content = file_get_contents($tmpFile);
@@ -458,7 +461,7 @@  discard block
 block discarded – undo
458 461
 	}
459 462
 
460 463
 	/**
461
-	 * @param $serverUrl
464
+	 * @param string $serverUrl
462 465
 	 * @return ClientObjectCollection[]
463 466
 	 */
464 467
 	private function getFolderContents($serverUrl) {
@@ -490,7 +493,7 @@  discard block
 block discarded – undo
490 493
 	}
491 494
 
492 495
 	/**
493
-	 * @param $serverUrl
496
+	 * @param string $serverUrl
494 497
 	 * @return File|Folder
495 498
 	 * @throws NotFoundException
496 499
 	 */
Please login to merge, or discard this patch.
Indentation   +497 added lines, -497 removed lines patch added patch discarded remove patch
@@ -39,502 +39,502 @@
 block discarded – undo
39 39
 use Office365\PHP\Client\SharePoint\ListItem;
40 40
 
41 41
 class SharePoint extends Common {
42
-	const SP_PROPERTY_SIZE = 'Length';
43
-	const SP_PROPERTY_MTIME = 'TimeLastModified';
44
-	const SP_PROPERTY_URL = 'ServerRelativeUrl';
45
-
46
-	/** @var  string */
47
-	protected $server;
48
-
49
-	/** @var  string */
50
-	protected $documentLibrary;
51
-
52
-	/** @var  string */
53
-	protected $authUser;
54
-
55
-	/** @var  string */
56
-	protected $authPwd;
57
-
58
-	/** @var  SharePointClient */
59
-	protected $spClient;
60
-
61
-	/** @var  CappedMemoryCache */
62
-	protected $fileCache;
63
-
64
-	/** @var ContextsFactory */
65
-	private $contextsFactory;
66
-
67
-	/** @var ITempManager */
68
-	private $tempManager;
69
-
70
-	public function __construct($parameters) {
71
-		$this->server = $parameters['host'];
72
-		$this->documentLibrary = $parameters['documentLibrary'];
73
-
74
-		if(strpos($this->documentLibrary, '"') !== false) {
75
-			// they are, amongst others, not allowed and we use it in the filter
76
-			// cf. https://support.microsoft.com/en-us/kb/2933738
77
-			// TODO: verify, it talks about files and folders mostly
78
-			throw new \InvalidArgumentException('Illegal character in Document Library Name');
79
-		}
80
-
81
-		if(!isset($parameters['user']) || !isset($parameters['password'])) {
82
-			throw new \UnexpectedValueException('No user or password given');
83
-		}
84
-		$this->authUser = $parameters['user'];
85
-		$this->authPwd  = $parameters['password'];
86
-
87
-		$this->fixDI($parameters);
88
-	}
89
-
90
-	/**
91
-	 * Get the identifier for the storage,
92
-	 * the returned id should be the same for every storage object that is created with the same parameters
93
-	 * and two storage objects with the same id should refer to two storages that display the same files.
94
-	 *
95
-	 * @return string
96
-	 * @since 6.0.0
97
-	 */
98
-	public function getId() {
99
-		return 'SharePoint::' . $this->server . '::' . $this->documentLibrary . '::' . $this->authUser;
100
-	}
101
-
102
-	/**
103
-	 * see http://php.net/manual/en/function.mkdir.php
104
-	 * implementations need to implement a recursive mkdir
105
-	 *
106
-	 * @param string $path
107
-	 * @return bool
108
-	 * @since 6.0.0
109
-	 */
110
-	public function mkdir($path) {
111
-		$serverUrl = $this->formatPath($path);
112
-		try {
113
-			$folder = $this->spClient->createFolder($serverUrl);
114
-			$this->fileCache->set($serverUrl, [
115
-				'instance' => $folder,
116
-				'children' => [
117
-					'folders' => $folder->getFolders(),
118
-					'files' => $folder->getFiles()
119
-				]
120
-			]);
121
-			return true;
122
-		} catch (\Exception $e) {
123
-			$this->fileCache->remove($serverUrl);
124
-			return false;
125
-		}
126
-	}
127
-
128
-	/**
129
-	 * see http://php.net/manual/en/function.rmdir.php
130
-	 *
131
-	 * @param string $path
132
-	 * @return bool
133
-	 * @since 6.0.0
134
-	 */
135
-	public function rmdir($path) {
136
-		$serverUrl = $this->formatPath($path);
137
-		try {
138
-			$folder = $this->getFileOrFolder($serverUrl);
139
-			$this->spClient->delete($folder);
140
-			$this->fileCache->set($serverUrl, false);
141
-			return true;
142
-		} catch (\Exception $e) {
143
-			$this->fileCache->remove($serverUrl);
144
-			return false;
145
-		}
146
-	}
147
-
148
-	/**
149
-	 * see http://php.net/manual/en/function.opendir.php
150
-	 *
151
-	 * @param string $path
152
-	 * @return resource|false
153
-	 * @since 6.0.0
154
-	 */
155
-	public function opendir($path) {
156
-		try {
157
-			$serverUrl = $this->formatPath($path);
158
-			//$collections = $this->spClient->fetchFolderContents($serverUrl, ['Name', 'ListItemAllFields']);	// does not work for some reason :(
159
-			$collections = $this->getFolderContents($serverUrl);
160
-			$files = [];
161
-
162
-			foreach ($collections as $collection) {
163
-				/** @var File[]|Folder[] $items */
164
-				$items = $collection->getData();
165
-				foreach ($items as $item) {
166
-					/** @var ListItem $fields */
167
-					if(!$this->spClient->isHidden($item)) {
168
-						$files[] = $item->getProperty('Name');
169
-					}
170
-				}
171
-			}
172
-
173
-			return IteratorDirectory::wrap($files);
174
-		} catch (NotFoundException $e) {
175
-			return false;
176
-		}
177
-	}
178
-
179
-	/**
180
-	 * see http://php.net/manual/en/function.stat.php
181
-	 * only the following keys are required in the result: size and mtime
182
-	 *
183
-	 * @param string $path
184
-	 * @return array|false
185
-	 * @since 6.0.0
186
-	 */
187
-	public function stat($path) {
188
-		$serverUrl = $this->formatPath($path);
189
-		try {
190
-			$file = $this->getFileOrFolder($serverUrl);
191
-		} catch (\Exception $e) {
192
-			return false;
193
-		}
194
-
195
-		$size = $file->getProperty(self::SP_PROPERTY_SIZE) ?: FileInfo::SPACE_UNKNOWN;
196
-		$mtimeValue = $file->getProperty(self::SP_PROPERTY_MTIME);
197
-		$mtime = $mtimeValue ? new \DateTime($mtimeValue) : null;
198
-
199
-		$stat = [
200
-			// int64, size in bytes, excluding the size of any Web Parts that are used in the file.
201
-			'size'  => $size,
202
-			'mtime' => $mtime->getTimestamp(),
203
-			// no property in SP 2013 & 2016, other storages do the same  :speak_no_evil:
204
-			'atime' => time(),
205
-		];
206
-
207
-		if(!is_null($stat['mtime'])) {
208
-			return $stat;
209
-		}
210
-
211
-		// If we do not get a mtime from SP, we treat it as an error
212
-		// thus returning false, according to PHP documentation on stat()
213
-		return false;
214
-	}
215
-
216
-	/**
217
-	 * see http://php.net/manual/en/function.filetype.php
218
-	 *
219
-	 * @param string $path
220
-	 * @return false|string
221
-	 * @throws \Exception
222
-	 * @since 6.0.0
223
-	 */
224
-	public function filetype($path) {
225
-		try {
226
-			$serverUrl = $this->formatPath($path);
227
-			$object = $this->getFileOrFolder($serverUrl);
228
-		} catch (NotFoundException $e) {
229
-			return false;
230
-		}
231
-		if($object instanceof File) {
232
-			return 'file';
233
-		} else if($object instanceof Folder) {
234
-			return 'dir';
235
-		} else {
236
-			return false;
237
-		}
238
-	}
239
-
240
-	/**
241
-	 * see http://php.net/manual/en/function.file_exists.php
242
-	 *
243
-	 * @param string $path
244
-	 * @return bool
245
-	 * @since 6.0.0
246
-	 */
247
-	public function file_exists($path) {
248
-		try {
249
-			$serverUrl = $this->formatPath($path);
250
-			// alternative approach is to use a CAML query instead of querying
251
-			// for file and folder. It is not necessarily faster, though.
252
-			// Would need evaluation of typical use cases (I assume most often
253
-			// existing files are checked) and measurements.
254
-			$this->getFileOrFolder($serverUrl);
255
-			return true;
256
-		} catch (NotFoundException $e) {
257
-			return false;
258
-		}
259
-	}
260
-
261
-	/**
262
-	 * see http://php.net/manual/en/function.unlink.php
263
-	 *
264
-	 * @param string $path
265
-	 * @return bool
266
-	 * @since 6.0.0
267
-	 */
268
-	public function unlink($path) {
269
-		// file methods get called twice at least, returning true
270
-		if(!$this->file_exists($path)) {
271
-			return true;
272
-		}
273
-		try {
274
-			$serverUrl = $this->formatPath($path);
275
-			$this->spClient->delete($this->getFileOrFolder($serverUrl));
276
-			$this->fileCache->set($serverUrl, false);
277
-			return true;
278
-		} catch (\Exception $e) {
279
-			return false;
280
-		}
281
-	}
282
-
283
-	public function rename($path1, $path2) {
284
-		$oldPath = $this->formatPath($path1);
285
-		$newPath = $this->formatPath($path2);
286
-
287
-		try {
288
-			$item = $this->getFileOrFolder($newPath);
289
-			$this->spClient->delete($item);
290
-			$this->fileCache->remove($newPath);
291
-		} catch(NotFoundException $e) {
292
-			// noop
293
-		}
294
-
295
-		try {
296
-			$isRenamed = $this->spClient->rename($oldPath, $newPath);
297
-			if($isRenamed) {
298
-				$entry = $this->fileCache->get($oldPath);
299
-				$this->fileCache->remove($newPath);
300
-				if($entry !== false) {
301
-					$this->fileCache->set($newPath, $entry);
302
-				}
303
-				$this->fileCache->remove($oldPath);
304
-			}
305
-			return $isRenamed;
306
-		} catch (\Exception $e) {
307
-			return false;
308
-		}
309
-	}
310
-
311
-	/**
312
-	 * see http://php.net/manual/en/function.fopen.php
313
-	 *
314
-	 * @param string $path
315
-	 * @param string $mode
316
-	 * @return resource|false
317
-	 * @since 6.0.0
318
-	 */
319
-	public function fopen($path, $mode) {
320
-		$serverUrl = $this->formatPath($path);
321
-
322
-		switch ($mode) {
323
-			case 'a':
324
-			case 'ab':
325
-			case 'a+':
326
-				// no native support
327
-				return false;
328
-			case 'r':
329
-			case 'rb':
330
-				$tmpFile = $this->tempManager->getTemporaryFile();
331
-
332
-				$fp = fopen($tmpFile, 'w+');
333
-				if(!$this->spClient->getFileViaStream($serverUrl, $fp)) {
334
-					fclose($fp);
335
-					return false;
336
-				}
337
-				fseek($fp, 0);
338
-				return $fp;
339
-				break;
340
-			case 'r+':
341
-			case 'rb+':
342
-			case 'r+b':
343
-				// fseek 0
344
-			case 'w':
345
-			case 'w+':
346
-			case 'wb':
347
-			case 'wb+':
348
-			case 'w+b':
349
-				// truncate
350
-				// fseek 0
351
-			case 'x':
352
-			case 'x+':
353
-			case 'xb':
354
-			case 'xb+':
355
-			case 'x+b':
356
-				// fseek 0
357
-			case 'c':
358
-			case 'cb':
359
-			case 'c+':
360
-			case 'cb+':
361
-			case 'c+b':
362
-				//fseek 0
363
-				if($mode[0] === 'x' && $this->file_exists($path)) {
364
-					return false;
365
-				}
366
-				$tmpFile = $this->tempManager->getTemporaryFile();
367
-				if($mode[0] !== 'w' && $this->file_exists($path)) {
368
-					$content = $this->fopen($path, 'r');
369
-					if($content === false) {
370
-						// should not happen, but let's be safe
371
-						return false;
372
-					}
373
-					$this->file_put_contents($tmpFile, $content);
374
-				}
375
-				$fp = fopen($tmpFile, $mode);
376
-				return CallbackWrapper::wrap($fp, null, null, function () use ($path, $tmpFile) {
377
-					$this->writeBack($tmpFile, $path);
378
-				});
379
-
380
-		}
381
-		return false;
382
-	}
383
-
384
-	public function writeBack($tmpFile, $path) {
385
-		$serverUrl = $this->formatPath($path);
386
-		$content = file_get_contents($tmpFile);
387
-		$fp = fopen($tmpFile, 'r');
388
-
389
-		try {
390
-			if ($this->file_exists($path)) {
391
-				$this->spClient->overwriteFileViaStream($serverUrl, $fp, $tmpFile);
392
-				fclose($fp);
393
-				$this->fileCache->remove($serverUrl);
394
-			} else {
395
-				$file = $this->spClient->uploadNewFile($serverUrl, $content);
396
-				$this->fileCache->set($serverUrl, ['instance' => $file]);
397
-			}
398
-		} catch (\Exception $e) {
399
-			return false;
400
-		}
401
-	}
402
-
403
-	/**
404
-	 * see http://php.net/manual/en/function.touch.php
405
-	 * If the backend does not support the operation, false should be returned
406
-	 *
407
-	 * @param string $path
408
-	 * @param int $mtime
409
-	 * @return bool
410
-	 * @since 6.0.0
411
-	 */
412
-	public function touch($path, $mtime = null) {
413
-		// TODO: Implement touch() method.
414
-		return true;
415
-	}
416
-
417
-
418
-	/**
419
-	 * work around dependency injection issues so we can test this class properly
420
-	 *
421
-	 * @param array $parameters
422
-	 */
423
-	private function fixDI(array $parameters) {
424
-		if(isset($parameters['contextFactory'])
425
-			&& $parameters['contextFactory'] instanceof ContextsFactory)
426
-		{
427
-			$this->contextsFactory = $parameters['contextFactory'];
428
-		} else {
429
-			$this->contextsFactory = new ContextsFactory();
430
-		}
431
-
432
-		if(isset($parameters['sharePointClientFactory'])
433
-			&& $parameters['sharePointClientFactory'] instanceof SharePointClientFactory)
434
-		{
435
-			$spcFactory = $parameters['sharePointClientFactory'];
436
-		} else {
437
-			$spcFactory = new SharePointClientFactory();
438
-		}
439
-		$this->spClient = $spcFactory->getClient(
440
-			$this->contextsFactory,
441
-			$this->server,
442
-			[ 'user' => $this->authUser, 'password' => $this->authPwd],
443
-			$this->documentLibrary
444
-		);
445
-
446
-		if(isset($parameters['cappedMemoryCache'])) {
447
-			$this->fileCache = $parameters['cappedMemoryCache'];
448
-		} else {
449
-			// there's no API to get such
450
-			$this->fileCache = new CappedMemoryCache();
451
-		}
452
-
453
-		if(isset($parameters['tempManager'])) {
454
-			$this->tempManager = $parameters['tempManager'];
455
-		} else {
456
-			$this->tempManager = \OC::$server->getTempManager();
457
-		}
458
-	}
459
-
460
-	/**
461
-	 * @param $serverUrl
462
-	 * @return ClientObjectCollection[]
463
-	 */
464
-	private function getFolderContents($serverUrl) {
465
-		$entry = $this->fileCache->get($serverUrl);
466
-		if($entry === null || !isset($entry['children'])) {
467
-			$folder = isset($entry['instance']) ? $entry['instance'] : null;
468
-			$contents = $this->spClient->fetchFolderContents($serverUrl, null, $folder);
469
-			$cacheItem = $entry ?: [];
470
-			$cacheItem['children'] = $contents;
471
-			$this->fileCache->set($serverUrl, $cacheItem);
472
-
473
-			// cache children instances
474
-			foreach ($contents as $collection) {
475
-				foreach ($collection->getData() as $item) {
476
-					/** @var  File|Folder $item */
477
-					$url = $item->getProperty(self::SP_PROPERTY_URL);
478
-					$itemEntry = $this->fileCache->get($url);
479
-					$itemEntry = $itemEntry ?: [];
480
-					if(!isset($itemEntry['instance'])) {
481
-						$itemEntry['instance'] = $item;
482
-						$this->fileCache->set($url, $itemEntry);
483
-					}
484
-				}
485
-			}
486
-		} else {
487
-			$contents = $entry['children'];
488
-		}
489
-		return $contents;
490
-	}
491
-
492
-	/**
493
-	 * @param $serverUrl
494
-	 * @return File|Folder
495
-	 * @throws NotFoundException
496
-	 */
497
-	private function getFileOrFolder($serverUrl) {
498
-		$entry = $this->fileCache->get($serverUrl);
499
-		if($entry === false) {
500
-			throw new NotFoundException('File or Folder not found');
501
-		} else if($entry === null || !isset($entry['instance'])) {
502
-			try {
503
-				$file = $this->spClient->fetchFileOrFolder($serverUrl, [self::SP_PROPERTY_SIZE, self::SP_PROPERTY_MTIME]);
504
-			} catch (NotFoundException $e) {
505
-				$this->fileCache->set($serverUrl, false);
506
-				throw $e;
507
-			}
508
-			$cacheItem = $entry ?: [];
509
-			$cacheItem['instance'] = $file;
510
-			$this->fileCache->set($serverUrl, $cacheItem);
511
-		} else {
512
-			$file = $entry['instance'];
513
-		}
514
-		return $file;
515
-	}
516
-
517
-	/**
518
-	 * creates the relative server "url" out of the provided path
519
-	 *
520
-	 * @param $path
521
-	 * @return string
522
-	 */
523
-	private function formatPath($path) {
524
-		$path = trim($path, '/');
525
-		$serverUrl = '/' . $this->documentLibrary;
526
-		if($path !== '') {
527
-			$serverUrl .= '/' . $path;
528
-		}
529
-
530
-		$pathParts = explode('/', $serverUrl);
531
-		$filename = array_pop($pathParts);
532
-		if($filename === '.') {
533
-			// remove /. from the end of the path
534
-			$serverUrl = mb_substr($serverUrl, 0, mb_strlen($serverUrl) - 2);
535
-		}
536
-
537
-		return $serverUrl;
538
-	}
42
+    const SP_PROPERTY_SIZE = 'Length';
43
+    const SP_PROPERTY_MTIME = 'TimeLastModified';
44
+    const SP_PROPERTY_URL = 'ServerRelativeUrl';
45
+
46
+    /** @var  string */
47
+    protected $server;
48
+
49
+    /** @var  string */
50
+    protected $documentLibrary;
51
+
52
+    /** @var  string */
53
+    protected $authUser;
54
+
55
+    /** @var  string */
56
+    protected $authPwd;
57
+
58
+    /** @var  SharePointClient */
59
+    protected $spClient;
60
+
61
+    /** @var  CappedMemoryCache */
62
+    protected $fileCache;
63
+
64
+    /** @var ContextsFactory */
65
+    private $contextsFactory;
66
+
67
+    /** @var ITempManager */
68
+    private $tempManager;
69
+
70
+    public function __construct($parameters) {
71
+        $this->server = $parameters['host'];
72
+        $this->documentLibrary = $parameters['documentLibrary'];
73
+
74
+        if(strpos($this->documentLibrary, '"') !== false) {
75
+            // they are, amongst others, not allowed and we use it in the filter
76
+            // cf. https://support.microsoft.com/en-us/kb/2933738
77
+            // TODO: verify, it talks about files and folders mostly
78
+            throw new \InvalidArgumentException('Illegal character in Document Library Name');
79
+        }
80
+
81
+        if(!isset($parameters['user']) || !isset($parameters['password'])) {
82
+            throw new \UnexpectedValueException('No user or password given');
83
+        }
84
+        $this->authUser = $parameters['user'];
85
+        $this->authPwd  = $parameters['password'];
86
+
87
+        $this->fixDI($parameters);
88
+    }
89
+
90
+    /**
91
+     * Get the identifier for the storage,
92
+     * the returned id should be the same for every storage object that is created with the same parameters
93
+     * and two storage objects with the same id should refer to two storages that display the same files.
94
+     *
95
+     * @return string
96
+     * @since 6.0.0
97
+     */
98
+    public function getId() {
99
+        return 'SharePoint::' . $this->server . '::' . $this->documentLibrary . '::' . $this->authUser;
100
+    }
101
+
102
+    /**
103
+     * see http://php.net/manual/en/function.mkdir.php
104
+     * implementations need to implement a recursive mkdir
105
+     *
106
+     * @param string $path
107
+     * @return bool
108
+     * @since 6.0.0
109
+     */
110
+    public function mkdir($path) {
111
+        $serverUrl = $this->formatPath($path);
112
+        try {
113
+            $folder = $this->spClient->createFolder($serverUrl);
114
+            $this->fileCache->set($serverUrl, [
115
+                'instance' => $folder,
116
+                'children' => [
117
+                    'folders' => $folder->getFolders(),
118
+                    'files' => $folder->getFiles()
119
+                ]
120
+            ]);
121
+            return true;
122
+        } catch (\Exception $e) {
123
+            $this->fileCache->remove($serverUrl);
124
+            return false;
125
+        }
126
+    }
127
+
128
+    /**
129
+     * see http://php.net/manual/en/function.rmdir.php
130
+     *
131
+     * @param string $path
132
+     * @return bool
133
+     * @since 6.0.0
134
+     */
135
+    public function rmdir($path) {
136
+        $serverUrl = $this->formatPath($path);
137
+        try {
138
+            $folder = $this->getFileOrFolder($serverUrl);
139
+            $this->spClient->delete($folder);
140
+            $this->fileCache->set($serverUrl, false);
141
+            return true;
142
+        } catch (\Exception $e) {
143
+            $this->fileCache->remove($serverUrl);
144
+            return false;
145
+        }
146
+    }
147
+
148
+    /**
149
+     * see http://php.net/manual/en/function.opendir.php
150
+     *
151
+     * @param string $path
152
+     * @return resource|false
153
+     * @since 6.0.0
154
+     */
155
+    public function opendir($path) {
156
+        try {
157
+            $serverUrl = $this->formatPath($path);
158
+            //$collections = $this->spClient->fetchFolderContents($serverUrl, ['Name', 'ListItemAllFields']);	// does not work for some reason :(
159
+            $collections = $this->getFolderContents($serverUrl);
160
+            $files = [];
161
+
162
+            foreach ($collections as $collection) {
163
+                /** @var File[]|Folder[] $items */
164
+                $items = $collection->getData();
165
+                foreach ($items as $item) {
166
+                    /** @var ListItem $fields */
167
+                    if(!$this->spClient->isHidden($item)) {
168
+                        $files[] = $item->getProperty('Name');
169
+                    }
170
+                }
171
+            }
172
+
173
+            return IteratorDirectory::wrap($files);
174
+        } catch (NotFoundException $e) {
175
+            return false;
176
+        }
177
+    }
178
+
179
+    /**
180
+     * see http://php.net/manual/en/function.stat.php
181
+     * only the following keys are required in the result: size and mtime
182
+     *
183
+     * @param string $path
184
+     * @return array|false
185
+     * @since 6.0.0
186
+     */
187
+    public function stat($path) {
188
+        $serverUrl = $this->formatPath($path);
189
+        try {
190
+            $file = $this->getFileOrFolder($serverUrl);
191
+        } catch (\Exception $e) {
192
+            return false;
193
+        }
194
+
195
+        $size = $file->getProperty(self::SP_PROPERTY_SIZE) ?: FileInfo::SPACE_UNKNOWN;
196
+        $mtimeValue = $file->getProperty(self::SP_PROPERTY_MTIME);
197
+        $mtime = $mtimeValue ? new \DateTime($mtimeValue) : null;
198
+
199
+        $stat = [
200
+            // int64, size in bytes, excluding the size of any Web Parts that are used in the file.
201
+            'size'  => $size,
202
+            'mtime' => $mtime->getTimestamp(),
203
+            // no property in SP 2013 & 2016, other storages do the same  :speak_no_evil:
204
+            'atime' => time(),
205
+        ];
206
+
207
+        if(!is_null($stat['mtime'])) {
208
+            return $stat;
209
+        }
210
+
211
+        // If we do not get a mtime from SP, we treat it as an error
212
+        // thus returning false, according to PHP documentation on stat()
213
+        return false;
214
+    }
215
+
216
+    /**
217
+     * see http://php.net/manual/en/function.filetype.php
218
+     *
219
+     * @param string $path
220
+     * @return false|string
221
+     * @throws \Exception
222
+     * @since 6.0.0
223
+     */
224
+    public function filetype($path) {
225
+        try {
226
+            $serverUrl = $this->formatPath($path);
227
+            $object = $this->getFileOrFolder($serverUrl);
228
+        } catch (NotFoundException $e) {
229
+            return false;
230
+        }
231
+        if($object instanceof File) {
232
+            return 'file';
233
+        } else if($object instanceof Folder) {
234
+            return 'dir';
235
+        } else {
236
+            return false;
237
+        }
238
+    }
239
+
240
+    /**
241
+     * see http://php.net/manual/en/function.file_exists.php
242
+     *
243
+     * @param string $path
244
+     * @return bool
245
+     * @since 6.0.0
246
+     */
247
+    public function file_exists($path) {
248
+        try {
249
+            $serverUrl = $this->formatPath($path);
250
+            // alternative approach is to use a CAML query instead of querying
251
+            // for file and folder. It is not necessarily faster, though.
252
+            // Would need evaluation of typical use cases (I assume most often
253
+            // existing files are checked) and measurements.
254
+            $this->getFileOrFolder($serverUrl);
255
+            return true;
256
+        } catch (NotFoundException $e) {
257
+            return false;
258
+        }
259
+    }
260
+
261
+    /**
262
+     * see http://php.net/manual/en/function.unlink.php
263
+     *
264
+     * @param string $path
265
+     * @return bool
266
+     * @since 6.0.0
267
+     */
268
+    public function unlink($path) {
269
+        // file methods get called twice at least, returning true
270
+        if(!$this->file_exists($path)) {
271
+            return true;
272
+        }
273
+        try {
274
+            $serverUrl = $this->formatPath($path);
275
+            $this->spClient->delete($this->getFileOrFolder($serverUrl));
276
+            $this->fileCache->set($serverUrl, false);
277
+            return true;
278
+        } catch (\Exception $e) {
279
+            return false;
280
+        }
281
+    }
282
+
283
+    public function rename($path1, $path2) {
284
+        $oldPath = $this->formatPath($path1);
285
+        $newPath = $this->formatPath($path2);
286
+
287
+        try {
288
+            $item = $this->getFileOrFolder($newPath);
289
+            $this->spClient->delete($item);
290
+            $this->fileCache->remove($newPath);
291
+        } catch(NotFoundException $e) {
292
+            // noop
293
+        }
294
+
295
+        try {
296
+            $isRenamed = $this->spClient->rename($oldPath, $newPath);
297
+            if($isRenamed) {
298
+                $entry = $this->fileCache->get($oldPath);
299
+                $this->fileCache->remove($newPath);
300
+                if($entry !== false) {
301
+                    $this->fileCache->set($newPath, $entry);
302
+                }
303
+                $this->fileCache->remove($oldPath);
304
+            }
305
+            return $isRenamed;
306
+        } catch (\Exception $e) {
307
+            return false;
308
+        }
309
+    }
310
+
311
+    /**
312
+     * see http://php.net/manual/en/function.fopen.php
313
+     *
314
+     * @param string $path
315
+     * @param string $mode
316
+     * @return resource|false
317
+     * @since 6.0.0
318
+     */
319
+    public function fopen($path, $mode) {
320
+        $serverUrl = $this->formatPath($path);
321
+
322
+        switch ($mode) {
323
+            case 'a':
324
+            case 'ab':
325
+            case 'a+':
326
+                // no native support
327
+                return false;
328
+            case 'r':
329
+            case 'rb':
330
+                $tmpFile = $this->tempManager->getTemporaryFile();
331
+
332
+                $fp = fopen($tmpFile, 'w+');
333
+                if(!$this->spClient->getFileViaStream($serverUrl, $fp)) {
334
+                    fclose($fp);
335
+                    return false;
336
+                }
337
+                fseek($fp, 0);
338
+                return $fp;
339
+                break;
340
+            case 'r+':
341
+            case 'rb+':
342
+            case 'r+b':
343
+                // fseek 0
344
+            case 'w':
345
+            case 'w+':
346
+            case 'wb':
347
+            case 'wb+':
348
+            case 'w+b':
349
+                // truncate
350
+                // fseek 0
351
+            case 'x':
352
+            case 'x+':
353
+            case 'xb':
354
+            case 'xb+':
355
+            case 'x+b':
356
+                // fseek 0
357
+            case 'c':
358
+            case 'cb':
359
+            case 'c+':
360
+            case 'cb+':
361
+            case 'c+b':
362
+                //fseek 0
363
+                if($mode[0] === 'x' && $this->file_exists($path)) {
364
+                    return false;
365
+                }
366
+                $tmpFile = $this->tempManager->getTemporaryFile();
367
+                if($mode[0] !== 'w' && $this->file_exists($path)) {
368
+                    $content = $this->fopen($path, 'r');
369
+                    if($content === false) {
370
+                        // should not happen, but let's be safe
371
+                        return false;
372
+                    }
373
+                    $this->file_put_contents($tmpFile, $content);
374
+                }
375
+                $fp = fopen($tmpFile, $mode);
376
+                return CallbackWrapper::wrap($fp, null, null, function () use ($path, $tmpFile) {
377
+                    $this->writeBack($tmpFile, $path);
378
+                });
379
+
380
+        }
381
+        return false;
382
+    }
383
+
384
+    public function writeBack($tmpFile, $path) {
385
+        $serverUrl = $this->formatPath($path);
386
+        $content = file_get_contents($tmpFile);
387
+        $fp = fopen($tmpFile, 'r');
388
+
389
+        try {
390
+            if ($this->file_exists($path)) {
391
+                $this->spClient->overwriteFileViaStream($serverUrl, $fp, $tmpFile);
392
+                fclose($fp);
393
+                $this->fileCache->remove($serverUrl);
394
+            } else {
395
+                $file = $this->spClient->uploadNewFile($serverUrl, $content);
396
+                $this->fileCache->set($serverUrl, ['instance' => $file]);
397
+            }
398
+        } catch (\Exception $e) {
399
+            return false;
400
+        }
401
+    }
402
+
403
+    /**
404
+     * see http://php.net/manual/en/function.touch.php
405
+     * If the backend does not support the operation, false should be returned
406
+     *
407
+     * @param string $path
408
+     * @param int $mtime
409
+     * @return bool
410
+     * @since 6.0.0
411
+     */
412
+    public function touch($path, $mtime = null) {
413
+        // TODO: Implement touch() method.
414
+        return true;
415
+    }
416
+
417
+
418
+    /**
419
+     * work around dependency injection issues so we can test this class properly
420
+     *
421
+     * @param array $parameters
422
+     */
423
+    private function fixDI(array $parameters) {
424
+        if(isset($parameters['contextFactory'])
425
+            && $parameters['contextFactory'] instanceof ContextsFactory)
426
+        {
427
+            $this->contextsFactory = $parameters['contextFactory'];
428
+        } else {
429
+            $this->contextsFactory = new ContextsFactory();
430
+        }
431
+
432
+        if(isset($parameters['sharePointClientFactory'])
433
+            && $parameters['sharePointClientFactory'] instanceof SharePointClientFactory)
434
+        {
435
+            $spcFactory = $parameters['sharePointClientFactory'];
436
+        } else {
437
+            $spcFactory = new SharePointClientFactory();
438
+        }
439
+        $this->spClient = $spcFactory->getClient(
440
+            $this->contextsFactory,
441
+            $this->server,
442
+            [ 'user' => $this->authUser, 'password' => $this->authPwd],
443
+            $this->documentLibrary
444
+        );
445
+
446
+        if(isset($parameters['cappedMemoryCache'])) {
447
+            $this->fileCache = $parameters['cappedMemoryCache'];
448
+        } else {
449
+            // there's no API to get such
450
+            $this->fileCache = new CappedMemoryCache();
451
+        }
452
+
453
+        if(isset($parameters['tempManager'])) {
454
+            $this->tempManager = $parameters['tempManager'];
455
+        } else {
456
+            $this->tempManager = \OC::$server->getTempManager();
457
+        }
458
+    }
459
+
460
+    /**
461
+     * @param $serverUrl
462
+     * @return ClientObjectCollection[]
463
+     */
464
+    private function getFolderContents($serverUrl) {
465
+        $entry = $this->fileCache->get($serverUrl);
466
+        if($entry === null || !isset($entry['children'])) {
467
+            $folder = isset($entry['instance']) ? $entry['instance'] : null;
468
+            $contents = $this->spClient->fetchFolderContents($serverUrl, null, $folder);
469
+            $cacheItem = $entry ?: [];
470
+            $cacheItem['children'] = $contents;
471
+            $this->fileCache->set($serverUrl, $cacheItem);
472
+
473
+            // cache children instances
474
+            foreach ($contents as $collection) {
475
+                foreach ($collection->getData() as $item) {
476
+                    /** @var  File|Folder $item */
477
+                    $url = $item->getProperty(self::SP_PROPERTY_URL);
478
+                    $itemEntry = $this->fileCache->get($url);
479
+                    $itemEntry = $itemEntry ?: [];
480
+                    if(!isset($itemEntry['instance'])) {
481
+                        $itemEntry['instance'] = $item;
482
+                        $this->fileCache->set($url, $itemEntry);
483
+                    }
484
+                }
485
+            }
486
+        } else {
487
+            $contents = $entry['children'];
488
+        }
489
+        return $contents;
490
+    }
491
+
492
+    /**
493
+     * @param $serverUrl
494
+     * @return File|Folder
495
+     * @throws NotFoundException
496
+     */
497
+    private function getFileOrFolder($serverUrl) {
498
+        $entry = $this->fileCache->get($serverUrl);
499
+        if($entry === false) {
500
+            throw new NotFoundException('File or Folder not found');
501
+        } else if($entry === null || !isset($entry['instance'])) {
502
+            try {
503
+                $file = $this->spClient->fetchFileOrFolder($serverUrl, [self::SP_PROPERTY_SIZE, self::SP_PROPERTY_MTIME]);
504
+            } catch (NotFoundException $e) {
505
+                $this->fileCache->set($serverUrl, false);
506
+                throw $e;
507
+            }
508
+            $cacheItem = $entry ?: [];
509
+            $cacheItem['instance'] = $file;
510
+            $this->fileCache->set($serverUrl, $cacheItem);
511
+        } else {
512
+            $file = $entry['instance'];
513
+        }
514
+        return $file;
515
+    }
516
+
517
+    /**
518
+     * creates the relative server "url" out of the provided path
519
+     *
520
+     * @param $path
521
+     * @return string
522
+     */
523
+    private function formatPath($path) {
524
+        $path = trim($path, '/');
525
+        $serverUrl = '/' . $this->documentLibrary;
526
+        if($path !== '') {
527
+            $serverUrl .= '/' . $path;
528
+        }
529
+
530
+        $pathParts = explode('/', $serverUrl);
531
+        $filename = array_pop($pathParts);
532
+        if($filename === '.') {
533
+            // remove /. from the end of the path
534
+            $serverUrl = mb_substr($serverUrl, 0, mb_strlen($serverUrl) - 2);
535
+        }
536
+
537
+        return $serverUrl;
538
+    }
539 539
 
540 540
 }
Please login to merge, or discard this patch.
Spacing   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -71,14 +71,14 @@  discard block
 block discarded – undo
71 71
 		$this->server = $parameters['host'];
72 72
 		$this->documentLibrary = $parameters['documentLibrary'];
73 73
 
74
-		if(strpos($this->documentLibrary, '"') !== false) {
74
+		if (strpos($this->documentLibrary, '"') !== false) {
75 75
 			// they are, amongst others, not allowed and we use it in the filter
76 76
 			// cf. https://support.microsoft.com/en-us/kb/2933738
77 77
 			// TODO: verify, it talks about files and folders mostly
78 78
 			throw new \InvalidArgumentException('Illegal character in Document Library Name');
79 79
 		}
80 80
 
81
-		if(!isset($parameters['user']) || !isset($parameters['password'])) {
81
+		if (!isset($parameters['user']) || !isset($parameters['password'])) {
82 82
 			throw new \UnexpectedValueException('No user or password given');
83 83
 		}
84 84
 		$this->authUser = $parameters['user'];
@@ -96,7 +96,7 @@  discard block
 block discarded – undo
96 96
 	 * @since 6.0.0
97 97
 	 */
98 98
 	public function getId() {
99
-		return 'SharePoint::' . $this->server . '::' . $this->documentLibrary . '::' . $this->authUser;
99
+		return 'SharePoint::'.$this->server.'::'.$this->documentLibrary.'::'.$this->authUser;
100 100
 	}
101 101
 
102 102
 	/**
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
 				$items = $collection->getData();
165 165
 				foreach ($items as $item) {
166 166
 					/** @var ListItem $fields */
167
-					if(!$this->spClient->isHidden($item)) {
167
+					if (!$this->spClient->isHidden($item)) {
168 168
 						$files[] = $item->getProperty('Name');
169 169
 					}
170 170
 				}
@@ -204,7 +204,7 @@  discard block
 block discarded – undo
204 204
 			'atime' => time(),
205 205
 		];
206 206
 
207
-		if(!is_null($stat['mtime'])) {
207
+		if (!is_null($stat['mtime'])) {
208 208
 			return $stat;
209 209
 		}
210 210
 
@@ -228,9 +228,9 @@  discard block
 block discarded – undo
228 228
 		} catch (NotFoundException $e) {
229 229
 			return false;
230 230
 		}
231
-		if($object instanceof File) {
231
+		if ($object instanceof File) {
232 232
 			return 'file';
233
-		} else if($object instanceof Folder) {
233
+		} else if ($object instanceof Folder) {
234 234
 			return 'dir';
235 235
 		} else {
236 236
 			return false;
@@ -267,7 +267,7 @@  discard block
 block discarded – undo
267 267
 	 */
268 268
 	public function unlink($path) {
269 269
 		// file methods get called twice at least, returning true
270
-		if(!$this->file_exists($path)) {
270
+		if (!$this->file_exists($path)) {
271 271
 			return true;
272 272
 		}
273 273
 		try {
@@ -288,16 +288,16 @@  discard block
 block discarded – undo
288 288
 			$item = $this->getFileOrFolder($newPath);
289 289
 			$this->spClient->delete($item);
290 290
 			$this->fileCache->remove($newPath);
291
-		} catch(NotFoundException $e) {
291
+		} catch (NotFoundException $e) {
292 292
 			// noop
293 293
 		}
294 294
 
295 295
 		try {
296 296
 			$isRenamed = $this->spClient->rename($oldPath, $newPath);
297
-			if($isRenamed) {
297
+			if ($isRenamed) {
298 298
 				$entry = $this->fileCache->get($oldPath);
299 299
 				$this->fileCache->remove($newPath);
300
-				if($entry !== false) {
300
+				if ($entry !== false) {
301 301
 					$this->fileCache->set($newPath, $entry);
302 302
 				}
303 303
 				$this->fileCache->remove($oldPath);
@@ -330,7 +330,7 @@  discard block
 block discarded – undo
330 330
 				$tmpFile = $this->tempManager->getTemporaryFile();
331 331
 
332 332
 				$fp = fopen($tmpFile, 'w+');
333
-				if(!$this->spClient->getFileViaStream($serverUrl, $fp)) {
333
+				if (!$this->spClient->getFileViaStream($serverUrl, $fp)) {
334 334
 					fclose($fp);
335 335
 					return false;
336 336
 				}
@@ -360,20 +360,20 @@  discard block
 block discarded – undo
360 360
 			case 'cb+':
361 361
 			case 'c+b':
362 362
 				//fseek 0
363
-				if($mode[0] === 'x' && $this->file_exists($path)) {
363
+				if ($mode[0] === 'x' && $this->file_exists($path)) {
364 364
 					return false;
365 365
 				}
366 366
 				$tmpFile = $this->tempManager->getTemporaryFile();
367
-				if($mode[0] !== 'w' && $this->file_exists($path)) {
367
+				if ($mode[0] !== 'w' && $this->file_exists($path)) {
368 368
 					$content = $this->fopen($path, 'r');
369
-					if($content === false) {
369
+					if ($content === false) {
370 370
 						// should not happen, but let's be safe
371 371
 						return false;
372 372
 					}
373 373
 					$this->file_put_contents($tmpFile, $content);
374 374
 				}
375 375
 				$fp = fopen($tmpFile, $mode);
376
-				return CallbackWrapper::wrap($fp, null, null, function () use ($path, $tmpFile) {
376
+				return CallbackWrapper::wrap($fp, null, null, function() use ($path, $tmpFile) {
377 377
 					$this->writeBack($tmpFile, $path);
378 378
 				});
379 379
 
@@ -421,7 +421,7 @@  discard block
 block discarded – undo
421 421
 	 * @param array $parameters
422 422
 	 */
423 423
 	private function fixDI(array $parameters) {
424
-		if(isset($parameters['contextFactory'])
424
+		if (isset($parameters['contextFactory'])
425 425
 			&& $parameters['contextFactory'] instanceof ContextsFactory)
426 426
 		{
427 427
 			$this->contextsFactory = $parameters['contextFactory'];
@@ -429,7 +429,7 @@  discard block
 block discarded – undo
429 429
 			$this->contextsFactory = new ContextsFactory();
430 430
 		}
431 431
 
432
-		if(isset($parameters['sharePointClientFactory'])
432
+		if (isset($parameters['sharePointClientFactory'])
433 433
 			&& $parameters['sharePointClientFactory'] instanceof SharePointClientFactory)
434 434
 		{
435 435
 			$spcFactory = $parameters['sharePointClientFactory'];
@@ -439,18 +439,18 @@  discard block
 block discarded – undo
439 439
 		$this->spClient = $spcFactory->getClient(
440 440
 			$this->contextsFactory,
441 441
 			$this->server,
442
-			[ 'user' => $this->authUser, 'password' => $this->authPwd],
442
+			['user' => $this->authUser, 'password' => $this->authPwd],
443 443
 			$this->documentLibrary
444 444
 		);
445 445
 
446
-		if(isset($parameters['cappedMemoryCache'])) {
446
+		if (isset($parameters['cappedMemoryCache'])) {
447 447
 			$this->fileCache = $parameters['cappedMemoryCache'];
448 448
 		} else {
449 449
 			// there's no API to get such
450 450
 			$this->fileCache = new CappedMemoryCache();
451 451
 		}
452 452
 
453
-		if(isset($parameters['tempManager'])) {
453
+		if (isset($parameters['tempManager'])) {
454 454
 			$this->tempManager = $parameters['tempManager'];
455 455
 		} else {
456 456
 			$this->tempManager = \OC::$server->getTempManager();
@@ -463,7 +463,7 @@  discard block
 block discarded – undo
463 463
 	 */
464 464
 	private function getFolderContents($serverUrl) {
465 465
 		$entry = $this->fileCache->get($serverUrl);
466
-		if($entry === null || !isset($entry['children'])) {
466
+		if ($entry === null || !isset($entry['children'])) {
467 467
 			$folder = isset($entry['instance']) ? $entry['instance'] : null;
468 468
 			$contents = $this->spClient->fetchFolderContents($serverUrl, null, $folder);
469 469
 			$cacheItem = $entry ?: [];
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
 					$url = $item->getProperty(self::SP_PROPERTY_URL);
478 478
 					$itemEntry = $this->fileCache->get($url);
479 479
 					$itemEntry = $itemEntry ?: [];
480
-					if(!isset($itemEntry['instance'])) {
480
+					if (!isset($itemEntry['instance'])) {
481 481
 						$itemEntry['instance'] = $item;
482 482
 						$this->fileCache->set($url, $itemEntry);
483 483
 					}
@@ -496,9 +496,9 @@  discard block
 block discarded – undo
496 496
 	 */
497 497
 	private function getFileOrFolder($serverUrl) {
498 498
 		$entry = $this->fileCache->get($serverUrl);
499
-		if($entry === false) {
499
+		if ($entry === false) {
500 500
 			throw new NotFoundException('File or Folder not found');
501
-		} else if($entry === null || !isset($entry['instance'])) {
501
+		} else if ($entry === null || !isset($entry['instance'])) {
502 502
 			try {
503 503
 				$file = $this->spClient->fetchFileOrFolder($serverUrl, [self::SP_PROPERTY_SIZE, self::SP_PROPERTY_MTIME]);
504 504
 			} catch (NotFoundException $e) {
@@ -522,14 +522,14 @@  discard block
 block discarded – undo
522 522
 	 */
523 523
 	private function formatPath($path) {
524 524
 		$path = trim($path, '/');
525
-		$serverUrl = '/' . $this->documentLibrary;
526
-		if($path !== '') {
527
-			$serverUrl .= '/' . $path;
525
+		$serverUrl = '/'.$this->documentLibrary;
526
+		if ($path !== '') {
527
+			$serverUrl .= '/'.$path;
528 528
 		}
529 529
 
530 530
 		$pathParts = explode('/', $serverUrl);
531 531
 		$filename = array_pop($pathParts);
532
-		if($filename === '.') {
532
+		if ($filename === '.') {
533 533
 			// remove /. from the end of the path
534 534
 			$serverUrl = mb_substr($serverUrl, 0, mb_strlen($serverUrl) - 2);
535 535
 		}
Please login to merge, or discard this patch.